1// META: global=window,dedicatedworker,jsshell
2
3test(() => {
4  const thisValues = [
5    undefined,
6    null,
7    true,
8    "",
9    Symbol(),
10    1,
11    {},
12    WebAssembly.Global,
13    WebAssembly.Global.prototype,
14  ];
15
16  const desc = Object.getOwnPropertyDescriptor(WebAssembly.Global.prototype, "value");
17  assert_equals(typeof desc, "object");
18
19  const getter = desc.get;
20  assert_equals(typeof getter, "function");
21
22  const setter = desc.set;
23  assert_equals(typeof setter, "function");
24
25  for (const thisValue of thisValues) {
26    assert_throws_js(TypeError, () => getter.call(thisValue), `getter with this=${format_value(thisValue)}`);
27    assert_throws_js(TypeError, () => setter.call(thisValue, 1), `setter with this=${format_value(thisValue)}`);
28  }
29}, "Branding");
30
31for (const type of ["i32", "i64", "f32", "f64"]) {
32  const [initial, value, invalid] = type === "i64" ? [0n, 1n, 2] : [0, 1, 2n];
33  const immutableOptions = [
34    [{}, "missing"],
35    [{ "mutable": undefined }, "undefined"],
36    [{ "mutable": null }, "null"],
37    [{ "mutable": false }, "false"],
38    [{ "mutable": "" }, "empty string"],
39    [{ "mutable": 0 }, "zero"],
40  ];
41  for (const [opts, name] of immutableOptions) {
42    test(() => {
43      opts.value = type;
44      const global = new WebAssembly.Global(opts);
45      assert_equals(global.value, initial, "initial value");
46      assert_equals(global.valueOf(), initial, "initial valueOf");
47
48      assert_throws_js(TypeError, () => global.value = value);
49
50      assert_equals(global.value, initial, "post-set value");
51      assert_equals(global.valueOf(), initial, "post-set valueOf");
52    }, `Immutable ${type} (${name})`);
53
54    test(t => {
55      opts.value = type;
56      const global = new WebAssembly.Global(opts);
57      assert_equals(global.value, initial, "initial value");
58      assert_equals(global.valueOf(), initial, "initial valueOf");
59
60      const value = {
61        valueOf: t.unreached_func("should not call valueOf"),
62        toString: t.unreached_func("should not call toString"),
63      };
64      assert_throws_js(TypeError, () => global.value = value);
65
66      assert_equals(global.value, initial, "post-set value");
67      assert_equals(global.valueOf(), initial, "post-set valueOf");
68    }, `Immutable ${type} with ToNumber side-effects (${name})`);
69  }
70
71  const mutableOptions = [
72    [{ "mutable": true }, "true"],
73    [{ "mutable": 1 }, "one"],
74    [{ "mutable": "x" }, "string"],
75    [Object.create({ "mutable": true }), "true on prototype"],
76  ];
77  for (const [opts, name] of mutableOptions) {
78    test(() => {
79      opts.value = type;
80      const global = new WebAssembly.Global(opts);
81      assert_equals(global.value, initial, "initial value");
82      assert_equals(global.valueOf(), initial, "initial valueOf");
83
84      global.value = value;
85
86      assert_throws_js(TypeError, () => global.value = invalid);
87
88      assert_equals(global.value, value, "post-set value");
89      assert_equals(global.valueOf(), value, "post-set valueOf");
90    }, `Mutable ${type} (${name})`);
91  }
92}
93
94test(() => {
95  const argument = { "value": "i64", "mutable": true };
96  const global = new WebAssembly.Global(argument);
97
98  assert_equals(global.value, 0n, "initial value using ToJSValue");
99
100  const valid = [
101    [123n, 123n],
102    [2n ** 63n, - (2n ** 63n)],
103    [true, 1n],
104    [false, 0n],
105    ["456", 456n],
106  ];
107  for (const [input, output] of valid) {
108    global.value = input;
109    assert_equals(global.valueOf(), output, "post-set valueOf");
110  }
111
112  const invalid = [
113    undefined,
114    null,
115    0,
116    1,
117    4.2,
118    Symbol(),
119  ];
120  for (const input of invalid) {
121    assert_throws_js(TypeError, () => global.value = input);
122  }
123}, "i64 mutability");
124
125test(() => {
126  const argument = { "value": "i32", "mutable": true };
127  const global = new WebAssembly.Global(argument);
128  const desc = Object.getOwnPropertyDescriptor(WebAssembly.Global.prototype, "value");
129  assert_equals(typeof desc, "object");
130
131  const setter = desc.set;
132  assert_equals(typeof setter, "function");
133
134  assert_throws_js(TypeError, () => setter.call(global));
135}, "Calling setter without argument");
136
137test(() => {
138  const argument = { "value": "i32", "mutable": true };
139  const global = new WebAssembly.Global(argument);
140  const desc = Object.getOwnPropertyDescriptor(WebAssembly.Global.prototype, "value");
141  assert_equals(typeof desc, "object");
142
143  const getter = desc.get;
144  assert_equals(typeof getter, "function");
145
146  const setter = desc.set;
147  assert_equals(typeof setter, "function");
148
149  assert_equals(getter.call(global, {}), 0);
150  assert_equals(setter.call(global, 1, {}), undefined);
151  assert_equals(global.value, 1);
152}, "Stray argument");
153