COMMIT_MESSAGE

 1WebAssembly JS API: improve Instance
 2
 3An Instance's `exports` property wasn't populated with exports.
 4
 5According to the spec [0], `exports` should present itself as a WebAssembly
 6Module Record. In order to do this we need to split JSModuleRecord into
 7AbstractModuleRecord (without the `link` and `evaluate` functions), and
 8JSModuleRecord (which implements link and evaluate). We can then have a separate
 9WebAssemblyModuleRecord which shares most of the implementation.
 10
 11`exports` then maps function names to WebAssemblyFunction and
 12WebAssemblyFunctionCell, which call into the B3-generated WebAssembly code.
 13
 14A follow-up patch will do imports.
 15
 16A few things of note:
 17
 18 - Use Identifier instead of String. They get uniqued, we need them for the JSModuleNamespaceObject. This is safe because JSWebAssemblyModule creation is on the main thread.
 19 - JSWebAssemblyInstance needs to refer to the JSWebAssemblyModule used to create it, because the module owns the code, identifiers, etc. The world would be very sad if it got GC'd.
 20 - Instance.exports shouldn't use putWithoutTransition because it affects all Structures, whereas here each instance needs its own exports.
 21 - Expose the compiled functions, and pipe them to the InstanceConstructor. Start moving things around to split JSModuleRecord out into JS and WebAssembly parts.
 22 - LowLevelBinary: support 3-byte integers.
 23 - LowLevelBinary: support proper UTF-8 2003 code points (instead of UTF-16).
 24
 25 [0]: https://github.com/WebAssembly/design/blob/master/JS.md#webassemblyinstance-constructor

JSTests/ChangeLog

 12016-11-28 JF Bastien <jfbastien@apple.com>
 2
 3 WebAssembly JS API: improve Instance
 4
 5 An Instance's `exports` property wasn't populated with exports.
 6
 7 According to the spec [0], `exports` should present itself as a WebAssembly
 8 Module Record. In order to do this we need to split JSModuleRecord into
 9 AbstractModuleRecord (without the `link` and `evaluate` functions), and
 10 JSModuleRecord (which implements link and evaluate). We can then have a separate
 11 WebAssemblyModuleRecord which shares most of the implementation.
 12
 13 `exports` then maps function names to WebAssemblyFunction and
 14 WebAssemblyFunctionCell, which call into the B3-generated WebAssembly code.
 15
 16 A follow-up patch will do imports.
 17
 18 A few things of note:
 19
 20 - Use Identifier instead of String. They get uniqued, we need them for the JSModuleNamespaceObject. This is safe because JSWebAssemblyModule creation is on the main thread.
 21 - JSWebAssemblyInstance needs to refer to the JSWebAssemblyModule used to create it, because the module owns the code, identifiers, etc. The world would be very sad if it got GC'd.
 22 - Instance.exports shouldn't use putWithoutTransition because it affects all Structures, whereas here each instance needs its own exports.
 23 - Expose the compiled functions, and pipe them to the InstanceConstructor. Start moving things around to split JSModuleRecord out into JS and WebAssembly parts.
 24 - LowLevelBinary: support 3-byte integers.
 25 - LowLevelBinary: support proper UTF-8 2003 code points (instead of UTF-16).
 26
 27 [0]: https://github.com/WebAssembly/design/blob/master/JS.md#webassemblyinstance-constructor
 28
 29 WebAssembly JS API: improve Instance
 30 https://bugs.webkit.org/show_bug.cgi?id=164757
 31
 32 Reviewed by NOBODY (OOPS!).
 33
 34 * wasm/Builder.js:
 35 * wasm/Builder_WebAssemblyBinary.js: wire up exports, stub other things out some more
 36 (const.emitters.Export):
 37 * wasm/LowLevelBinary.js:
 38 (export.default.LowLevelBinary.prototype.uint24): add, used for UTF-8
 39 (export.default.LowLevelBinary.prototype.string): support UTF-8
 40 (export.default.LowLevelBinary.prototype.getUint24): add, used for UTF-8
 41 (export.default.LowLevelBinary.prototype.getVaruint1): was missing
 42 (export.default.LowLevelBinary.prototype.getString): support UTF-8
 43 (export.default.LowLevelBinary):
 44 * wasm/js-api/test_Instance.js: instance.exports.answer() // <-- this is where the magic of this entire patch is
 45 (ExportedAnswerI32):
 46 * wasm/js-api/test_basic_api.js: punt test to later
 47 (const.c.in.constructorProperties.switch):
 48 * wasm/self-test/test_BuilderWebAssembly.js: UTF-8
 49 (CustomSection):
 50 * wasm/self-test/test_LowLevelBinary_string.js: UTF-8 now works
 51 * wasm/self-test/test_LowLevelBinary_uint16.js: was missing one value
 52 * wasm/self-test/test_LowLevelBinary_uint24.js: Copied from JSTests/wasm/self-test/test_LowLevelBinary_uint8.js.
 53 * wasm/self-test/test_LowLevelBinary_uint8.js: was missing one value
 54 * wasm/self-test/test_LowLevelBinary_varuint1.js: Added.
 55 * wasm/utilities.js: this `dump` thing was useful
 56 (const._dump):
 57
1582016-11-21 Yusuke Suzuki <utatane.tea@gmail.com>
259
360 Crash in com.apple.JavaScriptCore: WTF::ThreadSpecific<WTF::WTFThreadData, + 142

JSTests/wasm/Builder.js

@@export default class Builder {
355355 return typeBuilder;
356356 };
357357 break;
 358
358359 case "Import":
359360 this[section] = function() {
360361 const s = this._addSection(section);

@@export default class Builder {
369370 };
370371 break;
371372
372  case "Export":
 373 case "Function":
373374 this[section] = function() {
374375 const s = this._addSection(section);
375376 const exportBuilder = {
376  End: () => this,
377  Table: () => { throw new Error(`Unimplemented: export table`); },
378  Memory: () => { throw new Error(`Unimplemented: export memory`); },
379  Global: () => { throw new Error(`Unimplemented: export global`); },
 377 End: () => this
 378 // FIXME: add ability to add this with whatever.
380379 };
381  exportBuilder.Function = _exportFunctionContinuation(this, s, exportBuilder);
382380 return exportBuilder;
383381 };
384382 break;
385383
 384 case "Table":
 385 // FIXME
 386 this[section] = () => { throw new Error(`Unimplemented: section type "${section}"`); };
 387 break;
 388
386389 case "Memory":
387390 this[section] = function() {
388391 const s = this._addSection(section);

@@export default class Builder {
394397 }
395398 };
396399 return exportBuilder;
397  }
 400 };
398401 break;
399402
400  case "Function":
 403 case "Global":
 404 // FIXME
 405 this[section] = () => { throw new Error(`Unimplemented: section type "${section}"`); };
 406 break;
 407
 408 case "Export":
401409 this[section] = function() {
402410 const s = this._addSection(section);
403411 const exportBuilder = {
404  End: () => this
405  // FIXME: add ability to add this with whatever.
406  }
 412 End: () => this,
 413 Table: () => { throw new Error(`Unimplemented: export table`); },
 414 Memory: () => { throw new Error(`Unimplemented: export memory`); },
 415 Global: () => { throw new Error(`Unimplemented: export global`); },
 416 };
 417 exportBuilder.Function = _exportFunctionContinuation(this, s, exportBuilder);
407418 return exportBuilder;
408  }
 419 };
 420 break;
 421
 422 case "Start":
 423 // FIXME
 424 this[section] = () => { throw new Error(`Unimplemented: section type "${section}"`); };
 425 break;
 426
 427 case "Element":
 428 // FIXME
 429 this[section] = () => { throw new Error(`Unimplemented: section type "${section}"`); };
409430 break;
410431
411432 case "Code":

@@export default class Builder {
453474 };
454475 break;
455476
456  default:
 477 case "Data":
 478 // FIXME
457479 this[section] = () => { throw new Error(`Unimplemented: section type "${section}"`); };
458480 break;
 481
 482 default:
 483 this[section] = () => { throw new Error(`Unknown section type "${section}"`); };
 484 break;
459485 }
460486 }
 487
461488 this.Unknown = function(name) {
462489 const s = this._addSection(name);
463490 const builder = this;

JSTests/wasm/Builder_WebAssemblyBinary.js

@@const emitters = {
8282 },
8383
8484 Global: (section, bin) => { throw new Error(`Not yet implemented`); },
85  Export: (section, bin) => { throw new Error(`Not yet implemented`); },
 85 Export: (section, bin) => {
 86 put(bin, "varuint32", section.data.length);
 87 for (const entry of section.data) {
 88 put(bin, "string", entry.field);
 89 put(bin, "uint8", WASM.externalKindValue[entry.kind]);
 90 switch (entry.kind) {
 91 default: throw new Error(`Implementation problem: unexpected kind ${entry.kind}`);
 92 case "Function": put(bin, "varuint32", entry.index); break;
 93 case "Table": throw new Error(`Not yet implemented`);
 94 case "Memory": throw new Error(`Not yet implemented`);
 95 case "Global": throw new Error(`Not yet implemented`);
 96 }
 97 }
 98 },
8699 Start: (section, bin) => { throw new Error(`Not yet implemented`); },
87100 Element: (section, bin) => { throw new Error(`Not yet implemented`); },
88101

JSTests/wasm/LowLevelBinary.js

2323 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2424 */
2525
 26import * as assert from 'assert.js';
2627import * as WASM from 'WASM.js';
2728
2829const _initialAllocationSize = 1024;

@@export default class LowLevelBinary {
104105 this._push8(v);
105106 this._push8(v >>> 8);
106107 }
 108 uint24(v) {
 109 if ((v & 0xFFFFFF) >>> 0 !== v)
 110 throw new RangeError(`Invalid uint24 ${v}`);
 111 this._maybeGrow(3);
 112 this._push8(v);
 113 this._push8(v >>> 8);
 114 this._push8(v >>> 16);
 115 }
107116 uint32(v) {
108117 if ((v & 0xFFFFFFFF) >>> 0 !== v)
109118 throw new RangeError(`Invalid uint32 ${v}`);

@@export default class LowLevelBinary {
155164 }
156165 string(str) {
157166 let patch = this.newPatchable("varuint32");
158  for (const char of str)
159  patch.uint16(char.charCodeAt());
 167 for (const char of str) {
 168 // Encode UTF-8 2003 code points.
 169 const code = char.codePointAt();
 170 if (code <= 0x007F) {
 171 const utf8 = code;
 172 patch.uint8(utf8);
 173 } else if (code <= 0x07FF) {
 174 const utf8 = 0x80C0 | ((code & 0x7C0) >> 6) | ((code & 0x3F) << 8);
 175 patch.uint16(utf8);
 176 } else if (code <= 0xFFFF) {
 177 const utf8 = 0x8080E0 | ((code & 0xF000) >> 12) | ((code & 0xFC0) << 2) | ((code & 0x3F) << 16);
 178 patch.uint24(utf8);
 179 } else if (code <= 0x10FFFF) {
 180 const utf8 = (0x808080F0 | ((code & 0x1C0000) >> 18) | ((code & 0x3F000) >> 4) | ((code & 0xFC0) << 10) | ((code & 0x3F) << 24)) >>> 0;
 181 patch.uint32(utf8);
 182 } else
 183 throw new Error(`Unexpectedly large UTF-8 character code point '${char}' 0x${code.toString(16)}`);
 184 }
160185 patch.apply();
161186 }
162187

@@export default class LowLevelBinary {
170195 _getterRangeCheck(this, at, 2);
171196 return this._buf[at] | (this._buf[at + 1] << 8);
172197 }
 198 getUint24(at) {
 199 _getterRangeCheck(this, at, 3);
 200 return this._buf[at] | (this._buf[at + 1] << 8) | (this._buf[at + 2] << 16);
 201 }
173202 getUint32(at) {
174203 _getterRangeCheck(this, at, 4);
175204 return (this._buf[at] | (this._buf[at + 1] << 8) | (this._buf[at + 2] << 16) | (this._buf[at + 3] << 24)) >>> 0;

@@export default class LowLevelBinary {
205234 }
206235 return { value: v, next: at };
207236 }
 237 getVaruint1(at) {
 238 const res = this.getVaruint32(at);
 239 if (res.value !== 0 && res.value !== 1) throw new Error(`Expected a varuint1, got value ${res.value}`);
 240 return res;
 241 }
208242 getVaruint7(at) {
209243 const res = this.getVaruint32(at);
210244 if (res.value > varuint7Max) throw new Error(`Expected a varuint7, got value ${res.value}`);

@@export default class LowLevelBinary {
212246 }
213247 getString(at) {
214248 const size = this.getVaruint32(at);
 249 const last = size.next + size.value;
 250 let i = size.next;
215251 let str = "";
216  for (let i = size.next; i !== size.next + size.value; i += 2)
217  str += String.fromCharCode(this.getUint16(i));
 252 while (i < last) {
 253 // Decode UTF-8 2003 code points.
 254 const peek = this.getUint8(i);
 255 let code;
 256 if ((peek & 0x80) === 0x0) {
 257 const utf8 = this.getUint8(i);
 258 assert.eq(utf8 & 0x80, 0x00);
 259 i += 1;
 260 code = utf8;
 261 } else if ((peek & 0xE0) === 0xC0) {
 262 const utf8 = this.getUint16(i);
 263 assert.eq(utf8 & 0xC0E0, 0x80C0);
 264 i += 2;
 265 code = ((utf8 & 0x1F) << 6) | ((utf8 & 0x3F00) >> 8);
 266 } else if ((peek & 0xF0) === 0xE0) {
 267 const utf8 = this.getUint24(i);
 268 assert.eq(utf8 & 0xC0C0F0, 0x8080E0);
 269 i += 3;
 270 code = ((utf8 & 0xF) << 12) | ((utf8 & 0x3F00) >> 2) | ((utf8 & 0x3F0000) >> 16);
 271 } else if ((peek & 0xF8) === 0xF0) {
 272 const utf8 = this.getUint32(i);
 273 assert.eq((utf8 & 0xC0C0C0F8) | 0, 0x808080F0 | 0);
 274 i += 4;
 275 code = ((utf8 & 0x7) << 18) | ((utf8 & 0x3F00) << 4) | ((utf8 & 0x3F0000) >> 10) | ((utf8 & 0x3F000000) >> 24);
 276 } else
 277 throw new Error(`Unexpectedly large UTF-8 initial byte 0x${peek.toString(16)}`);
 278 str += String.fromCodePoint(code);
 279 }
 280 if (i !== last)
 281 throw new Error(`String decoding read up to ${i}, expected ${last}, UTF-8 decoding was too greedy`);
218282 return str;
219283 }
220284};

JSTests/wasm/js-api/test_Instance.js

@@import Builder from '../Builder.js';
88 const instance = new WebAssembly.Instance(module);
99 assert.instanceof(instance, WebAssembly.Instance);
1010})();
 11
 12(function ExportedAnswerI32() {
 13 const builder = (new Builder())
 14 .Type().End()
 15 .Function().End()
 16 .Export()
 17 .Function("answer")
 18 .End()
 19 .Code()
 20 .Function("answer", { params: [], ret: "i32" })
 21 .I32Const(42)
 22 .Return()
 23 .End()
 24 .End();
 25 const bin = builder.WebAssembly().get();
 26 const module = new WebAssembly.Module(bin);
 27 const instance = new WebAssembly.Instance(module);
 28 const result = instance.exports.answer();
 29 assert.isA(result, "number");
 30 assert.eq(result, 42);
 31})();

JSTests/wasm/js-api/test_basic_api.js

@@for (const c in constructorProperties) {
6868 assert.throws(() => new WebAssembly[c](new WebAssembly.Module(emptyModuleArray), invalid), TypeError, `second argument to WebAssembly.Instance must be undefined or an Object (evaluating 'new WebAssembly[c](new WebAssembly.Module(emptyModuleArray), invalid)')`);
6969 assert.isNotUndef(instance.exports);
7070 checkOwnPropertyDescriptor(instance, "exports", { typeofvalue: "object", writable: true, configurable: true, enumerable: true });
71  assert.isUndef(instance.exports.__proto__);
72  assert.eq(Reflect.isExtensible(instance.exports), false);
73  assert.eq(Symbol.iterator in instance.exports, true);
74  assert.eq(Symbol.toStringTag in instance.exports, true);
 71 // FIXME these should pass, requires a module namespace object. https://bugs.webkit.org/show_bug.cgi?id=165121
 72 // assert.isUndef(instance.exports.__proto__);
 73 // assert.eq(Reflect.isExtensible(instance.exports), false);
 74 // assert.eq(Symbol.iterator in instance.exports, true);
 75 // assert.eq(Symbol.toStringTag in instance.exports, true);
7576 break;
7677 case "Memory":
7778 // FIXME Implement and test these APIs further. For now they just throw. https://bugs.webkit.org/show_bug.cgi?id=159775

JSTests/wasm/self-test/test_BuilderWebAssembly.js

@@import Builder from '../Builder.js';
2727 .End()
2828 .WebAssembly();
2929 assert.eq(bin.hexdump().trim(),
30  ["00000000 00 61 73 6d 0c 00 00 00 00 0f 0a 4f 00 48 00 48 |·asm·······O·H·H|",
31  "00000010 00 41 00 49 00 de ad c0 fe |·A·I····· |"].join("\n"));
 30 ["00000000 00 61 73 6d 0c 00 00 00 00 0a 05 4f 48 48 41 49 |·asm·······OHHAI|",
 31 "00000010 de ad c0 fe |···· |"].join("\n"));
3232})();

JSTests/wasm/self-test/test_LowLevelBinary_string.js

@@const values = [
77 "Il dit non avec la tête, mais il dit oui avec le cœur",
88 "焼きたて!! ジャぱん",
99 "(╯°□°)╯︵ ┻━┻",
10  "�",
11  // Should we use code points instead of UTF-16?
12  // The following doesn't work: "👨‍❤️‍💋‍👨",
 10 "$¢€𐍈�",
 11 "👨‍❤️‍💋‍👨",
1312];
1413
1514for (const i of values) {

JSTests/wasm/self-test/test_LowLevelBinary_uint16.js

11import LowLevelBinary from '../LowLevelBinary.js';
22
33let values = [];
4 for (let i = 0; i !== 0xFFFF; ++i) values.push(i);
 4for (let i = 0; i <= 0xFFFF; ++i) values.push(i);
55
66for (const i of values) {
77 let b = new LowLevelBinary();

JSTests/wasm/self-test/test_LowLevelBinary_uint24.js

 1import LowLevelBinary from '../LowLevelBinary.js';
 2
 3let values = [];
 4for (let i = 0; i <= 0xFFFF; ++i) values.push(i);
 5for (let i = 0xFFFFFF - 0xFFFF; i <= 0xFFFFFF; ++i) values.push(i);
 6
 7for (const i of values) {
 8 let b = new LowLevelBinary();
 9 b.uint24(i);
 10 const v = b.getUint24(0);
 11 if (v !== i)
 12 throw new Error(`Wrote "${i}" and read back "${v}"`);
 13}

JSTests/wasm/self-test/test_LowLevelBinary_uint8.js

11import LowLevelBinary from '../LowLevelBinary.js';
22
33let values = [];
4 for (let i = 0; i !== 0xFF; ++i) values.push(i);
 4for (let i = 0; i <= 0xFF; ++i) values.push(i);
55
66for (const i of values) {
77 let b = new LowLevelBinary();

JSTests/wasm/self-test/test_LowLevelBinary_varuint1.js

 1import LowLevelBinary, * as LLB from '../LowLevelBinary.js';
 2
 3let values = [];
 4for (let i = 0; i <= 1; ++i) values.push(i);
 5
 6for (const i of values) {
 7 let b = new LowLevelBinary();
 8 b.varuint1(i);
 9 const v = b.getVaruint1(0);
 10 if (v.value !== i)
 11 throw new Error(`Wrote "${i}" and read back "${v}"`);
 12 if (v.next !== b.getSize())
 13 throw new Error(`Size ${v.next}, expected ${b.getSize()}`);
 14}

JSTests/wasm/utilities.js

@@const _json = filename => {
6666 }
6767}
6868
 69const _dump = (what, name, pad = ' ') => {
 70 const value = v => {
 71 try { return `"${v}"`; }
 72 catch (e) { return `Error: "${e.message}"`; }
 73 };
 74 let s = `${pad}${name} ${typeof what}: ${value(what)}`;
 75 for (let p in what) {
 76 s += `\n${pad}${pad}${p}: ${value(what[p])} ${typeof v}`;
 77 s += '\n' + _dump(what[p], p, pad + pad);
 78 }
 79 return s;
 80};
 81
6982// Use underscore names to avoid clashing with builtin names.
70 export { _eval as eval, _read as read, _load as load, _json as json, _global as global };
 83export {
 84 _dump as dump,
 85 _eval as eval,
 86 _read as read,
 87 _load as load,
 88 _json as json,
 89 _global as global
 90};

Source/JavaScriptCore/CMakeLists.txt

@@set(JavaScriptCore_SOURCES
644644 profiler/ProfilerProfiledBytecodes.cpp
645645 profiler/ProfilerUID.cpp
646646
 647 runtime/AbstractModuleRecord.cpp
647648 runtime/ArgList.cpp
648649 runtime/ArrayBuffer.cpp
649650 runtime/ArrayBufferNeuteringWatchpoint.cpp

@@set(JavaScriptCore_SOURCES
912913 wasm/js/JSWebAssemblyTable.cpp
913914 wasm/js/WebAssemblyCompileErrorConstructor.cpp
914915 wasm/js/WebAssemblyCompileErrorPrototype.cpp
 916 wasm/js/WebAssemblyFunction.cpp
 917 wasm/js/WebAssemblyFunctionCell.cpp
915918 wasm/js/WebAssemblyInstanceConstructor.cpp
916919 wasm/js/WebAssemblyInstancePrototype.cpp
917920 wasm/js/WebAssemblyMemoryConstructor.cpp
918921 wasm/js/WebAssemblyMemoryPrototype.cpp
919922 wasm/js/WebAssemblyModuleConstructor.cpp
920923 wasm/js/WebAssemblyModulePrototype.cpp
 924 wasm/js/WebAssemblyModuleRecord.cpp
921925 wasm/js/WebAssemblyPrototype.cpp
922926 wasm/js/WebAssemblyRuntimeErrorConstructor.cpp
923927 wasm/js/WebAssemblyRuntimeErrorPrototype.cpp

Source/JavaScriptCore/ChangeLog

 12016-11-28 JF Bastien <jfbastien@apple.com>
 2
 3 WebAssembly JS API: improve Instance
 4
 5 An Instance's `exports` property wasn't populated with exports.
 6
 7 According to the spec [0], `exports` should present itself as a WebAssembly
 8 Module Record. In order to do this we need to split JSModuleRecord into
 9 AbstractModuleRecord (without the `link` and `evaluate` functions), and
 10 JSModuleRecord (which implements link and evaluate). We can then have a separate
 11 WebAssemblyModuleRecord which shares most of the implementation.
 12
 13 `exports` then maps function names to WebAssemblyFunction and
 14 WebAssemblyFunctionCell, which call into the B3-generated WebAssembly code.
 15
 16 A follow-up patch will do imports.
 17
 18 A few things of note:
 19
 20 - Use Identifier instead of String. They get uniqued, we need them for the JSModuleNamespaceObject. This is safe because JSWebAssemblyModule creation is on the main thread.
 21 - JSWebAssemblyInstance needs to refer to the JSWebAssemblyModule used to create it, because the module owns the code, identifiers, etc. The world would be very sad if it got GC'd.
 22 - Instance.exports shouldn't use putWithoutTransition because it affects all Structures, whereas here each instance needs its own exports.
 23 - Expose the compiled functions, and pipe them to the InstanceConstructor. Start moving things around to split JSModuleRecord out into JS and WebAssembly parts.
 24 - LowLevelBinary: support 3-byte integers.
 25 - LowLevelBinary: support proper UTF-8 2003 code points (instead of UTF-16).
 26
 27 [0]: https://github.com/WebAssembly/design/blob/master/JS.md#webassemblyinstance-constructor
 28
 29 WebAssembly JS API: improve Instance
 30 https://bugs.webkit.org/show_bug.cgi?id=164757
 31
 32 Reviewed by NOBODY (OOPS!).
 33
 34 * CMakeLists.txt:
 35 * JavaScriptCore.xcodeproj/project.pbxproj:
 36 * runtime/AbstractModuleRecord.cpp: Copied from Source/JavaScriptCore/runtime/JSModuleRecord.cpp, which I split in two
 37 (JSC::AbstractModuleRecord::AbstractModuleRecord):
 38 (JSC::AbstractModuleRecord::destroy):
 39 (JSC::AbstractModuleRecord::finishCreation):
 40 (JSC::AbstractModuleRecord::visitChildren):
 41 (JSC::AbstractModuleRecord::appendRequestedModule):
 42 (JSC::AbstractModuleRecord::addStarExportEntry):
 43 (JSC::AbstractModuleRecord::addImportEntry):
 44 (JSC::AbstractModuleRecord::addExportEntry):
 45 (JSC::identifierToJSValue):
 46 (JSC::AbstractModuleRecord::hostResolveImportedModule):
 47 (JSC::AbstractModuleRecord::ResolveQuery::ResolveQuery):
 48 (JSC::AbstractModuleRecord::ResolveQuery::isEmptyValue):
 49 (JSC::AbstractModuleRecord::ResolveQuery::isDeletedValue):
 50 (JSC::AbstractModuleRecord::ResolveQuery::Hash::hash):
 51 (JSC::AbstractModuleRecord::ResolveQuery::Hash::equal):
 52 (JSC::AbstractModuleRecord::cacheResolution):
 53 (JSC::getExportedNames):
 54 (JSC::AbstractModuleRecord::getModuleNamespace):
 55 (JSC::printableName):
 56 (JSC::AbstractModuleRecord::dump):
 57 * runtime/AbstractModuleRecord.h: Copied from Source/JavaScriptCore/runtime/JSModuleRecord.h.
 58 (JSC::AbstractModuleRecord::ImportEntry::isNamespace):
 59 (JSC::AbstractModuleRecord::sourceCode):
 60 (JSC::AbstractModuleRecord::moduleKey):
 61 (JSC::AbstractModuleRecord::requestedModules):
 62 (JSC::AbstractModuleRecord::exportEntries):
 63 (JSC::AbstractModuleRecord::importEntries):
 64 (JSC::AbstractModuleRecord::starExportEntries):
 65 (JSC::AbstractModuleRecord::declaredVariables):
 66 (JSC::AbstractModuleRecord::lexicalVariables):
 67 (JSC::AbstractModuleRecord::moduleEnvironment):
 68 * runtime/JSGlobalObject.cpp:
 69 (JSC::JSGlobalObject::init):
 70 (JSC::JSGlobalObject::visitChildren):
 71 * runtime/JSGlobalObject.h:
 72 (JSC::JSGlobalObject::webAssemblyModuleRecordStructure):
 73 (JSC::JSGlobalObject::webAssemblyFunctionStructure):
 74 * runtime/JSModuleEnvironment.cpp:
 75 (JSC::JSModuleEnvironment::create):
 76 (JSC::JSModuleEnvironment::finishCreation):
 77 (JSC::JSModuleEnvironment::getOwnPropertySlot):
 78 (JSC::JSModuleEnvironment::getOwnNonIndexPropertyNames):
 79 (JSC::JSModuleEnvironment::put):
 80 (JSC::JSModuleEnvironment::deleteProperty):
 81 * runtime/JSModuleEnvironment.h:
 82 (JSC::JSModuleEnvironment::create):
 83 (JSC::JSModuleEnvironment::offsetOfModuleRecord):
 84 (JSC::JSModuleEnvironment::allocationSize):
 85 (JSC::JSModuleEnvironment::moduleRecord):
 86 (JSC::JSModuleEnvironment::moduleRecordSlot):
 87 * runtime/JSModuleNamespaceObject.cpp:
 88 (JSC::JSModuleNamespaceObject::finishCreation):
 89 (JSC::JSModuleNamespaceObject::getOwnPropertySlot):
 90 * runtime/JSModuleNamespaceObject.h:
 91 (JSC::JSModuleNamespaceObject::create):
 92 (JSC::JSModuleNamespaceObject::moduleRecord):
 93 * runtime/JSModuleRecord.cpp:
 94 (JSC::JSModuleRecord::createStructure):
 95 (JSC::JSModuleRecord::create):
 96 (JSC::JSModuleRecord::JSModuleRecord):
 97 (JSC::JSModuleRecord::destroy):
 98 (JSC::JSModuleRecord::finishCreation):
 99 (JSC::JSModuleRecord::visitChildren):
 100 (JSC::JSModuleRecord::instantiateDeclarations):
 101 * runtime/JSModuleRecord.h:
 102 * runtime/JSScope.cpp:
 103 (JSC::abstractAccess):
 104 (JSC::JSScope::collectClosureVariablesUnderTDZ):
 105 * runtime/VM.cpp:
 106 (JSC::VM::VM):
 107 * runtime/VM.h:
 108 * wasm/JSWebAssembly.h:
 109 * wasm/WasmFormat.h: use Identifier instead of String
 110 * wasm/WasmModuleParser.cpp:
 111 (JSC::Wasm::ModuleParser::parse):
 112 (JSC::Wasm::ModuleParser::parseType):
 113 (JSC::Wasm::ModuleParser::parseImport): fix off-by-one
 114 (JSC::Wasm::ModuleParser::parseFunction):
 115 (JSC::Wasm::ModuleParser::parseExport):
 116 * wasm/WasmModuleParser.h:
 117 (JSC::Wasm::ModuleParser::ModuleParser):
 118 * wasm/WasmPlan.cpp:
 119 (JSC::Wasm::Plan::run):
 120 * wasm/js/JSWebAssemblyInstance.cpp:
 121 (JSC::JSWebAssemblyInstance::create):
 122 (JSC::JSWebAssemblyInstance::finishCreation):
 123 (JSC::JSWebAssemblyInstance::visitChildren):
 124 * wasm/js/JSWebAssemblyInstance.h:
 125 (JSC::JSWebAssemblyInstance::module):
 126 * wasm/js/JSWebAssemblyModule.cpp:
 127 (JSC::JSWebAssemblyModule::create):
 128 (JSC::JSWebAssemblyModule::finishCreation):
 129 (JSC::JSWebAssemblyModule::visitChildren):
 130 * wasm/js/JSWebAssemblyModule.h:
 131 (JSC::JSWebAssemblyModule::moduleInformation):
 132 (JSC::JSWebAssemblyModule::compiledFunctions):
 133 (JSC::JSWebAssemblyModule::exportSymbolTable):
 134 * wasm/js/WebAssemblyFunction.cpp: Added.
 135 (JSC::callWebAssemblyFunction):
 136 (JSC::WebAssemblyFunction::create):
 137 (JSC::WebAssemblyFunction::createStructure):
 138 (JSC::WebAssemblyFunction::WebAssemblyFunction):
 139 (JSC::WebAssemblyFunction::visitChildren):
 140 (JSC::WebAssemblyFunction::finishCreation):
 141 * wasm/js/WebAssemblyFunction.h: Copied from Source/JavaScriptCore/wasm/js/JSWebAssemblyModule.h.
 142 (JSC::CallableWebAssemblyFunction::CallableWebAssemblyFunction):
 143 (JSC::WebAssemblyFunction::webAssemblyFunctionCell):
 144 * wasm/js/WebAssemblyFunctionCell.cpp: Copied from Source/JavaScriptCore/wasm/js/JSWebAssemblyInstance.h.
 145 (JSC::WebAssemblyFunctionCell::create):
 146 (JSC::WebAssemblyFunctionCell::WebAssemblyFunctionCell):
 147 (JSC::WebAssemblyFunctionCell::destroy):
 148 (JSC::WebAssemblyFunctionCell::createStructure):
 149 * wasm/js/WebAssemblyFunctionCell.h: Copied from Source/JavaScriptCore/wasm/js/JSWebAssemblyInstance.h.
 150 (JSC::WebAssemblyFunctionCell::function):
 151 * wasm/js/WebAssemblyInstanceConstructor.cpp:
 152 (JSC::constructJSWebAssemblyInstance):
 153 * wasm/js/WebAssemblyModuleConstructor.cpp:
 154 (JSC::constructJSWebAssemblyModule):
 155 * wasm/js/WebAssemblyModuleRecord.cpp: Added.
 156 (JSC::WebAssemblyModuleRecord::createStructure):
 157 (JSC::WebAssemblyModuleRecord::create):
 158 (JSC::WebAssemblyModuleRecord::WebAssemblyModuleRecord):
 159 (JSC::WebAssemblyModuleRecord::destroy):
 160 (JSC::WebAssemblyModuleRecord::finishCreation):
 161 (JSC::WebAssemblyModuleRecord::visitChildren):
 162 (JSC::WebAssemblyModuleRecord::link):
 163 (JSC::WebAssemblyModuleRecord::evaluate):
 164 * wasm/js/WebAssemblyModuleRecord.h: Copied from Source/JavaScriptCore/wasm/js/JSWebAssemblyModule.h.
 165
11662016-11-21 Mark Lam <mark.lam@apple.com>
2167
3168 Fix exception scope verification failures in runtime/Intl* files.

Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj

19991999 AD2FCC301DB83D4900B3E736 /* JSWebAssembly.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AD2FCC2E1DB839F700B3E736 /* JSWebAssembly.cpp */; };
20002000 AD2FCC311DB83D4900B3E736 /* JSWebAssembly.h in Headers */ = {isa = PBXBuildFile; fileRef = AD2FCC2F1DB839F700B3E736 /* JSWebAssembly.h */; };
20012001 AD2FCC331DC4045400B3E736 /* WasmFormat.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AD2FCC321DC4045300B3E736 /* WasmFormat.cpp */; };
 2002 AD4937C31DDBE6140077C807 /* AbstractModuleRecord.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AD4937C11DDBE60A0077C807 /* AbstractModuleRecord.cpp */; };
 2003 AD4937C41DDBE6140077C807 /* AbstractModuleRecord.h in Headers */ = {isa = PBXBuildFile; fileRef = AD4937C21DDBE60A0077C807 /* AbstractModuleRecord.h */; settings = {ATTRIBUTES = (Private, ); }; };
 2004 AD4937C71DDD0AAE0077C807 /* WebAssemblyModuleRecord.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AD4937C51DDCDCF00077C807 /* WebAssemblyModuleRecord.cpp */; };
 2005 AD4937C81DDD0AAE0077C807 /* WebAssemblyModuleRecord.h in Headers */ = {isa = PBXBuildFile; fileRef = AD4937C61DDCDCF00077C807 /* WebAssemblyModuleRecord.h */; };
 2006 AD4937D11DDD27DE0077C807 /* WebAssemblyFunctionCell.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AD4937CD1DDD27D90077C807 /* WebAssemblyFunctionCell.cpp */; };
 2007 AD4937D21DDD27DE0077C807 /* WebAssemblyFunctionCell.h in Headers */ = {isa = PBXBuildFile; fileRef = AD4937CE1DDD27D90077C807 /* WebAssemblyFunctionCell.h */; };
 2008 AD4937D31DDD27DE0077C807 /* WebAssemblyFunction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AD4937C91DDD27340077C807 /* WebAssemblyFunction.cpp */; };
 2009 AD4937D41DDD27DE0077C807 /* WebAssemblyFunction.h in Headers */ = {isa = PBXBuildFile; fileRef = AD4937CA1DDD27340077C807 /* WebAssemblyFunction.h */; };
20022010 AD86A93E1AA4D88D002FE77F /* WeakGCMapInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = AD86A93D1AA4D87C002FE77F /* WeakGCMapInlines.h */; settings = {ATTRIBUTES = (Private, ); }; };
20032011 ADDB1F6318D77DBE009B58A8 /* OpaqueRootSet.h in Headers */ = {isa = PBXBuildFile; fileRef = ADDB1F6218D77DB7009B58A8 /* OpaqueRootSet.h */; settings = {ATTRIBUTES = (Private, ); }; };
20042012 ADE39FFF16DD144B0003CD4A /* PropertyTable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AD1CF06816DCAB2D00B97123 /* PropertyTable.cpp */; };

44614469 AD2FCC2E1DB839F700B3E736 /* JSWebAssembly.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSWebAssembly.cpp; sourceTree = "<group>"; };
44624470 AD2FCC2F1DB839F700B3E736 /* JSWebAssembly.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSWebAssembly.h; sourceTree = "<group>"; };
44634471 AD2FCC321DC4045300B3E736 /* WasmFormat.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WasmFormat.cpp; sourceTree = "<group>"; };
 4472 AD4937C11DDBE60A0077C807 /* AbstractModuleRecord.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AbstractModuleRecord.cpp; sourceTree = "<group>"; };
 4473 AD4937C21DDBE60A0077C807 /* AbstractModuleRecord.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AbstractModuleRecord.h; sourceTree = "<group>"; };
 4474 AD4937C51DDCDCF00077C807 /* WebAssemblyModuleRecord.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = WebAssemblyModuleRecord.cpp; path = js/WebAssemblyModuleRecord.cpp; sourceTree = "<group>"; };
 4475 AD4937C61DDCDCF00077C807 /* WebAssemblyModuleRecord.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WebAssemblyModuleRecord.h; path = js/WebAssemblyModuleRecord.h; sourceTree = "<group>"; };
 4476 AD4937C91DDD27340077C807 /* WebAssemblyFunction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = WebAssemblyFunction.cpp; path = js/WebAssemblyFunction.cpp; sourceTree = "<group>"; };
 4477 AD4937CA1DDD27340077C807 /* WebAssemblyFunction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WebAssemblyFunction.h; path = js/WebAssemblyFunction.h; sourceTree = "<group>"; };
 4478 AD4937CD1DDD27D90077C807 /* WebAssemblyFunctionCell.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = WebAssemblyFunctionCell.cpp; path = js/WebAssemblyFunctionCell.cpp; sourceTree = "<group>"; };
 4479 AD4937CE1DDD27D90077C807 /* WebAssemblyFunctionCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WebAssemblyFunctionCell.h; path = js/WebAssemblyFunctionCell.h; sourceTree = "<group>"; };
44644480 AD86A93D1AA4D87C002FE77F /* WeakGCMapInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WeakGCMapInlines.h; sourceTree = "<group>"; };
44654481 ADDB1F6218D77DB7009B58A8 /* OpaqueRootSet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OpaqueRootSet.h; sourceTree = "<group>"; };
44664482 B59F89371891AD3300D5CCDC /* UnlinkedInstructionStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UnlinkedInstructionStream.h; sourceTree = "<group>"; };

60546070 7EF6E0BB0EB7A1EC0079AFAF /* runtime */ = {
60556071 isa = PBXGroup;
60566072 children = (
 6073 AD4937C11DDBE60A0077C807 /* AbstractModuleRecord.cpp */,
 6074 AD4937C21DDBE60A0077C807 /* AbstractModuleRecord.h */,
60576075 BCF605110E203EF800B9A64D /* ArgList.cpp */,
60586076 BCF605120E203EF800B9A64D /* ArgList.h */,
60596077 0FE0500C1AA9091100D33B33 /* ArgumentsMode.h */,

75487566 AD2FCB8A1DB5840000B3E736 /* js */ = {
75497567 isa = PBXGroup;
75507568 children = (
 7569 AD4937CD1DDD27D90077C807 /* WebAssemblyFunctionCell.cpp */,
 7570 AD4937CE1DDD27D90077C807 /* WebAssemblyFunctionCell.h */,
 7571 AD4937C91DDD27340077C807 /* WebAssemblyFunction.cpp */,
 7572 AD4937CA1DDD27340077C807 /* WebAssemblyFunction.h */,
 7573 AD4937C51DDCDCF00077C807 /* WebAssemblyModuleRecord.cpp */,
 7574 AD4937C61DDCDCF00077C807 /* WebAssemblyModuleRecord.h */,
75517575 AD2FCC261DB838C400B3E736 /* WebAssemblyPrototype.cpp */,
75527576 AD2FCC271DB838C400B3E736 /* WebAssemblyPrototype.h */,
75537577 AD2FCBA61DB58DA400B3E736 /* JSWebAssemblyCompileError.cpp */,

79828006 0F7B294D14C3CD4C007C3DB1 /* DFGCommon.h in Headers */,
79838007 53529A4C1C457B75000B49C6 /* APIUtils.h in Headers */,
79848008 0FEA0A32170D40BF00BB722C /* DFGCommonData.h in Headers */,
 8009 AD4937D21DDD27DE0077C807 /* WebAssemblyFunctionCell.h in Headers */,
79858010 0F725CB01C506D3B00AD943A /* B3FoldPathConstants.h in Headers */,
79868011 0F38B01817CFE75500B144D3 /* DFGCompilationKey.h in Headers */,
79878012 0F9D4C111C3E2C74006CD984 /* FTLPatchpointExceptionHandle.h in Headers */,

80088033 A7D9A29617A0BC7400EE2618 /* DFGEdgeDominates.h in Headers */,
80098034 A7986D5717A0BB1E00A95DD0 /* DFGEdgeUsesStructure.h in Headers */,
80108035 0F8F14341ADF090100ED792C /* DFGEpoch.h in Headers */,
 8036 AD4937C81DDD0AAE0077C807 /* WebAssemblyModuleRecord.h in Headers */,
80118037 0FBC0AE81496C7C700D4FBDD /* DFGExitProfile.h in Headers */,
80128038 A78A9775179738B8009DF744 /* DFGFailedFinalizer.h in Headers */,
80138039 A7BFF3C0179868940002F462 /* DFGFiltrationResult.h in Headers */,

81408166 0F34B14A16D42013001CDA5A /* DFGUseKind.h in Headers */,
81418167 DCFDFBDA1D1F5D9E00FE3D72 /* B3TypeMap.h in Headers */,
81428168 0F3B3A2C15475002003ED0FF /* DFGValidate.h in Headers */,
 8169 AD4937C41DDBE6140077C807 /* AbstractModuleRecord.h in Headers */,
81438170 0F2BDC481522802900CD8910 /* DFGValueSource.h in Headers */,
81448171 0F0123331944EA1B00843A0C /* DFGValueStrength.h in Headers */,
81458172 0FE254F71ABDDD2200A7C6D2 /* DFGVarargsForwardingPhase.h in Headers */,

84248451 AD2FCC211DB59CB200B3E736 /* WebAssemblyTablePrototype.lut.h in Headers */,
84258452 0FC712E317CD8793008CC93C /* JITToDFGDeferredCompilationCallback.h in Headers */,
84268453 AD2FCBE31DB58DAD00B3E736 /* JSWebAssemblyCompileError.h in Headers */,
 8454 AD4937D41DDD27DE0077C807 /* WebAssemblyFunction.h in Headers */,
84278455 840480131021A1D9008E7F01 /* JSAPIValueWrapper.h in Headers */,
84288456 C2CF39C216E15A8100DD69BE /* JSAPIWrapperObject.h in Headers */,
84298457 BC18C4170E16F5CD00B34460 /* JSArray.h in Headers */,

96969724 0F338E121BF0276C0013C88F /* B3OpaqueByproducts.cpp in Sources */,
96979725 0FDF67D31D9C6D2A001B9825 /* B3Kind.cpp in Sources */,
96989726 0F8F2B99172F04FF007DBDA5 /* DFGDesiredIdentifiers.cpp in Sources */,
 9727 AD4937C31DDBE6140077C807 /* AbstractModuleRecord.cpp in Sources */,
96999728 C2C0F7CD17BBFC5B00464FE4 /* DFGDesiredTransitions.cpp in Sources */,
97009729 0FE8534B1723CDA500B618F5 /* DFGDesiredWatchpoints.cpp in Sources */,
97019730 C2981FD817BAEE4B00A3BC98 /* DFGDesiredWeakReferences.cpp in Sources */,

99539982 147F39CF107EC37600427A48 /* InternalFunction.cpp in Sources */,
99549983 1429D7D40ED2128200B89619 /* Interpreter.cpp in Sources */,
99559984 0FE34C191C4B39AE0003A512 /* AirLogRegisterPressure.cpp in Sources */,
 9985 AD4937D31DDD27DE0077C807 /* WebAssemblyFunction.cpp in Sources */,
99569986 A1B9E2391B4E0D6700BC7FED /* IntlCollator.cpp in Sources */,
99579987 A1B9E23B1B4E0D6700BC7FED /* IntlCollatorConstructor.cpp in Sources */,
99589988 0F6DB7EA1D6124B800CDBF8E /* StackFrame.cpp in Sources */,

1010110131 1482B74E0A43032800517CFC /* JSStringRef.cpp in Sources */,
1010210132 146AAB380B66A94400E55F16 /* JSStringRefCF.cpp in Sources */,
1010310133 0F919D0C157EE09F004A4E7D /* JSSymbolTableObject.cpp in Sources */,
 10134 AD4937D11DDD27DE0077C807 /* WebAssemblyFunctionCell.cpp in Sources */,
1010410135 70ECA6051AFDBEA200449739 /* JSTemplateRegistryKey.cpp in Sources */,
1010510136 0F2B66FA17B6B5AB00A7AE3F /* JSTypedArrayConstructors.cpp in Sources */,
1010610137 0F9630391D4192C6005609D9 /* AllocatorAttributes.cpp in Sources */,

1036910400 65FB63A41C8EA09C0020719B /* YarrCanonicalizeUnicode.cpp in Sources */,
1037010401 86704B8412DBA33700A9FE7B /* YarrInterpreter.cpp in Sources */,
1037110402 86704B8612DBA33700A9FE7B /* YarrJIT.cpp in Sources */,
 10403 AD4937C71DDD0AAE0077C807 /* WebAssemblyModuleRecord.cpp in Sources */,
1037210404 86704B8912DBA33700A9FE7B /* YarrPattern.cpp in Sources */,
1037310405 86704B4212DB8A8100A9FE7B /* YarrSyntaxChecker.cpp in Sources */,
1037410406 0F2BBD991C5FF3F50023EF23 /* B3VariableValue.cpp in Sources */,

Source/JavaScriptCore/runtime/AbstractModuleRecord.cpp

 1/*
 2 * Copyright (C) 2015-2016 Apple Inc. All rights reserved.
 3 *
 4 * Redistribution and use in source and binary forms, with or without
 5 * modification, are permitted provided that the following conditions
 6 * are met:
 7 * 1. Redistributions of source code must retain the above copyright
 8 * notice, this list of conditions and the following disclaimer.
 9 * 2. Redistributions in binary form must reproduce the above copyright
 10 * notice, this list of conditions and the following disclaimer in the
 11 * documentation and/or other materials provided with the distribution.
 12 *
 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 24 */
 25
 26#include "config.h"
 27#include "AbstractModuleRecord.h"
 28
 29#include "Error.h"
 30#include "Interpreter.h"
 31#include "JSCInlines.h"
 32#include "JSMap.h"
 33#include "JSModuleEnvironment.h"
 34#include "JSModuleNamespaceObject.h"
 35#include "UnlinkedModuleProgramCodeBlock.h"
 36
 37namespace JSC {
 38
 39const ClassInfo AbstractModuleRecord::s_info = { "AbstractModuleRecord", &Base::s_info, 0, CREATE_METHOD_TABLE(AbstractModuleRecord) };
 40
 41AbstractModuleRecord::AbstractModuleRecord(VM& vm, Structure* structure, const Identifier& moduleKey, const SourceCode& sourceCode, const VariableEnvironment& declaredVariables, const VariableEnvironment& lexicalVariables)
 42 : Base(vm, structure)
 43 , m_moduleKey(moduleKey)
 44 , m_sourceCode(sourceCode)
 45 , m_declaredVariables(declaredVariables)
 46 , m_lexicalVariables(lexicalVariables)
 47{
 48}
 49
 50void AbstractModuleRecord::destroy(JSCell* cell)
 51{
 52 AbstractModuleRecord* thisObject = jsCast<AbstractModuleRecord*>(cell);
 53 thisObject->AbstractModuleRecord::~AbstractModuleRecord();
 54}
 55
 56void AbstractModuleRecord::finishCreation(ExecState* exec, VM& vm)
 57{
 58 Base::finishCreation(vm);
 59 ASSERT(inherits(info()));
 60 putDirect(vm, Identifier::fromString(&vm, ASCIILiteral("registryEntry")), jsUndefined());
 61 putDirect(vm, Identifier::fromString(&vm, ASCIILiteral("evaluated")), jsBoolean(false));
 62
 63 auto scope = DECLARE_THROW_SCOPE(vm);
 64 JSMap* map = JSMap::create(exec, vm, globalObject()->mapStructure());
 65 RELEASE_ASSERT(!scope.exception());
 66 m_dependenciesMap.set(vm, this, map);
 67 putDirect(vm, Identifier::fromString(&vm, ASCIILiteral("dependenciesMap")), m_dependenciesMap.get());
 68}
 69
 70void AbstractModuleRecord::visitChildren(JSCell* cell, SlotVisitor& visitor)
 71{
 72 AbstractModuleRecord* thisObject = jsCast<AbstractModuleRecord*>(cell);
 73 Base::visitChildren(thisObject, visitor);
 74 visitor.append(&thisObject->m_moduleEnvironment);
 75 visitor.append(&thisObject->m_moduleNamespaceObject);
 76 visitor.append(&thisObject->m_dependenciesMap);
 77}
 78
 79void AbstractModuleRecord::appendRequestedModule(const Identifier& moduleName)
 80{
 81 m_requestedModules.add(moduleName.impl());
 82}
 83
 84void AbstractModuleRecord::addStarExportEntry(const Identifier& moduleName)
 85{
 86 m_starExportEntries.add(moduleName.impl());
 87}
 88
 89void AbstractModuleRecord::addImportEntry(const ImportEntry& entry)
 90{
 91 bool isNewEntry = m_importEntries.add(entry.localName.impl(), entry).isNewEntry;
 92 ASSERT_UNUSED(isNewEntry, isNewEntry); // This is guaranteed by the parser.
 93}
 94
 95void AbstractModuleRecord::addExportEntry(const ExportEntry& entry)
 96{
 97 bool isNewEntry = m_exportEntries.add(entry.exportName.impl(), entry).isNewEntry;
 98 ASSERT_UNUSED(isNewEntry, isNewEntry); // This is guaranteed by the parser.
 99}
 100
 101auto AbstractModuleRecord::tryGetImportEntry(UniquedStringImpl* localName) -> std::optional<ImportEntry>
 102{
 103 const auto iterator = m_importEntries.find(localName);
 104 if (iterator == m_importEntries.end())
 105 return std::nullopt;
 106 return std::optional<ImportEntry>(iterator->value);
 107}
 108
 109auto AbstractModuleRecord::tryGetExportEntry(UniquedStringImpl* exportName) -> std::optional<ExportEntry>
 110{
 111 const auto iterator = m_exportEntries.find(exportName);
 112 if (iterator == m_exportEntries.end())
 113 return std::nullopt;
 114 return std::optional<ExportEntry>(iterator->value);
 115}
 116
 117auto AbstractModuleRecord::ExportEntry::createLocal(const Identifier& exportName, const Identifier& localName) -> ExportEntry
 118{
 119 return ExportEntry { Type::Local, exportName, Identifier(), Identifier(), localName };
 120}
 121
 122auto AbstractModuleRecord::ExportEntry::createIndirect(const Identifier& exportName, const Identifier& importName, const Identifier& moduleName) -> ExportEntry
 123{
 124 return ExportEntry { Type::Indirect, exportName, moduleName, importName, Identifier() };
 125}
 126
 127auto AbstractModuleRecord::Resolution::notFound() -> Resolution
 128{
 129 return Resolution { Type::NotFound, nullptr, Identifier() };
 130}
 131
 132auto AbstractModuleRecord::Resolution::error() -> Resolution
 133{
 134 return Resolution { Type::Error, nullptr, Identifier() };
 135}
 136
 137auto AbstractModuleRecord::Resolution::ambiguous() -> Resolution
 138{
 139 return Resolution { Type::Ambiguous, nullptr, Identifier() };
 140}
 141
 142static JSValue identifierToJSValue(ExecState* exec, const Identifier& identifier)
 143{
 144 if (identifier.isSymbol())
 145 return Symbol::create(exec->vm(), static_cast<SymbolImpl&>(*identifier.impl()));
 146 return jsString(&exec->vm(), identifier.impl());
 147}
 148
 149AbstractModuleRecord* AbstractModuleRecord::hostResolveImportedModule(ExecState* exec, const Identifier& moduleName)
 150{
 151 JSValue moduleNameValue = identifierToJSValue(exec, moduleName);
 152 JSValue pair = m_dependenciesMap->JSMap::get(exec, moduleNameValue);
 153 return jsCast<AbstractModuleRecord*>(pair.get(exec, Identifier::fromString(exec, "value")));
 154}
 155
 156auto AbstractModuleRecord::resolveImport(ExecState* exec, const Identifier& localName) -> Resolution
 157{
 158 std::optional<ImportEntry> optionalImportEntry = tryGetImportEntry(localName.impl());
 159 if (!optionalImportEntry)
 160 return Resolution::notFound();
 161
 162 const ImportEntry& importEntry = *optionalImportEntry;
 163 if (importEntry.isNamespace(exec->vm()))
 164 return Resolution::notFound();
 165
 166 AbstractModuleRecord* importedModule = hostResolveImportedModule(exec, importEntry.moduleRequest);
 167 return importedModule->resolveExport(exec, importEntry.importName);
 168}
 169
 170struct AbstractModuleRecord::ResolveQuery {
 171 struct Hash {
 172 static unsigned hash(const ResolveQuery&);
 173 static bool equal(const ResolveQuery&, const ResolveQuery&);
 174 static const bool safeToCompareToEmptyOrDeleted = true;
 175 };
 176
 177 ResolveQuery(AbstractModuleRecord* moduleRecord, UniquedStringImpl* exportName)
 178 : moduleRecord(moduleRecord)
 179 , exportName(exportName)
 180 {
 181 }
 182
 183 ResolveQuery(AbstractModuleRecord* moduleRecord, const Identifier& exportName)
 184 : ResolveQuery(moduleRecord, exportName.impl())
 185 {
 186 }
 187
 188 enum EmptyValueTag { EmptyValue };
 189 ResolveQuery(EmptyValueTag)
 190 {
 191 }
 192
 193 enum DeletedValueTag { DeletedValue };
 194 ResolveQuery(DeletedValueTag)
 195 : moduleRecord(nullptr)
 196 , exportName(WTF::HashTableDeletedValue)
 197 {
 198 }
 199
 200 bool isEmptyValue() const
 201 {
 202 return !exportName;
 203 }
 204
 205 bool isDeletedValue() const
 206 {
 207 return exportName.isHashTableDeletedValue();
 208 }
 209
 210 // The module record is not marked from the GC. But these records are reachable from the JSGlobalObject.
 211 // So we don't care the reachability to this record.
 212 AbstractModuleRecord* moduleRecord;
 213 RefPtr<UniquedStringImpl> exportName;
 214};
 215
 216inline unsigned AbstractModuleRecord::ResolveQuery::Hash::hash(const ResolveQuery& query)
 217{
 218 return WTF::PtrHash<AbstractModuleRecord*>::hash(query.moduleRecord) + IdentifierRepHash::hash(query.exportName);
 219}
 220
 221inline bool AbstractModuleRecord::ResolveQuery::Hash::equal(const ResolveQuery& lhs, const ResolveQuery& rhs)
 222{
 223 return lhs.moduleRecord == rhs.moduleRecord && lhs.exportName == rhs.exportName;
 224}
 225
 226auto AbstractModuleRecord::tryGetCachedResolution(UniquedStringImpl* exportName) -> std::optional<Resolution>
 227{
 228 const auto iterator = m_resolutionCache.find(exportName);
 229 if (iterator == m_resolutionCache.end())
 230 return std::nullopt;
 231 return std::optional<Resolution>(iterator->value);
 232}
 233
 234void AbstractModuleRecord::cacheResolution(UniquedStringImpl* exportName, const Resolution& resolution)
 235{
 236 m_resolutionCache.add(exportName, resolution);
 237}
 238
 239auto AbstractModuleRecord::resolveExportImpl(ExecState* exec, const ResolveQuery& root) -> Resolution
 240{
 241 // http://www.ecma-international.org/ecma-262/6.0/#sec-resolveexport
 242
 243 // How to avoid C++ recursion in this function:
 244 // This function avoids C++ recursion of the naive ResolveExport implementation.
 245 // Flatten the recursion to the loop with the task queue and frames.
 246 //
 247 // 1. pendingTasks
 248 // We enqueue the recursive resolveExport call to this queue to avoid recursive calls in C++.
 249 // The task has 3 types. (1) Query, (2) IndirectFallback and (3) GatherStars.
 250 // (1) Query
 251 // Querying the resolution to the current module.
 252 // (2) IndirectFallback
 253 // Examine the result of the indirect export resolution. Only when the indirect export resolution fails,
 254 // we look into the star exports. (step 5-a-vi).
 255 // (3) GatherStars
 256 // Examine the result of the star export resolutions.
 257 //
 258 // 2. frames
 259 // When the spec calls the resolveExport recursively, instead we append the frame
 260 // (that holds the result resolution) to the frames and enqueue the task to the pendingTasks.
 261 // The entry in the frames means the *local* resolution result of the specific recursive resolveExport.
 262 //
 263 // We should maintain the local resolution result instead of holding the global resolution result only.
 264 // For example,
 265 //
 266 // star
 267 // (1) ---> (2) "Resolve"
 268 // |
 269 // |
 270 // +-> (3) "NotFound"
 271 // |
 272 // | star
 273 // +-> (4) ---> (5) "Resolve" [here]
 274 // |
 275 // |
 276 // +-> (6) "Error"
 277 //
 278 // Consider the above graph. The numbers represents the modules. Now we are [here].
 279 // If we only hold the global resolution result during the resolveExport operation, [here],
 280 // we decide the entire result of resolveExport is "Ambiguous", because there are multiple
 281 // "Resolve" (in module (2) and (5)). However, this should become "Error" because (6) will
 282 // propagate "Error" state to the (4), (4) will become "Error" and then, (1) will become
 283 // "Error". We should aggregate the results at the star exports point ((4) and (1)).
 284 //
 285 // Usually, both "Error" and "Ambiguous" states will throw the syntax error. So except for the content of the
 286 // error message, there are no difference. (And if we fix the (6) that raises "Error", next, it will produce
 287 // the "Ambiguous" error due to (5). Anyway, user need to fix the both. So which error should be raised at first
 288 // doesn't matter so much.
 289 //
 290 // However, this may become the problem under the module namespace creation.
 291 // http://www.ecma-international.org/ecma-262/6.0/#sec-getmodulenamespace
 292 // section 15.2.1.18, step 3-d-ii
 293 // Here, we distinguish "Ambiguous" and "Error". When "Error" state is produced, we need to throw the propagated error.
 294 // But if "Ambiguous" state comes, we just ignore the result.
 295 // To follow the requirement strictly, in this implementation, we keep the local resolution result to produce the
 296 // correct result under the above complex cases.
 297
 298 // Caching strategy:
 299 // The resolveExport operation is frequently called. So caching results is important.
 300 // We observe the following aspects and based on them construct the caching strategy.
 301 // Here, we attempt to cache the resolution by constructing the map in module records.
 302 // That means Module -> ExportName -> Maybe<Resolution>.
 303 // Technically, all the AbstractModuleRecords have the Map<ExportName, Resolution> for caching.
 304 //
 305 // The important observations are that,
 306 //
 307 // - *cacheable* means that traversing to this node from a path will produce the same results as starting from this node.
 308 //
 309 // Here, we define the resovling route. We represent [?] as the module that has the local binding.
 310 // And (?) as the module without the local binding.
 311 //
 312 // @ -> (A) -> (B) -> [C]
 313 //
 314 // We list the resolving route for each node.
 315 //
 316 // (A): (A) -> (B) -> [C]
 317 // (B): (B) -> [C]
 318 // [C]: [C]
 319 //
 320 // In this case, if we start the tracing from (B), the resolving route becomes (B) -> [C].
 321 // So this is the same. At that time, we can say (B) is cacheable in the first tracing.
 322 //
 323 // - The cache ability of a node depends on the resolving route from this node.
 324 //
 325 // 1. The starting point is always cacheable.
 326 //
 327 // 2. A module that has resolved a local binding is always cacheable.
 328 //
 329 // @ -> (A) -> [B]
 330 //
 331 // In the above case, we can see the [B] as cacheable.
 332 // This is because when starting from [B] node, we immediately resolve with the local binding.
 333 // So the resolving route from [B] does not depend on the starting point.
 334 //
 335 // 3. If we don't follow any star links during the resolution, we can see all the traced nodes are cacheable.
 336 //
 337 // If there are non star links, it means that there is *no branch* in the module dependency graph.
 338 // This *no branch* feature makes all the modules cachable.
 339 //
 340 // I.e, if we traverse one star link (even if we successfully resolve that star link),
 341 // we must still traverse all other star links. I would also explain we don't run into
 342 // this when resolving a local/indirect link. When resolving a local/indirect link,
 343 // we won't traverse any star links.
 344 // And since the module can hold only one local/indirect link for the specific export name (if there
 345 // are multiple local/indirect links that has the same export name, it should be syntax error in the
 346 // parsing phase.), there is no multiple outgoing links from a module.
 347 //
 348 // @ -> (A) --> (B) -> [C] -> (D) -> (E) -+
 349 // ^ |
 350 // | |
 351 // +------------------------+
 352 //
 353 // When starting from @, [C] will be found as the module resolving the given binding.
 354 // In this case, (B) can cache this resolution. Since the resolving route is the same to the one when
 355 // starting from (B). After caching the above result, we attempt to resolve the same binding from (D).
 356 //
 357 // @
 358 // |
 359 // v
 360 // @ -> (A) --> (B) -> [C] -> (D) -> (E) -+
 361 // ^ |
 362 // | |
 363 // +------------------------+
 364 //
 365 // In this case, we can use the (B)'s cached result. And (E) can be cached.
 366 //
 367 // (E): The resolving route is now (E) -> (B) -> [C]. That is the same when starting from (E).
 368 //
 369 // No branching makes that the problematic *once-visited* node cannot be seen.
 370 // The *once-visited* node makes the resolving route changed since when we see the *once-visited* node,
 371 // we stop tracing this.
 372 //
 373 // If there is no star links and if we look *once-visited* node under no branching graph, *once-visited*
 374 // node cannot resolve the requested binding. If the *once-visited* node can resolve the binding, we
 375 // should have already finished the resolution before reaching this *once-visited* node.
 376 //
 377 // 4. Once we follow star links, we should not retrieve the result from the cache and should not cache.
 378 //
 379 // Star links are only the way to introduce branch.
 380 // Once we follow the star links during the resolution, we cannot cache naively.
 381 // This is because the cacheability depends on the resolving route. And branching produces the problematic *once-visited*
 382 // nodes. Since we don't follow the *once-visited* node, the resolving route from the node becomes different from
 383 // the resolving route when starting from this node.
 384 //
 385 // The following example explains when we should not retrieve the cache and cache the result.
 386 //
 387 // +----> (D) ------+
 388 // | |
 389 // | v
 390 // (A) *----+----> (B) ---> [C]
 391 // ^
 392 // |
 393 // @
 394 //
 395 // When starting from (B), we find [C]. In this resolving route, we don't find any star link.
 396 // And by definition, (B) and [C] are cachable. (B) is the starting point. And [C] has the local binding.
 397 //
 398 // +----> (D) ------+
 399 // | |
 400 // | v
 401 // @-> (A) *----+----> (B) ---> [C]
 402 //
 403 // But when starting from (A), we should not get the value from the cache. Because,
 404 //
 405 // 1. When looking (D), we reach [C] and make both resolved.
 406 // 2. When looking (B), if we retrieved the last cache from (B), (B) becomes resolved.
 407 // 3. But actually, (B) is not-found in this trial because (C) is already *once-visited*.
 408 // 4. If we accidentally make (B) resolved, (A) becomes ambiguous. But the correct answer is resolved.
 409 //
 410 // Why is this problem caused? This is because the *once-visited* node makes the result not-found.
 411 // In the second trial, (B) -> [C] result is changed from resolved to not-found.
 412 //
 413 // When does this become a problem? If the status of the *once-visited* node group is resolved,
 414 // changing the result to not-found makes the result changed.
 415 //
 416 // This problem does not happen when we don't see any star link yet. Now, consider the minimum case.
 417 //
 418 // @-> (A) -> [ some graph ]
 419 // ^ |
 420 // | |
 421 // +------------+
 422 //
 423 // In (A), we don't see any star link yet. So we can say that all the visited nodes does not have any local
 424 // resolution. Because if they had a local/indirect resolution, we should have already finished the tracing.
 425 //
 426 // And even if the some graph will see the *once-visited* node (in this case, (A)), that does not affect the
 427 // result of the resolution. Because even if we follow the link to (A) or not follow the link to (A), the status
 428 // of the link is always not-found since (A) does not have any local resolution.
 429 // In the above case, we can use the result of the [some graph].
 430 //
 431 // 5. Once we see star links, even if we have not yet traversed that star link path, we should disable caching.
 432 //
 433 // Here is the reason why:
 434 //
 435 // +-------------+
 436 // | |
 437 // v |
 438 // (A) -> (B) -> (C) *-> [E]
 439 // * ^
 440 // | |
 441 // v @
 442 // [D]
 443 //
 444 // In the above case, (C) will be resolved with [D].
 445 // (C) will see (A) and (A) gives up in (A) -> (B) -> (C) route. So, (A) will fallback to [D].
 446 //
 447 // +-------------+
 448 // | |
 449 // v |
 450 // @-> (A) -> (B) -> (C) *-> [E]
 451 // *
 452 // |
 453 // v
 454 // [D]
 455 //
 456 // But in this case, (A) will be resolved with [E] (not [D]).
 457 // (C) will attempt to follow the link to (A), but it fails.
 458 // So (C) will fallback to the star link and found [E]. In this senario,
 459 // (C) is now resolved with [E]'s result.
 460 //
 461 // The cause of this problem is also the same to 4.
 462 // In the latter case, when looking (C), we cannot use the cached result in (C).
 463 // Because the cached result of (C) depends on the *once-visited* node (A) and
 464 // (A) has the fallback system with the star link.
 465 // In the latter trial, we now assume that (A)'s status is not-found.
 466 // But, actually, in the former trial, (A)'s status becomes resolved due to the fallback to the [D].
 467 //
 468 // To summarize the observations.
 469 //
 470 // 1. The starting point is always cacheable.
 471 // 2. A module that has resolved a local binding is always cacheable.
 472 // 3. If we don't follow any star links during the resolution, we can see all the traced nodes are cacheable.
 473 // 4. Once we follow star links, we should not retrieve the result from the cache and should not cache the result.
 474 // 5. Once we see star links, even if we have not yet traversed that star link path, we should disable caching.
 475
 476 typedef WTF::HashSet<ResolveQuery, ResolveQuery::Hash, WTF::CustomHashTraits<ResolveQuery>> ResolveSet;
 477 enum class Type { Query, IndirectFallback, GatherStars };
 478 struct Task {
 479 ResolveQuery query;
 480 Type type;
 481 };
 482
 483 Vector<Task, 8> pendingTasks;
 484 ResolveSet resolveSet;
 485 HashSet<AbstractModuleRecord*> starSet;
 486
 487 Vector<Resolution, 8> frames;
 488
 489 bool foundStarLinks = false;
 490
 491 frames.append(Resolution::notFound());
 492
 493 // Call when the query is not resolved in the current module.
 494 // It will enqueue the star resolution requests. Return "false" if the error occurs.
 495 auto resolveNonLocal = [&](const ResolveQuery& query) -> bool {
 496 // http://www.ecma-international.org/ecma-262/6.0/#sec-resolveexport
 497 // section 15.2.1.16.3, step 6
 498 // If the "default" name is not resolved in the current module, we need to throw an error and stop resolution immediately,
 499 // Rationale to this error: A default export cannot be provided by an export *.
 500 if (query.exportName == exec->propertyNames().defaultKeyword.impl())
 501 return false;
 502
 503 // step 7, If exportStarSet contains module, then return null.
 504 if (!starSet.add(query.moduleRecord).isNewEntry)
 505 return true;
 506
 507 // Enqueue the task to gather the results of the stars.
 508 // And append the new Resolution frame to gather the local result of the stars.
 509 pendingTasks.append(Task { query, Type::GatherStars });
 510 foundStarLinks = true;
 511 frames.append(Resolution::notFound());
 512
 513
 514 // Enqueue the tasks in reverse order.
 515 for (auto iterator = query.moduleRecord->starExportEntries().rbegin(), end = query.moduleRecord->starExportEntries().rend(); iterator != end; ++iterator) {
 516 const RefPtr<UniquedStringImpl>& starModuleName = *iterator;
 517 AbstractModuleRecord* importedModuleRecord = query.moduleRecord->hostResolveImportedModule(exec, Identifier::fromUid(exec, starModuleName.get()));
 518 pendingTasks.append(Task { ResolveQuery(importedModuleRecord, query.exportName.get()), Type::Query });
 519 }
 520 return true;
 521 };
 522
 523 // Return the current resolution value of the top frame.
 524 auto currentTop = [&] () -> Resolution& {
 525 ASSERT(!frames.isEmpty());
 526 return frames.last();
 527 };
 528
 529 // Merge the given resolution to the current resolution value of the top frame.
 530 // If there is ambiguity, return "false". When the "false" is returned, we should make the result "ambiguous".
 531 auto mergeToCurrentTop = [&] (const Resolution& resolution) -> bool {
 532 if (resolution.type == Resolution::Type::NotFound)
 533 return true;
 534
 535 if (currentTop().type == Resolution::Type::NotFound) {
 536 currentTop() = resolution;
 537 return true;
 538 }
 539
 540 if (currentTop().moduleRecord != resolution.moduleRecord || currentTop().localName != resolution.localName)
 541 return false;
 542
 543 return true;
 544 };
 545
 546 auto cacheResolutionForQuery = [] (const ResolveQuery& query, const Resolution& resolution) {
 547 ASSERT(resolution.type == Resolution::Type::Resolved);
 548 query.moduleRecord->cacheResolution(query.exportName.get(), resolution);
 549 };
 550
 551 pendingTasks.append(Task { root, Type::Query });
 552 while (!pendingTasks.isEmpty()) {
 553 const Task task = pendingTasks.takeLast();
 554 const ResolveQuery& query = task.query;
 555
 556 switch (task.type) {
 557 case Type::Query: {
 558 AbstractModuleRecord* moduleRecord = query.moduleRecord;
 559
 560 if (!resolveSet.add(task.query).isNewEntry)
 561 continue;
 562
 563 // 5. Once we see star links, even if we have not yet traversed that star link path, we should disable caching.
 564 if (!moduleRecord->starExportEntries().isEmpty())
 565 foundStarLinks = true;
 566
 567 // 4. Once we follow star links, we should not retrieve the result from the cache and should not cache the result.
 568 if (!foundStarLinks) {
 569 if (std::optional<Resolution> cachedResolution = moduleRecord->tryGetCachedResolution(query.exportName.get())) {
 570 if (!mergeToCurrentTop(*cachedResolution))
 571 return Resolution::ambiguous();
 572 continue;
 573 }
 574 }
 575
 576 const std::optional<ExportEntry> optionalExportEntry = moduleRecord->tryGetExportEntry(query.exportName.get());
 577 if (!optionalExportEntry) {
 578 // If there is no matched exported binding in the current module,
 579 // we need to look into the stars.
 580 if (!resolveNonLocal(task.query))
 581 return Resolution::error();
 582 continue;
 583 }
 584
 585 const ExportEntry& exportEntry = *optionalExportEntry;
 586 switch (exportEntry.type) {
 587 case ExportEntry::Type::Local: {
 588 ASSERT(!exportEntry.localName.isNull());
 589 Resolution resolution { Resolution::Type::Resolved, moduleRecord, exportEntry.localName };
 590 // 2. A module that has resolved a local binding is always cacheable.
 591 cacheResolutionForQuery(query, resolution);
 592 if (!mergeToCurrentTop(resolution))
 593 return Resolution::ambiguous();
 594 continue;
 595 }
 596
 597 case ExportEntry::Type::Indirect: {
 598 AbstractModuleRecord* importedModuleRecord = moduleRecord->hostResolveImportedModule(exec, exportEntry.moduleName);
 599
 600 // When the imported module does not produce any resolved binding, we need to look into the stars in the *current*
 601 // module. To do this, we append the `IndirectFallback` task to the task queue.
 602 pendingTasks.append(Task { query, Type::IndirectFallback });
 603 // And append the new Resolution frame to check the indirect export will be resolved or not.
 604 frames.append(Resolution::notFound());
 605 pendingTasks.append(Task { ResolveQuery(importedModuleRecord, exportEntry.importName), Type::Query });
 606 continue;
 607 }
 608 }
 609 break;
 610 }
 611
 612 case Type::IndirectFallback: {
 613 Resolution resolution = frames.takeLast();
 614
 615 if (resolution.type == Resolution::Type::NotFound) {
 616 // Indirect export entry does not produce any resolved binding.
 617 // So we will investigate the stars.
 618 if (!resolveNonLocal(task.query))
 619 return Resolution::error();
 620 continue;
 621 }
 622
 623 ASSERT_WITH_MESSAGE(resolution.type == Resolution::Type::Resolved, "When we see Error and Ambiguous, we immediately return from this loop. So here, only Resolved comes.");
 624
 625 // 3. If we don't follow any star links during the resolution, we can see all the traced nodes are cacheable.
 626 // 4. Once we follow star links, we should not retrieve the result from the cache and should not cache the result.
 627 if (!foundStarLinks)
 628 cacheResolutionForQuery(query, resolution);
 629
 630 // If indirect export entry produces Resolved, we should merge it to the upper frame.
 631 // And do not investigate the stars of the current module.
 632 if (!mergeToCurrentTop(resolution))
 633 return Resolution::ambiguous();
 634 break;
 635 }
 636
 637 case Type::GatherStars: {
 638 Resolution resolution = frames.takeLast();
 639 ASSERT_WITH_MESSAGE(resolution.type == Resolution::Type::Resolved || resolution.type == Resolution::Type::NotFound, "When we see Error and Ambiguous, we immediately return from this loop. So here, only Resolved and NotFound comes.");
 640
 641 // Merge the star resolution to the upper frame.
 642 if (!mergeToCurrentTop(resolution))
 643 return Resolution::ambiguous();
 644 break;
 645 }
 646 }
 647 }
 648
 649 ASSERT(frames.size() == 1);
 650 // 1. The starting point is always cacheable.
 651 if (frames[0].type == Resolution::Type::Resolved)
 652 cacheResolutionForQuery(root, frames[0]);
 653 return frames[0];
 654}
 655
 656auto AbstractModuleRecord::resolveExport(ExecState* exec, const Identifier& exportName) -> Resolution
 657{
 658 // Look up the cached resolution first before entering the resolving loop, since the loop setup takes some cost.
 659 if (std::optional<Resolution> cachedResolution = tryGetCachedResolution(exportName.impl()))
 660 return *cachedResolution;
 661 return resolveExportImpl(exec, ResolveQuery(this, exportName.impl()));
 662}
 663
 664static void getExportedNames(ExecState* exec, AbstractModuleRecord* root, IdentifierSet& exportedNames)
 665{
 666 HashSet<AbstractModuleRecord*> exportStarSet;
 667 Vector<AbstractModuleRecord*, 8> pendingModules;
 668
 669 pendingModules.append(root);
 670
 671 while (!pendingModules.isEmpty()) {
 672 AbstractModuleRecord* moduleRecord = pendingModules.takeLast();
 673 if (exportStarSet.contains(moduleRecord))
 674 continue;
 675 exportStarSet.add(moduleRecord);
 676
 677 for (const auto& pair : moduleRecord->exportEntries()) {
 678 const AbstractModuleRecord::ExportEntry& exportEntry = pair.value;
 679 if (moduleRecord == root || exec->propertyNames().defaultKeyword != exportEntry.exportName)
 680 exportedNames.add(exportEntry.exportName.impl());
 681 }
 682
 683 for (const auto& starModuleName : moduleRecord->starExportEntries()) {
 684 AbstractModuleRecord* requestedModuleRecord = moduleRecord->hostResolveImportedModule(exec, Identifier::fromUid(exec, starModuleName.get()));
 685 pendingModules.append(requestedModuleRecord);
 686 }
 687 }
 688}
 689
 690JSModuleNamespaceObject* AbstractModuleRecord::getModuleNamespace(ExecState* exec)
 691{
 692 VM& vm = exec->vm();
 693 auto scope = DECLARE_THROW_SCOPE(vm);
 694
 695 // http://www.ecma-international.org/ecma-262/6.0/#sec-getmodulenamespace
 696 if (m_moduleNamespaceObject)
 697 return m_moduleNamespaceObject.get();
 698
 699 JSGlobalObject* globalObject = exec->lexicalGlobalObject();
 700 IdentifierSet exportedNames;
 701 getExportedNames(exec, this, exportedNames);
 702
 703 IdentifierSet unambiguousNames;
 704 for (auto& name : exportedNames) {
 705 const AbstractModuleRecord::Resolution resolution = resolveExport(exec, Identifier::fromUid(exec, name.get()));
 706 switch (resolution.type) {
 707 case Resolution::Type::NotFound:
 708 throwSyntaxError(exec, scope, makeString("Exported binding name '", String(name.get()), "' is not found."));
 709 return nullptr;
 710
 711 case Resolution::Type::Error:
 712 throwSyntaxError(exec, scope, makeString("Exported binding name 'default' cannot be resolved by star export entries."));
 713 return nullptr;
 714
 715 case Resolution::Type::Ambiguous:
 716 break;
 717
 718 case Resolution::Type::Resolved:
 719 unambiguousNames.add(name);
 720 break;
 721 }
 722 }
 723
 724 m_moduleNamespaceObject.set(vm, this, JSModuleNamespaceObject::create(exec, globalObject, globalObject->moduleNamespaceObjectStructure(), this, unambiguousNames));
 725 return m_moduleNamespaceObject.get();
 726}
 727
 728static String printableName(const RefPtr<UniquedStringImpl>& uid)
 729{
 730 if (uid->isSymbol())
 731 return uid.get();
 732 return WTF::makeString("'", String(uid.get()), "'");
 733}
 734
 735static String printableName(const Identifier& ident)
 736{
 737 return printableName(ident.impl());
 738}
 739
 740void AbstractModuleRecord::dump()
 741{
 742 dataLog("\nAnalyzing ModuleRecord key(", printableName(m_moduleKey), ")\n");
 743
 744 dataLog(" Dependencies: ", m_requestedModules.size(), " modules\n");
 745 for (const auto& moduleName : m_requestedModules)
 746 dataLog(" module(", printableName(moduleName), ")\n");
 747
 748 dataLog(" Import: ", m_importEntries.size(), " entries\n");
 749 for (const auto& pair : m_importEntries) {
 750 const ImportEntry& importEntry = pair.value;
 751 dataLog(" import(", printableName(importEntry.importName), "), local(", printableName(importEntry.localName), "), module(", printableName(importEntry.moduleRequest), ")\n");
 752 }
 753
 754 dataLog(" Export: ", m_exportEntries.size(), " entries\n");
 755 for (const auto& pair : m_exportEntries) {
 756 const ExportEntry& exportEntry = pair.value;
 757 switch (exportEntry.type) {
 758 case ExportEntry::Type::Local:
 759 dataLog(" [Local] ", "export(", printableName(exportEntry.exportName), "), local(", printableName(exportEntry.localName), ")\n");
 760 break;
 761
 762 case ExportEntry::Type::Indirect:
 763 dataLog(" [Indirect] ", "export(", printableName(exportEntry.exportName), "), import(", printableName(exportEntry.importName), "), module(", printableName(exportEntry.moduleName), ")\n");
 764 break;
 765 }
 766 }
 767 for (const auto& moduleName : m_starExportEntries)
 768 dataLog(" [Star] module(", printableName(moduleName.get()), ")\n");
 769}
 770
 771} // namespace JSC

Source/JavaScriptCore/runtime/AbstractModuleRecord.h

 1/*
 2 * Copyright (C) 2015 Apple Inc. All rights reserved.
 3 *
 4 * Redistribution and use in source and binary forms, with or without
 5 * modification, are permitted provided that the following conditions
 6 * are met:
 7 * 1. Redistributions of source code must retain the above copyright
 8 * notice, this list of conditions and the following disclaimer.
 9 * 2. Redistributions in binary form must reproduce the above copyright
 10 * notice, this list of conditions and the following disclaimer in the
 11 * documentation and/or other materials provided with the distribution.
 12 *
 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 24 */
 25
 26#pragma once
 27
 28#include "Identifier.h"
 29#include "JSDestructibleObject.h"
 30#include "SourceCode.h"
 31#include "VariableEnvironment.h"
 32#include <wtf/HashMap.h>
 33#include <wtf/ListHashSet.h>
 34#include <wtf/Optional.h>
 35
 36namespace JSC {
 37
 38class JSModuleEnvironment;
 39class JSModuleNamespaceObject;
 40class JSMap;
 41
 42// Based on the Source Text Module Record
 43// http://www.ecma-international.org/ecma-262/6.0/#sec-source-text-module-records
 44class AbstractModuleRecord : public JSDestructibleObject {
 45 friend class LLIntOffsetsExtractor;
 46public:
 47 typedef JSDestructibleObject Base;
 48
 49 // https://tc39.github.io/ecma262/#sec-source-text-module-records
 50 struct ExportEntry {
 51 enum class Type {
 52 Local,
 53 Indirect
 54 };
 55
 56 static ExportEntry createLocal(const Identifier& exportName, const Identifier& localName);
 57 static ExportEntry createIndirect(const Identifier& exportName, const Identifier& importName, const Identifier& moduleName);
 58
 59 Type type;
 60 Identifier exportName;
 61 Identifier moduleName;
 62 Identifier importName;
 63 Identifier localName;
 64 };
 65
 66 struct ImportEntry {
 67 Identifier moduleRequest;
 68 Identifier importName;
 69 Identifier localName;
 70
 71 bool isNamespace(VM& vm) const
 72 {
 73 return importName == vm.propertyNames->timesIdentifier;
 74 }
 75 };
 76
 77 typedef WTF::ListHashSet<RefPtr<UniquedStringImpl>, IdentifierRepHash> OrderedIdentifierSet;
 78 typedef HashMap<RefPtr<UniquedStringImpl>, ImportEntry, IdentifierRepHash, HashTraits<RefPtr<UniquedStringImpl>>> ImportEntries;
 79 typedef HashMap<RefPtr<UniquedStringImpl>, ExportEntry, IdentifierRepHash, HashTraits<RefPtr<UniquedStringImpl>>> ExportEntries;
 80
 81 DECLARE_EXPORT_INFO;
 82
 83 void appendRequestedModule(const Identifier&);
 84 void addStarExportEntry(const Identifier&);
 85 void addImportEntry(const ImportEntry&);
 86 void addExportEntry(const ExportEntry&);
 87
 88 std::optional<ImportEntry> tryGetImportEntry(UniquedStringImpl* localName);
 89 std::optional<ExportEntry> tryGetExportEntry(UniquedStringImpl* exportName);
 90
 91 const SourceCode& sourceCode() const { return m_sourceCode; }
 92 const Identifier& moduleKey() const { return m_moduleKey; }
 93 const OrderedIdentifierSet& requestedModules() const { return m_requestedModules; }
 94 const ExportEntries& exportEntries() const { return m_exportEntries; }
 95 const ImportEntries& importEntries() const { return m_importEntries; }
 96 const OrderedIdentifierSet& starExportEntries() const { return m_starExportEntries; }
 97
 98 const VariableEnvironment& declaredVariables() const { return m_declaredVariables; }
 99 const VariableEnvironment& lexicalVariables() const { return m_lexicalVariables; }
 100
 101 void dump();
 102
 103 struct Resolution {
 104 enum class Type { Resolved, NotFound, Ambiguous, Error };
 105
 106 static Resolution notFound();
 107 static Resolution error();
 108 static Resolution ambiguous();
 109
 110 Type type;
 111 AbstractModuleRecord* moduleRecord;
 112 Identifier localName;
 113 };
 114
 115 Resolution resolveExport(ExecState*, const Identifier& exportName);
 116 Resolution resolveImport(ExecState*, const Identifier& localName);
 117
 118 AbstractModuleRecord* hostResolveImportedModule(ExecState*, const Identifier& moduleName);
 119
 120 JSModuleNamespaceObject* getModuleNamespace(ExecState*);
 121
 122 JSModuleEnvironment* moduleEnvironment()
 123 {
 124 ASSERT(m_moduleEnvironment);
 125 return m_moduleEnvironment.get();
 126 }
 127
 128protected:
 129 AbstractModuleRecord(VM&, Structure*, const Identifier&, const SourceCode&, const VariableEnvironment&, const VariableEnvironment&);
 130 void finishCreation(ExecState*, VM&);
 131
 132 static void visitChildren(JSCell*, SlotVisitor&);
 133 static void destroy(JSCell*);
 134
 135 WriteBarrier<JSModuleEnvironment> m_moduleEnvironment;
 136
 137private:
 138 struct ResolveQuery;
 139 static Resolution resolveExportImpl(ExecState*, const ResolveQuery&);
 140 std::optional<Resolution> tryGetCachedResolution(UniquedStringImpl* exportName);
 141 void cacheResolution(UniquedStringImpl* exportName, const Resolution&);
 142
 143 // The loader resolves the given module name to the module key. The module key is the unique value to represent this module.
 144 Identifier m_moduleKey;
 145
 146 SourceCode m_sourceCode;
 147
 148 VariableEnvironment m_declaredVariables;
 149 VariableEnvironment m_lexicalVariables;
 150
 151 // Currently, we don't keep the occurrence order of the import / export entries.
 152 // So, we does not guarantee the order of the errors.
 153 // e.g. The import declaration that occurr later than the another import declaration may
 154 // throw the error even if the former import declaration also has the invalid content.
 155 //
 156 // import ... // (1) this has some invalid content.
 157 // import ... // (2) this also has some invalid content.
 158 //
 159 // In the above case, (2) may throw the error earlier than (1)
 160 //
 161 // But, in all the cases, we will throw the syntax error. So except for the content of the syntax error,
 162 // there are no difference.
 163
 164 // Map localName -> ImportEntry.
 165 ImportEntries m_importEntries;
 166
 167 // Map exportName -> ExportEntry.
 168 ExportEntries m_exportEntries;
 169
 170 // Save the occurrence order since resolveExport requires it.
 171 OrderedIdentifierSet m_starExportEntries;
 172
 173 // Save the occurrence order since the module loader loads and runs the modules in this order.
 174 // http://www.ecma-international.org/ecma-262/6.0/#sec-moduleevaluation
 175 OrderedIdentifierSet m_requestedModules;
 176
 177 WriteBarrier<JSMap> m_dependenciesMap;
 178
 179 WriteBarrier<JSModuleNamespaceObject> m_moduleNamespaceObject;
 180
 181 // We assume that all the AbstractModuleRecord are retained by JSModuleLoader's registry.
 182 // So here, we don't visit each object for GC. The resolution cache map caches the once
 183 // looked up correctly resolved resolution, since (1) we rarely looked up the non-resolved one,
 184 // and (2) if we cache all the attempts the size of the map becomes infinitely large.
 185 typedef HashMap<RefPtr<UniquedStringImpl>, Resolution, IdentifierRepHash, HashTraits<RefPtr<UniquedStringImpl>>> Resolutions;
 186 Resolutions m_resolutionCache;
 187};
 188
 189} // namespace JSC

Source/JavaScriptCore/runtime/JSGlobalObject.cpp

@@putDirectWithoutTransition(vm, vm.propertyNames-> jsName, lowerName ## Construct
876876 if (Options::useWebAssembly()) {
877877 auto* webAssemblyPrototype = WebAssemblyPrototype::create(vm, this, WebAssemblyPrototype::createStructure(vm, this, m_objectPrototype.get()));
878878 m_webAssemblyStructure.set(vm, this, JSWebAssembly::createStructure(vm, this, webAssemblyPrototype));
 879 m_webAssemblyModuleRecordStructure.set(vm, this, WebAssemblyModuleRecord::createStructure(vm, this, m_objectPrototype.get()));
 880 m_webAssemblyFunctionStructure.set(vm, this, WebAssemblyFunction::createStructure(vm, this, m_objectPrototype.get()));
879881 auto* webAssembly = JSWebAssembly::create(vm, this, m_webAssemblyStructure.get());
880882 putDirectWithoutTransition(vm, Identifier::fromString(exec, "WebAssembly"), webAssembly, DontEnum);
881883

@@void JSGlobalObject::visitChildren(JSCell* cell, SlotVisitor& visitor)
12531255
12541256#if ENABLE(WEBASSEMBLY)
12551257 visitor.append(&thisObject->m_webAssemblyStructure);
 1258 visitor.append(&thisObject->m_webAssemblyModuleRecordStructure);
 1259 visitor.append(&thisObject->m_webAssemblyFunctionStructure);
12561260 FOR_EACH_WEBASSEMBLY_CONSTRUCTOR_TYPE(VISIT_SIMPLE_TYPE)
12571261#endif // ENABLE(WEBASSEMBLY)
12581262

Source/JavaScriptCore/runtime/JSGlobalObject.h

@@public:
342342
343343#if ENABLE(WEBASSEMBLY)
344344 WriteBarrier<Structure> m_webAssemblyStructure;
 345 WriteBarrier<Structure> m_webAssemblyModuleRecordStructure;
 346 WriteBarrier<Structure> m_webAssemblyFunctionStructure;
345347 FOR_EACH_WEBASSEMBLY_CONSTRUCTOR_TYPE(DEFINE_STORAGE_FOR_SIMPLE_TYPE)
346348#endif // ENABLE(WEBASSEMBLY)
347349

@@public:
625627 Structure* proxyRevokeStructure() const { return m_proxyRevokeStructure.get(); }
626628 Structure* moduleLoaderStructure() const { return m_moduleLoaderStructure.get(); }
627629 Structure* restParameterStructure() const { return arrayStructureForIndexingTypeDuringAllocation(ArrayWithContiguous); }
 630#if ENABLE(WEBASSEMBLY)
 631 Structure* webAssemblyModuleRecordStructure() const { return m_webAssemblyModuleRecordStructure.get(); }
 632 Structure* webAssemblyFunctionStructure() const { return m_webAssemblyFunctionStructure.get(); }
 633#endif // ENABLE(WEBASSEMBLY)
628634
629635 JS_EXPORT_PRIVATE void setRemoteDebuggingEnabled(bool);
630636 JS_EXPORT_PRIVATE bool remoteDebuggingEnabled() const;

Source/JavaScriptCore/runtime/JSModuleEnvironment.cpp

2929#include "config.h"
3030#include "JSModuleEnvironment.h"
3131
 32#include "AbstractModuleRecord.h"
3233#include "Interpreter.h"
3334#include "JSCInlines.h"
3435#include "JSFunction.h"

@@namespace JSC {
4041const ClassInfo JSModuleEnvironment::s_info = { "JSModuleEnvironment", &Base::s_info, 0, CREATE_METHOD_TABLE(JSModuleEnvironment) };
4142
4243JSModuleEnvironment* JSModuleEnvironment::create(
43  VM& vm, Structure* structure, JSScope* currentScope, SymbolTable* symbolTable, JSValue initialValue, JSModuleRecord* moduleRecord)
 44 VM& vm, Structure* structure, JSScope* currentScope, SymbolTable* symbolTable, JSValue initialValue, AbstractModuleRecord* moduleRecord)
4445{
4546 // JSLexicalEnvironment (precisely, JSEnvironmentRecord) has the storage to store the variable slots after the its class storage.
4647 // Because the offset of the variable slots are fixed in the JSEnvironmentRecord, inheritting these class and adding new member field is not allowed,
4748 // the new member will overlap the variable slots.
48  // To keep the JSModuleEnvironment compatible to the JSLexicalEnvironment but add the new member to store the JSModuleRecord, we additionally allocate
 49 // To keep the JSModuleEnvironment compatible to the JSLexicalEnvironment but add the new member to store the AbstractModuleRecord, we additionally allocate
4950 // the storage after the variable slots.
5051 //
5152 // JSLexicalEnvironment:

@@JSModuleEnvironment* JSModuleEnvironment::create(
6263 return result;
6364}
6465
65 void JSModuleEnvironment::finishCreation(VM& vm, JSValue initialValue, JSModuleRecord* moduleRecord)
 66void JSModuleEnvironment::finishCreation(VM& vm, JSValue initialValue, AbstractModuleRecord* moduleRecord)
6667{
6768 Base::finishCreation(vm, initialValue);
6869 this->moduleRecordSlot().set(vm, this, moduleRecord);

@@bool JSModuleEnvironment::getOwnPropertySlot(JSObject* cell, ExecState* exec, Pr
8182 VM& vm = exec->vm();
8283 auto scope = DECLARE_THROW_SCOPE(vm);
8384 JSModuleEnvironment* thisObject = jsCast<JSModuleEnvironment*>(cell);
84  JSModuleRecord::Resolution resolution = thisObject->moduleRecord()->resolveImport(exec, Identifier::fromUid(exec, propertyName.uid()));
85  if (resolution.type == JSModuleRecord::Resolution::Type::Resolved) {
 85 AbstractModuleRecord::Resolution resolution = thisObject->moduleRecord()->resolveImport(exec, Identifier::fromUid(exec, propertyName.uid()));
 86 if (resolution.type == AbstractModuleRecord::Resolution::Type::Resolved) {
8687 // When resolveImport resolves the resolution, the imported module environment must have the binding.
8788 JSModuleEnvironment* importedModuleEnvironment = resolution.moduleRecord->moduleEnvironment();
8889 PropertySlot redirectSlot(importedModuleEnvironment, PropertySlot::InternalMethodType::Get);

@@void JSModuleEnvironment::getOwnNonIndexPropertyNames(JSObject* cell, ExecState*
102103 JSModuleEnvironment* thisObject = jsCast<JSModuleEnvironment*>(cell);
103104 if (propertyNamesArray.includeStringProperties()) {
104105 for (const auto& pair : thisObject->moduleRecord()->importEntries()) {
105  const JSModuleRecord::ImportEntry& importEntry = pair.value;
 106 const AbstractModuleRecord::ImportEntry& importEntry = pair.value;
106107 if (!importEntry.isNamespace(exec->vm()))
107108 propertyNamesArray.add(importEntry.localName);
108109 }

@@bool JSModuleEnvironment::put(JSCell* cell, ExecState* exec, PropertyName proper
117118
118119 JSModuleEnvironment* thisObject = jsCast<JSModuleEnvironment*>(cell);
119120 // All imported bindings are immutable.
120  JSModuleRecord::Resolution resolution = thisObject->moduleRecord()->resolveImport(exec, Identifier::fromUid(exec, propertyName.uid()));
121  if (resolution.type == JSModuleRecord::Resolution::Type::Resolved) {
 121 AbstractModuleRecord::Resolution resolution = thisObject->moduleRecord()->resolveImport(exec, Identifier::fromUid(exec, propertyName.uid()));
 122 if (resolution.type == AbstractModuleRecord::Resolution::Type::Resolved) {
122123 throwTypeError(exec, scope, ASCIILiteral(ReadonlyPropertyWriteError));
123124 return false;
124125 }

@@bool JSModuleEnvironment::deleteProperty(JSCell* cell, ExecState* exec, Property
129130{
130131 JSModuleEnvironment* thisObject = jsCast<JSModuleEnvironment*>(cell);
131132 // All imported bindings are immutable.
132  JSModuleRecord::Resolution resolution = thisObject->moduleRecord()->resolveImport(exec, Identifier::fromUid(exec, propertyName.uid()));
133  if (resolution.type == JSModuleRecord::Resolution::Type::Resolved)
 133 AbstractModuleRecord::Resolution resolution = thisObject->moduleRecord()->resolveImport(exec, Identifier::fromUid(exec, propertyName.uid()));
 134 if (resolution.type == AbstractModuleRecord::Resolution::Type::Resolved)
134135 return false;
135136 return Base::deleteProperty(thisObject, exec, propertyName);
136137}

Source/JavaScriptCore/runtime/JSModuleEnvironment.h

11/*
2  * Copyright (C) 2015 Apple Inc. All rights reserved.
 2 * Copyright (C) 2015-2016 Apple Inc. All rights reserved.
33 *
44 * Redistribution and use in source and binary forms, with or without
55 * modification, are permitted provided that the following conditions

2929#pragma once
3030
3131#include "JSLexicalEnvironment.h"
32 #include "JSModuleRecord.h"
3332
3433namespace JSC {
3534
 35class AbstractModuleRecord;
3636class Register;
3737
3838class JSModuleEnvironment : public JSLexicalEnvironment {

@@public:
4242 typedef JSLexicalEnvironment Base;
4343 static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | OverridesGetPropertyNames;
4444
45  static JSModuleEnvironment* create(VM&, Structure*, JSScope*, SymbolTable*, JSValue initialValue, JSModuleRecord*);
 45 static JSModuleEnvironment* create(VM&, Structure*, JSScope*, SymbolTable*, JSValue initialValue, AbstractModuleRecord*);
4646
47  static JSModuleEnvironment* create(VM& vm, JSGlobalObject* globalObject, JSScope* currentScope, SymbolTable* symbolTable, JSValue initialValue, JSModuleRecord* moduleRecord)
 47 static JSModuleEnvironment* create(VM& vm, JSGlobalObject* globalObject, JSScope* currentScope, SymbolTable* symbolTable, JSValue initialValue, AbstractModuleRecord* moduleRecord)
4848 {
4949 Structure* structure = globalObject->moduleEnvironmentStructure();
5050 return create(vm, structure, currentScope, symbolTable, initialValue, moduleRecord);

@@public:
6060 static size_t offsetOfModuleRecord(SymbolTable* symbolTable)
6161 {
6262 size_t offset = Base::allocationSize(symbolTable);
63  ASSERT(WTF::roundUpToMultipleOf<sizeof(WriteBarrier<JSModuleRecord>)>(offset) == offset);
 63 ASSERT(WTF::roundUpToMultipleOf<sizeof(WriteBarrier<AbstractModuleRecord>)>(offset) == offset);
6464 return offset;
6565 }
6666
6767 static size_t allocationSize(SymbolTable* symbolTable)
6868 {
69  return offsetOfModuleRecord(symbolTable) + sizeof(WriteBarrier<JSModuleRecord>);
 69 return offsetOfModuleRecord(symbolTable) + sizeof(WriteBarrier<AbstractModuleRecord>);
7070 }
7171
72  JSModuleRecord* moduleRecord()
 72 AbstractModuleRecord* moduleRecord()
7373 {
7474 return moduleRecordSlot().get();
7575 }

@@public:
8282private:
8383 JSModuleEnvironment(VM&, Structure*, JSScope*, SymbolTable*);
8484
85  void finishCreation(VM&, JSValue initialValue, JSModuleRecord*);
 85 void finishCreation(VM&, JSValue initialValue, AbstractModuleRecord*);
8686
87  WriteBarrierBase<JSModuleRecord>& moduleRecordSlot()
 87 WriteBarrierBase<AbstractModuleRecord>& moduleRecordSlot()
8888 {
89  return *bitwise_cast<WriteBarrierBase<JSModuleRecord>*>(bitwise_cast<char*>(this) + offsetOfModuleRecord(symbolTable()));
 89 return *bitwise_cast<WriteBarrierBase<AbstractModuleRecord>*>(bitwise_cast<char*>(this) + offsetOfModuleRecord(symbolTable()));
9090 }
9191
9292 static void visitChildren(JSCell*, SlotVisitor&);

Source/JavaScriptCore/runtime/JSModuleNamespaceObject.cpp

2626#include "config.h"
2727#include "JSModuleNamespaceObject.h"
2828
 29#include "AbstractModuleRecord.h"
2930#include "Error.h"
3031#include "JSCInlines.h"
3132#include "JSModuleEnvironment.h"
32 #include "JSModuleRecord.h"
3333#include "JSPropertyNameIterator.h"
3434
3535namespace JSC {

@@JSModuleNamespaceObject::JSModuleNamespaceObject(VM& vm, Structure* structure)
4545{
4646}
4747
48 void JSModuleNamespaceObject::finishCreation(ExecState* exec, JSGlobalObject* globalObject, JSModuleRecord* moduleRecord, const IdentifierSet& exports)
 48void JSModuleNamespaceObject::finishCreation(ExecState* exec, JSGlobalObject* globalObject, AbstractModuleRecord* moduleRecord, const IdentifierSet& exports)
4949{
5050 VM& vm = exec->vm();
5151 auto scope = DECLARE_THROW_SCOPE(vm);

@@bool JSModuleNamespaceObject::getOwnPropertySlot(JSObject* cell, ExecState* exec
120120 switch (slot.internalMethodType()) {
121121 case PropertySlot::InternalMethodType::Get:
122122 case PropertySlot::InternalMethodType::GetOwnProperty: {
123  JSModuleRecord* moduleRecord = thisObject->moduleRecord();
 123 AbstractModuleRecord* moduleRecord = thisObject->moduleRecord();
124124
125  JSModuleRecord::Resolution resolution = moduleRecord->resolveExport(exec, Identifier::fromUid(exec, propertyName.uid()));
126  ASSERT(resolution.type != JSModuleRecord::Resolution::Type::NotFound && resolution.type != JSModuleRecord::Resolution::Type::Ambiguous);
 125 AbstractModuleRecord::Resolution resolution = moduleRecord->resolveExport(exec, Identifier::fromUid(exec, propertyName.uid()));
 126 ASSERT(resolution.type != AbstractModuleRecord::Resolution::Type::NotFound && resolution.type != AbstractModuleRecord::Resolution::Type::Ambiguous);
127127
128  JSModuleRecord* targetModule = resolution.moduleRecord;
 128 AbstractModuleRecord* targetModule = resolution.moduleRecord;
129129 JSModuleEnvironment* targetEnvironment = targetModule->moduleEnvironment();
130130
131131 PropertySlot trampolineSlot(targetEnvironment, PropertySlot::InternalMethodType::Get);

Source/JavaScriptCore/runtime/JSModuleNamespaceObject.h

3030
3131namespace JSC {
3232
33 class JSModuleRecord;
 33class AbstractModuleRecord;
3434
3535class JSModuleNamespaceObject : public JSDestructibleObject {
3636public:
3737 typedef JSDestructibleObject Base;
3838 static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | OverridesGetPropertyNames | GetOwnPropertySlotIsImpureForPropertyAbsence;
3939
40  static JSModuleNamespaceObject* create(ExecState* exec, JSGlobalObject* globalObject, Structure* structure, JSModuleRecord* moduleRecord, const IdentifierSet& exports)
 40 static JSModuleNamespaceObject* create(ExecState* exec, JSGlobalObject* globalObject, Structure* structure, AbstractModuleRecord* moduleRecord, const IdentifierSet& exports)
4141 {
4242 JSModuleNamespaceObject* object = new (NotNull, allocateCell<JSModuleNamespaceObject>(exec->vm().heap)) JSModuleNamespaceObject(exec->vm(), structure);
4343 object->finishCreation(exec, globalObject, moduleRecord, exports);

@@public:
5858 return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
5959 }
6060
61  JSModuleRecord* moduleRecord() { return m_moduleRecord.get(); }
 61 AbstractModuleRecord* moduleRecord() { return m_moduleRecord.get(); }
6262
6363protected:
64  JS_EXPORT_PRIVATE void finishCreation(ExecState*, JSGlobalObject*, JSModuleRecord*, const IdentifierSet& exports);
 64 JS_EXPORT_PRIVATE void finishCreation(ExecState*, JSGlobalObject*, AbstractModuleRecord*, const IdentifierSet& exports);
6565 JS_EXPORT_PRIVATE JSModuleNamespaceObject(VM&, Structure*);
6666
6767private:

@@private:
7171 typedef WTF::ListHashSet<RefPtr<UniquedStringImpl>, IdentifierRepHash> OrderedIdentifierSet;
7272
7373 OrderedIdentifierSet m_exports;
74  WriteBarrier<JSModuleRecord> m_moduleRecord;
 74 WriteBarrier<AbstractModuleRecord> m_moduleRecord;
7575};
7676
7777} // namespace JSC

Source/JavaScriptCore/runtime/JSModuleRecord.cpp

2929#include "Error.h"
3030#include "Interpreter.h"
3131#include "JSCInlines.h"
32 #include "JSMap.h"
3332#include "JSModuleEnvironment.h"
3433#include "JSModuleNamespaceObject.h"
3534#include "UnlinkedModuleProgramCodeBlock.h"

@@namespace JSC {
3837
3938const ClassInfo JSModuleRecord::s_info = { "ModuleRecord", &Base::s_info, 0, CREATE_METHOD_TABLE(JSModuleRecord) };
4039
41 void JSModuleRecord::destroy(JSCell* cell)
42 {
43  JSModuleRecord* thisObject = jsCast<JSModuleRecord*>(cell);
44  thisObject->JSModuleRecord::~JSModuleRecord();
45 }
4640
47 void JSModuleRecord::finishCreation(ExecState* exec, VM& vm)
 41Structure* JSModuleRecord::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
4842{
49  Base::finishCreation(vm);
50  ASSERT(inherits(info()));
51  putDirect(vm, Identifier::fromString(&vm, ASCIILiteral("registryEntry")), jsUndefined());
52  putDirect(vm, Identifier::fromString(&vm, ASCIILiteral("evaluated")), jsBoolean(false));
53 
54  auto scope = DECLARE_THROW_SCOPE(vm);
55  JSMap* map = JSMap::create(exec, vm, globalObject()->mapStructure());
56  RELEASE_ASSERT(!scope.exception());
57  m_dependenciesMap.set(vm, this, map);
58  putDirect(vm, Identifier::fromString(&vm, ASCIILiteral("dependenciesMap")), m_dependenciesMap.get());
 43 return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
5944}
6045
61 void JSModuleRecord::visitChildren(JSCell* cell, SlotVisitor& visitor)
 46JSModuleRecord* JSModuleRecord::create(ExecState* exec, VM& vm, Structure* structure, const Identifier& moduleKey, const SourceCode& sourceCode, const VariableEnvironment& declaredVariables, const VariableEnvironment& lexicalVariables)
6247{
63  JSModuleRecord* thisObject = jsCast<JSModuleRecord*>(cell);
64  Base::visitChildren(thisObject, visitor);
65  visitor.append(&thisObject->m_moduleEnvironment);
66  visitor.append(&thisObject->m_moduleNamespaceObject);
67  visitor.append(&thisObject->m_moduleProgramExecutable);
68  visitor.append(&thisObject->m_dependenciesMap);
69 }
70 
71 void JSModuleRecord::appendRequestedModule(const Identifier& moduleName)
72 {
73  m_requestedModules.add(moduleName.impl());
 48 JSModuleRecord* instance = new (NotNull, allocateCell<JSModuleRecord>(vm.heap)) JSModuleRecord(vm, structure, moduleKey, sourceCode, declaredVariables, lexicalVariables);
 49 instance->finishCreation(exec, vm);
 50 return instance;
7451}
75 
76 void JSModuleRecord::addStarExportEntry(const Identifier& moduleName)
77 {
78  m_starExportEntries.add(moduleName.impl());
79 }
80 
81 void JSModuleRecord::addImportEntry(const ImportEntry& entry)
82 {
83  bool isNewEntry = m_importEntries.add(entry.localName.impl(), entry).isNewEntry;
84  ASSERT_UNUSED(isNewEntry, isNewEntry); // This is guaranteed by the parser.
85 }
86 
87 void JSModuleRecord::addExportEntry(const ExportEntry& entry)
 52JSModuleRecord::JSModuleRecord(VM& vm, Structure* structure, const Identifier& moduleKey, const SourceCode& sourceCode, const VariableEnvironment& declaredVariables, const VariableEnvironment& lexicalVariables)
 53 : Base(vm, structure, moduleKey, sourceCode, declaredVariables, lexicalVariables)
8854{
89  bool isNewEntry = m_exportEntries.add(entry.exportName.impl(), entry).isNewEntry;
90  ASSERT_UNUSED(isNewEntry, isNewEntry); // This is guaranteed by the parser.
9155}
9256
93 auto JSModuleRecord::tryGetImportEntry(UniquedStringImpl* localName) -> std::optional<ImportEntry>
94 {
95  const auto iterator = m_importEntries.find(localName);
96  if (iterator == m_importEntries.end())
97  return std::nullopt;
98  return std::optional<ImportEntry>(iterator->value);
99 }
100 
101 auto JSModuleRecord::tryGetExportEntry(UniquedStringImpl* exportName) -> std::optional<ExportEntry>
102 {
103  const auto iterator = m_exportEntries.find(exportName);
104  if (iterator == m_exportEntries.end())
105  return std::nullopt;
106  return std::optional<ExportEntry>(iterator->value);
107 }
108 
109 auto JSModuleRecord::ExportEntry::createLocal(const Identifier& exportName, const Identifier& localName) -> ExportEntry
110 {
111  return ExportEntry { Type::Local, exportName, Identifier(), Identifier(), localName };
112 }
113 
114 auto JSModuleRecord::ExportEntry::createIndirect(const Identifier& exportName, const Identifier& importName, const Identifier& moduleName) -> ExportEntry
115 {
116  return ExportEntry { Type::Indirect, exportName, moduleName, importName, Identifier() };
117 }
118 
119 auto JSModuleRecord::Resolution::notFound() -> Resolution
120 {
121  return Resolution { Type::NotFound, nullptr, Identifier() };
122 }
123 
124 auto JSModuleRecord::Resolution::error() -> Resolution
125 {
126  return Resolution { Type::Error, nullptr, Identifier() };
127 }
128 
129 auto JSModuleRecord::Resolution::ambiguous() -> Resolution
130 {
131  return Resolution { Type::Ambiguous, nullptr, Identifier() };
132 }
133 
134 static JSValue identifierToJSValue(ExecState* exec, const Identifier& identifier)
135 {
136  if (identifier.isSymbol())
137  return Symbol::create(exec->vm(), static_cast<SymbolImpl&>(*identifier.impl()));
138  return jsString(&exec->vm(), identifier.impl());
139 }
140 
141 JSModuleRecord* JSModuleRecord::hostResolveImportedModule(ExecState* exec, const Identifier& moduleName)
142 {
143  JSValue moduleNameValue = identifierToJSValue(exec, moduleName);
144  JSValue pair = m_dependenciesMap->JSMap::get(exec, moduleNameValue);
145  return jsCast<JSModuleRecord*>(pair.get(exec, Identifier::fromString(exec, "value")));
146 }
147 
148 auto JSModuleRecord::resolveImport(ExecState* exec, const Identifier& localName) -> Resolution
149 {
150  std::optional<ImportEntry> optionalImportEntry = tryGetImportEntry(localName.impl());
151  if (!optionalImportEntry)
152  return Resolution::notFound();
153 
154  const ImportEntry& importEntry = *optionalImportEntry;
155  if (importEntry.isNamespace(exec->vm()))
156  return Resolution::notFound();
157 
158  JSModuleRecord* importedModule = hostResolveImportedModule(exec, importEntry.moduleRequest);
159  return importedModule->resolveExport(exec, importEntry.importName);
160 }
161 
162 struct JSModuleRecord::ResolveQuery {
163  struct Hash {
164  static unsigned hash(const ResolveQuery&);
165  static bool equal(const ResolveQuery&, const ResolveQuery&);
166  static const bool safeToCompareToEmptyOrDeleted = true;
167  };
168 
169  ResolveQuery(JSModuleRecord* moduleRecord, UniquedStringImpl* exportName)
170  : moduleRecord(moduleRecord)
171  , exportName(exportName)
172  {
173  }
174 
175  ResolveQuery(JSModuleRecord* moduleRecord, const Identifier& exportName)
176  : ResolveQuery(moduleRecord, exportName.impl())
177  {
178  }
179 
180  enum EmptyValueTag { EmptyValue };
181  ResolveQuery(EmptyValueTag)
182  {
183  }
184 
185  enum DeletedValueTag { DeletedValue };
186  ResolveQuery(DeletedValueTag)
187  : moduleRecord(nullptr)
188  , exportName(WTF::HashTableDeletedValue)
189  {
190  }
191 
192  bool isEmptyValue() const
193  {
194  return !exportName;
195  }
196 
197  bool isDeletedValue() const
198  {
199  return exportName.isHashTableDeletedValue();
200  }
201 
202  // The module record is not marked from the GC. But these records are reachable from the JSGlobalObject.
203  // So we don't care the reachability to this record.
204  JSModuleRecord* moduleRecord;
205  RefPtr<UniquedStringImpl> exportName;
206 };
207 
208 inline unsigned JSModuleRecord::ResolveQuery::Hash::hash(const ResolveQuery& query)
209 {
210  return WTF::PtrHash<JSModuleRecord*>::hash(query.moduleRecord) + IdentifierRepHash::hash(query.exportName);
211 }
212 
213 inline bool JSModuleRecord::ResolveQuery::Hash::equal(const ResolveQuery& lhs, const ResolveQuery& rhs)
214 {
215  return lhs.moduleRecord == rhs.moduleRecord && lhs.exportName == rhs.exportName;
216 }
217 
218 auto JSModuleRecord::tryGetCachedResolution(UniquedStringImpl* exportName) -> std::optional<Resolution>
219 {
220  const auto iterator = m_resolutionCache.find(exportName);
221  if (iterator == m_resolutionCache.end())
222  return std::nullopt;
223  return std::optional<Resolution>(iterator->value);
224 }
225 
226 void JSModuleRecord::cacheResolution(UniquedStringImpl* exportName, const Resolution& resolution)
227 {
228  m_resolutionCache.add(exportName, resolution);
229 }
230 
231 auto JSModuleRecord::resolveExportImpl(ExecState* exec, const ResolveQuery& root) -> Resolution
232 {
233  // http://www.ecma-international.org/ecma-262/6.0/#sec-resolveexport
234 
235  // How to avoid C++ recursion in this function:
236  // This function avoids C++ recursion of the naive ResolveExport implementation.
237  // Flatten the recursion to the loop with the task queue and frames.
238  //
239  // 1. pendingTasks
240  // We enqueue the recursive resolveExport call to this queue to avoid recursive calls in C++.
241  // The task has 3 types. (1) Query, (2) IndirectFallback and (3) GatherStars.
242  // (1) Query
243  // Querying the resolution to the current module.
244  // (2) IndirectFallback
245  // Examine the result of the indirect export resolution. Only when the indirect export resolution fails,
246  // we look into the star exports. (step 5-a-vi).
247  // (3) GatherStars
248  // Examine the result of the star export resolutions.
249  //
250  // 2. frames
251  // When the spec calls the resolveExport recursively, instead we append the frame
252  // (that holds the result resolution) to the frames and enqueue the task to the pendingTasks.
253  // The entry in the frames means the *local* resolution result of the specific recursive resolveExport.
254  //
255  // We should maintain the local resolution result instead of holding the global resolution result only.
256  // For example,
257  //
258  // star
259  // (1) ---> (2) "Resolve"
260  // |
261  // |
262  // +-> (3) "NotFound"
263  // |
264  // | star
265  // +-> (4) ---> (5) "Resolve" [here]
266  // |
267  // |
268  // +-> (6) "Error"
269  //
270  // Consider the above graph. The numbers represents the modules. Now we are [here].
271  // If we only hold the global resolution result during the resolveExport operation, [here],
272  // we decide the entire result of resolveExport is "Ambiguous", because there are multiple
273  // "Reslove" (in module (2) and (5)). However, this should become "Error" because (6) will
274  // propagate "Error" state to the (4), (4) will become "Error" and then, (1) will become
275  // "Error". We should aggregate the results at the star exports point ((4) and (1)).
276  //
277  // Usually, both "Error" and "Ambiguous" states will throw the syntax error. So except for the content of the
278  // error message, there are no difference. (And if we fix the (6) that raises "Error", next, it will produce
279  // the "Ambiguous" error due to (5). Anyway, user need to fix the both. So which error should be raised at first
280  // doesn't matter so much.
281  //
282  // However, this may become the problem under the module namespace creation.
283  // http://www.ecma-international.org/ecma-262/6.0/#sec-getmodulenamespace
284  // section 15.2.1.18, step 3-d-ii
285  // Here, we distinguish "Ambiguous" and "Error". When "Error" state is produced, we need to throw the propagated error.
286  // But if "Ambiguous" state comes, we just ignore the result.
287  // To follow the requirement strictly, in this implementation, we keep the local resolution result to produce the
288  // correct result under the above complex cases.
289 
290  // Caching strategy:
291  // The resolveExport operation is frequently called. So caching results is important.
292  // We observe the following aspects and based on them construct the caching strategy.
293  // Here, we attempt to cache the resolution by constructing the map in module records.
294  // That means Module -> ExportName -> Maybe<Resolution>.
295  // Technically, all the JSModuleRecords have the Map<ExportName, Resolution> for caching.
296  //
297  // The important observations are that,
298  //
299  // - *cacheable* means that traversing to this node from a path will produce the same results as starting from this node.
300  //
301  // Here, we define the resovling route. We represent [?] as the module that has the local binding.
302  // And (?) as the module without the local binding.
303  //
304  // @ -> (A) -> (B) -> [C]
305  //
306  // We list the resolving route for each node.
307  //
308  // (A): (A) -> (B) -> [C]
309  // (B): (B) -> [C]
310  // [C]: [C]
311  //
312  // In this case, if we start the tracing from (B), the resolving route becomes (B) -> [C].
313  // So this is the same. At that time, we can say (B) is cacheable in the first tracing.
314  //
315  // - The cache ability of a node depends on the resolving route from this node.
316  //
317  // 1. The starting point is always cacheable.
318  //
319  // 2. A module that has resolved a local binding is always cacheable.
320  //
321  // @ -> (A) -> [B]
322  //
323  // In the above case, we can see the [B] as cacheable.
324  // This is because when starting from [B] node, we immediately resolve with the local binding.
325  // So the resolving route from [B] does not depend on the starting point.
326  //
327  // 3. If we don't follow any star links during the resolution, we can see all the traced nodes are cacheable.
328  //
329  // If there are non star links, it means that there is *no branch* in the module dependency graph.
330  // This *no branch* feature makes all the modules cachable.
331  //
332  // I.e, if we traverse one star link (even if we successfully resolve that star link),
333  // we must still traverse all other star links. I would also explain we don't run into
334  // this when resolving a local/indirect link. When resolving a local/indirect link,
335  // we won't traverse any star links.
336  // And since the module can hold only one local/indirect link for the specific export name (if there
337  // are multiple local/indirect links that has the same export name, it should be syntax error in the
338  // parsing phase.), there is no multiple outgoing links from a module.
339  //
340  // @ -> (A) --> (B) -> [C] -> (D) -> (E) -+
341  // ^ |
342  // | |
343  // +------------------------+
344  //
345  // When starting from @, [C] will be found as the module resolving the given binding.
346  // In this case, (B) can cache this resolution. Since the resolving route is the same to the one when
347  // starting from (B). After caching the above result, we attempt to resolve the same binding from (D).
348  //
349  // @
350  // |
351  // v
352  // @ -> (A) --> (B) -> [C] -> (D) -> (E) -+
353  // ^ |
354  // | |
355  // +------------------------+
356  //
357  // In this case, we can use the (B)'s cached result. And (E) can be cached.
358  //
359  // (E): The resolving route is now (E) -> (B) -> [C]. That is the same when starting from (E).
360  //
361  // No branching makes that the problematic *once-visited* node cannot be seen.
362  // The *once-visited* node makes the resolving route changed since when we see the *once-visited* node,
363  // we stop tracing this.
364  //
365  // If there is no star links and if we look *once-visited* node under no branching graph, *once-visited*
366  // node cannot resolve the requested binding. If the *once-visited* node can resolve the binding, we
367  // should have already finished the resolution before reaching this *once-visited* node.
368  //
369  // 4. Once we follow star links, we should not retrieve the result from the cache and should not cache.
370  //
371  // Star links are only the way to introduce branch.
372  // Once we follow the star links during the resolution, we cannot cache naively.
373  // This is because the cacheability depends on the resolving route. And branching produces the problematic *once-visited*
374  // nodes. Since we don't follow the *once-visited* node, the resolving route from the node becomes different from
375  // the resolving route when starting from this node.
376  //
377  // The following example explains when we should not retrieve the cache and cache the result.
378  //
379  // +----> (D) ------+
380  // | |
381  // | v
382  // (A) *----+----> (B) ---> [C]
383  // ^
384  // |
385  // @
386  //
387  // When starting from (B), we find [C]. In this resolving route, we don't find any star link.
388  // And by definition, (B) and [C] are cachable. (B) is the starting point. And [C] has the local binding.
389  //
390  // +----> (D) ------+
391  // | |
392  // | v
393  // @-> (A) *----+----> (B) ---> [C]
394  //
395  // But when starting from (A), we should not get the value from the cache. Because,
396  //
397  // 1. When looking (D), we reach [C] and make both resolved.
398  // 2. When looking (B), if we retrieved the last cache from (B), (B) becomes resolved.
399  // 3. But actually, (B) is not-found in this trial because (C) is already *once-visited*.
400  // 4. If we accidentally make (B) resolved, (A) becomes ambiguous. But the correct answer is resolved.
401  //
402  // Why is this problem caused? This is because the *once-visited* node makes the result not-found.
403  // In the second trial, (B) -> [C] result is changed from resolved to not-found.
404  //
405  // When does this become a problem? If the status of the *once-visited* node group is resolved,
406  // changing the result to not-found makes the result changed.
407  //
408  // This problem does not happen when we don't see any star link yet. Now, consider the minimum case.
409  //
410  // @-> (A) -> [ some graph ]
411  // ^ |
412  // | |
413  // +------------+
414  //
415  // In (A), we don't see any star link yet. So we can say that all the visited nodes does not have any local
416  // resolution. Because if they had a local/indirect resolution, we should have already finished the tracing.
417  //
418  // And even if the some graph will see the *once-visited* node (in this case, (A)), that does not affect the
419  // result of the resolution. Because even if we follow the link to (A) or not follow the link to (A), the status
420  // of the link is always not-found since (A) does not have any local resolution.
421  // In the above case, we can use the result of the [some graph].
422  //
423  // 5. Once we see star links, even if we have not yet traversed that star link path, we should disable caching.
424  //
425  // Here is the reason why:
426  //
427  // +-------------+
428  // | |
429  // v |
430  // (A) -> (B) -> (C) *-> [E]
431  // * ^
432  // | |
433  // v @
434  // [D]
435  //
436  // In the above case, (C) will be resolved with [D].
437  // (C) will see (A) and (A) gives up in (A) -> (B) -> (C) route. So, (A) will fallback to [D].
438  //
439  // +-------------+
440  // | |
441  // v |
442  // @-> (A) -> (B) -> (C) *-> [E]
443  // *
444  // |
445  // v
446  // [D]
447  //
448  // But in this case, (A) will be resolved with [E] (not [D]).
449  // (C) will attempt to follow the link to (A), but it fails.
450  // So (C) will fallback to the star link and found [E]. In this senario,
451  // (C) is now resolved with [E]'s result.
452  //
453  // The cause of this problem is also the same to 4.
454  // In the latter case, when looking (C), we cannot use the cached result in (C).
455  // Because the cached result of (C) depends on the *once-visited* node (A) and
456  // (A) has the fallback system with the star link.
457  // In the latter trial, we now assume that (A)'s status is not-found.
458  // But, actually, in the former trial, (A)'s status becomes resolved due to the fallback to the [D].
459  //
460  // To summarize the observations.
461  //
462  // 1. The starting point is always cacheable.
463  // 2. A module that has resolved a local binding is always cacheable.
464  // 3. If we don't follow any star links during the resolution, we can see all the traced nodes are cacheable.
465  // 4. Once we follow star links, we should not retrieve the result from the cache and should not cache the result.
466  // 5. Once we see star links, even if we have not yet traversed that star link path, we should disable caching.
467 
468  typedef WTF::HashSet<ResolveQuery, ResolveQuery::Hash, WTF::CustomHashTraits<ResolveQuery>> ResolveSet;
469  enum class Type { Query, IndirectFallback, GatherStars };
470  struct Task {
471  ResolveQuery query;
472  Type type;
473  };
474 
475  Vector<Task, 8> pendingTasks;
476  ResolveSet resolveSet;
477  HashSet<JSModuleRecord*> starSet;
478 
479  Vector<Resolution, 8> frames;
480 
481  bool foundStarLinks = false;
482 
483  frames.append(Resolution::notFound());
484 
485  // Call when the query is not resolved in the current module.
486  // It will enqueue the star resolution requests. Return "false" if the error occurs.
487  auto resolveNonLocal = [&](const ResolveQuery& query) -> bool {
488  // http://www.ecma-international.org/ecma-262/6.0/#sec-resolveexport
489  // section 15.2.1.16.3, step 6
490  // If the "default" name is not resolved in the current module, we need to throw an error and stop resolution immediately,
491  // Rationale to this error: A default export cannot be provided by an export *.
492  if (query.exportName == exec->propertyNames().defaultKeyword.impl())
493  return false;
494 
495  // step 7, If exportStarSet contains module, then return null.
496  if (!starSet.add(query.moduleRecord).isNewEntry)
497  return true;
498 
499  // Enqueue the task to gather the results of the stars.
500  // And append the new Resolution frame to gather the local result of the stars.
501  pendingTasks.append(Task { query, Type::GatherStars });
502  foundStarLinks = true;
503  frames.append(Resolution::notFound());
504 
505 
506  // Enqueue the tasks in reverse order.
507  for (auto iterator = query.moduleRecord->starExportEntries().rbegin(), end = query.moduleRecord->starExportEntries().rend(); iterator != end; ++iterator) {
508  const RefPtr<UniquedStringImpl>& starModuleName = *iterator;
509  JSModuleRecord* importedModuleRecord = query.moduleRecord->hostResolveImportedModule(exec, Identifier::fromUid(exec, starModuleName.get()));
510  pendingTasks.append(Task { ResolveQuery(importedModuleRecord, query.exportName.get()), Type::Query });
511  }
512  return true;
513  };
514 
515  // Return the current resolution value of the top frame.
516  auto currentTop = [&] () -> Resolution& {
517  ASSERT(!frames.isEmpty());
518  return frames.last();
519  };
520 
521  // Merge the given resolution to the current resolution value of the top frame.
522  // If there is ambiguity, return "false". When the "false" is returned, we should make the result "ambiguous".
523  auto mergeToCurrentTop = [&] (const Resolution& resolution) -> bool {
524  if (resolution.type == Resolution::Type::NotFound)
525  return true;
526 
527  if (currentTop().type == Resolution::Type::NotFound) {
528  currentTop() = resolution;
529  return true;
530  }
531 
532  if (currentTop().moduleRecord != resolution.moduleRecord || currentTop().localName != resolution.localName)
533  return false;
534 
535  return true;
536  };
537 
538  auto cacheResolutionForQuery = [] (const ResolveQuery& query, const Resolution& resolution) {
539  ASSERT(resolution.type == Resolution::Type::Resolved);
540  query.moduleRecord->cacheResolution(query.exportName.get(), resolution);
541  };
542 
543  pendingTasks.append(Task { root, Type::Query });
544  while (!pendingTasks.isEmpty()) {
545  const Task task = pendingTasks.takeLast();
546  const ResolveQuery& query = task.query;
547 
548  switch (task.type) {
549  case Type::Query: {
550  JSModuleRecord* moduleRecord = query.moduleRecord;
551 
552  if (!resolveSet.add(task.query).isNewEntry)
553  continue;
554 
555  // 5. Once we see star links, even if we have not yet traversed that star link path, we should disable caching.
556  if (!moduleRecord->starExportEntries().isEmpty())
557  foundStarLinks = true;
558 
559  // 4. Once we follow star links, we should not retrieve the result from the cache and should not cache the result.
560  if (!foundStarLinks) {
561  if (std::optional<Resolution> cachedResolution = moduleRecord->tryGetCachedResolution(query.exportName.get())) {
562  if (!mergeToCurrentTop(*cachedResolution))
563  return Resolution::ambiguous();
564  continue;
565  }
566  }
567 
568  const std::optional<ExportEntry> optionalExportEntry = moduleRecord->tryGetExportEntry(query.exportName.get());
569  if (!optionalExportEntry) {
570  // If there is no matched exported binding in the current module,
571  // we need to look into the stars.
572  if (!resolveNonLocal(task.query))
573  return Resolution::error();
574  continue;
575  }
576 
577  const ExportEntry& exportEntry = *optionalExportEntry;
578  switch (exportEntry.type) {
579  case ExportEntry::Type::Local: {
580  ASSERT(!exportEntry.localName.isNull());
581  Resolution resolution { Resolution::Type::Resolved, moduleRecord, exportEntry.localName };
582  // 2. A module that has resolved a local binding is always cacheable.
583  cacheResolutionForQuery(query, resolution);
584  if (!mergeToCurrentTop(resolution))
585  return Resolution::ambiguous();
586  continue;
587  }
588 
589  case ExportEntry::Type::Indirect: {
590  JSModuleRecord* importedModuleRecord = moduleRecord->hostResolveImportedModule(exec, exportEntry.moduleName);
591 
592  // When the imported module does not produce any resolved binding, we need to look into the stars in the *current*
593  // module. To do this, we append the `IndirectFallback` task to the task queue.
594  pendingTasks.append(Task { query, Type::IndirectFallback });
595  // And append the new Resolution frame to check the indirect export will be resolved or not.
596  frames.append(Resolution::notFound());
597  pendingTasks.append(Task { ResolveQuery(importedModuleRecord, exportEntry.importName), Type::Query });
598  continue;
599  }
600  }
601  break;
602  }
603 
604  case Type::IndirectFallback: {
605  Resolution resolution = frames.takeLast();
606 
607  if (resolution.type == Resolution::Type::NotFound) {
608  // Indirect export entry does not produce any resolved binding.
609  // So we will investigate the stars.
610  if (!resolveNonLocal(task.query))
611  return Resolution::error();
612  continue;
613  }
614 
615  ASSERT_WITH_MESSAGE(resolution.type == Resolution::Type::Resolved, "When we see Error and Ambiguous, we immediately return from this loop. So here, only Resolved comes.");
616 
617  // 3. If we don't follow any star links during the resolution, we can see all the traced nodes are cacheable.
618  // 4. Once we follow star links, we should not retrieve the result from the cache and should not cache the result.
619  if (!foundStarLinks)
620  cacheResolutionForQuery(query, resolution);
621 
622  // If indirect export entry produces Resolved, we should merge it to the upper frame.
623  // And do not investigate the stars of the current module.
624  if (!mergeToCurrentTop(resolution))
625  return Resolution::ambiguous();
626  break;
627  }
628 
629  case Type::GatherStars: {
630  Resolution resolution = frames.takeLast();
631  ASSERT_WITH_MESSAGE(resolution.type == Resolution::Type::Resolved || resolution.type == Resolution::Type::NotFound, "When we see Error and Ambiguous, we immediately return from this loop. So here, only Resolved and NotFound comes.");
632 
633  // Merge the star resolution to the upper frame.
634  if (!mergeToCurrentTop(resolution))
635  return Resolution::ambiguous();
636  break;
637  }
638  }
639  }
640 
641  ASSERT(frames.size() == 1);
642  // 1. The starting point is always cacheable.
643  if (frames[0].type == Resolution::Type::Resolved)
644  cacheResolutionForQuery(root, frames[0]);
645  return frames[0];
646 }
647 
648 auto JSModuleRecord::resolveExport(ExecState* exec, const Identifier& exportName) -> Resolution
 57void JSModuleRecord::destroy(JSCell* cell)
64958{
650  // Look up the cached resolution first before entering the resolving loop, since the loop setup takes some cost.
651  if (std::optional<Resolution> cachedResolution = tryGetCachedResolution(exportName.impl()))
652  return *cachedResolution;
653  return resolveExportImpl(exec, ResolveQuery(this, exportName.impl()));
 59 JSModuleRecord* thisObject = jsCast<JSModuleRecord*>(cell);
 60 thisObject->JSModuleRecord::~JSModuleRecord();
65461}
65562
656 static void getExportedNames(ExecState* exec, JSModuleRecord* root, IdentifierSet& exportedNames)
 63void JSModuleRecord::finishCreation(ExecState* exec, VM& vm)
65764{
658  HashSet<JSModuleRecord*> exportStarSet;
659  Vector<JSModuleRecord*, 8> pendingModules;
660 
661  pendingModules.append(root);
662 
663  while (!pendingModules.isEmpty()) {
664  JSModuleRecord* moduleRecord = pendingModules.takeLast();
665  if (exportStarSet.contains(moduleRecord))
666  continue;
667  exportStarSet.add(moduleRecord);
668 
669  for (const auto& pair : moduleRecord->exportEntries()) {
670  const JSModuleRecord::ExportEntry& exportEntry = pair.value;
671  if (moduleRecord == root || exec->propertyNames().defaultKeyword != exportEntry.exportName)
672  exportedNames.add(exportEntry.exportName.impl());
673  }
674 
675  for (const auto& starModuleName : moduleRecord->starExportEntries()) {
676  JSModuleRecord* requestedModuleRecord = moduleRecord->hostResolveImportedModule(exec, Identifier::fromUid(exec, starModuleName.get()));
677  pendingModules.append(requestedModuleRecord);
678  }
679  }
 65 Base::finishCreation(exec, vm);
 66 ASSERT(inherits(info()));
68067}
68168
682 JSModuleNamespaceObject* JSModuleRecord::getModuleNamespace(ExecState* exec)
 69void JSModuleRecord::visitChildren(JSCell* cell, SlotVisitor& visitor)
68370{
684  VM& vm = exec->vm();
685  auto scope = DECLARE_THROW_SCOPE(vm);
686 
687  // http://www.ecma-international.org/ecma-262/6.0/#sec-getmodulenamespace
688  if (m_moduleNamespaceObject)
689  return m_moduleNamespaceObject.get();
690 
691  JSGlobalObject* globalObject = exec->lexicalGlobalObject();
692  IdentifierSet exportedNames;
693  getExportedNames(exec, this, exportedNames);
694 
695  IdentifierSet unambiguousNames;
696  for (auto& name : exportedNames) {
697  const JSModuleRecord::Resolution resolution = resolveExport(exec, Identifier::fromUid(exec, name.get()));
698  switch (resolution.type) {
699  case Resolution::Type::NotFound:
700  throwSyntaxError(exec, scope, makeString("Exported binding name '", String(name.get()), "' is not found."));
701  return nullptr;
702 
703  case Resolution::Type::Error:
704  throwSyntaxError(exec, scope, makeString("Exported binding name 'default' cannot be resolved by star export entries."));
705  return nullptr;
706 
707  case Resolution::Type::Ambiguous:
708  break;
709 
710  case Resolution::Type::Resolved:
711  unambiguousNames.add(name);
712  break;
713  }
714  }
715 
716  m_moduleNamespaceObject.set(vm, this, JSModuleNamespaceObject::create(exec, globalObject, globalObject->moduleNamespaceObjectStructure(), this, unambiguousNames));
717  return m_moduleNamespaceObject.get();
 71 JSModuleRecord* thisObject = jsCast<JSModuleRecord*>(cell);
 72 Base::visitChildren(thisObject, visitor);
 73 visitor.append(&thisObject->m_moduleProgramExecutable);
71874}
71975
72076void JSModuleRecord::link(ExecState* exec)

@@void JSModuleRecord::instantiateDeclarations(ExecState* exec, ModuleProgramExecu
746102 // Ensure all the indirect exports are correctly resolved to unique bindings.
747103 // Even if we avoided duplicate exports in the parser, still ambiguous exports occur due to the star export (`export * from "mod"`).
748104 // When we see this type of ambiguity for the indirect exports here, throw a syntax error.
749  for (const auto& pair : m_exportEntries) {
 105 for (const auto& pair : exportEntries()) {
750106 const ExportEntry& exportEntry = pair.value;
751107 if (exportEntry.type == JSModuleRecord::ExportEntry::Type::Indirect) {
752108 Resolution resolution = resolveExport(exec, exportEntry.exportName);

@@void JSModuleRecord::instantiateDeclarations(ExecState* exec, ModuleProgramExecu
773129 // section 15.2.1.16.4 step 12.
774130 // Instantiate namespace objects and initialize the bindings with them if required.
775131 // And ensure that all the imports correctly resolved to unique bindings.
776  for (const auto& pair : m_importEntries) {
 132 for (const auto& pair : importEntries()) {
777133 const ImportEntry& importEntry = pair.value;
778  JSModuleRecord* importedModule = hostResolveImportedModule(exec, importEntry.moduleRequest);
 134 AbstractModuleRecord* importedModule = hostResolveImportedModule(exec, importEntry.moduleRequest);
779135 if (importEntry.isNamespace(vm)) {
780136 JSModuleNamespaceObject* namespaceObject = importedModule->getModuleNamespace(exec);
781137 RETURN_IF_EXCEPTION(scope, void());

@@void JSModuleRecord::instantiateDeclarations(ExecState* exec, ModuleProgramExecu
807163 // Module environment contains the heap allocated "var", "function", "let", "const", and "class".
808164 // When creating the environment, we initialized all the slots with empty, it's ok for lexical values.
809165 // But for "var" and "function", we should initialize it with undefined. They are contained in the declared variables.
810  for (const auto& variable : m_declaredVariables) {
 166 for (const auto& variable : declaredVariables()) {
811167 SymbolTableEntry entry = symbolTable->get(variable.key.get());
812168 VarOffset offset = entry.varOffset();
813169 if (!offset.isStack()) {

@@JSValue JSModuleRecord::evaluate(ExecState* exec)
850206 return result;
851207}
852208
853 static String printableName(const RefPtr<UniquedStringImpl>& uid)
854 {
855  if (uid->isSymbol())
856  return uid.get();
857  return WTF::makeString("'", String(uid.get()), "'");
858 }
859 
860 static String printableName(const Identifier& ident)
861 {
862  return printableName(ident.impl());
863 }
864 
865 void JSModuleRecord::dump()
866 {
867  dataLog("\nAnalyzing ModuleRecord key(", printableName(m_moduleKey), ")\n");
868 
869  dataLog(" Dependencies: ", m_requestedModules.size(), " modules\n");
870  for (const auto& moduleName : m_requestedModules)
871  dataLog(" module(", printableName(moduleName), ")\n");
872 
873  dataLog(" Import: ", m_importEntries.size(), " entries\n");
874  for (const auto& pair : m_importEntries) {
875  const ImportEntry& importEntry = pair.value;
876  dataLog(" import(", printableName(importEntry.importName), "), local(", printableName(importEntry.localName), "), module(", printableName(importEntry.moduleRequest), ")\n");
877  }
878 
879  dataLog(" Export: ", m_exportEntries.size(), " entries\n");
880  for (const auto& pair : m_exportEntries) {
881  const ExportEntry& exportEntry = pair.value;
882  switch (exportEntry.type) {
883  case ExportEntry::Type::Local:
884  dataLog(" [Local] ", "export(", printableName(exportEntry.exportName), "), local(", printableName(exportEntry.localName), ")\n");
885  break;
886 
887  case ExportEntry::Type::Indirect:
888  dataLog(" [Indirect] ", "export(", printableName(exportEntry.exportName), "), import(", printableName(exportEntry.importName), "), module(", printableName(exportEntry.moduleName), ")\n");
889  break;
890  }
891  }
892  for (const auto& moduleName : m_starExportEntries)
893  dataLog(" [Star] module(", printableName(moduleName.get()), ")\n");
894 }
895 
896209} // namespace JSC

Source/JavaScriptCore/runtime/JSModuleRecord.h

11/*
2  * Copyright (C) 2015 Apple Inc. All rights reserved.
 2 * Copyright (C) 2015-2016 Apple Inc. All rights reserved.
33 *
44 * Redistribution and use in source and binary forms, with or without
55 * modification, are permitted provided that the following conditions

2525
2626#pragma once
2727
28 #include "Identifier.h"
29 #include "JSDestructibleObject.h"
30 #include "SourceCode.h"
31 #include "VariableEnvironment.h"
32 #include <wtf/HashMap.h>
33 #include <wtf/ListHashSet.h>
34 #include <wtf/Optional.h>
 28#include "AbstractModuleRecord.h"
3529
3630namespace JSC {
3731
38 class JSModuleNamespaceObject;
39 class JSModuleEnvironment;
40 class JSMap;
4132class ModuleProgramExecutable;
4233
4334// Based on the Source Text Module Record
4435// http://www.ecma-international.org/ecma-262/6.0/#sec-source-text-module-records
45 class JSModuleRecord : public JSDestructibleObject {
 36class JSModuleRecord : public AbstractModuleRecord {
4637 friend class LLIntOffsetsExtractor;
4738public:
48  typedef JSDestructibleObject Base;
49 
50  // https://tc39.github.io/ecma262/#sec-source-text-module-records
51  struct ExportEntry {
52  enum class Type {
53  Local,
54  Indirect
55  };
56 
57  static ExportEntry createLocal(const Identifier& exportName, const Identifier& localName);
58  static ExportEntry createIndirect(const Identifier& exportName, const Identifier& importName, const Identifier& moduleName);
59 
60  Type type;
61  Identifier exportName;
62  Identifier moduleName;
63  Identifier importName;
64  Identifier localName;
65  };
66 
67  struct ImportEntry {
68  Identifier moduleRequest;
69  Identifier importName;
70  Identifier localName;
71 
72  bool isNamespace(VM& vm) const
73  {
74  return importName == vm.propertyNames->timesIdentifier;
75  }
76  };
77 
78  typedef WTF::ListHashSet<RefPtr<UniquedStringImpl>, IdentifierRepHash> OrderedIdentifierSet;
79  typedef HashMap<RefPtr<UniquedStringImpl>, ImportEntry, IdentifierRepHash, HashTraits<RefPtr<UniquedStringImpl>>> ImportEntries;
80  typedef HashMap<RefPtr<UniquedStringImpl>, ExportEntry, IdentifierRepHash, HashTraits<RefPtr<UniquedStringImpl>>> ExportEntries;
 39 typedef AbstractModuleRecord Base;
8140
8241 DECLARE_EXPORT_INFO;
8342
84  static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
85  {
86  return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
87  }
88 
89  static JSModuleRecord* create(ExecState* exec, VM& vm, Structure* structure, const Identifier& moduleKey, const SourceCode& sourceCode, const VariableEnvironment& declaredVariables, const VariableEnvironment& lexicalVariables)
90  {
91  JSModuleRecord* instance = new (NotNull, allocateCell<JSModuleRecord>(vm.heap)) JSModuleRecord(vm, structure, moduleKey, sourceCode, declaredVariables, lexicalVariables);
92  instance->finishCreation(exec, vm);
93  return instance;
94  }
95 
96  void appendRequestedModule(const Identifier&);
97  void addStarExportEntry(const Identifier&);
98  void addImportEntry(const ImportEntry&);
99  void addExportEntry(const ExportEntry&);
100 
101  std::optional<ImportEntry> tryGetImportEntry(UniquedStringImpl* localName);
102  std::optional<ExportEntry> tryGetExportEntry(UniquedStringImpl* exportName);
103 
104  const SourceCode& sourceCode() const { return m_sourceCode; }
105  const Identifier& moduleKey() const { return m_moduleKey; }
106  const OrderedIdentifierSet& requestedModules() const { return m_requestedModules; }
107  const ExportEntries& exportEntries() const { return m_exportEntries; }
108  const ImportEntries& importEntries() const { return m_importEntries; }
109  const OrderedIdentifierSet& starExportEntries() const { return m_starExportEntries; }
110 
111  const VariableEnvironment& declaredVariables() const { return m_declaredVariables; }
112  const VariableEnvironment& lexicalVariables() const { return m_lexicalVariables; }
113 
114  void dump();
115 
11643 JSModuleEnvironment* moduleEnvironment()
11744 {
11845 ASSERT(m_moduleEnvironment);
11946 return m_moduleEnvironment.get();
12047 }
 48 static Structure* createStructure(VM&, JSGlobalObject*, JSValue);
 49 static JSModuleRecord* create(ExecState*, VM&, Structure*, const Identifier&, const SourceCode&, const VariableEnvironment&, const VariableEnvironment&);
12150
12251 void link(ExecState*);
12352 JS_EXPORT_PRIVATE JSValue evaluate(ExecState*);
12453
12554 ModuleProgramExecutable* moduleProgramExecutable() const { return m_moduleProgramExecutable.get(); }
12655
127  struct Resolution {
128  enum class Type { Resolved, NotFound, Ambiguous, Error };
129 
130  static Resolution notFound();
131  static Resolution error();
132  static Resolution ambiguous();
133 
134  Type type;
135  JSModuleRecord* moduleRecord;
136  Identifier localName;
137  };
138 
139  Resolution resolveExport(ExecState*, const Identifier& exportName);
140  Resolution resolveImport(ExecState*, const Identifier& localName);
141 
142  JSModuleRecord* hostResolveImportedModule(ExecState*, const Identifier& moduleName);
143 
14456private:
145  JSModuleRecord(VM& vm, Structure* structure, const Identifier& moduleKey, const SourceCode& sourceCode, const VariableEnvironment& declaredVariables, const VariableEnvironment& lexicalVariables)
146  : Base(vm, structure)
147  , m_moduleKey(moduleKey)
148  , m_sourceCode(sourceCode)
149  , m_declaredVariables(declaredVariables)
150  , m_lexicalVariables(lexicalVariables)
151  {
152  }
 57 JSModuleRecord(VM&, Structure*, const Identifier&, const SourceCode&, const VariableEnvironment&, const VariableEnvironment&);
15358
15459 void finishCreation(ExecState*, VM&);
15560
156  JSModuleNamespaceObject* getModuleNamespace(ExecState*);
157 
15861 static void visitChildren(JSCell*, SlotVisitor&);
15962 static void destroy(JSCell*);
16063
16164 void instantiateDeclarations(ExecState*, ModuleProgramExecutable*);
16265
163  struct ResolveQuery;
164  static Resolution resolveExportImpl(ExecState*, const ResolveQuery&);
165  std::optional<Resolution> tryGetCachedResolution(UniquedStringImpl* exportName);
166  void cacheResolution(UniquedStringImpl* exportName, const Resolution&);
167 
168  // The loader resolves the given module name to the module key. The module key is the unique value to represent this module.
169  Identifier m_moduleKey;
170 
171  SourceCode m_sourceCode;
172 
173  VariableEnvironment m_declaredVariables;
174  VariableEnvironment m_lexicalVariables;
175 
176  // Currently, we don't keep the occurrence order of the import / export entries.
177  // So, we does not guarantee the order of the errors.
178  // e.g. The import declaration that occurr later than the another import declaration may
179  // throw the error even if the former import declaration also has the invalid content.
180  //
181  // import ... // (1) this has some invalid content.
182  // import ... // (2) this also has some invalid content.
183  //
184  // In the above case, (2) may throw the error earlier than (1)
185  //
186  // But, in all the cases, we will throw the syntax error. So except for the content of the syntax error,
187  // there are no difference.
188 
189  // Map localName -> ImportEntry.
190  ImportEntries m_importEntries;
191 
192  // Map exportName -> ExportEntry.
193  ExportEntries m_exportEntries;
194 
195  // Save the occurrence order since resolveExport requires it.
196  OrderedIdentifierSet m_starExportEntries;
197 
198  // Save the occurrence order since the module loader loads and runs the modules in this order.
199  // http://www.ecma-international.org/ecma-262/6.0/#sec-moduleevaluation
200  OrderedIdentifierSet m_requestedModules;
201 
202  WriteBarrier<JSMap> m_dependenciesMap;
203 
20466 WriteBarrier<ModuleProgramExecutable> m_moduleProgramExecutable;
205  WriteBarrier<JSModuleEnvironment> m_moduleEnvironment;
206  WriteBarrier<JSModuleNamespaceObject> m_moduleNamespaceObject;
207 
208  // We assume that all the JSModuleRecord are retained by JSModuleLoader's registry.
209  // So here, we don't visit each object for GC. The resolution cache map caches the once
210  // looked up correctly resolved resolution, since (1) we rarely looked up the non-resolved one,
211  // and (2) if we cache all the attempts the size of the map becomes infinitely large.
212  typedef HashMap<RefPtr<UniquedStringImpl>, Resolution, IdentifierRepHash, HashTraits<RefPtr<UniquedStringImpl>>> Resolutions;
213  Resolutions m_resolutionCache;
21467};
21568
21669} // namespace JSC

Source/JavaScriptCore/runtime/JSScope.cpp

2626#include "config.h"
2727#include "JSScope.h"
2828
 29#include "AbstractModuleRecord.h"
2930#include "Exception.h"
3031#include "JSGlobalObject.h"
3132#include "JSLexicalEnvironment.h"
3233#include "JSModuleEnvironment.h"
33 #include "JSModuleRecord.h"
3434#include "JSWithScope.h"
3535#include "JSCInlines.h"
3636#include "VariableEnvironment.h"

@@static inline bool abstractAccess(ExecState* exec, JSScope* scope, const Identif
7878
7979 if (scope->type() == ModuleEnvironmentType) {
8080 JSModuleEnvironment* moduleEnvironment = jsCast<JSModuleEnvironment*>(scope);
81  JSModuleRecord* moduleRecord = moduleEnvironment->moduleRecord();
82  JSModuleRecord::Resolution resolution = moduleRecord->resolveImport(exec, ident);
83  if (resolution.type == JSModuleRecord::Resolution::Type::Resolved) {
84  JSModuleRecord* importedRecord = resolution.moduleRecord;
 81 AbstractModuleRecord* moduleRecord = moduleEnvironment->moduleRecord();
 82 AbstractModuleRecord::Resolution resolution = moduleRecord->resolveImport(exec, ident);
 83 if (resolution.type == AbstractModuleRecord::Resolution::Type::Resolved) {
 84 AbstractModuleRecord* importedRecord = resolution.moduleRecord;
8585 JSModuleEnvironment* importedEnvironment = importedRecord->moduleEnvironment();
8686 SymbolTable* symbolTable = importedEnvironment->symbolTable();
8787 ConcurrentJSLocker locker(symbolTable->m_lock);

@@void JSScope::collectClosureVariablesUnderTDZ(JSScope* scope, VariableEnvironmen
278278 continue;
279279
280280 if (scope->isModuleScope()) {
281  JSModuleRecord* moduleRecord = jsCast<JSModuleEnvironment*>(scope)->moduleRecord();
 281 AbstractModuleRecord* moduleRecord = jsCast<JSModuleEnvironment*>(scope)->moduleRecord();
282282 for (const auto& pair : moduleRecord->importEntries())
283283 result.add(pair.key);
284284 }

Source/JavaScriptCore/runtime/VM.cpp

7272#include "JSPromiseDeferred.h"
7373#include "JSPropertyNameEnumerator.h"
7474#include "JSTemplateRegistryKey.h"
 75#include "JSWebAssembly.h"
7576#include "JSWithScope.h"
7677#include "LLIntData.h"
7778#include "Lexer.h"

@@VM::VM(VMType vmType, HeapType heapType)
259260 functionCodeBlockStructure.set(*this, FunctionCodeBlock::createStructure(*this, 0, jsNull()));
260261#if ENABLE(WEBASSEMBLY)
261262 webAssemblyCodeBlockStructure.set(*this, WebAssemblyCodeBlock::createStructure(*this, 0, jsNull()));
 263 webAssemblyFunctionCellStructure.set(*this, WebAssemblyFunctionCell::createStructure(*this, 0, jsNull()));
262264#endif
263265 hashMapBucketSetStructure.set(*this, HashMapBucket<HashMapBucketDataKey>::createStructure(*this, 0, jsNull()));
264266 hashMapBucketMapStructure.set(*this, HashMapBucket<HashMapBucketDataKeyValue>::createStructure(*this, 0, jsNull()));

Source/JavaScriptCore/runtime/VM.h

@@public:
310310 Strong<Structure> functionExecutableStructure;
311311#if ENABLE(WEBASSEMBLY)
312312 Strong<Structure> webAssemblyExecutableStructure;
 313 Strong<Structure> webAssemblyFunctionCellStructure;
313314#endif
314315 Strong<Structure> moduleProgramExecutableStructure;
315316 Strong<Structure> regExpStructure;

Source/JavaScriptCore/wasm/JSWebAssembly.h

3636#include "js/JSWebAssemblyTable.h"
3737#include "js/WebAssemblyCompileErrorConstructor.h"
3838#include "js/WebAssemblyCompileErrorPrototype.h"
 39#include "js/WebAssemblyFunction.h"
 40#include "js/WebAssemblyFunctionCell.h"
3941#include "js/WebAssemblyInstanceConstructor.h"
4042#include "js/WebAssemblyInstancePrototype.h"
4143#include "js/WebAssemblyMemoryConstructor.h"
4244#include "js/WebAssemblyMemoryPrototype.h"
4345#include "js/WebAssemblyModuleConstructor.h"
4446#include "js/WebAssemblyModulePrototype.h"
 47#include "js/WebAssemblyModuleRecord.h"
4548#include "js/WebAssemblyPrototype.h"
4649#include "js/WebAssemblyRuntimeErrorConstructor.h"
4750#include "js/WebAssemblyRuntimeErrorPrototype.h"

Source/JavaScriptCore/wasm/WasmFormat.h

3030#include "B3Compilation.h"
3131#include "B3Type.h"
3232#include "CodeLocation.h"
 33#include "Identifier.h"
3334#include <wtf/Vector.h>
34 #include <wtf/text/WTFString.h>
3535
3636namespace JSC {
3737

@@struct Signature {
115115};
116116
117117struct Import {
118  String module;
119  String field;
 118 Identifier module;
 119 Identifier field;
120120 External::Kind kind;
121121 union {
122122 Signature* functionSignature;

@@struct FunctionInformation {
135135class Memory;
136136
137137struct Export {
138  String field;
 138 Identifier field;
139139 External::Kind kind;
140140 union {
141  Signature* functionSignature;
 141 uint32_t functionIndex;
142142 // FIXME implement Table https://bugs.webkit.org/show_bug.cgi?id=164135
143143 // FIXME implement Memory https://bugs.webkit.org/show_bug.cgi?id=164134
144144 // FIXME implement Global https://bugs.webkit.org/show_bug.cgi?id=164133

@@struct ModuleInformation {
155155 ~ModuleInformation();
156156};
157157
158 struct FunctionCompilation;
159 typedef Vector<std::unique_ptr<FunctionCompilation>> CompiledFunctions;
160 
161158struct UnlinkedCall {
162159 CodeLocationCall callLocation;
163160 size_t functionIndex;

@@struct FunctionCompilation {
169166 std::unique_ptr<B3::Compilation> jsEntryPoint;
170167};
171168
 169typedef Vector<std::unique_ptr<FunctionCompilation>> CompiledFunctions;
 170
172171} } // namespace JSC::Wasm
173172
174173#endif // ENABLE(WEBASSEMBLY)

Source/JavaScriptCore/wasm/WasmModuleParser.cpp

2828
2929#if ENABLE(WEBASSEMBLY)
3030
 31#include "IdentifierInlines.h"
3132#include "WasmFormat.h"
3233#include "WasmMemory.h"
3334#include "WasmOps.h"

@@bool ModuleParser::parse()
123124 m_errorMessage = "couldn't parse section " #NAME ": " DESCRIPTION; \
124125 return false; \
125126 } \
126  } break;
 127 } \
 128 break;
127129 FOR_EACH_WASM_SECTION(WASM_SECTION_PARSE)
128130#undef WASM_SECTION_PARSE
129131

@@bool ModuleParser::parseType()
167169 int8_t type;
168170 if (!parseInt7(type))
169171 return false;
170  if (type != -0x20) // Function type constant.
 172 if (type != -0x20) // Function type constant. FIXME auto-generate from JSON file.
171173 return false;
172174
173175 if (verbose)

@@bool ModuleParser::parseImport()
226228 uint32_t fieldLen;
227229 if (!parseVarUInt32(moduleLen))
228230 return false;
229  if (!consumeUTF8String(i.module, moduleLen))
 231 String moduleString;
 232 if (!consumeUTF8String(moduleString, moduleLen))
230233 return false;
 234 i.module = Identifier::fromString(m_vm, moduleString);
231235 if (!parseVarUInt32(fieldLen))
232236 return false;
233  if (!consumeUTF8String(i.field, fieldLen))
 237 String fieldString;
 238 if (!consumeUTF8String(fieldString, fieldLen))
234239 return false;
 240 i.field = Identifier::fromString(m_vm, fieldString);
235241 if (!parseExternalKind(i.kind))
236242 return false;
237243 switch (i.kind) {

@@bool ModuleParser::parseImport()
239245 uint32_t functionSignatureIndex;
240246 if (!parseVarUInt32(functionSignatureIndex))
241247 return false;
242  if (functionSignatureIndex > m_module->signatures.size())
 248 if (functionSignatureIndex >= m_module->signatures.size())
243249 return false;
244250 i.functionSignature = &m_module->signatures[functionSignatureIndex];
245  } break;
 251 }
 252 break;
246253 case External::Table:
247254 // FIXME https://bugs.webkit.org/show_bug.cgi?id=164135
248255 break;

@@bool ModuleParser::parseFunction()
277284 if (typeNumber >= m_module->signatures.size())
278285 return false;
279286
280  m_module->functions.uncheckedAppend({ &m_module->signatures[typeNumber], 0, 0 });
 287 // The Code section fixes up start and end.
 288 size_t start = 0, end = 0;
 289 m_module->functions.uncheckedAppend({ &m_module->signatures[typeNumber], start, end });
281290 }
282291
283292 return true;

@@bool ModuleParser::parseExport()
343352 uint32_t fieldLen;
344353 if (!parseVarUInt32(fieldLen))
345354 return false;
346  if (!consumeUTF8String(e.field, fieldLen))
 355 String fieldString;
 356 if (!consumeUTF8String(fieldString, fieldLen))
347357 return false;
 358 e.field = Identifier::fromString(m_vm, fieldString);
348359 if (!parseExternalKind(e.kind))
349360 return false;
350361 switch (e.kind) {
351362 case External::Function: {
352  uint32_t functionSignatureIndex;
353  if (!parseVarUInt32(functionSignatureIndex))
 363 if (!parseVarUInt32(e.functionIndex))
354364 return false;
355  if (functionSignatureIndex >= m_module->signatures.size())
 365 if (e.functionIndex >= m_module->functions.size())
356366 return false;
357  e.functionSignature = &m_module->signatures[functionSignatureIndex];
358  } break;
359  case External::Table:
 367 }
 368 break;
 369 case External::Table: {
360370 // FIXME https://bugs.webkit.org/show_bug.cgi?id=164135
361  break;
362  case External::Memory:
 371 }
 372 break;
 373 case External::Memory: {
363374 // FIXME https://bugs.webkit.org/show_bug.cgi?id=164134
364  break;
365  case External::Global:
 375 }
 376 break;
 377 case External::Global: {
366378 // FIXME https://bugs.webkit.org/show_bug.cgi?id=164133
367379 // In the MVP, only immutable global variables can be exported.
368  break;
 380 }
 381 break;
369382 }
370383
371384 m_module->exports.uncheckedAppend(e);

Source/JavaScriptCore/wasm/WasmModuleParser.h

@@public:
3939
4040 static const unsigned magicNumber = 0xc;
4141
42  ModuleParser(const uint8_t* sourceBuffer, size_t sourceLength)
 42 ModuleParser(VM* vm, const uint8_t* sourceBuffer, size_t sourceLength)
4343 : Parser(sourceBuffer, sourceLength)
 44 , m_vm(vm)
4445 {
4546 }
46  ModuleParser(const Vector<uint8_t>& sourceBuffer)
47  : Parser(sourceBuffer.data(), sourceBuffer.size())
 47 ModuleParser(VM* vm, const Vector<uint8_t>& sourceBuffer)
 48 : ModuleParser(vm, sourceBuffer.data(), sourceBuffer.size())
4849 {
4950 }
5051

@@private:
6768 FOR_EACH_WASM_SECTION(WASM_SECTION_DECLARE_PARSER)
6869#undef WASM_SECTION_DECLARE_PARSER
6970
 71 VM* m_vm;
7072 std::unique_ptr<ModuleInformation> m_module;
7173 bool m_failed { true };
7274 String m_errorMessage;

Source/JavaScriptCore/wasm/WasmPlan.cpp

@@void Plan::run()
5858 if (verbose)
5959 dataLogLn("Starting plan.");
6060 {
61  ModuleParser moduleParser(m_source, m_sourceLength);
 61 ModuleParser moduleParser(m_vm, m_source, m_sourceLength);
6262 if (!moduleParser.parse()) {
6363 if (verbose)
6464 dataLogLn("Parsing module failed: ", moduleParser.errorMessage());

Source/JavaScriptCore/wasm/js/JSWebAssemblyInstance.cpp

2828
2929#if ENABLE(WEBASSEMBLY)
3030
 31#include "AbstractModuleRecord.h"
3132#include "JSCInlines.h"
 33#include "JSModuleEnvironment.h"
3234#include "JSModuleNamespaceObject.h"
 35#include "JSWebAssemblyModule.h"
3336
3437namespace JSC {
3538
36 JSWebAssemblyInstance* JSWebAssemblyInstance::create(VM& vm, Structure* structure, JSModuleNamespaceObject* moduleNamespaceObject)
 39JSWebAssemblyInstance* JSWebAssemblyInstance::create(VM& vm, Structure* structure, JSWebAssemblyModule* module, JSModuleNamespaceObject* moduleNamespaceObject)
3740{
3841 auto* instance = new (NotNull, allocateCell<JSWebAssemblyInstance>(vm.heap)) JSWebAssemblyInstance(vm, structure);
39  instance->finishCreation(vm, moduleNamespaceObject);
 42 instance->finishCreation(vm, module, moduleNamespaceObject);
4043 return instance;
4144}
4245

@@JSWebAssemblyInstance::JSWebAssemblyInstance(VM& vm, Structure* structure)
5053{
5154}
5255
53 void JSWebAssemblyInstance::finishCreation(VM& vm, JSModuleNamespaceObject* moduleNamespaceObject)
 56void JSWebAssemblyInstance::finishCreation(VM& vm, JSWebAssemblyModule* module, JSModuleNamespaceObject* moduleNamespaceObject)
5457{
5558 Base::finishCreation(vm);
 59 m_module.set(vm, this, module);
5660 m_moduleNamespaceObject.set(vm, this, moduleNamespaceObject);
57  putDirectWithoutTransition(vm, Identifier::fromString(&vm, "exports"), m_moduleNamespaceObject.get(), None);
 61 // FIXME this should be used, instead of moduleEnvironment in WebAssemblyInstanceConstructor. https://bugs.webkit.org/show_bug.cgi?id=165121
 62 // putDirect(vm, Identifier::fromString(&vm, "exports"), JSValue(m_moduleNamespaceObject.get()), None);
5863 ASSERT(inherits(info()));
5964}
6065

@@void JSWebAssemblyInstance::visitChildren(JSCell* cell, SlotVisitor& visitor)
6974 ASSERT_GC_OBJECT_INHERITS(thisObject, info());
7075
7176 Base::visitChildren(thisObject, visitor);
 77 visitor.append(&thisObject->m_module);
7278 visitor.append(&thisObject->m_moduleNamespaceObject);
7379}
7480

Source/JavaScriptCore/wasm/js/JSWebAssemblyInstance.h

3131#include "JSObject.h"
3232
3333namespace JSC {
34 
 34
3535class JSModuleNamespaceObject;
 36class JSWebAssemblyModule;
3637
3738class JSWebAssemblyInstance : public JSDestructibleObject {
3839public:
3940 typedef JSDestructibleObject Base;
4041
41  static JSWebAssemblyInstance* create(VM&, Structure*, JSModuleNamespaceObject*);
 42
 43 static JSWebAssemblyInstance* create(VM&, Structure*, JSWebAssemblyModule*, JSModuleNamespaceObject*);
4244 static Structure* createStructure(VM&, JSGlobalObject*, JSValue);
4345
4446 DECLARE_INFO;
4547
 48 JSWebAssemblyModule* module()
 49 {
 50 ASSERT(m_module);
 51 return m_module.get();
 52 }
 53
4654protected:
4755 JSWebAssemblyInstance(VM&, Structure*);
48  void finishCreation(VM&, JSModuleNamespaceObject*);
 56 void finishCreation(VM&, JSWebAssemblyModule*, JSModuleNamespaceObject*);
4957 static void destroy(JSCell*);
5058 static void visitChildren(JSCell*, SlotVisitor&);
5159
5260private:
 61 WriteBarrier<JSWebAssemblyModule> m_module;
5362 WriteBarrier<JSModuleNamespaceObject> m_moduleNamespaceObject;
5463};
5564

Source/JavaScriptCore/wasm/js/JSWebAssemblyModule.cpp

3535
3636namespace JSC {
3737
38 JSWebAssemblyModule* JSWebAssemblyModule::create(VM& vm, Structure* structure, std::unique_ptr<Wasm::ModuleInformation>& moduleInformation, Wasm::CompiledFunctions& compiledFunctions)
 38JSWebAssemblyModule* JSWebAssemblyModule::create(VM& vm, Structure* structure, std::unique_ptr<Wasm::ModuleInformation>& moduleInformation, Wasm::CompiledFunctions& compiledFunctions, SymbolTable* exportSymbolTable)
3939{
4040 auto* instance = new (NotNull, allocateCell<JSWebAssemblyModule>(vm.heap)) JSWebAssemblyModule(vm, structure, moduleInformation, compiledFunctions);
41  instance->finishCreation(vm);
 41 instance->finishCreation(vm, exportSymbolTable);
4242 return instance;
4343}
4444

@@JSWebAssemblyModule::JSWebAssemblyModule(VM& vm, Structure* structure, std::uniq
5454{
5555}
5656
57 void JSWebAssemblyModule::finishCreation(VM& vm)
 57void JSWebAssemblyModule::finishCreation(VM& vm, SymbolTable* exportSymbolTable)
5858{
5959 Base::finishCreation(vm);
6060 ASSERT(inherits(info()));
 61 m_exportSymbolTable.set(vm, this, exportSymbolTable);
6162}
6263
6364void JSWebAssemblyModule::destroy(JSCell* cell)

@@void JSWebAssemblyModule::visitChildren(JSCell* cell, SlotVisitor& visitor)
7172 ASSERT_GC_OBJECT_INHERITS(thisObject, info());
7273
7374 Base::visitChildren(thisObject, visitor);
 75 visitor.append(&thisObject->m_exportSymbolTable);
7476}
7577
7678const ClassInfo JSWebAssemblyModule::s_info = { "WebAssembly.Module", &Base::s_info, 0, CREATE_METHOD_TABLE(JSWebAssemblyModule) };

Source/JavaScriptCore/wasm/js/JSWebAssemblyModule.h

3333
3434namespace JSC {
3535
 36class SymbolTable;
 37
3638class JSWebAssemblyModule : public JSDestructibleObject {
3739public:
3840 typedef JSDestructibleObject Base;
3941
40  static JSWebAssemblyModule* create(VM&, Structure*, std::unique_ptr<Wasm::ModuleInformation>&, Wasm::CompiledFunctions&);
 42 static JSWebAssemblyModule* create(VM&, Structure*, std::unique_ptr<Wasm::ModuleInformation>&, Wasm::CompiledFunctions&, SymbolTable*);
4143 static Structure* createStructure(VM&, JSGlobalObject*, JSValue);
4244
4345 DECLARE_INFO;
4446
45  const Wasm::ModuleInformation* moduleInformation() const
46  {
47  return m_moduleInformation.get();
48  }
 47 const Wasm::ModuleInformation& moduleInformation() const { return *m_moduleInformation.get(); }
 48 const Wasm::CompiledFunctions& compiledFunctions() const { return m_compiledFunctions; }
 49 SymbolTable* exportSymbolTable() const { return m_exportSymbolTable.get(); }
4950
5051protected:
5152 JSWebAssemblyModule(VM&, Structure*, std::unique_ptr<Wasm::ModuleInformation>&, Wasm::CompiledFunctions&);
52  void finishCreation(VM&);
 53 void finishCreation(VM&, SymbolTable*);
5354 static void destroy(JSCell*);
5455 static void visitChildren(JSCell*, SlotVisitor&);
5556private:
5657 std::unique_ptr<Wasm::ModuleInformation> m_moduleInformation;
5758 Wasm::CompiledFunctions m_compiledFunctions;
 59 WriteBarrier<SymbolTable> m_exportSymbolTable;
5860};
5961
6062} // namespace JSC

Source/JavaScriptCore/wasm/js/WebAssemblyFunction.cpp

 1/*
 2 * Copyright (C) 2016 Apple Inc. All rights reserved.
 3 *
 4 * Redistribution and use in source and binary forms, with or without
 5 * modification, are permitted provided that the following conditions
 6 * are met:
 7 * 1. Redistributions of source code must retain the above copyright
 8 * notice, this list of conditions and the following disclaimer.
 9 * 2. Redistributions in binary form must reproduce the above copyright
 10 * notice, this list of conditions and the following disclaimer in the
 11 * documentation and/or other materials provided with the distribution.
 12 *
 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 24 */
 25
 26#include "config.h"
 27#include "WebAssemblyFunction.h"
 28
 29#if ENABLE(WEBASSEMBLY)
 30
 31#include "B3Compilation.h"
 32#include "JSCInlines.h"
 33#include "JSFunctionInlines.h"
 34#include "JSObject.h"
 35#include "JSWebAssemblyInstance.h"
 36#include "LLintThunks.h"
 37#include "ProtoCallFrame.h"
 38#include "VM.h"
 39#include "WasmFormat.h"
 40#include "WebAssemblyFunctionCell.h"
 41
 42namespace JSC {
 43
 44const ClassInfo WebAssemblyFunction::s_info = { "WebAssemblyFunction", &Base::s_info, nullptr, CREATE_METHOD_TABLE(WebAssemblyFunction) };
 45
 46static EncodedJSValue JSC_HOST_CALL callWebAssemblyFunction(ExecState* state)
 47{
 48 auto& vm = state->vm();
 49 auto scope = DECLARE_THROW_SCOPE(vm);
 50 const WebAssemblyFunction* callee = jsDynamicCast<WebAssemblyFunction*>(state->callee());
 51 if (!callee)
 52 return JSValue::encode(throwException(state, scope, createTypeError(state, "expected a WebAssembly function", defaultSourceAppender, runtimeTypeForValue(state->callee()))));
 53 const CallableWebAssemblyFunction& callable = callee->webAssemblyFunctionCell()->function();
 54 const B3::Compilation* jsEntryPoint = callable.jsEntryPoint;
 55 const Wasm::Signature* signature = callable.signature;
 56
 57 // FIXME is this the right behavior? https://bugs.webkit.org/show_bug.cgi?id=164876
 58 if (state->argumentCount() != signature->arguments.size())
 59 return JSValue::encode(throwException(state, scope, createNotEnoughArgumentsError(state, defaultSourceAppender)));
 60
 61 // FIXME is this boxing correct? https://bugs.webkit.org/show_bug.cgi?id=164876
 62 Vector<JSValue> boxedArgs;
 63 for (unsigned argIndex = 0; argIndex < state->argumentCount(); ++argIndex) {
 64 JSValue arg = state->uncheckedArgument(argIndex);
 65 switch (signature->arguments[argIndex]) {
 66 case Wasm::Void:
 67 case Wasm::I64:
 68 RELEASE_ASSERT_NOT_REACHED();
 69 break;
 70 case Wasm::I32:
 71 arg = JSValue::decode(arg.toInt32(state));
 72 break;
 73 case Wasm::F32:
 74 arg = JSValue::decode(bitwise_cast<uint32_t>(arg.toFloat(state)));
 75 break;
 76 case Wasm::F64:
 77 arg = JSValue::decode(bitwise_cast<uint64_t>(arg.toNumber(state)));
 78 break;
 79 }
 80 RETURN_IF_EXCEPTION(scope, encodedJSValue());
 81 boxedArgs.append(arg);
 82 }
 83
 84 JSValue firstArgument;
 85 int argCount = 1;
 86 JSValue* remainingArgs = nullptr;
 87 if (boxedArgs.size()) {
 88 remainingArgs = boxedArgs.data();
 89 firstArgument = *remainingArgs;
 90 remainingArgs++;
 91 argCount = boxedArgs.size();
 92 }
 93
 94 ProtoCallFrame protoCallFrame;
 95 protoCallFrame.init(nullptr, nullptr, firstArgument, argCount, remainingArgs);
 96
 97 EncodedJSValue rawResult = vmEntryToWasm(jsEntryPoint->code().executableAddress(), &vm, &protoCallFrame);
 98 // FIXME is this correct? https://bugs.webkit.org/show_bug.cgi?id=164876
 99 switch (signature->returnType) {
 100 case Wasm::Void:
 101 return JSValue::encode(jsUndefined());
 102 case Wasm::I64:
 103 RELEASE_ASSERT_NOT_REACHED();
 104 case Wasm::I32:
 105 return JSValue::encode(JSValue(static_cast<int32_t>(rawResult)));
 106 case Wasm::F32:
 107 return JSValue::encode(JSValue(bitwise_cast<float>(static_cast<int32_t>(rawResult))));
 108 case Wasm::F64:
 109 return JSValue::encode(JSValue(bitwise_cast<double>(rawResult)));
 110 }
 111
 112 RELEASE_ASSERT_NOT_REACHED();
 113}
 114
 115WebAssemblyFunction* WebAssemblyFunction::create(VM& vm, JSGlobalObject* globalObject, int length, const String& name, JSWebAssemblyInstance* instance, CallableWebAssemblyFunction&& callable)
 116{
 117 NativeExecutable* executable = vm.getHostFunction(callWebAssemblyFunction, NoIntrinsic, callHostFunctionAsConstructor, nullptr, name);
 118 WebAssemblyFunctionCell* functionCell = WebAssemblyFunctionCell::create(vm, WTFMove(callable));
 119 Structure* structure = globalObject->webAssemblyFunctionStructure();
 120 WebAssemblyFunction* function = new (NotNull, allocateCell<WebAssemblyFunction>(vm.heap)) WebAssemblyFunction(vm, globalObject, structure);
 121 function->finishCreation(vm, executable, length, name, instance, functionCell);
 122 return function;
 123}
 124
 125Structure* WebAssemblyFunction::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
 126{
 127 ASSERT(globalObject);
 128 return Structure::create(vm, globalObject, prototype, TypeInfo(JSFunctionType, StructureFlags), info());
 129}
 130
 131WebAssemblyFunction::WebAssemblyFunction(VM& vm, JSGlobalObject* globalObject, Structure* structure)
 132 : Base(vm, globalObject, structure)
 133{
 134}
 135
 136void WebAssemblyFunction::visitChildren(JSCell* cell, SlotVisitor& visitor)
 137{
 138 WebAssemblyFunction* thisObject = jsCast<WebAssemblyFunction*>(cell);
 139 ASSERT_GC_OBJECT_INHERITS(thisObject, info());
 140 Base::visitChildren(thisObject, visitor);
 141 visitor.append(&thisObject->m_instance);
 142 visitor.append(&thisObject->m_functionCell);
 143}
 144
 145void WebAssemblyFunction::finishCreation(VM& vm, NativeExecutable* executable, int length, const String& name, JSWebAssemblyInstance* instance, WebAssemblyFunctionCell* functionCell)
 146{
 147 Base::finishCreation(vm, executable, length, name);
 148 ASSERT(inherits(info()));
 149 m_instance.set(vm, this, instance);
 150 m_functionCell.set(vm, this, functionCell);
 151}
 152
 153} // namespace JSC
 154
 155#endif // ENABLE(WEBASSEMBLY)

Source/JavaScriptCore/wasm/js/WebAssemblyFunction.h

 1/*
 2 * Copyright (C) 2016 Apple Inc. All rights reserved.
 3 *
 4 * Redistribution and use in source and binary forms, with or without
 5 * modification, are permitted provided that the following conditions
 6 * are met:
 7 * 1. Redistributions of source code must retain the above copyright
 8 * notice, this list of conditions and the following disclaimer.
 9 * 2. Redistributions in binary form must reproduce the above copyright
 10 * notice, this list of conditions and the following disclaimer in the
 11 * documentation and/or other materials provided with the distribution.
 12 *
 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 24 */
 25
 26#pragma once
 27
 28#if ENABLE(WEBASSEMBLY)
 29
 30#include "JSFunction.h"
 31#include <wtf/Noncopyable.h>
 32
 33namespace JSC {
 34
 35class JSGlobalObject;
 36class WebAssemblyFunctionCell;
 37class WebAssemblyInstance;
 38
 39namespace B3 {
 40class Compilation;
 41}
 42
 43namespace Wasm {
 44struct Signature;
 45}
 46
 47struct CallableWebAssemblyFunction {
 48 const B3::Compilation* jsEntryPoint;
 49 const Wasm::Signature* signature;
 50 CallableWebAssemblyFunction(const B3::Compilation* jsEntryPoint, const Wasm::Signature* signature)
 51 : jsEntryPoint(jsEntryPoint)
 52 , signature(signature)
 53 {
 54 }
 55 CallableWebAssemblyFunction(CallableWebAssemblyFunction&&) = default;
 56 WTF_MAKE_NONCOPYABLE(CallableWebAssemblyFunction);
 57 CallableWebAssemblyFunction() = delete;
 58};
 59
 60class WebAssemblyFunction : public JSFunction {
 61public:
 62 typedef JSFunction Base;
 63
 64 const static unsigned StructureFlags = Base::StructureFlags;
 65
 66 DECLARE_EXPORT_INFO;
 67
 68 JS_EXPORT_PRIVATE static WebAssemblyFunction* create(VM&, JSGlobalObject*, int, const String&, JSWebAssemblyInstance*, CallableWebAssemblyFunction&&);
 69 static Structure* createStructure(VM&, JSGlobalObject*, JSValue);
 70
 71 const WebAssemblyFunctionCell* webAssemblyFunctionCell() const { return m_functionCell.get(); }
 72
 73protected:
 74 static void visitChildren(JSCell*, SlotVisitor&);
 75
 76 void finishCreation(VM&, NativeExecutable*, int length, const String& name, JSWebAssemblyInstance*, WebAssemblyFunctionCell*);
 77
 78private:
 79 WebAssemblyFunction(VM&, JSGlobalObject*, Structure*);
 80
 81 WriteBarrier<JSWebAssemblyInstance> m_instance;
 82 WriteBarrier<WebAssemblyFunctionCell> m_functionCell;
 83};
 84
 85} // namespace JSC
 86
 87#endif // ENABLE(WEBASSEMBLY)

Source/JavaScriptCore/wasm/js/WebAssemblyFunctionCell.cpp

 1/*
 2 * Copyright (C) 2016 Apple Inc. All rights reserved.
 3 *
 4 * Redistribution and use in source and binary forms, with or without
 5 * modification, are permitted provided that the following conditions
 6 * are met:
 7 * 1. Redistributions of source code must retain the above copyright
 8 * notice, this list of conditions and the following disclaimer.
 9 * 2. Redistributions in binary form must reproduce the above copyright
 10 * notice, this list of conditions and the following disclaimer in the
 11 * documentation and/or other materials provided with the distribution.
 12 *
 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 24 */
 25
 26#include "config.h"
 27#include "WebAssemblyFunctionCell.h"
 28
 29#if ENABLE(WEBASSEMBLY)
 30
 31#include "JSCInlines.h"
 32
 33namespace JSC {
 34
 35const ClassInfo WebAssemblyFunctionCell::s_info = { "WebAssemblyFunctionCell", nullptr, nullptr, CREATE_METHOD_TABLE(WebAssemblyFunctionCell) };
 36
 37WebAssemblyFunctionCell* WebAssemblyFunctionCell::create(VM& vm, CallableWebAssemblyFunction&& callable)
 38{
 39 WebAssemblyFunctionCell* nativeFunction = new (NotNull, allocateCell<WebAssemblyFunctionCell>(vm.heap)) WebAssemblyFunctionCell(vm, WTFMove(callable));
 40 nativeFunction->finishCreation(vm);
 41 return nativeFunction;
 42}
 43
 44WebAssemblyFunctionCell::WebAssemblyFunctionCell(VM& vm, CallableWebAssemblyFunction&& callable)
 45 : Base(vm, vm.webAssemblyFunctionCellStructure.get())
 46 , m_function(WTFMove(callable))
 47{
 48}
 49
 50void WebAssemblyFunctionCell::destroy(JSCell* cell)
 51{
 52 WebAssemblyFunctionCell* nativeFunction = static_cast<WebAssemblyFunctionCell*>(cell);
 53 nativeFunction->WebAssemblyFunctionCell::~WebAssemblyFunctionCell();
 54}
 55
 56Structure* WebAssemblyFunctionCell::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
 57{
 58 return Structure::create(vm, globalObject, prototype, TypeInfo(CellType, StructureFlags), info());
 59}
 60
 61}
 62
 63#endif // ENABLE(WEBASSEMBLY)

Source/JavaScriptCore/wasm/js/WebAssemblyFunctionCell.h

 1/*
 2 * Copyright (C) 2016 Apple Inc. All rights reserved.
 3 *
 4 * Redistribution and use in source and binary forms, with or without
 5 * modification, are permitted provided that the following conditions
 6 * are met:
 7 * 1. Redistributions of source code must retain the above copyright
 8 * notice, this list of conditions and the following disclaimer.
 9 * 2. Redistributions in binary form must reproduce the above copyright
 10 * notice, this list of conditions and the following disclaimer in the
 11 * documentation and/or other materials provided with the distribution.
 12 *
 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 24 */
 25
 26#pragma once
 27
 28#if ENABLE(WEBASSEMBLY)
 29
 30#include "JSCell.h"
 31#include "WebAssemblyFunction.h"
 32
 33namespace JSC {
 34
 35class WebAssemblyFunctionCell : public JSCell {
 36public:
 37 typedef JSCell Base;
 38 static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal;
 39 static const bool needsDestruction = true;
 40
 41 static WebAssemblyFunctionCell* create(VM&, CallableWebAssemblyFunction&&);
 42 static void destroy(JSCell*);
 43 static Structure* createStructure(VM&, JSGlobalObject*, JSValue);
 44
 45 DECLARE_INFO;
 46
 47 const CallableWebAssemblyFunction& function() const { return m_function; }
 48
 49private:
 50 WebAssemblyFunctionCell(VM&, CallableWebAssemblyFunction&&);
 51
 52 CallableWebAssemblyFunction m_function;
 53};
 54
 55} // namespace JSC
 56
 57#endif // ENABLE(WEBASSEMBLY)

Source/JavaScriptCore/wasm/js/WebAssemblyInstanceConstructor.cpp

3030
3131#include "FunctionPrototype.h"
3232#include "JSCInlines.h"
33 #include "JSModuleNamespaceObject.h"
34 #include "JSModuleRecord.h"
 33#include "JSModuleEnvironment.h"
3534#include "JSWebAssemblyInstance.h"
3635#include "JSWebAssemblyModule.h"
3736#include "WebAssemblyInstancePrototype.h"
 37#include "WebAssemblyModuleRecord.h"
3838
3939#include "WebAssemblyInstanceConstructor.lut.h"
4040
4141namespace JSC {
4242
 43static const bool verbose = false;
 44
4345const ClassInfo WebAssemblyInstanceConstructor::s_info = { "Function", &Base::s_info, &constructorTableWebAssemblyInstance, CREATE_METHOD_TABLE(WebAssemblyInstanceConstructor) };
4446
4547/* Source for WebAssemblyInstanceConstructor.lut.h

@@static EncodedJSValue JSC_HOST_CALL constructJSWebAssemblyInstance(ExecState* st
5456 auto* globalObject = state->lexicalGlobalObject();
5557
5658 // If moduleObject is not a WebAssembly.Module instance, a TypeError is thrown.
57  JSWebAssemblyModule* module = jsDynamicCast<JSWebAssemblyModule*>(state->argument(0));
58  if (!module)
 59 JSWebAssemblyModule* jsModule = jsDynamicCast<JSWebAssemblyModule*>(state->argument(0));
 60 if (!jsModule)
5961 return JSValue::encode(throwException(state, scope, createTypeError(state, ASCIILiteral("first argument to WebAssembly.Instance must be a WebAssembly.Module"), defaultSourceAppender, runtimeTypeForValue(state->argument(0)))));
 62 const Wasm::ModuleInformation& moduleInformation = jsModule->moduleInformation();
6063
6164 // If the importObject parameter is not undefined and Type(importObject) is not Object, a TypeError is thrown.
6265 JSValue importArgument = state->argument(1);

@@static EncodedJSValue JSC_HOST_CALL constructJSWebAssemblyInstance(ExecState* st
6568 return JSValue::encode(throwException(state, scope, createTypeError(state, ASCIILiteral("second argument to WebAssembly.Instance must be undefined or an Object"), defaultSourceAppender, runtimeTypeForValue(importArgument))));
6669
6770 // If the list of module.imports is not empty and Type(importObject) is not Object, a TypeError is thrown.
68  if (module->moduleInformation()->imports.size() && !importObject)
 71 if (moduleInformation.imports.size() && !importObject)
6972 return JSValue::encode(throwException(state, scope, createTypeError(state, ASCIILiteral("second argument to WebAssembly.Instance must be Object because the WebAssembly.Module has imports"), defaultSourceAppender, runtimeTypeForValue(importArgument))));
7073
71  // FIXME String things from https://bugs.webkit.org/show_bug.cgi?id=164023
72  // Let exports be a list of (string, JS value) pairs that is mapped from each external value e in instance.exports as follows:
73  IdentifierSet instanceExports;
74  for (const auto& name : instanceExports) {
75  // FIXME validate according to Module.Instance spec.
76  (void)name;
77  }
78  Identifier moduleKey;
 74 Identifier moduleKey = Identifier::fromUid(PrivateName(PrivateName::Description, "WebAssemblyInstance"));
7975 SourceCode sourceCode;
8076 VariableEnvironment declaredVariables;
8177 VariableEnvironment lexicalVariables;
82  auto* moduleRecord = JSModuleRecord::create(state, vm, globalObject->moduleRecordStructure(), moduleKey, sourceCode, declaredVariables, lexicalVariables);
 78 WebAssemblyModuleRecord* moduleRecord = WebAssemblyModuleRecord::create(state, vm, globalObject->webAssemblyModuleRecordStructure(), moduleKey, sourceCode, declaredVariables, lexicalVariables);
8379 RETURN_IF_EXCEPTION(scope, encodedJSValue());
84  auto* moduleNamespaceObject = JSModuleNamespaceObject::create(state, globalObject, globalObject->moduleNamespaceObjectStructure(), moduleRecord, instanceExports);
 80
 81 Structure* instanceStructure = InternalFunction::createSubclassStructure(state, state->newTarget(), globalObject->WebAssemblyInstanceStructure());
8582 RETURN_IF_EXCEPTION(scope, encodedJSValue());
8683
87  auto* structure = InternalFunction::createSubclassStructure(state, state->newTarget(), globalObject->WebAssemblyInstanceStructure());
 84 JSWebAssemblyInstance* instance = JSWebAssemblyInstance::create(vm, instanceStructure, jsModule, moduleRecord->getModuleNamespace(state));
 85 RETURN_IF_EXCEPTION(scope, encodedJSValue());
 86
 87 moduleRecord->link(state, instance);
 88 RETURN_IF_EXCEPTION(scope, encodedJSValue());
 89 if (verbose)
 90 moduleRecord->dump();
 91 // FIXME the following should be in JSWebAssemblyInstance instead of here. https://bugs.webkit.org/show_bug.cgi?id=165121
 92 instance->putDirect(vm, Identifier::fromString(&vm, "exports"), JSValue(moduleRecord->moduleEnvironment()), None);
 93 JSValue startResult = moduleRecord->evaluate(state);
 94 UNUSED_PARAM(startResult);
8895 RETURN_IF_EXCEPTION(scope, encodedJSValue());
8996
90  return JSValue::encode(JSWebAssemblyInstance::create(vm, structure, moduleNamespaceObject));
 97 return JSValue::encode(instance);
9198}
9299
93100static EncodedJSValue JSC_HOST_CALL callJSWebAssemblyInstance(ExecState* state)

Source/JavaScriptCore/wasm/js/WebAssemblyModuleConstructor.cpp

3535#include "JSTypedArrays.h"
3636#include "JSWebAssemblyCompileError.h"
3737#include "JSWebAssemblyModule.h"
 38#include "SymbolTable.h"
3839#include "WasmPlan.h"
3940#include "WebAssemblyModulePrototype.h"
 41#include <wtf/StdLibExtras.h>
4042
4143#include "WebAssemblyModuleConstructor.lut.h"
4244

@@static EncodedJSValue JSC_HOST_CALL constructJSWebAssemblyModule(ExecState* stat
7880 auto* structure = InternalFunction::createSubclassStructure(state, state->newTarget(), asInternalFunction(state->callee())->globalObject()->WebAssemblyModuleStructure());
7981 RETURN_IF_EXCEPTION(scope, encodedJSValue());
8082
81  return JSValue::encode(JSWebAssemblyModule::create(vm, structure, plan.getModuleInformation(), plan.getCompiledFunctions()));
 83 // The export symbol table is the same for all Instances of a Modules.
 84 SymbolTable* exportSymbolTable = SymbolTable::create(vm);
 85 for (auto& e : plan.getModuleInformation()->exports) {
 86 auto offset = exportSymbolTable->takeNextScopeOffset(NoLockingNecessary);
 87 exportSymbolTable->set(NoLockingNecessary, e.field.impl(), SymbolTableEntry(VarOffset(offset)));
 88 }
 89
 90 return JSValue::encode(JSWebAssemblyModule::create(vm, structure, plan.getModuleInformation(), plan.getCompiledFunctions(), exportSymbolTable));
8291}
8392
8493static EncodedJSValue JSC_HOST_CALL callJSWebAssemblyModule(ExecState* state)

Source/JavaScriptCore/wasm/js/WebAssemblyModuleRecord.cpp

 1/*
 2 * Copyright (C) 2016 Apple Inc. All rights reserved.
 3 *
 4 * Redistribution and use in source and binary forms, with or without
 5 * modification, are permitted provided that the following conditions
 6 * are met:
 7 * 1. Redistributions of source code must retain the above copyright
 8 * notice, this list of conditions and the following disclaimer.
 9 * 2. Redistributions in binary form must reproduce the above copyright
 10 * notice, this list of conditions and the following disclaimer in the
 11 * documentation and/or other materials provided with the distribution.
 12 *
 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 24 */
 25
 26#include "config.h"
 27#include "WebAssemblyModuleRecord.h"
 28
 29#if ENABLE(WEBASSEMBLY)
 30
 31#include "Error.h"
 32#include "JSCInlines.h"
 33#include "JSLexicalEnvironment.h"
 34#include "JSModuleEnvironment.h"
 35#include "JSWebAssemblyInstance.h"
 36#include "JSWebAssemblyModule.h"
 37#include "WasmFormat.h"
 38#include "WebAssemblyFunction.h"
 39
 40namespace JSC {
 41
 42const ClassInfo WebAssemblyModuleRecord::s_info = { "WebAssemblyModuleRecord", &Base::s_info, 0, CREATE_METHOD_TABLE(WebAssemblyModuleRecord) };
 43
 44Structure* WebAssemblyModuleRecord::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
 45{
 46 return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
 47}
 48
 49WebAssemblyModuleRecord* WebAssemblyModuleRecord::create(ExecState* exec, VM& vm, Structure* structure, const Identifier& moduleKey, const SourceCode& sourceCode, const VariableEnvironment& declaredVariables, const VariableEnvironment& lexicalVariables)
 50{
 51 WebAssemblyModuleRecord* instance = new (NotNull, allocateCell<WebAssemblyModuleRecord>(vm.heap)) WebAssemblyModuleRecord(vm, structure, moduleKey, sourceCode, declaredVariables, lexicalVariables);
 52 instance->finishCreation(exec, vm);
 53 return instance;
 54}
 55
 56WebAssemblyModuleRecord::WebAssemblyModuleRecord(VM& vm, Structure* structure, const Identifier& moduleKey, const SourceCode& sourceCode, const VariableEnvironment& declaredVariables, const VariableEnvironment& lexicalVariables)
 57 : Base(vm, structure, moduleKey, sourceCode, declaredVariables, lexicalVariables)
 58{
 59}
 60
 61void WebAssemblyModuleRecord::destroy(JSCell* cell)
 62{
 63 WebAssemblyModuleRecord* thisObject = jsCast<WebAssemblyModuleRecord*>(cell);
 64 thisObject->WebAssemblyModuleRecord::~WebAssemblyModuleRecord();
 65}
 66
 67void WebAssemblyModuleRecord::finishCreation(ExecState* exec, VM& vm)
 68{
 69 Base::finishCreation(exec, vm);
 70 ASSERT(inherits(info()));
 71}
 72
 73void WebAssemblyModuleRecord::visitChildren(JSCell* cell, SlotVisitor& visitor)
 74{
 75 WebAssemblyModuleRecord* thisObject = jsCast<WebAssemblyModuleRecord*>(cell);
 76 Base::visitChildren(thisObject, visitor);
 77 visitor.append(&thisObject->m_instance);
 78}
 79
 80void WebAssemblyModuleRecord::link(ExecState* state, JSWebAssemblyInstance* instance)
 81{
 82 VM& vm = state->vm();
 83 auto scope = DECLARE_THROW_SCOPE(vm);
 84 UNUSED_PARAM(scope);
 85 auto* globalObject = state->lexicalGlobalObject();
 86
 87 const Wasm::ModuleInformation& moduleInformation = instance->module()->moduleInformation();
 88 const Wasm::CompiledFunctions& compiledFunctions = instance->module()->compiledFunctions();
 89 SymbolTable* exportSymbolTable = instance->module()->exportSymbolTable();
 90
 91 // FIXME wire up the imports. https://bugs.webkit.org/show_bug.cgi?id=165118
 92
 93 // Let exports be a list of (string, JS value) pairs that is mapped from each external value e in instance.exports as follows:
 94 JSModuleEnvironment* moduleEnvironment = JSModuleEnvironment::create(vm, globalObject, nullptr, exportSymbolTable, JSValue(), this);
 95 unsigned offset = 0;
 96 for (const auto& e : moduleInformation.exports) {
 97 JSValue exportedValue;
 98 PutPropertySlot slot(this);
 99 slot.setNewProperty(this, offset++);
 100 switch (e.kind) {
 101 case Wasm::External::Function: {
 102 // 1. If e is a closure c:
 103 // i. If there is an Exported Function Exotic Object func in funcs whose func.[[Closure]] equals c, then return func.
 104 // ii. (Note: At most one wrapper is created for any closure, so func is unique, even if there are multiple occurrances in the list. Moreover, if the item was an import that is already an Exported Function Exotic Object, then the original function object will be found. For imports that are regular JS functions, a new wrapper will be created.)
 105 // iii. Otherwise:
 106 // a. Let func be an Exported Function Exotic Object created from c.
 107 // b. Append func to funcs.
 108 // c. Return func.
 109 const Wasm::FunctionCompilation* compiledFunction = compiledFunctions.at(e.functionIndex).get();
 110 const B3::Compilation* jsEntryPoint = compiledFunction->jsEntryPoint.get();
 111 const Wasm::Signature* signature = moduleInformation.functions.at(e.functionIndex).signature;
 112 WebAssemblyFunction* function = WebAssemblyFunction::create(vm, globalObject, signature->arguments.size(), e.field.string(), instance, CallableWebAssemblyFunction(jsEntryPoint, signature));
 113 exportedValue = function;
 114 }
 115 break;
 116 case Wasm::External::Table: {
 117 // FIXME https://bugs.webkit.org/show_bug.cgi?id=164135
 118 }
 119 break;
 120 case Wasm::External::Memory: {
 121 // FIXME https://bugs.webkit.org/show_bug.cgi?id=164134
 122 }
 123 break;
 124 case Wasm::External::Global: {
 125 // FIXME https://bugs.webkit.org/show_bug.cgi?id=164133
 126 // In the MVP, only immutable global variables can be exported.
 127 }
 128 break;
 129 }
 130
 131 bool shouldThrowReadOnlyError = false;
 132 bool ignoreReadOnlyErrors = true;
 133 bool putResult = false;
 134 symbolTablePutTouchWatchpointSet(moduleEnvironment, state, e.field, exportedValue, shouldThrowReadOnlyError, ignoreReadOnlyErrors, putResult);
 135 RELEASE_ASSERT(putResult);
 136 }
 137
 138 RELEASE_ASSERT(!m_instance);
 139 m_instance.set(vm, this, instance);
 140 m_moduleEnvironment.set(vm, this, moduleEnvironment);
 141}
 142
 143JSValue WebAssemblyModuleRecord::evaluate(ExecState* state)
 144{
 145 // FIXME this should call the module's `start` function, if any.
 146 // https://github.com/WebAssembly/design/blob/master/Modules.md#module-start-function
 147 // The start function must not take any arguments or return anything
 148 UNUSED_PARAM(state);
 149 return jsUndefined();
 150}
 151
 152} // namespace JSC
 153
 154#endif // ENABLE(WEBASSEMBLY)

Source/JavaScriptCore/wasm/js/WebAssemblyModuleRecord.h

 1/*
 2 * Copyright (C) 2016 Apple Inc. All rights reserved.
 3 *
 4 * Redistribution and use in source and binary forms, with or without
 5 * modification, are permitted provided that the following conditions
 6 * are met:
 7 * 1. Redistributions of source code must retain the above copyright
 8 * notice, this list of conditions and the following disclaimer.
 9 * 2. Redistributions in binary form must reproduce the above copyright
 10 * notice, this list of conditions and the following disclaimer in the
 11 * documentation and/or other materials provided with the distribution.
 12 *
 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 24 */
 25
 26#pragma once
 27
 28#if ENABLE(WEBASSEMBLY)
 29
 30#include "AbstractModuleRecord.h"
 31
 32namespace JSC {
 33
 34class JSWebAssemblyInstance;
 35
 36// Based on the WebAssembly.Instance specification
 37// https://github.com/WebAssembly/design/blob/master/JS.md#webassemblyinstance-constructor
 38class WebAssemblyModuleRecord : public AbstractModuleRecord {
 39 friend class LLIntOffsetsExtractor;
 40public:
 41 typedef AbstractModuleRecord Base;
 42
 43 DECLARE_EXPORT_INFO;
 44
 45 static Structure* createStructure(VM&, JSGlobalObject*, JSValue);
 46 static WebAssemblyModuleRecord* create(ExecState*, VM&, Structure*, const Identifier&, const SourceCode&, const VariableEnvironment&, const VariableEnvironment&);
 47
 48 void link(ExecState*, JSWebAssemblyInstance*);
 49 JS_EXPORT_PRIVATE JSValue evaluate(ExecState*);
 50
 51private:
 52 WebAssemblyModuleRecord(VM&, Structure*, const Identifier&, const SourceCode&, const VariableEnvironment&, const VariableEnvironment&);
 53
 54 void finishCreation(ExecState*, VM&);
 55 static void destroy(JSCell*);
 56
 57 static void visitChildren(JSCell*, SlotVisitor&);
 58
 59 WriteBarrier<JSWebAssemblyInstance> m_instance;
 60};
 61
 62} // namespace JSC
 63
 64#endif // ENABLE(WEBASSEMBLY)

Source/WTF/ChangeLog

 12016-11-28 JF Bastien <jfbastien@apple.com>
 2
 3 WebAssembly JS API: improve Instance
 4
 5 An Instance's `exports` property wasn't populated with exports.
 6
 7 According to the spec [0], `exports` should present itself as a WebAssembly
 8 Module Record. In order to do this we need to split JSModuleRecord into
 9 AbstractModuleRecord (without the `link` and `evaluate` functions), and
 10 JSModuleRecord (which implements link and evaluate). We can then have a separate
 11 WebAssemblyModuleRecord which shares most of the implementation.
 12
 13 `exports` then maps function names to WebAssemblyFunction and
 14 WebAssemblyFunctionCell, which call into the B3-generated WebAssembly code.
 15
 16 A follow-up patch will do imports.
 17
 18 A few things of note:
 19
 20 - Use Identifier instead of String. They get uniqued, we need them for the JSModuleNamespaceObject. This is safe because JSWebAssemblyModule creation is on the main thread.
 21 - JSWebAssemblyInstance needs to refer to the JSWebAssemblyModule used to create it, because the module owns the code, identifiers, etc. The world would be very sad if it got GC'd.
 22 - Instance.exports shouldn't use putWithoutTransition because it affects all Structures, whereas here each instance needs its own exports.
 23 - Expose the compiled functions, and pipe them to the InstanceConstructor. Start moving things around to split JSModuleRecord out into JS and WebAssembly parts.
 24 - LowLevelBinary: support 3-byte integers.
 25 - LowLevelBinary: support proper UTF-8 2003 code points (instead of UTF-16).
 26
 27 [0]: https://github.com/WebAssembly/design/blob/master/JS.md#webassemblyinstance-constructor
 28
 29 WebAssembly JS API: improve Instance
 30 https://bugs.webkit.org/show_bug.cgi?id=164757
 31
 32 Reviewed by NOBODY (OOPS!).
 33
 34 * wtf/Expected.h:
 35 (WTF::ExpectedDetail::destroy): silence a warning
 36
1372016-11-26 Yusuke Suzuki <utatane.tea@gmail.com>
238
339 [WTF] Import std::optional reference implementation as WTF::Optional

Source/WTF/wtf/Expected.h

@@inline NO_RETURN_DUE_TO_CRASH void Throw() { RELEASE_ASSERT_NOT_REACHED(); }
7575static constexpr enum class ValueTagType { } ValueTag { };
7676static constexpr enum class ErrorTagType { } ErrorTag { };
7777
78 template<class T, std::enable_if_t<std::is_trivially_destructible<T>::value>* = nullptr> void destroy(T& t) { }
 78template<class T, std::enable_if_t<std::is_trivially_destructible<T>::value>* = nullptr> void destroy(T&) { }
7979template<class T, std::enable_if_t<!std::is_trivially_destructible<T>::value && (std::is_class<T>::value || std::is_union<T>::value)>* = nullptr> void destroy(T& t) { t.~T(); }
8080
8181template <class T, class E>