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).Get": struct{}{},
|
||||||
"(syscall/js.Value).New": struct{}{},
|
"(syscall/js.Value).New": struct{}{},
|
||||||
"(syscall/js.Value).Int": struct{}{},
|
"(syscall/js.Value).Int": struct{}{},
|
||||||
|
"os.init$1": struct{}{},
|
||||||
}
|
}
|
||||||
|
|
||||||
// Interpret instructions as far as possible, and drop those instructions from
|
// 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 {
|
if callee == nil {
|
||||||
return i, nil // don't understand dynamic dispatch
|
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
|
// These calls are not needed and can be ignored, for the time
|
||||||
// being.
|
// being.
|
||||||
var err error
|
results := make([]Value, callee.Signature.Results().Len())
|
||||||
locals[instr], err = p.getZeroValue(callee.Signature.Results().At(0).Type())
|
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 {
|
if err != nil {
|
||||||
return i, err
|
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
|
continue
|
||||||
}
|
}
|
||||||
if canInterpret(callee) {
|
if canInterpret(callee) {
|
||||||
|
@ -165,6 +219,12 @@ func (p *Program) interpret(instrs []ssa.Instruction, paramKeys []*ssa.Parameter
|
||||||
}
|
}
|
||||||
case *ssa.DebugRef:
|
case *ssa.DebugRef:
|
||||||
// ignore
|
// 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:
|
case *ssa.FieldAddr:
|
||||||
x, err := p.getValue(instr.X, locals)
|
x, err := p.getValue(instr.X, locals)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -311,6 +371,7 @@ func canInterpret(callee *ssa.Function) bool {
|
||||||
case *ssa.Alloc:
|
case *ssa.Alloc:
|
||||||
case *ssa.Convert:
|
case *ssa.Convert:
|
||||||
case *ssa.DebugRef:
|
case *ssa.DebugRef:
|
||||||
|
case *ssa.Extract:
|
||||||
case *ssa.FieldAddr:
|
case *ssa.FieldAddr:
|
||||||
case *ssa.IndexAddr:
|
case *ssa.IndexAddr:
|
||||||
case *ssa.MakeInterface:
|
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"
|
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.
|
// Copy size bytes from src to dst. The memory areas must not overlap.
|
||||||
func memcpy(dst, src unsafe.Pointer, size uintptr) {
|
func memcpy(dst, src unsafe.Pointer, size uintptr) {
|
||||||
for i := uintptr(0); i < size; i++ {
|
for i := uintptr(0); i < size; i++ {
|
||||||
|
|
|
@ -1 +1,13 @@
|
||||||
package runtime
|
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")
|
||||||
|
}
|
Загрузка…
Создание таблицы
Сослаться в новой задаче