Skip to content

Commit

Permalink
syscall/js: revise for go1.12
Browse files Browse the repository at this point in the history
Update #3
  • Loading branch information
changkun committed Jan 27, 2019
1 parent 37b5a51 commit 91b1445
Show file tree
Hide file tree
Showing 4 changed files with 147 additions and 133 deletions.
122 changes: 0 additions & 122 deletions gosrc/1.11.5/syscall/js/callback.go

This file was deleted.

92 changes: 92 additions & 0 deletions gosrc/1.11.5/syscall/js/func.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build js,wasm

package js

import "sync"

var (
funcsMu sync.Mutex
funcs = make(map[uint32]func(Value, []Value) interface{})
nextFuncID uint32 = 1
)

var _ Wrapper = Func{} // Func must implement Wrapper

// Func is a wrapped Go function to be called by JavaScript.
type Func struct {
Value // the JavaScript function that invokes the Go function
id uint32
}

// FuncOf returns a wrapped function.
//
// Invoking the JavaScript function will synchronously call the Go function fn with the value of JavaScript's
// "this" keyword and the arguments of the invocation.
// The return value of the invocation is the result of the Go function mapped back to JavaScript according to ValueOf.
//
// A wrapped function triggered during a call from Go to JavaScript gets executed on the same goroutine.
// A wrapped function triggered by JavaScript's event loop gets executed on an extra goroutine.
// Blocking operations in the wrapped function will block the event loop.
// As a consequence, if one wrapped function blocks, other wrapped funcs will not be processed.
// A blocking function should therefore explicitly start a new goroutine.
//
// Func.Release must be called to free up resources when the function will not be used any more.
func FuncOf(fn func(this Value, args []Value) interface{}) Func {
funcsMu.Lock()
id := nextFuncID
nextFuncID++
funcs[id] = fn
funcsMu.Unlock()
return Func{
id: id,
Value: jsGo.Call("_makeFuncWrapper", id),
}
}

// Release frees up resources allocated for the function.
// The function must not be invoked after calling Release.
func (c Func) Release() {
funcsMu.Lock()
delete(funcs, c.id)
funcsMu.Unlock()
}

// setEventHandler is defined in the runtime package.
func setEventHandler(fn func())

func init() {
setEventHandler(handleEvent)
}

func handleEvent() {
cb := jsGo.Get("_pendingEvent")
if cb == Null() {
return
}
jsGo.Set("_pendingEvent", Null())

id := uint32(cb.Get("id").Int())
if id == 0 { // zero indicates deadlock
select {}
}
funcsMu.Lock()
f, ok := funcs[id]
funcsMu.Unlock()
if !ok {
Global().Get("console").Call("error", "call to released function")
return
}

this := cb.Get("this")
argsObj := cb.Get("args")
args := make([]Value, argsObj.Length())
for i := range args {
args[i] = argsObj.Index(i)
}
result := f(this, args)
cb.Set("result", result)
}
64 changes: 53 additions & 11 deletions gosrc/1.11.5/syscall/js/js.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,32 @@ import (
)

// ref is used to identify a JavaScript value, since the value itself can not be passed to WebAssembly.
// A JavaScript number (64-bit float, except NaN) is represented by its IEEE 754 binary representation.
//
// The JavaScript value "undefined" is represented by the value 0.
// A JavaScript number (64-bit float, except 0 and NaN) is represented by its IEEE 754 binary representation.
// All other values are represented as an IEEE 754 binary representation of NaN with bits 0-31 used as
// an ID and bits 32-33 used to differentiate between string, symbol, function and object.
type ref uint64

// nanHead are the upper 32 bits of a ref which are set if the value is not a JavaScript number or NaN itself.
// nanHead are the upper 32 bits of a ref which are set if the value is not encoded as an IEEE 754 number (see above).
const nanHead = 0x7FF80000

// Value represents a JavaScript value.
// Wrapper is implemented by types that are backed by a JavaScript value.
type Wrapper interface {
// JSValue returns a JavaScript value associated with an object.
JSValue() Value
}

// Value represents a JavaScript value. The zero value is the JavaScript value "undefined".
type Value struct {
ref ref
}

// JSValue implements Wrapper interface.
func (v Value) JSValue() Value {
return v
}

func makeValue(v ref) Value {
return Value{ref: v}
}
Expand All @@ -38,6 +51,9 @@ func predefValue(id uint32) Value {
}

func floatValue(f float64) Value {
if f == 0 {
return valueZero
}
if f != f {
return valueNaN
}
Expand All @@ -56,8 +72,9 @@ func (e Error) Error() string {
}

var (
valueUndefined = Value{ref: 0}
valueNaN = predefValue(0)
valueUndefined = predefValue(1)
valueZero = predefValue(1)
valueNull = predefValue(2)
valueTrue = predefValue(3)
valueFalse = predefValue(4)
Expand Down Expand Up @@ -90,21 +107,21 @@ func Global() Value {
// | ---------------------- | ---------------------- |
// | js.Value | [its value] |
// | js.TypedArray | typed array |
// | js.Callback | function |
// | js.Func | function |
// | nil | null |
// | bool | boolean |
// | integers and floats | number |
// | string | string |
// | []interface{} | new array |
// | map[string]interface{} | new object |
//
// Panics if x is not one of the expected types.
func ValueOf(x interface{}) Value {
switch x := x.(type) {
case Value:
case Value: // should precede Wrapper to avoid a loop
return x
case TypedArray:
return x.Value
case Callback:
return x.Value
case Wrapper:
return x.JSValue()
case nil:
return valueNull
case bool:
Expand Down Expand Up @@ -318,13 +335,18 @@ func (v Value) New(args ...interface{}) Value {
func valueNew(v ref, args []ref) (ref, bool)

func (v Value) isNumber() bool {
return v.ref>>32&nanHead != nanHead || v.ref == valueNaN.ref
return v.ref == valueZero.ref ||
v.ref == valueNaN.ref ||
(v.ref != valueUndefined.ref && v.ref>>32&nanHead != nanHead)
}

func (v Value) float(method string) float64 {
if !v.isNumber() {
panic(&ValueError{method, v.Type()})
}
if v.ref == valueZero.ref {
return 0
}
return *(*float64)(unsafe.Pointer(&v.ref))
}

Expand All @@ -350,6 +372,26 @@ func (v Value) Bool() bool {
}
}

// Truthy returns the JavaScript "truthiness" of the value v. In JavaScript,
// false, 0, "", null, undefined, and NaN are "falsy", and everything else is
// "truthy". See https://developer.mozilla.org/en-US/docs/Glossary/Truthy.
func (v Value) Truthy() bool {
switch v.Type() {
case TypeUndefined, TypeNull:
return false
case TypeBoolean:
return v.Bool()
case TypeNumber:
return v.ref != valueNaN.ref && v.ref != valueZero.ref
case TypeString:
return v.String() != ""
case TypeSymbol, TypeFunction, TypeObject:
return true
default:
panic("bad type")
}
}

// String returns the value v converted to string according to JavaScript type conversions.
func (v Value) String() string {
str, length := valuePrepareString(v.ref)
Expand Down
2 changes: 2 additions & 0 deletions gosrc/1.11.5/syscall/js/typedarray.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ var (
float64Array = Global().Get("Float64Array")
)

var _ Wrapper = TypedArray{} // TypedArray must implement Wrapper

// TypedArray represents a JavaScript typed array.
type TypedArray struct {
Value
Expand Down

0 comments on commit 91b1445

Please sign in to comment.