all: basic support for the os package

The resulting binary is pretty big due to lacking optimizations
(probably because of interfaces), so that should be fixed.
Этот коммит содержится в:
Ayke van Laethem 2018-09-15 18:54:36 +02:00
родитель c237633d34
коммит 1484bb5c2c
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: E97FF5335DFDFDED
6 изменённых файлов: 141 добавлений и 3 удалений

Просмотреть файл

@ -22,6 +22,7 @@ var ignoreInitCalls = map[string]struct{}{
"(syscall/js.Value).Get": struct{}{},
"(syscall/js.Value).New": struct{}{},
"(syscall/js.Value).Int": struct{}{},
"os.init$1": struct{}{},
}
// Interpret instructions as far as possible, and drop those instructions from
@ -91,14 +92,67 @@ func (p *Program) interpret(instrs []ssa.Instruction, paramKeys []*ssa.Parameter
if callee == nil {
return i, nil // don't understand dynamic dispatch
}
if _, ok := ignoreInitCalls[callee.String()]; ok && callee.Signature.Results().Len() == 1 {
if _, ok := ignoreInitCalls[callee.String()]; ok {
// These calls are not needed and can be ignored, for the time
// being.
var err error
locals[instr], err = p.getZeroValue(callee.Signature.Results().At(0).Type())
results := make([]Value, callee.Signature.Results().Len())
for i := range results {
var err error
results[i], err = p.getZeroValue(callee.Signature.Results().At(i).Type())
if err != nil {
return i, err
}
}
if len(results) == 1 {
locals[instr] = results[0]
} else if len(results) > 1 {
locals[instr] = &StructValue{Fields: results}
}
continue
}
if callee.String() == "os.NewFile" {
// Emulate the creation of os.Stdin, os.Stdout and os.Stderr.
resultPtrType := callee.Signature.Results().At(0).Type().(*types.Pointer)
resultStructOuterType := resultPtrType.Elem().Underlying().(*types.Struct)
if resultStructOuterType.NumFields() != 1 {
panic("expected 1 field in os.File struct")
}
fileInnerPtrType := resultStructOuterType.Field(0).Type().(*types.Pointer)
fileInnerType := fileInnerPtrType.Elem().(*types.Named)
fileInnerStructType := fileInnerType.Underlying().(*types.Struct)
fileInner, err := p.getZeroValue(fileInnerType) // os.file
if err != nil {
return i, err
}
for fieldIndex := 0; fieldIndex < fileInnerStructType.NumFields(); fieldIndex++ {
field := fileInnerStructType.Field(fieldIndex)
if field.Name() == "name" {
// Set the 'name' field.
name, err := p.getValue(common.Args[1], locals)
if err != nil {
return i, err
}
fileInner.(*StructValue).Fields[fieldIndex] = name
} else if field.Type().String() == "internal/poll.FD" {
// Set the file descriptor field.
field := field.Type().Underlying().(*types.Struct)
for subfieldIndex := 0; subfieldIndex < field.NumFields(); subfieldIndex++ {
subfield := field.Field(subfieldIndex)
if subfield.Name() == "Sysfd" {
sysfd, err := p.getValue(common.Args[0], locals)
if err != nil {
return i, err
}
sysfd = &ConstValue{Expr: ssa.NewConst(sysfd.(*ConstValue).Expr.Value, subfield.Type())}
fileInner.(*StructValue).Fields[fieldIndex].(*StructValue).Fields[subfieldIndex] = sysfd
}
}
}
}
fileInnerPtr := &PointerValue{fileInnerPtrType, &fileInner} // *os.file
var fileOuter Value = &StructValue{Type: resultPtrType.Elem(), Fields: []Value{fileInnerPtr}} // os.File
result := &PointerValue{resultPtrType.Elem(), &fileOuter} // *os.File
locals[instr] = result
continue
}
if canInterpret(callee) {
@ -165,6 +219,12 @@ func (p *Program) interpret(instrs []ssa.Instruction, paramKeys []*ssa.Parameter
}
case *ssa.DebugRef:
// ignore
case *ssa.Extract:
tuple, err := p.getValue(instr.Tuple, locals)
if err != nil {
return i, err
}
locals[instr] = tuple.(*StructValue).Fields[instr.Index]
case *ssa.FieldAddr:
x, err := p.getValue(instr.X, locals)
if err != nil {
@ -311,6 +371,7 @@ func canInterpret(callee *ssa.Function) bool {
case *ssa.Alloc:
case *ssa.Convert:
case *ssa.DebugRef:
case *ssa.Extract:
case *ssa.FieldAddr:
case *ssa.IndexAddr:
case *ssa.MakeInterface:

24
src/runtime/atomic.go Обычный файл
Просмотреть файл

@ -0,0 +1,24 @@
package runtime
// This file contains implementations for the sync/atomic package.
// All implementations assume there are no goroutines, threads or interrupts.
//go:linkname loadUint64 sync/atomic.LoadUint64
func loadUint64(addr *uint64) uint64 {
return *addr
}
//go:linkname storeUint32 sync/atomic.StoreUint32
func storeUint32(addr *uint32, val uint32) {
*addr = val
}
//go:linkname compareAndSwapUint64 sync/atomic.CompareAndSwapUint64
func compareAndSwapUint64(addr *uint64, old, new uint64) bool {
if *addr == old {
*addr = new
return true
}
return false
}

23
src/runtime/poll.go Обычный файл
Просмотреть файл

@ -0,0 +1,23 @@
package runtime
// This file implements stub functions for internal/poll.
//go:linkname poll_runtime_pollServerInit internal/poll.runtime_pollServerInit
func poll_runtime_pollServerInit(ctx *uint8) {
panic("todo: runtime_pollServerInit")
}
//go:linkname poll_runtime_pollOpen internal/poll.runtime_pollOpen
func poll_runtime_pollOpen(fd uintptr) (uintptr, int) {
panic("todo: runtime_pollOpen")
}
//go:linkname poll_runtime_pollClose internal/poll.runtime_pollClose
func poll_runtime_pollClose(ctx uintptr) {
panic("todo: runtime_pollClose")
}
//go:linkname poll_runtime_pollUnblock internal/poll.runtime_pollUnblock
func poll_runtime_pollUnblock(ctx uintptr) {
panic("todo: runtime_pollUnblock")
}

Просмотреть файл

@ -49,6 +49,11 @@ func GOROOT() string {
return "/usr/local/go"
}
//go:linkname os_runtime_args os.runtime_args
func os_runtime_args() []string {
return nil
}
// Copy size bytes from src to dst. The memory areas must not overlap.
func memcpy(dst, src unsafe.Pointer, size uintptr) {
for i := uintptr(0); i < size; i++ {

Просмотреть файл

@ -1 +1,13 @@
package runtime
// This file contains stub implementations for internal/poll.
//go:linkname semacquire internal/poll.runtime_Semacquire
func semacquire(sema *uint32) {
panic("todo: semacquire")
}
//go:linkname semrelease internal/poll.runtime_Semrelease
func semrelease(sema *uint32) {
panic("todo: semrelease")
}

13
src/runtime/syscall.go Обычный файл
Просмотреть файл

@ -0,0 +1,13 @@
package runtime
// This file implements syscall.Syscall and the like.
//go:linkname syscall_Syscall syscall.Syscall
func syscall_Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err uintptr) {
panic("syscall")
}
//go:linkname syscall_Syscall6 syscall.Syscall6
func syscall_Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err uintptr) {
panic("syscall6")
}