Skip to content

Commit

Permalink
syscall/js: rename js.Callback to js.Func
Browse files Browse the repository at this point in the history
The name "Callback" does not fit to all use cases of js.Callback.
This commit changes its name to Func. Accordingly NewCallback
gets renamed to FuncOf, which matches ValueOf and TypedArrayOf.

The package syscall/js is currently exempt from Go's compatibility
promise and js.Callback is already affected by a breaking change in
this release cycle. See golang#28711 for details.

Fixes golang#28711

Change-Id: I2c380970c3822bed6a3893909672c15d0cbe9da3
Reviewed-on: https://go-review.googlesource.com/c/153559
Run-TryBot: Brad Fitzpatrick <[email protected]>
TryBot-Result: Gobot Gobot <[email protected]>
Reviewed-by: Brad Fitzpatrick <[email protected]>
  • Loading branch information
neelance authored and bradfitz committed Dec 13, 2018
1 parent f95578c commit 7d9649b
Show file tree
Hide file tree
Showing 11 changed files with 158 additions and 159 deletions.
34 changes: 17 additions & 17 deletions misc/wasm/wasm_exec.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,8 @@
this._exitPromise = new Promise((resolve) => {
this._resolveExitPromise = resolve;
});
this._pendingCallback = null;
this._callbackTimeouts = new Map();
this._pendingEvent = null;
this._scheduledTimeouts = new Map();
this._nextCallbackTimeoutID = 1;

const mem = () => {
Expand Down Expand Up @@ -204,7 +204,7 @@
this.importObject = {
go: {
// Go's SP does not change as long as no Go code is running. Some operations (e.g. calls, getters and setters)
// may trigger a synchronous callback to Go. This makes Go code get executed in the middle of the imported
// may synchronously trigger a Go event handler. This makes Go code get executed in the middle of the imported
// function. A goroutine can switch to a new stack if the current stack is too small (see morestack function).
// This changes the SP, thus we have to update the SP used by the imported function.

Expand Down Expand Up @@ -238,22 +238,22 @@
mem().setInt32(sp + 16, (msec % 1000) * 1000000, true);
},

// func scheduleCallback(delay int64) int32
"runtime.scheduleCallback": (sp) => {
// func scheduleTimeoutEvent(delay int64) int32
"runtime.scheduleTimeoutEvent": (sp) => {
const id = this._nextCallbackTimeoutID;
this._nextCallbackTimeoutID++;
this._callbackTimeouts.set(id, setTimeout(
this._scheduledTimeouts.set(id, setTimeout(
() => { this._resume(); },
getInt64(sp + 8) + 1, // setTimeout has been seen to fire up to 1 millisecond early
));
mem().setInt32(sp + 16, id, true);
},

// func clearScheduledCallback(id int32)
"runtime.clearScheduledCallback": (sp) => {
// func clearTimeoutEvent(id int32)
"runtime.clearTimeoutEvent": (sp) => {
const id = mem().getInt32(sp + 8, true);
clearTimeout(this._callbackTimeouts.get(id));
this._callbackTimeouts.delete(id);
clearTimeout(this._scheduledTimeouts.get(id));
this._scheduledTimeouts.delete(id);
},

// func getRandomData(r []byte)
Expand Down Expand Up @@ -420,21 +420,21 @@

_resume() {
if (this.exited) {
throw new Error("bad callback: Go program has already exited");
throw new Error("Go program has already exited");
}
this._inst.exports.resume();
if (this.exited) {
this._resolveExitPromise();
}
}

_makeCallbackHelper(id) {
_makeFuncWrapper(id) {
const go = this;
return function () {
const cb = { id: id, this: this, args: arguments };
go._pendingCallback = cb;
const event = { id: id, this: this, args: arguments };
go._pendingEvent = event;
go._resume();
return cb.result;
return event.result;
};
}
}
Expand All @@ -450,10 +450,10 @@
go.env = Object.assign({ TMPDIR: require("os").tmpdir() }, process.env);
go.exit = process.exit;
WebAssembly.instantiate(fs.readFileSync(process.argv[2]), go.importObject).then((result) => {
process.on("exit", (code) => { // Node.js exits if no callback is pending
process.on("exit", (code) => { // Node.js exits if no event handler is pending
if (code === 0 && !go.exited) {
// deadlock, make Go print error and stack traces
go._pendingCallback = { id: 0 };
go._pendingEvent = { id: 0 };
go._resume();
}
});
Expand Down
2 changes: 1 addition & 1 deletion src/cmd/vet/all/whitelist/wasm.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ runtime/asm_wasm.s: [wasm] rt0_go: use of 8(SP) points beyond argument frame

// Calling WebAssembly import. No write from Go assembly.
runtime/sys_wasm.s: [wasm] nanotime: RET without writing to 8-byte ret+0(FP)
runtime/sys_wasm.s: [wasm] scheduleCallback: RET without writing to 4-byte ret+8(FP)
runtime/sys_wasm.s: [wasm] scheduleTimeoutEvent: RET without writing to 4-byte ret+8(FP)
syscall/js/js_js.s: [wasm] stringVal: RET without writing to 8-byte ret+16(FP)
syscall/js/js_js.s: [wasm] valueGet: RET without writing to 8-byte ret+24(FP)
syscall/js/js_js.s: [wasm] valueIndex: RET without writing to 8-byte ret+16(FP)
Expand Down
12 changes: 6 additions & 6 deletions src/net/http/roundtrip_js.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ func (t *Transport) RoundTrip(req *Request) (*Response, error) {
respCh = make(chan *Response, 1)
errCh = make(chan error, 1)
)
success := js.NewCallback(func(this js.Value, args []js.Value) interface{} {
success := js.FuncOf(func(this js.Value, args []js.Value) interface{} {
result := args[0]
header := Header{}
// https://developer.mozilla.org/en-US/docs/Web/API/Headers/entries
Expand Down Expand Up @@ -141,7 +141,7 @@ func (t *Transport) RoundTrip(req *Request) (*Response, error) {
return nil
})
defer success.Release()
failure := js.NewCallback(func(this js.Value, args []js.Value) interface{} {
failure := js.FuncOf(func(this js.Value, args []js.Value) interface{} {
err := fmt.Errorf("net/http: fetch() failed: %s", args[0].String())
select {
case errCh <- err:
Expand Down Expand Up @@ -190,7 +190,7 @@ func (r *streamReader) Read(p []byte) (n int, err error) {
bCh = make(chan []byte, 1)
errCh = make(chan error, 1)
)
success := js.NewCallback(func(this js.Value, args []js.Value) interface{} {
success := js.FuncOf(func(this js.Value, args []js.Value) interface{} {
result := args[0]
if result.Get("done").Bool() {
errCh <- io.EOF
Expand All @@ -204,7 +204,7 @@ func (r *streamReader) Read(p []byte) (n int, err error) {
return nil
})
defer success.Release()
failure := js.NewCallback(func(this js.Value, args []js.Value) interface{} {
failure := js.FuncOf(func(this js.Value, args []js.Value) interface{} {
// Assumes it's a TypeError. See
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypeError
// for more information on this type. See
Expand Down Expand Up @@ -258,7 +258,7 @@ func (r *arrayReader) Read(p []byte) (n int, err error) {
bCh = make(chan []byte, 1)
errCh = make(chan error, 1)
)
success := js.NewCallback(func(this js.Value, args []js.Value) interface{} {
success := js.FuncOf(func(this js.Value, args []js.Value) interface{} {
// Wrap the input ArrayBuffer with a Uint8Array
uint8arrayWrapper := js.Global().Get("Uint8Array").New(args[0])
value := make([]byte, uint8arrayWrapper.Get("byteLength").Int())
Expand All @@ -269,7 +269,7 @@ func (r *arrayReader) Read(p []byte) (n int, err error) {
return nil
})
defer success.Release()
failure := js.NewCallback(func(this js.Value, args []js.Value) interface{} {
failure := js.FuncOf(func(this js.Value, args []js.Value) interface{} {
// Assumes it's a TypeError. See
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypeError
// for more information on this type.
Expand Down
51 changes: 25 additions & 26 deletions src/runtime/lock_js.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,15 +92,15 @@ func notetsleepg(n *note, ns int64) bool {
delay = 1<<31 - 1 // cap to max int32
}

id := scheduleCallback(delay)
id := scheduleTimeoutEvent(delay)
mp := acquirem()
notes[n] = gp
notesWithTimeout[n] = noteWithTimeout{gp: gp, deadline: deadline}
releasem(mp)

gopark(nil, nil, waitReasonSleep, traceEvNone, 1)

clearScheduledCallback(id) // note might have woken early, clear timeout
clearTimeoutEvent(id) // note might have woken early, clear timeout
mp = acquirem()
delete(notes, n)
delete(notesWithTimeout, n)
Expand Down Expand Up @@ -134,62 +134,61 @@ func checkTimeouts() {
}
}

var returnedCallback *g
var returnedEventHandler *g

func init() {
// At the toplevel we need an extra goroutine that handles asynchronous callbacks.
// At the toplevel we need an extra goroutine that handles asynchronous events.
initg := getg()
go func() {
returnedCallback = getg()
returnedEventHandler = getg()
goready(initg, 1)

gopark(nil, nil, waitReasonZero, traceEvNone, 1)
returnedCallback = nil
returnedEventHandler = nil

pause(getcallersp() - 16)
}()
gopark(nil, nil, waitReasonZero, traceEvNone, 1)
}

// beforeIdle gets called by the scheduler if no goroutine is awake.
// If a callback has returned, then we resume the callback handler which
// will pause the execution.
// We resume the event handler (if available) which will pause the execution.
func beforeIdle() bool {
if returnedCallback != nil {
goready(returnedCallback, 1)
if returnedEventHandler != nil {
goready(returnedEventHandler, 1)
return true
}
return false
}

// pause sets SP to newsp and pauses the execution of Go's WebAssembly code until a callback is triggered.
// pause sets SP to newsp and pauses the execution of Go's WebAssembly code until an event is triggered.
func pause(newsp uintptr)

// scheduleCallback tells the WebAssembly environment to trigger a callback after ms milliseconds.
// It returns a timer id that can be used with clearScheduledCallback.
func scheduleCallback(ms int64) int32
// scheduleTimeoutEvent tells the WebAssembly environment to trigger an event after ms milliseconds.
// It returns a timer id that can be used with clearTimeoutEvent.
func scheduleTimeoutEvent(ms int64) int32

// clearScheduledCallback clears a callback scheduled by scheduleCallback.
func clearScheduledCallback(id int32)
// clearTimeoutEvent clears a timeout event scheduled by scheduleTimeoutEvent.
func clearTimeoutEvent(id int32)

func handleCallback() {
prevReturnedCallback := returnedCallback
returnedCallback = nil
func handleEvent() {
prevReturnedEventHandler := returnedEventHandler
returnedEventHandler = nil

checkTimeouts()
callbackHandler()
eventHandler()

returnedCallback = getg()
returnedEventHandler = getg()
gopark(nil, nil, waitReasonZero, traceEvNone, 1)

returnedCallback = prevReturnedCallback
returnedEventHandler = prevReturnedEventHandler

pause(getcallersp() - 16)
}

var callbackHandler func()
var eventHandler func()

//go:linkname setCallbackHandler syscall/js.setCallbackHandler
func setCallbackHandler(fn func()) {
callbackHandler = fn
//go:linkname setEventHandler syscall/js.setEventHandler
func setEventHandler(fn func()) {
eventHandler = fn
}
6 changes: 3 additions & 3 deletions src/runtime/rt0_js_wasm.s
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ TEXT _rt0_wasm_js(SB),NOSPLIT,$0
Drop

// wasm_export_run gets called from JavaScript. It initializes the Go runtime and executes Go code until it needs
// to wait for a callback. It does NOT follow the Go ABI. It has two WebAssembly parameters:
// to wait for an event. It does NOT follow the Go ABI. It has two WebAssembly parameters:
// R0: argc (i32)
// R1: argv (i32)
TEXT wasm_export_run(SB),NOSPLIT,$0
Expand Down Expand Up @@ -44,9 +44,9 @@ TEXT wasm_export_run(SB),NOSPLIT,$0
Return

// wasm_export_resume gets called from JavaScript. It resumes the execution of Go code until it needs to wait for
// a callback.
// an event.
TEXT wasm_export_resume(SB),NOSPLIT,$0
I32Const $runtime·handleCallback(SB)
I32Const $runtime·handleEvent(SB)
I32Const $16
I32ShrU
Set PC_F
Expand Down
4 changes: 2 additions & 2 deletions src/runtime/sys_wasm.s
Original file line number Diff line number Diff line change
Expand Up @@ -187,11 +187,11 @@ TEXT ·walltime(SB), NOSPLIT, $0
CallImport
RET

TEXT ·scheduleCallback(SB), NOSPLIT, $0
TEXT ·scheduleTimeoutEvent(SB), NOSPLIT, $0
CallImport
RET

TEXT ·clearScheduledCallback(SB), NOSPLIT, $0
TEXT ·clearTimeoutEvent(SB), NOSPLIT, $0
CallImport
RET

Expand Down
2 changes: 1 addition & 1 deletion src/syscall/fs_js.go
Original file line number Diff line number Diff line change
Expand Up @@ -474,7 +474,7 @@ func fsCall(name string, args ...interface{}) (js.Value, error) {
}

c := make(chan callResult, 1)
jsFS.Call(name, append(args, js.NewCallback(func(this js.Value, args []js.Value) interface{} {
jsFS.Call(name, append(args, js.FuncOf(func(this js.Value, args []js.Value) interface{} {
var res callResult

if len(args) >= 1 { // on Node.js 8, fs.utimes calls the callback without any arguments
Expand Down
92 changes: 0 additions & 92 deletions src/syscall/js/callback.go

This file was deleted.

Loading

0 comments on commit 7d9649b

Please sign in to comment.