X Tutup
Skip to content

Commit 138bfc2

Browse files
neelanceRichard Musiol
authored andcommitted
syscall/js: make zero js.Value represent "undefined"
This commit changes the encoding of js.Value so that the zero js.Value represents the JavaScript value "undefined". This is what users intuitively expect. Specifically, the encodings of "undefined" and the number zero have been swapped. Fixes golang#27592. Change-Id: Icfc832c8cdf7a8a78bd69d20e00a04dbed0ccd10 Reviewed-on: https://go-review.googlesource.com/c/143137 Run-TryBot: Richard Musiol <neelance@gmail.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
1 parent 8ccafb1 commit 138bfc2

File tree

3 files changed

+42
-10
lines changed

3 files changed

+42
-10
lines changed

misc/wasm/wasm_exec.js

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,9 @@
9595

9696
const loadValue = (addr) => {
9797
const f = mem().getFloat64(addr, true);
98+
if (f === 0) {
99+
return undefined;
100+
}
98101
if (!isNaN(f)) {
99102
return f;
100103
}
@@ -112,14 +115,18 @@
112115
mem().setUint32(addr, 0, true);
113116
return;
114117
}
118+
if (v === 0) {
119+
mem().setUint32(addr + 4, nanHead, true);
120+
mem().setUint32(addr, 1, true);
121+
return;
122+
}
115123
mem().setFloat64(addr, v, true);
116124
return;
117125
}
118126

119127
switch (v) {
120128
case undefined:
121-
mem().setUint32(addr + 4, nanHead, true);
122-
mem().setUint32(addr, 1, true);
129+
mem().setFloat64(addr, 0, true);
123130
return;
124131
case null:
125132
mem().setUint32(addr + 4, nanHead, true);
@@ -334,7 +341,7 @@
334341
this._inst = instance;
335342
this._values = [ // TODO: garbage collection
336343
NaN,
337-
undefined,
344+
0,
338345
null,
339346
true,
340347
false,
@@ -396,14 +403,14 @@
396403
}
397404

398405
static _makeCallbackHelper(id, pendingCallbacks, go) {
399-
return function() {
406+
return function () {
400407
pendingCallbacks.push({ id: id, args: arguments });
401408
go._resolveCallbackPromise();
402409
};
403410
}
404411

405412
static _makeEventCallbackHelper(preventDefault, stopPropagation, stopImmediatePropagation, fn) {
406-
return function(event) {
413+
return function (event) {
407414
if (preventDefault) {
408415
event.preventDefault();
409416
}

src/syscall/js/js.go

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,17 @@ import (
1616
)
1717

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

24-
// nanHead are the upper 32 bits of a ref which are set if the value is not a JavaScript number or NaN itself.
26+
// 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).
2527
const nanHead = 0x7FF80000
2628

27-
// Value represents a JavaScript value.
29+
// Value represents a JavaScript value. The zero value is the JavaScript value "undefined".
2830
type Value struct {
2931
ref ref
3032
}
@@ -38,6 +40,9 @@ func predefValue(id uint32) Value {
3840
}
3941

4042
func floatValue(f float64) Value {
43+
if f == 0 {
44+
return valueZero
45+
}
4146
if f != f {
4247
return valueNaN
4348
}
@@ -56,8 +61,9 @@ func (e Error) Error() string {
5661
}
5762

5863
var (
64+
valueUndefined = Value{ref: 0}
5965
valueNaN = predefValue(0)
60-
valueUndefined = predefValue(1)
66+
valueZero = predefValue(1)
6167
valueNull = predefValue(2)
6268
valueTrue = predefValue(3)
6369
valueFalse = predefValue(4)
@@ -318,13 +324,18 @@ func (v Value) New(args ...interface{}) Value {
318324
func valueNew(v ref, args []ref) (ref, bool)
319325

320326
func (v Value) isNumber() bool {
321-
return v.ref>>32&nanHead != nanHead || v.ref == valueNaN.ref
327+
return v.ref == valueZero.ref ||
328+
v.ref == valueNaN.ref ||
329+
(v.ref != valueUndefined.ref && v.ref>>32&nanHead != nanHead)
322330
}
323331

324332
func (v Value) float(method string) float64 {
325333
if !v.isNumber() {
326334
panic(&ValueError{method, v.Type()})
327335
}
336+
if v.ref == valueZero.ref {
337+
return 0
338+
}
328339
return *(*float64)(unsafe.Pointer(&v.ref))
329340
}
330341

src/syscall/js/js_test.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ var dummys = js.Global().Call("eval", `({
2222
add: function(a, b) {
2323
return a + b;
2424
},
25+
zero: 0,
2526
NaN: NaN,
2627
})`)
2728

@@ -74,6 +75,9 @@ func TestInt(t *testing.T) {
7475
if dummys.Get("someInt") != dummys.Get("someInt") {
7576
t.Errorf("same value not equal")
7677
}
78+
if got := dummys.Get("zero").Int(); got != 0 {
79+
t.Errorf("got %#v, want %#v", got, 0)
80+
}
7781
}
7882

7983
func TestIntConversion(t *testing.T) {
@@ -237,6 +241,9 @@ func TestType(t *testing.T) {
237241
if got, want := js.ValueOf(true).Type(), js.TypeBoolean; got != want {
238242
t.Errorf("got %s, want %s", got, want)
239243
}
244+
if got, want := js.ValueOf(0).Type(), js.TypeNumber; got != want {
245+
t.Errorf("got %s, want %s", got, want)
246+
}
240247
if got, want := js.ValueOf(42).Type(), js.TypeNumber; got != want {
241248
t.Errorf("got %s, want %s", got, want)
242249
}
@@ -269,6 +276,13 @@ func TestValueOf(t *testing.T) {
269276
}
270277
}
271278

279+
func TestZeroValue(t *testing.T) {
280+
var v js.Value
281+
if v != js.Undefined() {
282+
t.Error("zero js.Value is not js.Undefined()")
283+
}
284+
}
285+
272286
func TestCallback(t *testing.T) {
273287
c := make(chan struct{})
274288
cb := js.NewCallback(func(args []js.Value) {

0 commit comments

Comments
 (0)
X Tutup