Changeset 207929 in webkit


Ignore:
Timestamp:
Oct 26, 2016 7:18:51 PM (7 years ago)
Author:
jfbastien@apple.com
Message:

WebAssembly API: implement Instance

As described in: https://github.com/WebAssembly/design/blob/master/JS.md#webassemblyinstance-objects

  • Take ownership of Wasm::Plan's compilation result when successfully creating a JSWebAssemblyModule object.
  • Construct a basic Instance with a Module.
  • Handle second argument (importObject) of WebAssembly.Instance.
  • Add reference text from the spec to WebAssembly.Module's code.
  • Expose and test an empty 'exports' ModuleNamespaceObject on WebAssembly.Instance.

The implementation isn't complete yet: it relies on further work for which I've filed bugs.

WebAssembly API: implement Instance
https://bugs.webkit.org/show_bug.cgi?id=163998

Reviewed by Keith Miller.

JSTests:

  • wasm/js-api/test_Instance.js: Added.

(EmptyModule): use the Builder, create the simplest Module possible, and create an Instance from it

  • wasm/js-api/test_basic_api.js:

(const.c.in.constructorProperties.switch): basic tests of the API

Source/JavaScriptCore:

  • wasm/WasmPlan.h:

(JSC::Wasm::Plan::getFunctions): allow transfering state out
(JSC::Wasm::Plan::getMemory): allow transfering state out

  • wasm/js/JSWebAssemblyInstance.cpp:

(JSC::JSWebAssemblyInstance::create):
(JSC::JSWebAssemblyInstance::finishCreation): set the ModuleNamespaceObject, and expose it as "exports"
(JSC::JSWebAssemblyInstance::visitChildren): visit the ModuleNamespaceObject child

  • wasm/js/JSWebAssemblyInstance.h:
  • wasm/js/JSWebAssemblyModule.cpp:

(JSC::JSWebAssemblyModule::create):
(JSC::JSWebAssemblyModule::JSWebAssemblyModule): move in the compiled functions and the memory

  • wasm/js/JSWebAssemblyModule.h:
  • wasm/js/WebAssemblyInstanceConstructor.cpp:

(JSC::constructJSWebAssemblyInstance): take the Module, extract the Plan's results, and create the (empty for now) ModuleNamespaceObject

  • wasm/js/WebAssemblyModuleConstructor.cpp:

(JSC::constructJSWebAssemblyModule): add a few comments from the spec, and pass out the Plan's results

Location:
trunk
Files:
1 added
10 edited

Legend:

Unmodified
Added
Removed
  • trunk/JSTests/ChangeLog

    r207906 r207929  
     12016-10-26  JF Bastien  <jfbastien@apple.com>
     2
     3        WebAssembly API: implement Instance
     4
     5        As described in: https://github.com/WebAssembly/design/blob/master/JS.md#webassemblyinstance-objects
     6
     7         - Take ownership of Wasm::Plan's compilation result when successfully creating a JSWebAssemblyModule object.
     8         - Construct a basic Instance with a Module.
     9         - Handle second argument (importObject) of WebAssembly.Instance.
     10         - Add reference text from the spec to WebAssembly.Module's code.
     11         - Expose and test an empty 'exports' ModuleNamespaceObject on WebAssembly.Instance.
     12
     13        The implementation isn't complete yet: it relies on further work for which I've filed bugs.
     14
     15        WebAssembly API: implement Instance
     16        https://bugs.webkit.org/show_bug.cgi?id=163998
     17
     18        Reviewed by Keith Miller.
     19
     20        * wasm/js-api/test_Instance.js: Added.
     21        (EmptyModule): use the Builder, create the simplest Module possible, and create an Instance from it
     22        * wasm/js-api/test_basic_api.js:
     23        (const.c.in.constructorProperties.switch): basic tests of the API
     24
    1252016-10-26  Mark Lam  <mark.lam@apple.com>
    226
  • trunk/JSTests/wasm/js-api/test_basic_api.js

    r207825 r207929  
    33
    44const version = 0xC;
    5 const emptyModule = Uint8Array.of(0x0, 0x61, 0x73, 0x6d, version, 0x00, 0x00, 0x00);
     5const emptyModuleArray = Uint8Array.of(0x0, 0x61, 0x73, 0x6d, version, 0x00, 0x00, 0x00);
     6const invalidConstructorInputs = [undefined, null, "", 1, {}, []];
     7const invalidInstanceImports = [null, "", 1];
    68
    79const checkOwnPropertyDescriptor = (obj, prop, expect) => {
     
    5052    switch (c) {
    5153    case "Module":
    52         for (const invalid of [undefined, "", 1, {}, []])
     54        for (const invalid of invalidConstructorInputs)
    5355            assert.throws(() => new WebAssembly[c](invalid), TypeError, `first argument to WebAssembly.Module must be an ArrayBufferView or an ArrayBuffer (evaluating 'new WebAssembly[c](invalid)')`);
    5456        for (const buffer of [new ArrayBuffer(), new DataView(new ArrayBuffer()), new Int8Array(), new Uint8Array(), new Uint8ClampedArray(), new Int16Array(), new Uint16Array(), new Int32Array(), new Uint32Array(), new Float32Array(), new Float64Array()])
    5557            // FIXME the following should be WebAssembly.CompileError. https://bugs.webkit.org/show_bug.cgi?id=163768
    5658            assert.throws(() => new WebAssembly[c](buffer), Error, `Module is 0 bytes, expected at least 8 bytes (evaluating 'new WebAssembly[c](buffer)')`);
    57         assert.instanceof(new WebAssembly[c](emptyModule), WebAssembly.Module);
     59        assert.instanceof(new WebAssembly[c](emptyModuleArray), WebAssembly.Module);
    5860        // FIXME test neutered TypedArray and TypedArrayView. https://bugs.webkit.org/show_bug.cgi?id=163899
    5961        break;
    6062    case "Instance":
    61         // FIXME Implement and test these APIs further. For now they just throw. https://bugs.webkit.org/show_bug.cgi?id=159775
    62         assert.throws(() => new WebAssembly[c](), Error, `WebAssembly doesn't yet implement the ${c} constructor property`);
     63        for (const invalid of invalidConstructorInputs)
     64            assert.throws(() => new WebAssembly[c](invalid), TypeError, `first argument to WebAssembly.Instance must be a WebAssembly.Module (evaluating 'new WebAssembly[c](invalid)')`);
     65        const instance = new WebAssembly[c](new WebAssembly.Module(emptyModuleArray));
     66        assert.instanceof(instance, WebAssembly.Instance);
     67        for (const invalid of invalidInstanceImports)
     68            assert.throws(() => new WebAssembly[c](new WebAssembly.Module(emptyModuleArray), invalid), TypeError, `second argument to WebAssembly.Instance must be undefined or an Object (evaluating 'new WebAssembly[c](new WebAssembly.Module(emptyModuleArray), invalid)')`);
     69        assert.notUndef(instance.exports);
     70        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);
    6375        break;
    6476    case "Memory":
  • trunk/Source/JavaScriptCore/ChangeLog

    r207928 r207929  
     12016-10-26  JF Bastien  <jfbastien@apple.com>
     2
     3        WebAssembly API: implement Instance
     4
     5        As described in: https://github.com/WebAssembly/design/blob/master/JS.md#webassemblyinstance-objects
     6
     7         - Take ownership of Wasm::Plan's compilation result when successfully creating a JSWebAssemblyModule object.
     8         - Construct a basic Instance with a Module.
     9         - Handle second argument (importObject) of WebAssembly.Instance.
     10         - Add reference text from the spec to WebAssembly.Module's code.
     11         - Expose and test an empty 'exports' ModuleNamespaceObject on WebAssembly.Instance.
     12
     13        The implementation isn't complete yet: it relies on further work for which I've filed bugs.
     14
     15        WebAssembly API: implement Instance
     16        https://bugs.webkit.org/show_bug.cgi?id=163998
     17
     18        Reviewed by Keith Miller.
     19
     20        * wasm/WasmPlan.h:
     21        (JSC::Wasm::Plan::getFunctions): allow transfering state out
     22        (JSC::Wasm::Plan::getMemory): allow transfering state out
     23        * wasm/js/JSWebAssemblyInstance.cpp:
     24        (JSC::JSWebAssemblyInstance::create):
     25        (JSC::JSWebAssemblyInstance::finishCreation): set the ModuleNamespaceObject, and expose it as "exports"
     26        (JSC::JSWebAssemblyInstance::visitChildren): visit the ModuleNamespaceObject child
     27        * wasm/js/JSWebAssemblyInstance.h:
     28        * wasm/js/JSWebAssemblyModule.cpp:
     29        (JSC::JSWebAssemblyModule::create):
     30        (JSC::JSWebAssemblyModule::JSWebAssemblyModule): move in the compiled functions and the memory
     31        * wasm/js/JSWebAssemblyModule.h:
     32        * wasm/js/WebAssemblyInstanceConstructor.cpp:
     33        (JSC::constructJSWebAssemblyInstance): take the Module, extract the Plan's results, and create the (empty for now) ModuleNamespaceObject
     34        * wasm/js/WebAssemblyModuleConstructor.cpp:
     35        (JSC::constructJSWebAssemblyModule): add a few comments from the spec, and pass out the Plan's results
     36
    1372016-10-26  Brian Burg  <bburg@apple.com>
    238
  • trunk/Source/JavaScriptCore/wasm/WasmPlan.h

    r207825 r207929  
    3939class Plan {
    4040public:
     41    typedef Vector<std::unique_ptr<FunctionCompilation>> CompiledFunctions;
     42
    4143    JS_EXPORT_PRIVATE Plan(VM&, Vector<uint8_t>);
    4244    JS_EXPORT_PRIVATE Plan(VM&, const uint8_t*, size_t);
     
    6466        return m_memory.get();
    6567    }
     68   
     69    CompiledFunctions* getFunctions()
     70    {
     71        RELEASE_ASSERT(!failed());
     72        return &m_result;
     73    }
     74    std::unique_ptr<Memory>* getMemory()
     75    {
     76        RELEASE_ASSERT(!failed());
     77        return &m_memory;
     78    }
    6679
    6780private:
    68     Vector<std::unique_ptr<FunctionCompilation>> m_result;
     81    CompiledFunctions m_result;
    6982    std::unique_ptr<Memory> m_memory;
    7083    bool m_failed { true };
  • trunk/Source/JavaScriptCore/wasm/js/JSWebAssemblyInstance.cpp

    r207650 r207929  
    3030
    3131#include "JSCInlines.h"
     32#include "JSModuleNamespaceObject.h"
    3233
    3334namespace JSC {
    3435
    35 JSWebAssemblyInstance* JSWebAssemblyInstance::create(VM& vm, Structure* structure)
     36JSWebAssemblyInstance* JSWebAssemblyInstance::create(VM& vm, Structure* structure, JSModuleNamespaceObject* moduleNamespaceObject)
    3637{
    3738    auto* instance = new (NotNull, allocateCell<JSWebAssemblyInstance>(vm.heap)) JSWebAssemblyInstance(vm, structure);
    38     instance->finishCreation(vm);
     39    instance->finishCreation(vm, moduleNamespaceObject);
    3940    return instance;
    4041}
     
    5051}
    5152
    52 void JSWebAssemblyInstance::finishCreation(VM& vm)
     53void JSWebAssemblyInstance::finishCreation(VM& vm, JSModuleNamespaceObject* moduleNamespaceObject)
    5354{
    5455    Base::finishCreation(vm);
     56    m_moduleNamespaceObject.set(vm, this, moduleNamespaceObject);
     57    putDirectWithoutTransition(vm, Identifier::fromString(&vm, "exports"), m_moduleNamespaceObject.get(), None);
    5558    ASSERT(inherits(info()));
    5659}
     
    6770
    6871    Base::visitChildren(thisObject, visitor);
     72    visitor.append(&thisObject->m_moduleNamespaceObject);
    6973}
    7074
  • trunk/Source/JavaScriptCore/wasm/js/JSWebAssemblyInstance.h

    r207650 r207929  
    3232
    3333namespace JSC {
     34   
     35class JSModuleNamespaceObject;
    3436
    3537class JSWebAssemblyInstance : public JSDestructibleObject {
     
    3739    typedef JSDestructibleObject Base;
    3840
    39     static JSWebAssemblyInstance* create(VM&, Structure*);
     41    static JSWebAssemblyInstance* create(VM&, Structure*, JSModuleNamespaceObject*);
    4042    static Structure* createStructure(VM&, JSGlobalObject*, JSValue);
    4143
     
    4446protected:
    4547    JSWebAssemblyInstance(VM&, Structure*);
    46     void finishCreation(VM&);
     48    void finishCreation(VM&, JSModuleNamespaceObject*);
    4749    static void destroy(JSCell*);
    4850    static void visitChildren(JSCell*, SlotVisitor&);
     51
     52private:
     53    WriteBarrier<JSModuleNamespaceObject> m_moduleNamespaceObject;
    4954};
    5055
  • trunk/Source/JavaScriptCore/wasm/js/JSWebAssemblyModule.cpp

    r207650 r207929  
    3030
    3131#include "JSCInlines.h"
     32#include "WasmFormat.h"
     33#include "WasmMemory.h"
     34#include <wtf/StdLibExtras.h>
    3235
    3336namespace JSC {
    3437
    35 JSWebAssemblyModule* JSWebAssemblyModule::create(VM& vm, Structure* structure)
     38JSWebAssemblyModule* JSWebAssemblyModule::create(VM& vm, Structure* structure, Vector<std::unique_ptr<Wasm::FunctionCompilation>>* compiledFunctions, std::unique_ptr<Wasm::Memory>* memory)
    3639{
    37     auto* instance = new (NotNull, allocateCell<JSWebAssemblyModule>(vm.heap)) JSWebAssemblyModule(vm, structure);
     40    auto* instance = new (NotNull, allocateCell<JSWebAssemblyModule>(vm.heap)) JSWebAssemblyModule(vm, structure, compiledFunctions, memory);
    3841    instance->finishCreation(vm);
    3942    return instance;
     
    4548}
    4649
    47 JSWebAssemblyModule::JSWebAssemblyModule(VM& vm, Structure* structure)
     50JSWebAssemblyModule::JSWebAssemblyModule(VM& vm, Structure* structure, Vector<std::unique_ptr<Wasm::FunctionCompilation>>* compiledFunctions, std::unique_ptr<Wasm::Memory>* memory)
    4851    : Base(vm, structure)
     52    , m_compiledFunctions(WTFMove(*compiledFunctions))
     53    , m_memory(WTFMove(*memory))
    4954{
    5055}
  • trunk/Source/JavaScriptCore/wasm/js/JSWebAssemblyModule.h

    r207650 r207929  
    3333namespace JSC {
    3434
     35namespace Wasm {
     36struct FunctionCompilation;
     37class Memory;
     38}
     39
    3540class JSWebAssemblyModule : public JSDestructibleObject {
    3641public:
    3742    typedef JSDestructibleObject Base;
    3843
    39     static JSWebAssemblyModule* create(VM&, Structure*);
     44    static JSWebAssemblyModule* create(VM&, Structure*, Vector<std::unique_ptr<Wasm::FunctionCompilation>>*, std::unique_ptr<Wasm::Memory>*);
    4045    static Structure* createStructure(VM&, JSGlobalObject*, JSValue);
    4146
     
    4348
    4449protected:
    45     JSWebAssemblyModule(VM&, Structure*);
     50    JSWebAssemblyModule(VM&, Structure*, Vector<std::unique_ptr<Wasm::FunctionCompilation>>*, std::unique_ptr<Wasm::Memory>*);
    4651    void finishCreation(VM&);
    4752    static void destroy(JSCell*);
    4853    static void visitChildren(JSCell*, SlotVisitor&);
     54
     55private:
     56    Vector<std::unique_ptr<Wasm::FunctionCompilation>> m_compiledFunctions;
     57    std::unique_ptr<Wasm::Memory> m_memory;
    4958};
    5059
  • trunk/Source/JavaScriptCore/wasm/js/WebAssemblyInstanceConstructor.cpp

    r207825 r207929  
    3131#include "FunctionPrototype.h"
    3232#include "JSCInlines.h"
     33#include "JSModuleNamespaceObject.h"
     34#include "JSModuleRecord.h"
     35#include "JSWebAssemblyInstance.h"
     36#include "JSWebAssemblyModule.h"
    3337#include "WebAssemblyInstancePrototype.h"
    3438
     
    4650static EncodedJSValue JSC_HOST_CALL constructJSWebAssemblyInstance(ExecState* state)
    4751{
    48     VM& vm = state->vm();
     52    auto& vm = state->vm();
    4953    auto scope = DECLARE_THROW_SCOPE(vm);
    50     return JSValue::encode(throwException(state, scope, createError(state, ASCIILiteral("WebAssembly doesn't yet implement the Instance constructor property"))));
     54    auto* globalObject = state->lexicalGlobalObject();
     55
     56    // If moduleObject is not a WebAssembly.Module instance, a TypeError is thrown.
     57    JSWebAssemblyModule* module = jsDynamicCast<JSWebAssemblyModule*>(state->argument(0));
     58    if (!module)
     59        return JSValue::encode(throwException(state, scope, createTypeError(state, ASCIILiteral("first argument to WebAssembly.Instance must be a WebAssembly.Module"), defaultSourceAppender, runtimeTypeForValue(state->argument(0)))));
     60
     61    // If the importObject parameter is not undefined and Type(importObject) is not Object, a TypeError is thrown.
     62    JSValue importArgument = state->argument(1);
     63    JSObject* importObject = importArgument.getObject();
     64    if (!importArgument.isUndefined() && !importObject)
     65        return JSValue::encode(throwException(state, scope, createTypeError(state, ASCIILiteral("second argument to WebAssembly.Instance must be undefined or an Object"), defaultSourceAppender, runtimeTypeForValue(importArgument))));
     66
     67    // FIXME use the importObject. https://bugs.webkit.org/show_bug.cgi?id=164039
     68    // If the list of module.imports is not empty and Type(importObject) is not Object, a TypeError is thrown.
     69
     70    // FIXME String things from https://bugs.webkit.org/show_bug.cgi?id=164023
     71    // Let exports be a list of (string, JS value) pairs that is mapped from each external value e in instance.exports as follows:
     72    IdentifierSet instanceExports;
     73    for (const auto& name : instanceExports) {
     74        // FIXME validate according to Module.Instance spec.
     75        (void)name;
     76    }
     77    Identifier moduleKey;
     78    SourceCode sourceCode;
     79    VariableEnvironment declaredVariables;
     80    VariableEnvironment lexicalVariables;
     81    auto* moduleRecord = JSModuleRecord::create(state, vm, globalObject->moduleRecordStructure(), moduleKey, sourceCode, declaredVariables, lexicalVariables);
     82    auto* moduleNamespaceObject = JSModuleNamespaceObject::create(state, globalObject, globalObject->moduleNamespaceObjectStructure(), moduleRecord, instanceExports);
     83
     84    auto* structure = InternalFunction::createSubclassStructure(state, state->newTarget(), globalObject->WebAssemblyInstanceStructure());
     85    RETURN_IF_EXCEPTION(scope, encodedJSValue());
     86
     87    return JSValue::encode(JSWebAssemblyInstance::create(vm, structure, moduleNamespaceObject));
    5188}
    5289
  • trunk/Source/JavaScriptCore/wasm/js/WebAssemblyModuleConstructor.cpp

    r207825 r207929  
    5555    auto scope = DECLARE_THROW_SCOPE(vm);
    5656    JSValue val = state->argument(0);
     57
     58    // If the given bytes argument is not a BufferSource, a TypeError exception is thrown.
    5759    JSArrayBuffer* arrayBuffer = val.getObject() ? jsDynamicCast<JSArrayBuffer*>(val.getObject()) : nullptr;
    5860    JSArrayBufferView* arrayBufferView = val.getObject() ? jsDynamicCast<JSArrayBufferView*>(val.getObject()) : nullptr;
     
    6870
    6971    Wasm::Plan plan(vm, base + byteOffset, byteSize);
     72    // On failure, a new WebAssembly.CompileError is thrown.
    7073    if (plan.failed())
    7174        return JSValue::encode(throwException(state, scope, createWebAssemblyCompileError(state, plan.errorMessage())));
    7275
    73     // FIXME take content from Plan.
     76    // The spec string values inside Ast.module are decoded as UTF8 as described in Web.md. FIXME https://bugs.webkit.org/show_bug.cgi?id=164023
    7477
     78    // On success, a new WebAssembly.Module object is returned with [[Module]] set to the validated Ast.module.
    7579    auto* structure = InternalFunction::createSubclassStructure(state, state->newTarget(), asInternalFunction(state->callee())->globalObject()->WebAssemblyModuleStructure());
    7680    RETURN_IF_EXCEPTION(scope, encodedJSValue());
    77     return JSValue::encode(JSWebAssemblyModule::create(vm, structure));
     81
     82    return JSValue::encode(JSWebAssemblyModule::create(vm, structure, plan.getFunctions(), plan.getMemory()));
    7883}
    7984
Note: See TracChangeset for help on using the changeset viewer.