Changeset 209123 in webkit


Ignore:
Timestamp:
Nov 29, 2016 11:22:17 PM (7 years ago)
Author:
jfbastien@apple.com
Message:

WebAssembly JS API: improve Instance
https://bugs.webkit.org/show_bug.cgi?id=164757

Reviewed by Keith Miller.

JSTests:

An Instance's exports property wasn't populated with exports.

A follow-up patch will do imports.

A few things of note:

  • LowLevelBinary: support 3-byte integers.
  • LowLevelBinary: support proper UTF-8 2003 code points (instead of UTF-16).
  • wasm/Builder.js:
  • wasm/Builder_WebAssemblyBinary.js: wire up exports, stub other things out some more

(const.emitters.Export):

  • wasm/LowLevelBinary.js:

(export.default.LowLevelBinary.prototype.uint24): add, used for UTF-8
(export.default.LowLevelBinary.prototype.string): support UTF-8
(export.default.LowLevelBinary.prototype.getUint24): add, used for UTF-8
(export.default.LowLevelBinary.prototype.getVaruint1): was missing
(export.default.LowLevelBinary.prototype.getString): support UTF-8
(export.default.LowLevelBinary):

  • wasm/js-api/test_Instance.js: instance.exports.answer() <-- this is where the magic of this entire patch is

(ExportedAnswerI32):

  • wasm/js-api/test_basic_api.js: punt test to later

(const.c.in.constructorProperties.switch):

  • wasm/self-test/test_BuilderWebAssembly.js: UTF-8

(CustomSection):

  • wasm/self-test/test_LowLevelBinary_string.js: UTF-8 now works
  • wasm/self-test/test_LowLevelBinary_uint16.js: was missing one value
  • wasm/self-test/test_LowLevelBinary_uint24.js: Copied from JSTests/wasm/self-test/test_LowLevelBinary_uint8.js.
  • wasm/self-test/test_LowLevelBinary_uint8.js: was missing one value
  • wasm/self-test/test_LowLevelBinary_varuint1.js: Added.
  • wasm/utilities.js: this dump thing was useful

(const._dump):

Source/JavaScriptCore:

An Instance's exports property wasn't populated with exports.

According to the spec [0], exports should present itself as a WebAssembly
Module Record. In order to do this we need to split JSModuleRecord into
AbstractModuleRecord (without the link and evaluate functions), and
JSModuleRecord (which implements link and evaluate). We can then have a separate
WebAssemblyModuleRecord which shares most of the implementation.

exports then maps function names to WebAssemblyFunction and
WebAssemblyFunctionCell, which call into the B3-generated WebAssembly code.

A follow-up patch will do imports.

A few things of note:

  • 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.
  • 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.
  • Instance.exports shouldn't use putWithoutTransition because it affects all Structures, whereas here each instance needs its own exports.
  • Expose the compiled functions, and pipe them to the InstanceConstructor. Start moving things around to split JSModuleRecord out into JS and WebAssembly parts.

[0]: https://github.com/WebAssembly/design/blob/master/JS.md#webassemblyinstance-constructor

  • CMakeLists.txt:
  • JavaScriptCore.xcodeproj/project.pbxproj:
  • runtime/AbstractModuleRecord.cpp: Copied from Source/JavaScriptCore/runtime/JSModuleRecord.cpp, which I split in two

(JSC::AbstractModuleRecord::AbstractModuleRecord):
(JSC::AbstractModuleRecord::destroy):
(JSC::AbstractModuleRecord::finishCreation):
(JSC::AbstractModuleRecord::visitChildren):
(JSC::AbstractModuleRecord::appendRequestedModule):
(JSC::AbstractModuleRecord::addStarExportEntry):
(JSC::AbstractModuleRecord::addImportEntry):
(JSC::AbstractModuleRecord::addExportEntry):
(JSC::identifierToJSValue):
(JSC::AbstractModuleRecord::hostResolveImportedModule):
(JSC::AbstractModuleRecord::ResolveQuery::ResolveQuery):
(JSC::AbstractModuleRecord::ResolveQuery::isEmptyValue):
(JSC::AbstractModuleRecord::ResolveQuery::isDeletedValue):
(JSC::AbstractModuleRecord::ResolveQuery::Hash::hash):
(JSC::AbstractModuleRecord::ResolveQuery::Hash::equal):
(JSC::AbstractModuleRecord::cacheResolution):
(JSC::getExportedNames):
(JSC::AbstractModuleRecord::getModuleNamespace):
(JSC::printableName):
(JSC::AbstractModuleRecord::dump):

  • runtime/AbstractModuleRecord.h: Copied from Source/JavaScriptCore/runtime/JSModuleRecord.h.

(JSC::AbstractModuleRecord::ImportEntry::isNamespace):
(JSC::AbstractModuleRecord::sourceCode):
(JSC::AbstractModuleRecord::moduleKey):
(JSC::AbstractModuleRecord::requestedModules):
(JSC::AbstractModuleRecord::exportEntries):
(JSC::AbstractModuleRecord::importEntries):
(JSC::AbstractModuleRecord::starExportEntries):
(JSC::AbstractModuleRecord::declaredVariables):
(JSC::AbstractModuleRecord::lexicalVariables):
(JSC::AbstractModuleRecord::moduleEnvironment):

  • runtime/JSGlobalObject.cpp:

(JSC::JSGlobalObject::init):
(JSC::JSGlobalObject::visitChildren):

  • runtime/JSGlobalObject.h:

(JSC::JSGlobalObject::webAssemblyModuleRecordStructure):
(JSC::JSGlobalObject::webAssemblyFunctionStructure):

  • runtime/JSModuleEnvironment.cpp:

(JSC::JSModuleEnvironment::create):
(JSC::JSModuleEnvironment::finishCreation):
(JSC::JSModuleEnvironment::getOwnPropertySlot):
(JSC::JSModuleEnvironment::getOwnNonIndexPropertyNames):
(JSC::JSModuleEnvironment::put):
(JSC::JSModuleEnvironment::deleteProperty):

  • runtime/JSModuleEnvironment.h:

(JSC::JSModuleEnvironment::create):
(JSC::JSModuleEnvironment::offsetOfModuleRecord):
(JSC::JSModuleEnvironment::allocationSize):
(JSC::JSModuleEnvironment::moduleRecord):
(JSC::JSModuleEnvironment::moduleRecordSlot):

  • runtime/JSModuleNamespaceObject.cpp:

(JSC::JSModuleNamespaceObject::finishCreation):
(JSC::JSModuleNamespaceObject::getOwnPropertySlot):

  • runtime/JSModuleNamespaceObject.h:

(JSC::JSModuleNamespaceObject::create):
(JSC::JSModuleNamespaceObject::moduleRecord):

  • runtime/JSModuleRecord.cpp:

(JSC::JSModuleRecord::createStructure):
(JSC::JSModuleRecord::create):
(JSC::JSModuleRecord::JSModuleRecord):
(JSC::JSModuleRecord::destroy):
(JSC::JSModuleRecord::finishCreation):
(JSC::JSModuleRecord::visitChildren):
(JSC::JSModuleRecord::instantiateDeclarations):

  • runtime/JSModuleRecord.h:
  • runtime/JSScope.cpp:

(JSC::abstractAccess):
(JSC::JSScope::collectClosureVariablesUnderTDZ):

  • runtime/VM.cpp:

(JSC::VM::VM):

  • runtime/VM.h:
  • wasm/JSWebAssembly.h:
  • wasm/WasmFormat.h: use Identifier instead of String
  • wasm/WasmModuleParser.cpp:

(JSC::Wasm::ModuleParser::parse):
(JSC::Wasm::ModuleParser::parseType):
(JSC::Wasm::ModuleParser::parseImport): fix off-by-one
(JSC::Wasm::ModuleParser::parseFunction):
(JSC::Wasm::ModuleParser::parseExport):

  • wasm/WasmModuleParser.h:

(JSC::Wasm::ModuleParser::ModuleParser):

  • wasm/WasmPlan.cpp:

(JSC::Wasm::Plan::run):

  • wasm/js/JSWebAssemblyInstance.cpp:

(JSC::JSWebAssemblyInstance::create):
(JSC::JSWebAssemblyInstance::finishCreation):
(JSC::JSWebAssemblyInstance::visitChildren):

  • wasm/js/JSWebAssemblyInstance.h:

(JSC::JSWebAssemblyInstance::module):

  • wasm/js/JSWebAssemblyModule.cpp:

(JSC::JSWebAssemblyModule::create):
(JSC::JSWebAssemblyModule::finishCreation):
(JSC::JSWebAssemblyModule::visitChildren):

  • wasm/js/JSWebAssemblyModule.h:

(JSC::JSWebAssemblyModule::moduleInformation):
(JSC::JSWebAssemblyModule::compiledFunctions):
(JSC::JSWebAssemblyModule::exportSymbolTable):

  • wasm/js/WebAssemblyFunction.cpp: Added.

(JSC::callWebAssemblyFunction):
(JSC::WebAssemblyFunction::create):
(JSC::WebAssemblyFunction::createStructure):
(JSC::WebAssemblyFunction::WebAssemblyFunction):
(JSC::WebAssemblyFunction::visitChildren):
(JSC::WebAssemblyFunction::finishCreation):

  • wasm/js/WebAssemblyFunction.h: Copied from Source/JavaScriptCore/wasm/js/JSWebAssemblyModule.h.

(JSC::CallableWebAssemblyFunction::CallableWebAssemblyFunction):
(JSC::WebAssemblyFunction::webAssemblyFunctionCell):

  • wasm/js/WebAssemblyFunctionCell.cpp: Copied from Source/JavaScriptCore/wasm/js/JSWebAssemblyInstance.h.

(JSC::WebAssemblyFunctionCell::create):
(JSC::WebAssemblyFunctionCell::WebAssemblyFunctionCell):
(JSC::WebAssemblyFunctionCell::destroy):
(JSC::WebAssemblyFunctionCell::createStructure):

  • wasm/js/WebAssemblyFunctionCell.h: Copied from Source/JavaScriptCore/wasm/js/JSWebAssemblyInstance.h.

(JSC::WebAssemblyFunctionCell::function):

  • wasm/js/WebAssemblyInstanceConstructor.cpp:

(JSC::constructJSWebAssemblyInstance):

  • wasm/js/WebAssemblyModuleConstructor.cpp:

(JSC::constructJSWebAssemblyModule):

  • wasm/js/WebAssemblyModuleRecord.cpp: Added.

(JSC::WebAssemblyModuleRecord::createStructure):
(JSC::WebAssemblyModuleRecord::create):
(JSC::WebAssemblyModuleRecord::WebAssemblyModuleRecord):
(JSC::WebAssemblyModuleRecord::destroy):
(JSC::WebAssemblyModuleRecord::finishCreation):
(JSC::WebAssemblyModuleRecord::visitChildren):
(JSC::WebAssemblyModuleRecord::link):
(JSC::WebAssemblyModuleRecord::evaluate):

  • wasm/js/WebAssemblyModuleRecord.h: Copied from Source/JavaScriptCore/wasm/js/JSWebAssemblyModule.h.

Source/WTF:

  • wtf/Expected.h:

(WTF::ExpectedDetail::destroy): silence a warning

Location:
trunk
Files:
3 added
40 edited
7 copied

Legend:

Unmodified
Added
Removed
  • trunk/JSTests/ChangeLog

    r209121 r209123  
     12016-11-29  JF Bastien  <jfbastien@apple.com>
     2
     3        WebAssembly JS API: improve Instance
     4        https://bugs.webkit.org/show_bug.cgi?id=164757
     5
     6        Reviewed by Keith Miller.
     7
     8        An Instance's `exports` property wasn't populated with exports.
     9
     10        A follow-up patch will do imports.
     11
     12        A few things of note:
     13
     14         - LowLevelBinary: support 3-byte integers.
     15         - LowLevelBinary: support proper UTF-8 2003 code points (instead of UTF-16).
     16
     17        * wasm/Builder.js:
     18        * wasm/Builder_WebAssemblyBinary.js: wire up exports, stub other things out some more
     19        (const.emitters.Export):
     20        * wasm/LowLevelBinary.js:
     21        (export.default.LowLevelBinary.prototype.uint24): add, used for UTF-8
     22        (export.default.LowLevelBinary.prototype.string): support UTF-8
     23        (export.default.LowLevelBinary.prototype.getUint24): add, used for UTF-8
     24        (export.default.LowLevelBinary.prototype.getVaruint1): was missing
     25        (export.default.LowLevelBinary.prototype.getString): support UTF-8
     26        (export.default.LowLevelBinary):
     27        * wasm/js-api/test_Instance.js: instance.exports.answer() // <-- this is where the magic of this entire patch is
     28        (ExportedAnswerI32):
     29        * wasm/js-api/test_basic_api.js: punt test to later
     30        (const.c.in.constructorProperties.switch):
     31        * wasm/self-test/test_BuilderWebAssembly.js: UTF-8
     32        (CustomSection):
     33        * wasm/self-test/test_LowLevelBinary_string.js: UTF-8 now works
     34        * wasm/self-test/test_LowLevelBinary_uint16.js: was missing one value
     35        * wasm/self-test/test_LowLevelBinary_uint24.js: Copied from JSTests/wasm/self-test/test_LowLevelBinary_uint8.js.
     36        * wasm/self-test/test_LowLevelBinary_uint8.js: was missing one value
     37        * wasm/self-test/test_LowLevelBinary_varuint1.js: Added.
     38        * wasm/utilities.js: this `dump` thing was useful
     39        (const._dump):
     40
    1412016-11-29  Saam Barati  <sbarati@apple.com>
    242
  • trunk/JSTests/wasm/Builder.js

    r208634 r209123  
    217217        case "default_target": throw new Error(`Unimplemented: "${expect.name}" on "${op}"`);
    218218        case "relative_depth": throw new Error(`Unimplemented: "${expect.name}" on "${op}"`);
    219         case "sig": throw new Error(`Unimplemented: "${expect.name}" on "${op}"`);
     219        case "sig":
     220            // FIXME this should be isValidBlockType https://bugs.webkit.org/show_bug.cgi?id=164724
     221            assert.truthy(WASM.isValidValueType(imms[idx]), `Invalid block type on ${op}: "${imms[idx]}"`);
     222            break;
    220223        case "target_count": throw new Error(`Unimplemented: "${expect.name}" on "${op}"`);
    221224        case "target_table": throw new Error(`Unimplemented: "${expect.name}" on "${op}"`);
     
    356359                };
    357360                break;
     361
    358362            case "Import":
    359363                this[section] = function() {
     
    370374                break;
    371375
     376            case "Function":
     377                this[section] = function() {
     378                    const s = this._addSection(section);
     379                    const exportBuilder = {
     380                        End: () => this
     381                        // FIXME: add ability to add this with whatever.
     382                    };
     383                    return exportBuilder;
     384                };
     385                break;
     386
     387            case "Table":
     388                // FIXME Implement table https://bugs.webkit.org/show_bug.cgi?id=164135
     389                this[section] = () => { throw new Error(`Unimplemented: section type "${section}"`); };
     390                break;
     391
     392            case "Memory":
     393                this[section] = function() {
     394                    const s = this._addSection(section);
     395                    const exportBuilder = {
     396                        End: () => this,
     397                        InitialMaxPages: (initial, max) => {
     398                            s.data.push({ initial, max });
     399                            return exportBuilder;
     400                        }
     401                    };
     402                    return exportBuilder;
     403                };
     404                break;
     405
     406            case "Global":
     407                // FIXME implement global https://bugs.webkit.org/show_bug.cgi?id=164133
     408                this[section] = () => { throw new Error(`Unimplemented: section type "${section}"`); };
     409                break;
     410
    372411            case "Export":
    373412                this[section] = function() {
     
    384423                break;
    385424
    386             case "Memory":
    387                 this[section] = function() {
    388                     const s = this._addSection(section);
    389                     const exportBuilder = {
    390                         End: () => this,
    391                         InitialMaxPages: (initial, max) => {
    392                             s.data.push({ initial, max });
    393                             return exportBuilder;
    394                         }
    395                     };
    396                     return exportBuilder;
    397                 }
    398                 break;
    399 
    400             case "Function":
    401                 this[section] = function() {
    402                     const s = this._addSection(section);
    403                     const exportBuilder = {
    404                         End: () => this
    405                         // FIXME: add ability to add this with whatever.
    406                     }
    407                     return exportBuilder;
    408                 }
     425            case "Start":
     426                // FIXME implement start https://bugs.webkit.org/show_bug.cgi?id=161709
     427                this[section] = () => { throw new Error(`Unimplemented: section type "${section}"`); };
     428                break;
     429
     430            case "Element":
     431                // FIXME implement element https://bugs.webkit.org/show_bug.cgi?id=161709
     432                this[section] = () => { throw new Error(`Unimplemented: section type "${section}"`); };
    409433                break;
    410434
     
    454478                break;
    455479
     480            case "Data":
     481                // FIXME implement data https://bugs.webkit.org/show_bug.cgi?id=161709
     482                this[section] = () => { throw new Error(`Unimplemented: section type "${section}"`); };
     483                break;
     484
    456485            default:
    457                 this[section] = () => { throw new Error(`Unimplemented: section type "${section}"`); };
     486                this[section] = () => { throw new Error(`Unknown section type "${section}"`); };
    458487                break;
    459488            }
    460489        }
     490
    461491        this.Unknown = function(name) {
    462492            const s = this._addSection(name);
  • trunk/JSTests/wasm/Builder_WebAssemblyBinary.js

    r208627 r209123  
    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`); },
  • trunk/JSTests/wasm/LowLevelBinary.js

    r208634 r209123  
    2424 */
    2525
     26import * as assert from 'assert.js';
    2627import * as WASM from 'WASM.js';
    2728
     
    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)
     
    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    }
     
    170195        _getterRangeCheck(this, at, 2);
    171196        return this._buf[at] | (this._buf[at + 1] << 8);
     197    }
     198    getUint24(at) {
     199        _getterRangeCheck(this, at, 3);
     200        return this._buf[at] | (this._buf[at + 1] << 8) | (this._buf[at + 2] << 16);
    172201    }
    173202    getUint32(at) {
     
    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);
     
    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    }
  • trunk/JSTests/wasm/README.md

    r207363 r209123  
    11# `wasmjs`: JavaScript tooling for WebAssembly
    22
    3 `wasmjs` is a self-contained collection of JavaScript tools which can manipulate
    4 WebAssembly. At its core is `wasm.json`, a JSON decription of the WebAssembly
    5 format and other interesting facts about WebAssembly as used by the Webkit
    6 project (such as the names of associated JavaScriptCore opcodes).
     3`wasmjs` is a self-contained collection of JavaScript tools which can create and
     4manipulate WebAssembly representations and binaries. At its core is `wasm.json`,
     5a JSON decription of the WebAssembly format and other interesting facts about
     6WebAssembly as used by the Webkit project (such as the names of associated
     7JavaScriptCore B3 opcodes).
    78
    89`wasmjs` requires modern JavaScript features such as ES6 modules, which is
     
    1314
    1415The current core API of `wasmjs` is the `Builder` API from `Builder.js`. It is
    15 used to build WebAssembly modules.
     16used to build WebAssembly modules, and assemble them to valid `.wasm` binaries
     17(held in an `ArrayBuffer`). The `Builder` is a small DSL which looks similar to
     18the WebAssembly [binary format][]. Each section is declared through a property
     19on the `Builder` object, and each declaration returns a proxy object which has
     20properties specific to that section. Proxies are "popped" back by invoking their
     21`.End()` property.
     22
     23The `Code` section has properties for each [WebAssembly opcode][]. Opcode which
     24create a scope can be nested using a lambda.
     25
     26  [binary format]: https://github.com/WebAssembly/design/blob/master/BinaryEncoding.md#high-level-structure
     27  [WebAssembly opcode]: https://github.com/WebAssembly/design/blob/master/Semantics.md
    1628
    1729A simple example:
     
    2234const builder = new Builder();
    2335
    24 // Construct the equivalent of: (module (func (nop) (nop)))
     36// Construct the equivalent of: (module (func "answer" (i32.const 42) (return)))
    2537builder
     38    .setChecked(false) // FIXME remove once checking is better implemented.
     39    // Declare a Type section, which the builder will auto-fill as functions are defined.
     40    .Type().End()
     41    // Declare a Function section, which the builder will auto-fill as functions are defined.
     42    .Function().End()
     43    .Export()
     44        // Export the "answer" function (defined below) to JavaScript.
     45        .Function("answer")
     46    .End()
    2647    .Code()
    27         .Function()
    28             .Nop()
    29             .Nop()
    30         .End()
    31     .End();
     48        // The "answer" function takes an i32 parameters, and returns an i32.
     49        .Function("answer", { params: ["i32"], ret: "i32" })
     50            // Create a block returning an i32, whose body is the enclosed lambda.
     51            .Block("i32", b => b
     52                .GetLocal(0) // Parameters are in the same index space as locals.
     53                .I32Const(0) // Generate an i32 constant.
     54                .I32Eq()     // A comparison, using the two values currently on the stack.
     55                .If("i32")   // Consume the comparison result, returning an i32.
     56                    .I32Const(42)
     57                .Else()
     58                    .I32Const(1)
     59                .End()
     60            )
     61            .Return() // Return the top of the stack: the value returned by the block.
     62        .End() // End the current function.
     63    .End(); // End the Code section.
    3264
    3365// Create an ArrayBuffer which is a valid WebAssembly `.wasm` file.
    34 const binary = builder.WebAssembly();
     66const bin = builder.WebAssembly().get();
     67
     68// Use the standard WebAssembly JavaScript API to compile the module, and instantiate it.
     69const module = new WebAssembly.Module(bin);
     70const instance = new WebAssembly.Instance(module);
     71
     72// Invoke the compiled WebAssembly function.
     73const result0 = instance.exports.answer(0);
     74if (result0 !== 42)
     75    throw new Error(`Expected 42, got ${result0}.`);
     76
     77const result1 = instance.exports.answer(1);
     78if (result1 !== 1)
     79    throw new Error(`Expected 1, got ${result1}.`);
    3580```
    36 
    37 Code such as the above can then be used with JavaScript's `WebAssembly` global
    38 object.
    3981
    4082
    4183# Testing
    4284
    43 Tests can be executed using:
     85* `self-test` tests `wasmjs` itself.
     86* `js-api` tests the [WebAssembly JavaScript API](https://github.com/WebAssembly/design/blob/master/JS.md).
     87* `function-tests` tests the WebAssembly compiler's implementation.
     88
     89All tests can be executed using:
    4490
    4591```bash
     
    5298./Tools/Scripts/run-javascriptcore-tests --release --filter wasm -arch x86_64
    5399```
    54 
    55 The `self-test` folder contains tests for `wasmjs` itself. Future additions will
    56 also test the JavaScript engine's WebAssembly implementation (both JavaScript
    57 API and usage of that API to compile and execute WebAssembly modules).
  • trunk/JSTests/wasm/js-api/test_Instance.js

    r207929 r209123  
    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})();
  • trunk/JSTests/wasm/js-api/test_basic_api.js

    r208401 r209123  
    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":
  • trunk/JSTests/wasm/self-test/test_BuilderWebAssembly.js

    r208401 r209123  
    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})();
  • trunk/JSTests/wasm/self-test/test_LowLevelBinary_string.js

    r207363 r209123  
    88    "焼きたて!! ジャぱん",
    99    "(╯°□°)╯︵ ┻━┻",
    10     "�",
    11     // Should we use code points instead of UTF-16?
    12     //        The following doesn't work: "👨‍❤️‍💋‍👨",
     10    "$¢€𐍈�",
     11    "👨‍❤️‍💋‍👨",
    1312];
    1413
  • trunk/JSTests/wasm/self-test/test_LowLevelBinary_uint16.js

    r207363 r209123  
    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) {
  • trunk/JSTests/wasm/self-test/test_LowLevelBinary_uint24.js

    r209122 r209123  
    22
    33let values = [];
    4 for (let i = 0; i !== 0xFF; ++i) values.push(i);
     4for (let i = 0; i <= 0xFFFF; ++i) values.push(i);
     5for (let i = 0xFFFFFF - 0xFFFF; i <= 0xFFFFFF; ++i) values.push(i);
    56
    67for (const i of values) {
    78    let b = new LowLevelBinary();
    8     b.uint8(i);
    9     const v = b.getUint8(0);
     9    b.uint24(i);
     10    const v = b.getUint24(0);
    1011    if (v !== i)
    1112        throw new Error(`Wrote "${i}" and read back "${v}"`);
  • trunk/JSTests/wasm/self-test/test_LowLevelBinary_uint8.js

    r207363 r209123  
    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) {
  • trunk/JSTests/wasm/test.sh

    r207363 r209123  
    99    xargs -n1 -t -I{} "$JSSHELL" -m {}
    1010
    11 "$JSSHELL" -m generate-wasmops-header.js > /dev/null
    12 
    1311echo "All tests passed"
  • trunk/JSTests/wasm/utilities.js

    r207572 r209123  
    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};
  • trunk/Source/JavaScriptCore/CMakeLists.txt

    r208953 r209123  
    645645    profiler/ProfilerUID.cpp
    646646
     647    runtime/AbstractModuleRecord.cpp
    647648    runtime/ArgList.cpp
    648649    runtime/ArrayBuffer.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
     
    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
  • trunk/Source/JavaScriptCore/ChangeLog

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

    r208953 r209123  
    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, ); }; };
     
    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>"; };
     
    60556071                        isa = PBXGroup;
    60566072                        children = (
     6073                                AD4937C11DDBE60A0077C807 /* AbstractModuleRecord.cpp */,
     6074                                AD4937C21DDBE60A0077C807 /* AbstractModuleRecord.h */,
    60576075                                BCF605110E203EF800B9A64D /* ArgList.cpp */,
    60586076                                BCF605120E203EF800B9A64D /* ArgList.h */,
     
    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 */,
     
    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 */,
     
    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 */,
     
    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 */,
     
    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 */,
     
    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 */,
     
    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 */,
     
    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 */,
     
    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 */,
  • trunk/Source/JavaScriptCore/runtime/AbstractModuleRecord.cpp

    r209122 r209123  
    2525
    2626#include "config.h"
    27 #include "JSModuleRecord.h"
     27#include "AbstractModuleRecord.h"
    2828
    2929#include "Error.h"
     
    3737namespace JSC {
    3838
    39 const ClassInfo JSModuleRecord::s_info = { "ModuleRecord", &Base::s_info, 0, CREATE_METHOD_TABLE(JSModuleRecord) };
    40 
    41 void JSModuleRecord::destroy(JSCell* cell)
    42 {
    43     JSModuleRecord* thisObject = jsCast<JSModuleRecord*>(cell);
    44     thisObject->JSModuleRecord::~JSModuleRecord();
    45 }
    46 
    47 void JSModuleRecord::finishCreation(ExecState* exec, VM& vm)
     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)
    4857{
    4958    Base::finishCreation(vm);
     
    5968}
    6069
    61 void JSModuleRecord::visitChildren(JSCell* cell, SlotVisitor& visitor)
    62 {
    63     JSModuleRecord* thisObject = jsCast<JSModuleRecord*>(cell);
     70void AbstractModuleRecord::visitChildren(JSCell* cell, SlotVisitor& visitor)
     71{
     72    AbstractModuleRecord* thisObject = jsCast<AbstractModuleRecord*>(cell);
    6473    Base::visitChildren(thisObject, visitor);
    6574    visitor.append(&thisObject->m_moduleEnvironment);
    6675    visitor.append(&thisObject->m_moduleNamespaceObject);
    67     visitor.append(&thisObject->m_moduleProgramExecutable);
    6876    visitor.append(&thisObject->m_dependenciesMap);
    6977}
    7078
    71 void JSModuleRecord::appendRequestedModule(const Identifier& moduleName)
     79void AbstractModuleRecord::appendRequestedModule(const Identifier& moduleName)
    7280{
    7381    m_requestedModules.add(moduleName.impl());
    7482}
    7583
    76 void JSModuleRecord::addStarExportEntry(const Identifier& moduleName)
     84void AbstractModuleRecord::addStarExportEntry(const Identifier& moduleName)
    7785{
    7886    m_starExportEntries.add(moduleName.impl());
    7987}
    8088
    81 void JSModuleRecord::addImportEntry(const ImportEntry& entry)
     89void AbstractModuleRecord::addImportEntry(const ImportEntry& entry)
    8290{
    8391    bool isNewEntry = m_importEntries.add(entry.localName.impl(), entry).isNewEntry;
     
    8593}
    8694
    87 void JSModuleRecord::addExportEntry(const ExportEntry& entry)
     95void AbstractModuleRecord::addExportEntry(const ExportEntry& entry)
    8896{
    8997    bool isNewEntry = m_exportEntries.add(entry.exportName.impl(), entry).isNewEntry;
     
    9199}
    92100
    93 auto JSModuleRecord::tryGetImportEntry(UniquedStringImpl* localName) -> std::optional<ImportEntry>
     101auto AbstractModuleRecord::tryGetImportEntry(UniquedStringImpl* localName) -> std::optional<ImportEntry>
    94102{
    95103    const auto iterator = m_importEntries.find(localName);
     
    99107}
    100108
    101 auto JSModuleRecord::tryGetExportEntry(UniquedStringImpl* exportName) -> std::optional<ExportEntry>
     109auto AbstractModuleRecord::tryGetExportEntry(UniquedStringImpl* exportName) -> std::optional<ExportEntry>
    102110{
    103111    const auto iterator = m_exportEntries.find(exportName);
     
    107115}
    108116
    109 auto JSModuleRecord::ExportEntry::createLocal(const Identifier& exportName, const Identifier& localName) -> ExportEntry
     117auto AbstractModuleRecord::ExportEntry::createLocal(const Identifier& exportName, const Identifier& localName) -> ExportEntry
    110118{
    111119    return ExportEntry { Type::Local, exportName, Identifier(), Identifier(), localName };
    112120}
    113121
    114 auto JSModuleRecord::ExportEntry::createIndirect(const Identifier& exportName, const Identifier& importName, const Identifier& moduleName) -> ExportEntry
     122auto AbstractModuleRecord::ExportEntry::createIndirect(const Identifier& exportName, const Identifier& importName, const Identifier& moduleName) -> ExportEntry
    115123{
    116124    return ExportEntry { Type::Indirect, exportName, moduleName, importName, Identifier() };
    117125}
    118126
    119 auto JSModuleRecord::Resolution::notFound() -> Resolution
     127auto AbstractModuleRecord::Resolution::notFound() -> Resolution
    120128{
    121129    return Resolution { Type::NotFound, nullptr, Identifier() };
    122130}
    123131
    124 auto JSModuleRecord::Resolution::error() -> Resolution
     132auto AbstractModuleRecord::Resolution::error() -> Resolution
    125133{
    126134    return Resolution { Type::Error, nullptr, Identifier() };
    127135}
    128136
    129 auto JSModuleRecord::Resolution::ambiguous() -> Resolution
     137auto AbstractModuleRecord::Resolution::ambiguous() -> Resolution
    130138{
    131139    return Resolution { Type::Ambiguous, nullptr, Identifier() };
     
    139147}
    140148
    141 JSModuleRecord* JSModuleRecord::hostResolveImportedModule(ExecState* exec, const Identifier& moduleName)
     149AbstractModuleRecord* AbstractModuleRecord::hostResolveImportedModule(ExecState* exec, const Identifier& moduleName)
    142150{
    143151    JSValue moduleNameValue = identifierToJSValue(exec, moduleName);
    144152    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
     153    return jsCast<AbstractModuleRecord*>(pair.get(exec, Identifier::fromString(exec, "value")));
     154}
     155
     156auto AbstractModuleRecord::resolveImport(ExecState* exec, const Identifier& localName) -> Resolution
    149157{
    150158    std::optional<ImportEntry> optionalImportEntry = tryGetImportEntry(localName.impl());
     
    156164        return Resolution::notFound();
    157165
    158     JSModuleRecord* importedModule = hostResolveImportedModule(exec, importEntry.moduleRequest);
     166    AbstractModuleRecord* importedModule = hostResolveImportedModule(exec, importEntry.moduleRequest);
    159167    return importedModule->resolveExport(exec, importEntry.importName);
    160168}
    161169
    162 struct JSModuleRecord::ResolveQuery {
     170struct AbstractModuleRecord::ResolveQuery {
    163171    struct Hash {
    164172        static unsigned hash(const ResolveQuery&);
     
    167175    };
    168176
    169     ResolveQuery(JSModuleRecord* moduleRecord, UniquedStringImpl* exportName)
     177    ResolveQuery(AbstractModuleRecord* moduleRecord, UniquedStringImpl* exportName)
    170178        : moduleRecord(moduleRecord)
    171179        , exportName(exportName)
     
    173181    }
    174182
    175     ResolveQuery(JSModuleRecord* moduleRecord, const Identifier& exportName)
     183    ResolveQuery(AbstractModuleRecord* moduleRecord, const Identifier& exportName)
    176184        : ResolveQuery(moduleRecord, exportName.impl())
    177185    {
     
    202210    // The module record is not marked from the GC. But these records are reachable from the JSGlobalObject.
    203211    // So we don't care the reachability to this record.
    204     JSModuleRecord* moduleRecord;
     212    AbstractModuleRecord* moduleRecord;
    205213    RefPtr<UniquedStringImpl> exportName;
    206214};
    207215
    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)
     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)
    214222{
    215223    return lhs.moduleRecord == rhs.moduleRecord && lhs.exportName == rhs.exportName;
    216224}
    217225
    218 auto JSModuleRecord::tryGetCachedResolution(UniquedStringImpl* exportName) -> std::optional<Resolution>
     226auto AbstractModuleRecord::tryGetCachedResolution(UniquedStringImpl* exportName) -> std::optional<Resolution>
    219227{
    220228    const auto iterator = m_resolutionCache.find(exportName);
     
    224232}
    225233
    226 void JSModuleRecord::cacheResolution(UniquedStringImpl* exportName, const Resolution& resolution)
     234void AbstractModuleRecord::cacheResolution(UniquedStringImpl* exportName, const Resolution& resolution)
    227235{
    228236    m_resolutionCache.add(exportName, resolution);
    229237}
    230238
    231 auto JSModuleRecord::resolveExportImpl(ExecState* exec, const ResolveQuery& root) -> Resolution
     239auto AbstractModuleRecord::resolveExportImpl(ExecState* exec, const ResolveQuery& root) -> Resolution
    232240{
    233241    // http://www.ecma-international.org/ecma-262/6.0/#sec-resolveexport
     
    271279    // If we only hold the global resolution result during the resolveExport operation, [here],
    272280    // 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
     281    // "Resolve" (in module (2) and (5)). However, this should become "Error" because (6) will
    274282    // propagate "Error" state to the (4), (4) will become "Error" and then, (1) will become
    275283    // "Error". We should aggregate the results at the star exports point ((4) and (1)).
     
    293301    // Here, we attempt to cache the resolution by constructing the map in module records.
    294302    // That means  Module -> ExportName -> Maybe<Resolution>.
    295     // Technically, all the JSModuleRecords have the Map<ExportName, Resolution> for caching.
     303    // Technically, all the AbstractModuleRecords have the Map<ExportName, Resolution> for caching.
    296304    //
    297305    // The important observations are that,
     
    475483    Vector<Task, 8> pendingTasks;
    476484    ResolveSet resolveSet;
    477     HashSet<JSModuleRecord*> starSet;
     485    HashSet<AbstractModuleRecord*> starSet;
    478486
    479487    Vector<Resolution, 8> frames;
     
    507515        for (auto iterator = query.moduleRecord->starExportEntries().rbegin(), end = query.moduleRecord->starExportEntries().rend(); iterator != end; ++iterator) {
    508516            const RefPtr<UniquedStringImpl>& starModuleName = *iterator;
    509             JSModuleRecord* importedModuleRecord = query.moduleRecord->hostResolveImportedModule(exec, Identifier::fromUid(exec, starModuleName.get()));
     517            AbstractModuleRecord* importedModuleRecord = query.moduleRecord->hostResolveImportedModule(exec, Identifier::fromUid(exec, starModuleName.get()));
    510518            pendingTasks.append(Task { ResolveQuery(importedModuleRecord, query.exportName.get()), Type::Query });
    511519        }
     
    548556        switch (task.type) {
    549557        case Type::Query: {
    550             JSModuleRecord* moduleRecord = query.moduleRecord;
     558            AbstractModuleRecord* moduleRecord = query.moduleRecord;
    551559
    552560            if (!resolveSet.add(task.query).isNewEntry)
     
    588596
    589597            case ExportEntry::Type::Indirect: {
    590                 JSModuleRecord* importedModuleRecord = moduleRecord->hostResolveImportedModule(exec, exportEntry.moduleName);
     598                AbstractModuleRecord* importedModuleRecord = moduleRecord->hostResolveImportedModule(exec, exportEntry.moduleName);
    591599
    592600                // When the imported module does not produce any resolved binding, we need to look into the stars in the *current*
     
    646654}
    647655
    648 auto JSModuleRecord::resolveExport(ExecState* exec, const Identifier& exportName) -> Resolution
     656auto AbstractModuleRecord::resolveExport(ExecState* exec, const Identifier& exportName) -> Resolution
    649657{
    650658    // Look up the cached resolution first before entering the resolving loop, since the loop setup takes some cost.
     
    654662}
    655663
    656 static void getExportedNames(ExecState* exec, JSModuleRecord* root, IdentifierSet& exportedNames)
    657 {
    658     HashSet<JSModuleRecord*> exportStarSet;
    659     Vector<JSModuleRecord*, 8> pendingModules;
     664static void getExportedNames(ExecState* exec, AbstractModuleRecord* root, IdentifierSet& exportedNames)
     665{
     666    HashSet<AbstractModuleRecord*> exportStarSet;
     667    Vector<AbstractModuleRecord*, 8> pendingModules;
    660668
    661669    pendingModules.append(root);
    662670
    663671    while (!pendingModules.isEmpty()) {
    664         JSModuleRecord* moduleRecord = pendingModules.takeLast();
     672        AbstractModuleRecord* moduleRecord = pendingModules.takeLast();
    665673        if (exportStarSet.contains(moduleRecord))
    666674            continue;
     
    668676
    669677        for (const auto& pair : moduleRecord->exportEntries()) {
    670             const JSModuleRecord::ExportEntry& exportEntry = pair.value;
     678            const AbstractModuleRecord::ExportEntry& exportEntry = pair.value;
    671679            if (moduleRecord == root || exec->propertyNames().defaultKeyword != exportEntry.exportName)
    672680                exportedNames.add(exportEntry.exportName.impl());
     
    674682
    675683        for (const auto& starModuleName : moduleRecord->starExportEntries()) {
    676             JSModuleRecord* requestedModuleRecord = moduleRecord->hostResolveImportedModule(exec, Identifier::fromUid(exec, starModuleName.get()));
     684            AbstractModuleRecord* requestedModuleRecord = moduleRecord->hostResolveImportedModule(exec, Identifier::fromUid(exec, starModuleName.get()));
    677685            pendingModules.append(requestedModuleRecord);
    678686        }
     
    680688}
    681689
    682 JSModuleNamespaceObject* JSModuleRecord::getModuleNamespace(ExecState* exec)
     690JSModuleNamespaceObject* AbstractModuleRecord::getModuleNamespace(ExecState* exec)
    683691{
    684692    VM& vm = exec->vm();
     
    695703    IdentifierSet unambiguousNames;
    696704    for (auto& name : exportedNames) {
    697         const JSModuleRecord::Resolution resolution = resolveExport(exec, Identifier::fromUid(exec, name.get()));
     705        const AbstractModuleRecord::Resolution resolution = resolveExport(exec, Identifier::fromUid(exec, name.get()));
    698706        switch (resolution.type) {
    699707        case Resolution::Type::NotFound:
     
    718726}
    719727
    720 void JSModuleRecord::link(ExecState* exec)
    721 {
    722     VM& vm = exec->vm();
    723     auto scope = DECLARE_THROW_SCOPE(vm);
    724 
    725     ModuleProgramExecutable* executable = ModuleProgramExecutable::create(exec, sourceCode());
    726     if (!executable) {
    727         throwSyntaxError(exec, scope);
    728         return;
    729     }
    730     m_moduleProgramExecutable.set(vm, this, executable);
    731     instantiateDeclarations(exec, executable);
    732 }
    733 
    734 void JSModuleRecord::instantiateDeclarations(ExecState* exec, ModuleProgramExecutable* moduleProgramExecutable)
    735 {
    736     VM& vm = exec->vm();
    737     auto scope = DECLARE_THROW_SCOPE(vm);
    738 
    739     // http://www.ecma-international.org/ecma-262/6.0/#sec-moduledeclarationinstantiation
    740 
    741     SymbolTable* symbolTable = moduleProgramExecutable->moduleEnvironmentSymbolTable();
    742     JSModuleEnvironment* moduleEnvironment = JSModuleEnvironment::create(vm, exec->lexicalGlobalObject(), exec->lexicalGlobalObject(), symbolTable, jsTDZValue(), this);
    743 
    744     // http://www.ecma-international.org/ecma-262/6.0/#sec-moduledeclarationinstantiation
    745     // section 15.2.1.16.4 step 9.
    746     // Ensure all the indirect exports are correctly resolved to unique bindings.
    747     // Even if we avoided duplicate exports in the parser, still ambiguous exports occur due to the star export (`export * from "mod"`).
    748     // When we see this type of ambiguity for the indirect exports here, throw a syntax error.
    749     for (const auto& pair : m_exportEntries) {
    750         const ExportEntry& exportEntry = pair.value;
    751         if (exportEntry.type == JSModuleRecord::ExportEntry::Type::Indirect) {
    752             Resolution resolution = resolveExport(exec, exportEntry.exportName);
    753             switch (resolution.type) {
    754             case Resolution::Type::NotFound:
    755                 throwSyntaxError(exec, scope, makeString("Indirectly exported binding name '", String(exportEntry.exportName.impl()), "' is not found."));
    756                 return;
    757 
    758             case Resolution::Type::Ambiguous:
    759                 throwSyntaxError(exec, scope, makeString("Indirectly exported binding name '", String(exportEntry.exportName.impl()), "' cannot be resolved due to ambiguous multiple bindings."));
    760                 return;
    761 
    762             case Resolution::Type::Error:
    763                 throwSyntaxError(exec, scope, makeString("Indirectly exported binding name 'default' cannot be resolved by star export entries."));
    764                 return;
    765 
    766             case Resolution::Type::Resolved:
    767                 break;
    768             }
    769         }
    770     }
    771 
    772     // http://www.ecma-international.org/ecma-262/6.0/#sec-moduledeclarationinstantiation
    773     // section 15.2.1.16.4 step 12.
    774     // Instantiate namespace objects and initialize the bindings with them if required.
    775     // And ensure that all the imports correctly resolved to unique bindings.
    776     for (const auto& pair : m_importEntries) {
    777         const ImportEntry& importEntry = pair.value;
    778         JSModuleRecord* importedModule = hostResolveImportedModule(exec, importEntry.moduleRequest);
    779         if (importEntry.isNamespace(vm)) {
    780             JSModuleNamespaceObject* namespaceObject = importedModule->getModuleNamespace(exec);
    781             RETURN_IF_EXCEPTION(scope, void());
    782             bool putResult = false;
    783             symbolTablePutTouchWatchpointSet(moduleEnvironment, exec, importEntry.localName, namespaceObject, /* shouldThrowReadOnlyError */ false, /* ignoreReadOnlyErrors */ true, putResult);
    784         } else {
    785             Resolution resolution = importedModule->resolveExport(exec, importEntry.importName);
    786             switch (resolution.type) {
    787             case Resolution::Type::NotFound:
    788                 throwSyntaxError(exec, scope, makeString("Importing binding name '", String(importEntry.importName.impl()), "' is not found."));
    789                 return;
    790 
    791             case Resolution::Type::Ambiguous:
    792                 throwSyntaxError(exec, scope, makeString("Importing binding name '", String(importEntry.importName.impl()), "' cannot be resolved due to ambiguous multiple bindings."));
    793                 return;
    794 
    795             case Resolution::Type::Error:
    796                 throwSyntaxError(exec, scope, makeString("Importing binding name 'default' cannot be resolved by star export entries."));
    797                 return;
    798 
    799             case Resolution::Type::Resolved:
    800                 break;
    801             }
    802         }
    803     }
    804 
    805     // http://www.ecma-international.org/ecma-262/6.0/#sec-moduledeclarationinstantiation
    806     // section 15.2.1.16.4 step 14.
    807     // Module environment contains the heap allocated "var", "function", "let", "const", and "class".
    808     // When creating the environment, we initialized all the slots with empty, it's ok for lexical values.
    809     // 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) {
    811         SymbolTableEntry entry = symbolTable->get(variable.key.get());
    812         VarOffset offset = entry.varOffset();
    813         if (!offset.isStack()) {
    814             bool putResult = false;
    815             symbolTablePutTouchWatchpointSet(moduleEnvironment, exec, Identifier::fromUid(exec, variable.key.get()), jsUndefined(), /* shouldThrowReadOnlyError */ false, /* ignoreReadOnlyErrors */ true, putResult);
    816         }
    817     }
    818 
    819     // http://www.ecma-international.org/ecma-262/6.0/#sec-moduledeclarationinstantiation
    820     // section 15.2.1.16.4 step 16-a-iv.
    821     // Initialize heap allocated function declarations.
    822     // They can be called before the body of the module is executed under circular dependencies.
    823     UnlinkedModuleProgramCodeBlock* unlinkedCodeBlock = moduleProgramExecutable->unlinkedModuleProgramCodeBlock();
    824     for (size_t i = 0, numberOfFunctions = unlinkedCodeBlock->numberOfFunctionDecls(); i < numberOfFunctions; ++i) {
    825         UnlinkedFunctionExecutable* unlinkedFunctionExecutable = unlinkedCodeBlock->functionDecl(i);
    826         SymbolTableEntry entry = symbolTable->get(unlinkedFunctionExecutable->name().impl());
    827         VarOffset offset = entry.varOffset();
    828         if (!offset.isStack()) {
    829             ASSERT(!unlinkedFunctionExecutable->name().isEmpty());
    830             if (vm.typeProfiler() || vm.controlFlowProfiler()) {
    831                 vm.functionHasExecutedCache()->insertUnexecutedRange(moduleProgramExecutable->sourceID(),
    832                     unlinkedFunctionExecutable->typeProfilingStartOffset(),
    833                     unlinkedFunctionExecutable->typeProfilingEndOffset());
    834             }
    835             JSFunction* function = JSFunction::create(vm, unlinkedFunctionExecutable->link(vm, moduleProgramExecutable->source()), moduleEnvironment);
    836             bool putResult = false;
    837             symbolTablePutTouchWatchpointSet(moduleEnvironment, exec, unlinkedFunctionExecutable->name(), function, /* shouldThrowReadOnlyError */ false, /* ignoreReadOnlyErrors */ true, putResult);
    838         }
    839     }
    840 
    841     m_moduleEnvironment.set(vm, this, moduleEnvironment);
    842 }
    843 
    844 JSValue JSModuleRecord::evaluate(ExecState* exec)
    845 {
    846     if (!m_moduleProgramExecutable)
    847         return jsUndefined();
    848     JSValue result = exec->interpreter()->execute(m_moduleProgramExecutable.get(), exec, m_moduleEnvironment.get());
    849     m_moduleProgramExecutable.clear();
    850     return result;
    851 }
    852 
    853728static String printableName(const RefPtr<UniquedStringImpl>& uid)
    854729{
     
    863738}
    864739
    865 void JSModuleRecord::dump()
     740void AbstractModuleRecord::dump()
    866741{
    867742    dataLog("\nAnalyzing ModuleRecord key(", printableName(m_moduleKey), ")\n");
  • trunk/Source/JavaScriptCore/runtime/AbstractModuleRecord.h

    r209122 r209123  
    3636namespace JSC {
    3737
     38class JSModuleEnvironment;
    3839class JSModuleNamespaceObject;
    39 class JSModuleEnvironment;
    4040class JSMap;
    41 class ModuleProgramExecutable;
    4241
    4342// Based on the Source Text Module Record
    4443// http://www.ecma-international.org/ecma-262/6.0/#sec-source-text-module-records
    45 class JSModuleRecord : public JSDestructibleObject {
     44class AbstractModuleRecord : public JSDestructibleObject {
    4645    friend class LLIntOffsetsExtractor;
    4746public:
     
    8281    DECLARE_EXPORT_INFO;
    8382
    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 
    9683    void appendRequestedModule(const Identifier&);
    9784    void addStarExportEntry(const Identifier&);
     
    114101    void dump();
    115102
    116     JSModuleEnvironment* moduleEnvironment()
    117     {
    118         ASSERT(m_moduleEnvironment);
    119         return m_moduleEnvironment.get();
    120     }
    121 
    122     void link(ExecState*);
    123     JS_EXPORT_PRIVATE JSValue evaluate(ExecState*);
    124 
    125     ModuleProgramExecutable* moduleProgramExecutable() const { return m_moduleProgramExecutable.get(); }
    126 
    127103    struct Resolution {
    128104        enum class Type { Resolved, NotFound, Ambiguous, Error };
     
    133109
    134110        Type type;
    135         JSModuleRecord* moduleRecord;
     111        AbstractModuleRecord* moduleRecord;
    136112        Identifier localName;
    137113    };
     
    140116    Resolution resolveImport(ExecState*, const Identifier& localName);
    141117
    142     JSModuleRecord* hostResolveImportedModule(ExecState*, const Identifier& moduleName);
     118    AbstractModuleRecord* hostResolveImportedModule(ExecState*, const Identifier& moduleName);
    143119
    144 private:
    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)
     120    JSModuleNamespaceObject* getModuleNamespace(ExecState*);
     121   
     122    JSModuleEnvironment* moduleEnvironment()
    151123    {
     124        ASSERT(m_moduleEnvironment);
     125        return m_moduleEnvironment.get();
    152126    }
    153127
     128protected:
     129    AbstractModuleRecord(VM&, Structure*, const Identifier&, const SourceCode&, const VariableEnvironment&, const VariableEnvironment&);
    154130    void finishCreation(ExecState*, VM&);
    155 
    156     JSModuleNamespaceObject* getModuleNamespace(ExecState*);
    157131
    158132    static void visitChildren(JSCell*, SlotVisitor&);
    159133    static void destroy(JSCell*);
    160134
    161     void instantiateDeclarations(ExecState*, ModuleProgramExecutable*);
     135    WriteBarrier<JSModuleEnvironment> m_moduleEnvironment;
    162136
     137private:
    163138    struct ResolveQuery;
    164139    static Resolution resolveExportImpl(ExecState*, const ResolveQuery&);
     
    201176
    202177    WriteBarrier<JSMap> m_dependenciesMap;
    203 
    204     WriteBarrier<ModuleProgramExecutable> m_moduleProgramExecutable;
    205     WriteBarrier<JSModuleEnvironment> m_moduleEnvironment;
     178   
    206179    WriteBarrier<JSModuleNamespaceObject> m_moduleNamespaceObject;
    207180
    208     // We assume that all the JSModuleRecord are retained by JSModuleLoader's registry.
     181    // We assume that all the AbstractModuleRecord are retained by JSModuleLoader's registry.
    209182    // So here, we don't visit each object for GC. The resolution cache map caches the once
    210183    // looked up correctly resolved resolution, since (1) we rarely looked up the non-resolved one,
  • trunk/Source/JavaScriptCore/runtime/JSGlobalObject.cpp

    r208953 r209123  
    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);
     
    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)
  • trunk/Source/JavaScriptCore/runtime/JSGlobalObject.h

    r208712 r209123  
    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)
     
    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);
  • trunk/Source/JavaScriptCore/runtime/JSModuleEnvironment.cpp

    r207023 r209123  
    3030#include "JSModuleEnvironment.h"
    3131
     32#include "AbstractModuleRecord.h"
    3233#include "Interpreter.h"
    3334#include "JSCInlines.h"
     
    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    //
     
    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);
     
    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();
     
    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);
     
    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;
     
    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);
  • trunk/Source/JavaScriptCore/runtime/JSModuleEnvironment.h

    r206525 r209123  
    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
     
    3030
    3131#include "JSLexicalEnvironment.h"
    32 #include "JSModuleRecord.h"
    3332
    3433namespace JSC {
    3534
     35class AbstractModuleRecord;
    3636class Register;
    3737
     
    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();
     
    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    }
     
    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();
     
    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
  • trunk/Source/JavaScriptCore/runtime/JSModuleNamespaceObject.cpp

    r207411 r209123  
    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
     
    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();
     
    121121    case PropertySlot::InternalMethodType::Get:
    122122    case PropertySlot::InternalMethodType::GetOwnProperty: {
    123         JSModuleRecord* moduleRecord = thisObject->moduleRecord();
    124 
    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);
    127 
    128         JSModuleRecord* targetModule = resolution.moduleRecord;
     123        AbstractModuleRecord* moduleRecord = thisObject->moduleRecord();
     124
     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);
     127
     128        AbstractModuleRecord* targetModule = resolution.moduleRecord;
    129129        JSModuleEnvironment* targetEnvironment = targetModule->moduleEnvironment();
    130130
  • trunk/Source/JavaScriptCore/runtime/JSModuleNamespaceObject.h

    r206525 r209123  
    3131namespace JSC {
    3232
    33 class JSModuleRecord;
     33class AbstractModuleRecord;
    3434
    3535class JSModuleNamespaceObject : public JSDestructibleObject {
     
    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);
     
    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
     
    7272
    7373    OrderedIdentifierSet m_exports;
    74     WriteBarrier<JSModuleRecord> m_moduleRecord;
     74    WriteBarrier<AbstractModuleRecord> m_moduleRecord;
    7575};
    7676
  • trunk/Source/JavaScriptCore/runtime/JSModuleRecord.cpp

    r208985 r209123  
    3030#include "Interpreter.h"
    3131#include "JSCInlines.h"
    32 #include "JSMap.h"
    3332#include "JSModuleEnvironment.h"
    3433#include "JSModuleNamespaceObject.h"
     
    3938const ClassInfo JSModuleRecord::s_info = { "ModuleRecord", &Base::s_info, 0, CREATE_METHOD_TABLE(JSModuleRecord) };
    4039
     40
     41Structure* JSModuleRecord::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
     42{
     43    return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
     44}
     45
     46JSModuleRecord* JSModuleRecord::create(ExecState* exec, VM& vm, Structure* structure, const Identifier& moduleKey, const SourceCode& sourceCode, const VariableEnvironment& declaredVariables, const VariableEnvironment& lexicalVariables)
     47{
     48    JSModuleRecord* instance = new (NotNull, allocateCell<JSModuleRecord>(vm.heap)) JSModuleRecord(vm, structure, moduleKey, sourceCode, declaredVariables, lexicalVariables);
     49    instance->finishCreation(exec, vm);
     50    return instance;
     51}
     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)
     54{
     55}
     56
    4157void JSModuleRecord::destroy(JSCell* cell)
    4258{
     
    4763void JSModuleRecord::finishCreation(ExecState* exec, VM& vm)
    4864{
    49     Base::finishCreation(vm);
     65    Base::finishCreation(exec, vm);
    5066    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());
    5967}
    6068
     
    6371    JSModuleRecord* thisObject = jsCast<JSModuleRecord*>(cell);
    6472    Base::visitChildren(thisObject, visitor);
    65     visitor.append(&thisObject->m_moduleEnvironment);
    66     visitor.append(&thisObject->m_moduleNamespaceObject);
    6773    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());
    74 }
    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)
    88 {
    89     bool isNewEntry = m_exportEntries.add(entry.exportName.impl(), entry).isNewEntry;
    90     ASSERT_UNUSED(isNewEntry, isNewEntry); // This is guaranteed by the parser.
    91 }
    92 
    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
    649 {
    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()));
    654 }
    655 
    656 static void getExportedNames(ExecState* exec, JSModuleRecord* root, IdentifierSet& exportedNames)
    657 {
    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     }
    680 }
    681 
    682 JSModuleNamespaceObject* JSModuleRecord::getModuleNamespace(ExecState* exec)
    683 {
    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();
    71874}
    71975
     
    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) {
     
    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);
     
    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();
     
    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
  • trunk/Source/JavaScriptCore/runtime/JSModuleRecord.h

    r208985 r209123  
    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
     
    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;
    83 
    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();
    11542
    11643    JSModuleEnvironment* 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*);
     
    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&);
    155 
    156     JSModuleNamespaceObject* getModuleNamespace(ExecState*);
    15760
    15861    static void visitChildren(JSCell*, SlotVisitor&);
     
    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
  • trunk/Source/JavaScriptCore/runtime/JSScope.cpp

    r209028 r209123  
    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"
     
    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();
     
    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);
  • trunk/Source/JavaScriptCore/runtime/VM.cpp

    r208637 r209123  
    7373#include "JSPropertyNameEnumerator.h"
    7474#include "JSTemplateRegistryKey.h"
     75#include "JSWebAssembly.h"
    7576#include "JSWithScope.h"
    7677#include "LLIntData.h"
     
    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()));
  • trunk/Source/JavaScriptCore/runtime/VM.h

    r208953 r209123  
    311311#if ENABLE(WEBASSEMBLY)
    312312    Strong<Structure> webAssemblyExecutableStructure;
     313    Strong<Structure> webAssemblyFunctionCellStructure;
    313314#endif
    314315    Strong<Structure> moduleProgramExecutableStructure;
  • trunk/Source/JavaScriptCore/wasm/JSWebAssembly.h

    r207650 r209123  
    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"
     
    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"
  • trunk/Source/JavaScriptCore/wasm/WasmFormat.h

    r208401 r209123  
    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 {
     
    116116   
    117117struct Import {
    118     String module;
    119     String field;
     118    Identifier module;
     119    Identifier field;
    120120    External::Kind kind;
    121121    union {
     
    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
     
    156156};
    157157
    158 struct FunctionCompilation;
    159 typedef Vector<std::unique_ptr<FunctionCompilation>> CompiledFunctions;
    160 
    161158struct UnlinkedCall {
    162159    CodeLocationCall callLocation;
     
    170167};
    171168
     169typedef Vector<std::unique_ptr<FunctionCompilation>> CompiledFunctions;
     170
    172171} } // namespace JSC::Wasm
    173172
  • trunk/Source/JavaScriptCore/wasm/WasmModuleParser.cpp

    r209083 r209123  
    2929#if ENABLE(WEBASSEMBLY)
    3030
     31#include "IdentifierInlines.h"
    3132#include "WasmFormat.h"
    3233#include "WasmMemory.h"
     
    124125                return false; \
    125126            } \
    126         } break;
     127            break; \
     128        }
    127129        FOR_EACH_WASM_SECTION(WASM_SECTION_PARSE)
    128130#undef WASM_SECTION_PARSE
     
    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
     
    222224
    223225    for (uint32_t importNumber = 0; importNumber != importCount; ++importNumber) {
    224         Import i;
     226        Import imp;
    225227        uint32_t moduleLen;
    226228        uint32_t fieldLen;
    227229        if (!parseVarUInt32(moduleLen))
    228230            return false;
    229         if (!consumeUTF8String(i.module, moduleLen))
    230             return false;
     231        String moduleString;
     232        if (!consumeUTF8String(moduleString, moduleLen))
     233            return false;
     234        imp.module = Identifier::fromString(m_vm, moduleString);
    231235        if (!parseVarUInt32(fieldLen))
    232236            return false;
    233         if (!consumeUTF8String(i.field, fieldLen))
    234             return false;
    235         if (!parseExternalKind(i.kind))
    236             return false;
    237         switch (i.kind) {
     237        String fieldString;
     238        if (!consumeUTF8String(fieldString, fieldLen))
     239            return false;
     240        imp.field = Identifier::fromString(m_vm, fieldString);
     241        if (!parseExternalKind(imp.kind))
     242            return false;
     243        switch (imp.kind) {
    238244        case External::Function: {
    239245            uint32_t functionSignatureIndex;
    240246            if (!parseVarUInt32(functionSignatureIndex))
    241247                return false;
    242             if (functionSignatureIndex > m_module->signatures.size())
    243                 return false;
    244             i.functionSignature = &m_module->signatures[functionSignatureIndex];
    245         } break;
    246         case External::Table:
     248            if (functionSignatureIndex >= m_module->signatures.size())
     249                return false;
     250            imp.functionSignature = &m_module->signatures[functionSignatureIndex];
     251            break;
     252        }
     253        case External::Table: {
    247254            // FIXME https://bugs.webkit.org/show_bug.cgi?id=164135
    248255            break;
    249         case External::Memory:
     256        }
     257        case External::Memory: {
    250258            // FIXME https://bugs.webkit.org/show_bug.cgi?id=164134
    251259            break;
    252         case External::Global:
     260        }
     261        case External::Global: {
    253262            // FIXME https://bugs.webkit.org/show_bug.cgi?id=164133
    254263            // In the MVP, only immutable global variables can be imported.
    255264            break;
    256265        }
    257 
    258         m_module->imports.uncheckedAppend(i);
     266        }
     267
     268        m_module->imports.uncheckedAppend(imp);
    259269    }
    260270
     
    278288            return false;
    279289
    280         m_module->functions.uncheckedAppend({ &m_module->signatures[typeNumber], 0, 0 });
     290        // The Code section fixes up start and end.
     291        size_t start = 0;
     292        size_t end = 0;
     293        m_module->functions.uncheckedAppend({ &m_module->signatures[typeNumber], start, end });
    281294    }
    282295
     
    340353
    341354    for (uint32_t exportNumber = 0; exportNumber != exportCount; ++exportNumber) {
    342         Export e;
     355        Export exp;
    343356        uint32_t fieldLen;
    344357        if (!parseVarUInt32(fieldLen))
    345358            return false;
    346         if (!consumeUTF8String(e.field, fieldLen))
    347             return false;
    348         if (!parseExternalKind(e.kind))
    349             return false;
    350         switch (e.kind) {
     359        String fieldString;
     360        if (!consumeUTF8String(fieldString, fieldLen))
     361            return false;
     362        exp.field = Identifier::fromString(m_vm, fieldString);
     363        if (!parseExternalKind(exp.kind))
     364            return false;
     365        switch (exp.kind) {
    351366        case External::Function: {
    352             uint32_t functionSignatureIndex;
    353             if (!parseVarUInt32(functionSignatureIndex))
    354                 return false;
    355             if (functionSignatureIndex >= m_module->signatures.size())
    356                 return false;
    357             e.functionSignature = &m_module->signatures[functionSignatureIndex];
    358         } break;
    359         case External::Table:
     367            if (!parseVarUInt32(exp.functionIndex))
     368                return false;
     369            if (exp.functionIndex >= m_module->functions.size())
     370                return false;
     371            break;
     372        }
     373        case External::Table: {
    360374            // FIXME https://bugs.webkit.org/show_bug.cgi?id=164135
    361375            break;
    362         case External::Memory:
     376        }
     377        case External::Memory: {
    363378            // FIXME https://bugs.webkit.org/show_bug.cgi?id=164134
    364379            break;
    365         case External::Global:
     380        }
     381        case External::Global: {
    366382            // FIXME https://bugs.webkit.org/show_bug.cgi?id=164133
    367383            // In the MVP, only immutable global variables can be exported.
    368384            break;
    369385        }
    370 
    371         m_module->exports.uncheckedAppend(e);
     386        }
     387
     388        m_module->exports.uncheckedAppend(exp);
    372389    }
    373390
  • trunk/Source/JavaScriptCore/wasm/WasmModuleParser.h

    r208401 r209123  
    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    }
     
    6869#undef WASM_SECTION_DECLARE_PARSER
    6970
     71    VM* m_vm;
    7072    std::unique_ptr<ModuleInformation> m_module;
    7173    bool m_failed { true };
  • trunk/Source/JavaScriptCore/wasm/WasmPlan.cpp

    r208627 r209123  
    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)
  • trunk/Source/JavaScriptCore/wasm/js/JSWebAssemblyInstance.cpp

    r207929 r209123  
    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}
     
    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 put the module namespace object onto the exports object, instead of moduleEnvironment in WebAssemblyInstanceConstructor. https://bugs.webkit.org/show_bug.cgi?id=165121
    5862    ASSERT(inherits(info()));
    5963}
     
    7074
    7175    Base::visitChildren(thisObject, visitor);
     76    visitor.append(&thisObject->m_module);
    7277    visitor.append(&thisObject->m_moduleNamespaceObject);
    7378}
  • trunk/Source/JavaScriptCore/wasm/js/JSWebAssemblyInstance.h

    r207929 r209123  
    3232
    3333namespace JSC {
    34    
     34
    3535class JSModuleNamespaceObject;
     36class JSWebAssemblyModule;
    3637
    3738class JSWebAssemblyInstance : public JSDestructibleObject {
     
    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};
  • trunk/Source/JavaScriptCore/wasm/js/JSWebAssemblyModule.cpp

    r208401 r209123  
    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}
     
    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
     
    7273
    7374    Base::visitChildren(thisObject, visitor);
     75    visitor.append(&thisObject->m_exportSymbolTable);
    7476}
    7577
  • trunk/Source/JavaScriptCore/wasm/js/JSWebAssemblyModule.h

    r208401 r209123  
    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&);
     
    5657    std::unique_ptr<Wasm::ModuleInformation> m_moduleInformation;
    5758    Wasm::CompiledFunctions m_compiledFunctions;
     59    WriteBarrier<SymbolTable> m_exportSymbolTable;
    5860};
    5961
  • trunk/Source/JavaScriptCore/wasm/js/WebAssemblyFunction.h

    r209122 r209123  
    2828#if ENABLE(WEBASSEMBLY)
    2929
    30 #include "JSDestructibleObject.h"
    31 #include "JSObject.h"
    32 #include "WasmFormat.h"
     30#include "JSFunction.h"
     31#include <wtf/Noncopyable.h>
    3332
    3433namespace JSC {
    3534
    36 class JSWebAssemblyModule : public JSDestructibleObject {
     35class JSGlobalObject;
     36class WebAssemblyFunctionCell;
     37class WebAssemblyInstance;
     38
     39namespace B3 {
     40class Compilation;
     41}
     42
     43namespace Wasm {
     44struct Signature;
     45}
     46
     47class CallableWebAssemblyFunction {
     48    WTF_MAKE_NONCOPYABLE(CallableWebAssemblyFunction);
     49    CallableWebAssemblyFunction() = delete;
     50
    3751public:
    38     typedef JSDestructibleObject Base;
     52    CallableWebAssemblyFunction(CallableWebAssemblyFunction&&) = default;
    3953
    40     static JSWebAssemblyModule* create(VM&, Structure*, std::unique_ptr<Wasm::ModuleInformation>&, Wasm::CompiledFunctions&);
     54    const B3::Compilation* jsEntryPoint;
     55    const Wasm::Signature* signature;
     56    CallableWebAssemblyFunction(const B3::Compilation* jsEntryPoint, const Wasm::Signature* signature)
     57        : jsEntryPoint(jsEntryPoint)
     58        , signature(signature)
     59    {
     60    }
     61};
     62
     63class WebAssemblyFunction : public JSFunction {
     64public:
     65    typedef JSFunction Base;
     66
     67    const static unsigned StructureFlags = Base::StructureFlags;
     68
     69    DECLARE_EXPORT_INFO;
     70
     71    JS_EXPORT_PRIVATE static WebAssemblyFunction* create(VM&, JSGlobalObject*, int, const String&, JSWebAssemblyInstance*, CallableWebAssemblyFunction&&);
    4172    static Structure* createStructure(VM&, JSGlobalObject*, JSValue);
    4273
    43     DECLARE_INFO;
    44 
    45     const Wasm::ModuleInformation* moduleInformation() const
    46     {
    47         return m_moduleInformation.get();
    48     }
     74    const WebAssemblyFunctionCell* webAssemblyFunctionCell() const { return m_functionCell.get(); }
    4975
    5076protected:
    51     JSWebAssemblyModule(VM&, Structure*, std::unique_ptr<Wasm::ModuleInformation>&, Wasm::CompiledFunctions&);
    52     void finishCreation(VM&);
    53     static void destroy(JSCell*);
    5477    static void visitChildren(JSCell*, SlotVisitor&);
     78
     79    void finishCreation(VM&, NativeExecutable*, int length, const String& name, JSWebAssemblyInstance*, WebAssemblyFunctionCell*);
     80
    5581private:
    56     std::unique_ptr<Wasm::ModuleInformation> m_moduleInformation;
    57     Wasm::CompiledFunctions m_compiledFunctions;
     82    WebAssemblyFunction(VM&, JSGlobalObject*, Structure*);
     83
     84    WriteBarrier<JSWebAssemblyInstance> m_instance;
     85    WriteBarrier<WebAssemblyFunctionCell> m_functionCell;
    5886};
    5987
  • trunk/Source/JavaScriptCore/wasm/js/WebAssemblyFunctionCell.cpp

    r209122 r209123  
    2424 */
    2525
    26 #pragma once
     26#include "config.h"
     27#include "WebAssemblyFunctionCell.h"
    2728
    2829#if ENABLE(WEBASSEMBLY)
    2930
    30 #include "JSDestructibleObject.h"
    31 #include "JSObject.h"
     31#include "JSCInlines.h"
    3232
    3333namespace JSC {
    34    
    35 class JSModuleNamespaceObject;
    3634
    37 class JSWebAssemblyInstance : public JSDestructibleObject {
    38 public:
    39     typedef JSDestructibleObject Base;
     35const ClassInfo WebAssemblyFunctionCell::s_info = { "WebAssemblyFunctionCell", nullptr, nullptr, CREATE_METHOD_TABLE(WebAssemblyFunctionCell) };
    4036
    41     static JSWebAssemblyInstance* create(VM&, Structure*, JSModuleNamespaceObject*);
    42     static Structure* createStructure(VM&, JSGlobalObject*, JSValue);
     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}
    4343
    44     DECLARE_INFO;
     44WebAssemblyFunctionCell::WebAssemblyFunctionCell(VM& vm, CallableWebAssemblyFunction&& callable)
     45    : Base(vm, vm.webAssemblyFunctionCellStructure.get())
     46    , m_function(WTFMove(callable))
     47{
     48}
    4549
    46 protected:
    47     JSWebAssemblyInstance(VM&, Structure*);
    48     void finishCreation(VM&, JSModuleNamespaceObject*);
    49     static void destroy(JSCell*);
    50     static void visitChildren(JSCell*, SlotVisitor&);
     50void WebAssemblyFunctionCell::destroy(JSCell* cell)
     51{
     52    WebAssemblyFunctionCell* nativeFunction = static_cast<WebAssemblyFunctionCell*>(cell);
     53    nativeFunction->WebAssemblyFunctionCell::~WebAssemblyFunctionCell();
     54}
    5155
    52 private:
    53     WriteBarrier<JSModuleNamespaceObject> m_moduleNamespaceObject;
    54 };
     56Structure* WebAssemblyFunctionCell::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
     57{
     58    return Structure::create(vm, globalObject, prototype, TypeInfo(CellType, StructureFlags), info());
     59}
    5560
    56 } // namespace JSC
     61}
    5762
    5863#endif // ENABLE(WEBASSEMBLY)
  • trunk/Source/JavaScriptCore/wasm/js/WebAssemblyFunctionCell.h

    r209122 r209123  
    2828#if ENABLE(WEBASSEMBLY)
    2929
    30 #include "JSDestructibleObject.h"
    31 #include "JSObject.h"
     30#include "JSCell.h"
     31#include "WebAssemblyFunction.h"
    3232
    3333namespace JSC {
    34    
    35 class JSModuleNamespaceObject;
    3634
    37 class JSWebAssemblyInstance : public JSDestructibleObject {
     35class WebAssemblyFunctionCell : public JSCell {
    3836public:
    39     typedef JSDestructibleObject Base;
     37    typedef JSCell Base;
     38    static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal;
     39    static const bool needsDestruction = true;
    4040
    41     static JSWebAssemblyInstance* create(VM&, Structure*, JSModuleNamespaceObject*);
     41    static WebAssemblyFunctionCell* create(VM&, CallableWebAssemblyFunction&&);
     42    static void destroy(JSCell*);
    4243    static Structure* createStructure(VM&, JSGlobalObject*, JSValue);
    4344
    4445    DECLARE_INFO;
    4546
    46 protected:
    47     JSWebAssemblyInstance(VM&, Structure*);
    48     void finishCreation(VM&, JSModuleNamespaceObject*);
    49     static void destroy(JSCell*);
    50     static void visitChildren(JSCell*, SlotVisitor&);
     47    const CallableWebAssemblyFunction& function() const { return m_function; }
    5148
    5249private:
    53     WriteBarrier<JSModuleNamespaceObject> m_moduleNamespaceObject;
     50    WebAssemblyFunctionCell(VM&, CallableWebAssemblyFunction&&);
     51
     52    CallableWebAssemblyFunction m_function;
    5453};
    5554
  • trunk/Source/JavaScriptCore/wasm/js/WebAssemblyInstanceConstructor.cpp

    r209025 r209123  
    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 {
     42
     43static const bool verbose = false;
    4244
    4345const ClassInfo WebAssemblyInstanceConstructor::s_info = { "Function", &Base::s_info, &constructorTableWebAssemblyInstance, CREATE_METHOD_TABLE(WebAssemblyInstanceConstructor) };
     
    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.
     
    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);
    83     RETURN_IF_EXCEPTION(scope, encodedJSValue());
    84     auto* moduleNamespaceObject = JSModuleNamespaceObject::create(state, globalObject, globalObject->moduleNamespaceObjectStructure(), moduleRecord, instanceExports);
     78    WebAssemblyModuleRecord* moduleRecord = WebAssemblyModuleRecord::create(state, vm, globalObject->webAssemblyModuleRecordStructure(), moduleKey, sourceCode, declaredVariables, lexicalVariables);
    8579    RETURN_IF_EXCEPTION(scope, encodedJSValue());
    8680
    87     auto* structure = InternalFunction::createSubclassStructure(state, state->newTarget(), globalObject->WebAssemblyInstanceStructure());
     81    Structure* instanceStructure = InternalFunction::createSubclassStructure(state, state->newTarget(), globalObject->WebAssemblyInstanceStructure());
    8882    RETURN_IF_EXCEPTION(scope, encodedJSValue());
    8983
    90     return JSValue::encode(JSWebAssemblyInstance::create(vm, structure, moduleNamespaceObject));
     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);
     95    RETURN_IF_EXCEPTION(scope, encodedJSValue());
     96
     97    return JSValue::encode(instance);
    9198}
    9299
  • trunk/Source/JavaScriptCore/wasm/js/WebAssemblyModuleConstructor.cpp

    r208627 r209123  
    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"
     
    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 Module.
     84    SymbolTable* exportSymbolTable = SymbolTable::create(vm);
     85    for (auto& exp : plan.getModuleInformation()->exports) {
     86        auto offset = exportSymbolTable->takeNextScopeOffset(NoLockingNecessary);
     87        exportSymbolTable->set(NoLockingNecessary, exp.field.impl(), SymbolTableEntry(VarOffset(offset)));
     88    }
     89
     90    return JSValue::encode(JSWebAssemblyModule::create(vm, structure, plan.getModuleInformation(), plan.getCompiledFunctions(), exportSymbolTable));
    8291}
    8392
  • trunk/Source/JavaScriptCore/wasm/js/WebAssemblyModuleRecord.h

    r209122 r209123  
    2828#if ENABLE(WEBASSEMBLY)
    2929
    30 #include "JSDestructibleObject.h"
    31 #include "JSObject.h"
    32 #include "WasmFormat.h"
     30#include "AbstractModuleRecord.h"
    3331
    3432namespace JSC {
    3533
    36 class JSWebAssemblyModule : public JSDestructibleObject {
     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;
    3740public:
    38     typedef JSDestructibleObject Base;
     41    typedef AbstractModuleRecord Base;
    3942
    40     static JSWebAssemblyModule* create(VM&, Structure*, std::unique_ptr<Wasm::ModuleInformation>&, Wasm::CompiledFunctions&);
     43    DECLARE_EXPORT_INFO;
     44
    4145    static Structure* createStructure(VM&, JSGlobalObject*, JSValue);
     46    static WebAssemblyModuleRecord* create(ExecState*, VM&, Structure*, const Identifier&, const SourceCode&, const VariableEnvironment&, const VariableEnvironment&);
    4247
    43     DECLARE_INFO;
     48    void link(ExecState*, JSWebAssemblyInstance*);
     49    JS_EXPORT_PRIVATE JSValue evaluate(ExecState*);
    4450
    45     const Wasm::ModuleInformation* moduleInformation() const
    46     {
    47         return m_moduleInformation.get();
    48     }
     51private:
     52    WebAssemblyModuleRecord(VM&, Structure*, const Identifier&, const SourceCode&, const VariableEnvironment&, const VariableEnvironment&);
    4953
    50 protected:
    51     JSWebAssemblyModule(VM&, Structure*, std::unique_ptr<Wasm::ModuleInformation>&, Wasm::CompiledFunctions&);
    52     void finishCreation(VM&);
     54    void finishCreation(ExecState*, VM&);
    5355    static void destroy(JSCell*);
     56
    5457    static void visitChildren(JSCell*, SlotVisitor&);
    55 private:
    56     std::unique_ptr<Wasm::ModuleInformation> m_moduleInformation;
    57     Wasm::CompiledFunctions m_compiledFunctions;
     58
     59    WriteBarrier<JSWebAssemblyInstance> m_instance;
    5860};
    5961
  • trunk/Source/WTF/ChangeLog

    r209120 r209123  
     12016-11-29  JF Bastien  <jfbastien@apple.com>
     2
     3        WebAssembly JS API: improve Instance
     4        https://bugs.webkit.org/show_bug.cgi?id=164757
     5
     6        Reviewed by Keith Miller.
     7
     8        * wtf/Expected.h:
     9        (WTF::ExpectedDetail::destroy): silence a warning
     10
    1112016-11-29  Commit Queue  <commit-queue@webkit.org>
    212
  • trunk/Source/WTF/wtf/Expected.h

    r208985 r209123  
    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
Note: See TracChangeset for help on using the changeset viewer.