const loadValue = (addr) => {
const f = mem().getFloat64(addr, true);
+ if (f === 0) {
+ return undefined;
+ }
if (!isNaN(f)) {
return f;
}
mem().setUint32(addr, 0, true);
return;
}
+ if (v === 0) {
+ mem().setUint32(addr + 4, nanHead, true);
+ mem().setUint32(addr, 1, true);
+ return;
+ }
mem().setFloat64(addr, v, true);
return;
}
switch (v) {
case undefined:
- mem().setUint32(addr + 4, nanHead, true);
- mem().setUint32(addr, 1, true);
+ mem().setFloat64(addr, 0, true);
return;
case null:
mem().setUint32(addr + 4, nanHead, true);
this._inst = instance;
this._values = [ // TODO: garbage collection
NaN,
- undefined,
+ 0,
null,
true,
false,
}
static _makeCallbackHelper(id, pendingCallbacks, go) {
- return function() {
+ return function () {
pendingCallbacks.push({ id: id, args: arguments });
go._resolveCallbackPromise();
};
}
static _makeEventCallbackHelper(preventDefault, stopPropagation, stopImmediatePropagation, fn) {
- return function(event) {
+ return function (event) {
if (preventDefault) {
event.preventDefault();
}
)
// 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.
+// Value represents a JavaScript value. The zero value is the JavaScript value "undefined".
type Value struct {
ref ref
}
}
func floatValue(f float64) Value {
+ if f == 0 {
+ return valueZero
+ }
if f != f {
return valueNaN
}
}
var (
+ valueUndefined = Value{ref: 0}
valueNaN = predefValue(0)
- valueUndefined = predefValue(1)
+ valueZero = predefValue(1)
valueNull = predefValue(2)
valueTrue = predefValue(3)
valueFalse = predefValue(4)
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))
}
add: function(a, b) {
return a + b;
},
+ zero: 0,
NaN: NaN,
})`)
if dummys.Get("someInt") != dummys.Get("someInt") {
t.Errorf("same value not equal")
}
+ if got := dummys.Get("zero").Int(); got != 0 {
+ t.Errorf("got %#v, want %#v", got, 0)
+ }
}
func TestIntConversion(t *testing.T) {
if got, want := js.ValueOf(true).Type(), js.TypeBoolean; got != want {
t.Errorf("got %s, want %s", got, want)
}
+ if got, want := js.ValueOf(0).Type(), js.TypeNumber; got != want {
+ t.Errorf("got %s, want %s", got, want)
+ }
if got, want := js.ValueOf(42).Type(), js.TypeNumber; got != want {
t.Errorf("got %s, want %s", got, want)
}
}
}
+func TestZeroValue(t *testing.T) {
+ var v js.Value
+ if v != js.Undefined() {
+ t.Error("zero js.Value is not js.Undefined()")
+ }
+}
+
func TestCallback(t *testing.T) {
c := make(chan struct{})
cb := js.NewCallback(func(args []js.Value) {