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.
Этот коммит содержится в:
родитель
c237633d34
коммит
1484bb5c2c
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
Обычный файл
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
Обычный файл
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
Обычный файл
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")
|
||||
}
|
Загрузка…
Создание таблицы
Сослаться в новой задаче