Skip to content

Commit 3daf7b8

Browse files
committed
internal/abi: support importing dagger functions into Go (needs syscall/js for now)
1 parent eb35964 commit 3daf7b8

File tree

10 files changed

+143
-50
lines changed

10 files changed

+143
-50
lines changed

dagger/doc.go

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
// Package dagger is a runtime library for programs run on dagger.
2+
package dagger

dagger/file_js.go

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package dagger
2+
3+
import (
4+
"fmt"
5+
)
6+
7+
func OpenFile(furl string, flags int32) int32 {
8+
return openFD(furl, flags)
9+
}
10+
11+
func openFD(furl string, flags int32) int32
12+
13+
type file struct {
14+
fd int
15+
}
16+
17+
func read(fd int, buf []byte) int
18+
19+
func (f file) Read(buf []byte) (int, error) {
20+
n := read(f.fd, buf)
21+
if n < 0 {
22+
return -1, fmt.Errorf("error code %d", n*-1)
23+
}
24+
25+
return n, nil
26+
}

dagger/file_js.s

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#include "textflag.h"
2+
3+
TEXT ·openFD(SB), NOSPLIT, $0
4+
CallImport
5+
RET
6+
7+
TEXT ·read(SB), NOSPLIT, $0
8+
CallImport
9+
RET
10+

internal/abi/dagger/process.go

+66-45
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ func (p Process) Files() []abi.File {
2525
}
2626

2727
// NewProcess creates a new process.
28-
func NewProcess(name string) abi.ABI {
28+
func NewProcess(name string) *Process {
2929
return &Process{name: name}
3030
}
3131

@@ -46,88 +46,109 @@ func (p *Process) insertFile(file abi.File) int {
4646
// Name returns this process's name.
4747
func (p *Process) Name() string { return p.name }
4848

49+
func (p *Process) OpenFD(furl string, flags uint32) int64 {
50+
fd, err := p.open(furl, flags)
51+
52+
if err != nil {
53+
log.Printf("%s: OpenFD(%s, %x): %v", p.name, furl, flags, err)
54+
return int64(-1 * int64(err.(Error).Errno))
55+
}
56+
57+
return int64(fd)
58+
}
59+
60+
func (p *Process) CloseFD(fd int64) int64 {
61+
err := p.files[fd].Close()
62+
if err != nil {
63+
log.Printf("%s: CloseFD(%d): %v", p.name, fd, err)
64+
return -1
65+
}
66+
67+
return 0
68+
}
69+
70+
func (p *Process) WriteFD(fd int64, data []byte) int64 {
71+
n, err := p.files[int(fd)].Write(data)
72+
if err != nil {
73+
log.Printf("%s: WriteFD(%d, []byte{%d}): %v", p.name, fd, len(data), err)
74+
return -1
75+
}
76+
77+
return int64(n)
78+
}
79+
80+
func (p *Process) SyncFD(fd int64) int64 {
81+
err := p.files[fd].Sync()
82+
if err != nil {
83+
log.Printf("%s: Sync(%d) %v", p.name, fd, err)
84+
return -1
85+
}
86+
87+
return 0
88+
}
89+
90+
func (p *Process) ReadFD(fd int64, buf []byte) int64 {
91+
n, err := p.files[fd].Read(buf)
92+
if err != nil {
93+
log.Printf("%s: ReadFD(%d, []byte{%d}): %v", p.name, fd, len(buf), err)
94+
return -1
95+
}
96+
97+
return int64(n)
98+
}
99+
49100
// ResolveFunc resolves dagger's ABI and importable functions.
50101
func (p *Process) ResolveFunc(module, field string) exec.FunctionImport {
51102
switch module {
52103
case "dagger":
53104
switch field {
54-
case "open":
105+
case "open": // :: String -> Int32 -> Int64
55106
return func(vm *exec.VirtualMachine) int64 {
56107
f := vm.GetCurrentFrame()
57108
furlPtr := uint32(f.Locals[0])
58109
flags := uint32(f.Locals[1])
59110
furl := string(readMem(vm.Memory, furlPtr))
60111

61-
fd, err := p.open(furl, flags)
62-
if err != nil {
63-
// TODO(Xe): Log
64-
return int64(-1 * int64(err.(Error).Errno))
65-
}
66-
67-
return int64(fd)
112+
return p.OpenFD(furl, flags)
68113
}
69-
case "close":
114+
case "close": // :: Int64 -> IO Int64
70115
return func(vm *exec.VirtualMachine) int64 {
71116
f := vm.GetCurrentFrame()
72-
fd := int(f.Locals[0])
73-
74-
err := p.files[fd].Close()
75-
if err != nil {
76-
// TODO(Xe): Log
77-
return -1
78-
}
117+
fd := f.Locals[0]
79118

80-
return 0
119+
return p.CloseFD(fd)
81120
}
82-
case "write":
121+
case "write": // :: Int64 -> String -> IO Int64
83122
return func(vm *exec.VirtualMachine) int64 {
84123
f := vm.GetCurrentFrame()
85124
fd := f.Locals[0]
86125
ptr := f.Locals[1]
87126
len := f.Locals[2]
88-
89127
mem := vm.Memory[int(ptr):int(ptr+len)]
90128

91-
n, err := p.files[int(fd)].Write(mem)
92-
if err != nil {
93-
// TODO(Xe): Log
94-
return -1
95-
}
96-
97-
return int64(n)
129+
return p.WriteFD(fd, mem)
98130
}
99-
case "sync":
131+
case "sync": // :: Int64 -> IO Int64
100132
return func(vm *exec.VirtualMachine) int64 {
101133
f := vm.GetCurrentFrame()
102134
fd := f.Locals[0]
103135

104-
err := p.files[fd].Sync()
105-
if err != nil {
106-
log.Printf("sync error: %d (%s) %v", fd, p.files[fd].Name(), err)
107-
return -1
108-
}
109-
110-
return 0
136+
return p.SyncFD(fd)
111137
}
112-
case "read":
138+
case "read": // :: Int64 -> String -> IO Int64
113139
return func(vm *exec.VirtualMachine) int64 {
114140
f := vm.GetCurrentFrame()
115141
fd := f.Locals[0]
116-
ptr := f.Locals[1]
142+
ptr := int32(f.Locals[1])
117143
len := f.Locals[2]
118-
119144
buf := make([]byte, int(len))
120-
n, err := p.files[fd].Read(buf)
121-
if err != nil {
122-
// TODO(Xe): Log
123-
return -1
124-
}
145+
ret := p.ReadFD(fd, buf)
125146

126147
for i, d := range buf {
127-
vm.Memory[int(ptr)+i] = d
148+
vm.Memory[ptr+int32(i)] = d
128149
}
129150

130-
return int64(n)
151+
return ret
131152
}
132153
}
133154
}

internal/abi/wasmgo/abi.go

+9-3
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,12 @@ func (w *wasmGo) goRuntimeGetRandomData(sp int32) {
142142
w.writeMem(sp+8, data)
143143
}
144144

145-
func (wasmGo) notImplemented(sp int32) { panic("not implemented") }
145+
func (w *wasmGo) notImplemented(module, field string) goABIFunc {
146+
return func(sp int32) {
147+
w.vm.PrintStackTrace()
148+
log.Panicf("not implemented: %s %s", module, field)
149+
}
150+
}
146151

147152
type goABIFunc func(int32)
148153

@@ -182,7 +187,6 @@ func (w *wasmGo) runGoABI(doer func(int32)) exec.FunctionImport {
182187
func (w *wasmGo) ResolveGlobal(module, field string) int64 { return 0 }
183188

184189
func (w *wasmGo) ResolveFunc(module, field string) exec.FunctionImport {
185-
log.Printf("resolveFunc(%q, %q)", module, field)
186190
val := w.child.ResolveFunc(module, field)
187191
if val != nil {
188192
return val
@@ -212,9 +216,11 @@ func (w *wasmGo) ResolveFunc(module, field string) exec.FunctionImport {
212216
return w.runGoABI(w.goRuntimeClearScheduledCallback)
213217
case "runtime.getRandomData":
214218
return w.runGoABI(w.goRuntimeGetRandomData)
219+
case "github.com/Xe/olin/dagger.openFD":
220+
return w.runGoABI(w.daggerOpenFD)
215221
default:
216222
log.Printf("unknown module+field %s %s, using shim", module, field)
217-
return w.runGoABI(w.notImplemented)
223+
return w.runGoABI(w.notImplemented(module, field))
218224
}
219225
default:
220226
log.Panicf("unknown module+field %s %s", module, field)

internal/abi/wasmgo/abi_test.go

+7
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ type testWasmGoFragment func(t *testing.T, w *wasmGo)
3535
func TestWasmGo(t *testing.T) {
3636
cases := []testWasmGoFragment{
3737
testNothing,
38+
testDagger,
3839
}
3940

4041
for _, cs := range cases {
@@ -59,6 +60,12 @@ func testNothing(t *testing.T, w *wasmGo) {
5960
defer w.ensureExitStatus(t, true, 0)
6061
}
6162

63+
func testDagger(t *testing.T, w *wasmGo) {
64+
t.Skip("need syscall/js :(")
65+
openAndRunWasmRun(t, w, "./testdata/dagger.wasm")
66+
defer w.ensureExitStatus(t, true, 0)
67+
}
68+
6269
func openAndRunWasmRun(t *testing.T, w *wasmGo, fname string) {
6370
data, err := ioutil.ReadFile(fname)
6471
if err != nil {

internal/abi/wasmgo/dagger.go

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package wasmgo
2+
3+
func (w *wasmGo) daggerOpenFD(sp int32) {
4+
fname := string(w.goLoadSlice(sp))
5+
flags := uint32(w.getInt32(sp + 4))
6+
w.setInt64(sp+8, w.child.OpenFD(fname, flags))
7+
}
+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// +build js,wasm ignore
2+
3+
package main
4+
5+
import (
6+
"fmt"
7+
8+
"github.com/Xe/olin/dagger"
9+
)
10+
11+
func main() {
12+
fd := dagger.OpenFile("fd://1", 0)
13+
println(fmt.Sprint(fd))
14+
}
2.31 MB
Binary file not shown.

internal/abi/wasmgo/wasmgo.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@ package wasmgo
33
import (
44
"time"
55

6-
"github.com/Xe/olin/internal/abi"
6+
"github.com/Xe/olin/internal/abi/dagger"
77
"github.com/perlin-network/life/exec"
88
)
99

1010
type wasmGo struct {
11-
child abi.ABI
11+
child *dagger.Process
1212

1313
BootTime time.Time
1414
Exited bool

0 commit comments

Comments
 (0)