⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 230763 in webkit


Ignore:
Timestamp:
Apr 18, 2018, 9:33:33 AM (8 years ago)
Author:
Yusuke Suzuki
Message:

[WebAssembly][Modules] Import globals from wasm modules
​https://bugs.webkit.org/show_bug.cgi?id=184736

Reviewed by JF Bastien.

JSTests:

  • wasm.yaml:
  • wasm/modules/wasm-imports-js-re-exports-wasm-exports.js:
  • wasm/modules/wasm-imports-js-re-exports-wasm-exports/imports.wasm:
  • wasm/modules/wasm-imports-js-re-exports-wasm-exports/imports.wat:
  • wasm/modules/wasm-imports-js-re-exports-wasm-exports/re-export.js:
  • wasm/modules/wasm-imports-js-re-exports-wasm-exports/sum.wasm:
  • wasm/modules/wasm-imports-js-re-exports-wasm-exports/sum.wat:
  • wasm/modules/wasm-imports-wasm-exports.js:
  • wasm/modules/wasm-imports-wasm-exports/imports.wasm:
  • wasm/modules/wasm-imports-wasm-exports/imports.wat:
  • wasm/modules/wasm-imports-wasm-exports/sum.wasm:
  • wasm/modules/wasm-imports-wasm-exports/sum.wat:

Source/JavaScriptCore:

This patch implements a feature importing globals to/from wasm modules.
Since we are not supporting mutable globals now, we can just copy the
global data when importing. Currently we do not support importing/exporting
i64 globals. This will be supported once (1) mutable global bindings are
specified and (2) BigInt based i64 importing/exporting is specified.

  • wasm/js/JSWebAssemblyInstance.cpp:

(JSC::JSWebAssemblyInstance::create):

  • wasm/js/WebAssemblyModuleRecord.cpp:

(JSC::WebAssemblyModuleRecord::link):

Location:
trunk
Files:
6 added
17 edited

Legend:

Unmodified
Added
Removed
  • trunk/JSTests/ChangeLog

    r230759 r230763  
     12018-04-18  Yusuke Suzuki  <utatane.tea@gmail.com>
     2
     3        [WebAssembly][Modules] Import globals from wasm modules
     4        https://bugs.webkit.org/show_bug.cgi?id=184736
     5
     6        Reviewed by JF Bastien.
     7
     8        * wasm.yaml:
     9        * wasm/modules/wasm-imports-js-re-exports-wasm-exports.js:
     10        * wasm/modules/wasm-imports-js-re-exports-wasm-exports/imports.wasm:
     11        * wasm/modules/wasm-imports-js-re-exports-wasm-exports/imports.wat:
     12        * wasm/modules/wasm-imports-js-re-exports-wasm-exports/re-export.js:
     13        * wasm/modules/wasm-imports-js-re-exports-wasm-exports/sum.wasm:
     14        * wasm/modules/wasm-imports-js-re-exports-wasm-exports/sum.wat:
     15        * wasm/modules/wasm-imports-wasm-exports.js:
     16        * wasm/modules/wasm-imports-wasm-exports/imports.wasm:
     17        * wasm/modules/wasm-imports-wasm-exports/imports.wat:
     18        * wasm/modules/wasm-imports-wasm-exports/sum.wasm:
     19        * wasm/modules/wasm-imports-wasm-exports/sum.wat:
     20
    1212018-04-18  Yusuke Suzuki  <utatane.tea@gmail.com>
    222
  • trunk/JSTests/wasm.yaml

    r230759 r230763  
    3939  cmd: runWebAssemblySuite unless parseRunCommands
    4040- path: wasm/modules/
    41   cmd: runWebAssemblySuite unless parseRunCommands
     41  cmd: runWebAssembly unless parseRunCommands
    4242
    4343- path: wasm/spec-tests/address.wast.js
  • trunk/JSTests/wasm/modules/wasm-imports-js-re-exports-wasm-exports.js

    r230759 r230763  
    1 import { addOne } from "./wasm-imports-js-re-exports-wasm-exports/imports.wasm"
     1import { addOne, getAnswer } from "./wasm-imports-js-re-exports-wasm-exports/imports.wasm"
    22import * as assert from '../assert.js';
    33
    … …  
    66assert.eq(addOne(-2), -1);
    77assert.eq(addOne(0x7fffffff), -2147483648);
     8
     9assert.eq(getAnswer(), 42);
  • trunk/JSTests/wasm/modules/wasm-imports-js-re-exports-wasm-exports/imports.wat

    r230759 r230763  
    11(module
    22    (import "./re-export.js" "sum" (func $sum (param i32 i32) (result i32)))
     3    (import "./re-export.js" "answer" (global i32))
    34    (type $t0 (func (param i32) (result i32)))
    45    (func $addOne (export "addOne") (type $t0) (param $p0 i32) (result i32)
    56        i32.const 1
    67        get_local $p0
    7         call $sum))
     8        call $sum)
     9    (type $t1 (func (result i32)))
     10    (func $getAnswer (export "getAnswer") (type $t1) (result i32)
     11        get_global 0))
  • trunk/JSTests/wasm/modules/wasm-imports-js-re-exports-wasm-exports/re-export.js

    r230759 r230763  
    1 export { sum } from "./sum.wasm"
     1export { sum, answer } from "./sum.wasm"
  • trunk/JSTests/wasm/modules/wasm-imports-js-re-exports-wasm-exports/sum.wat

    r230759 r230763  
    44        get_local $p1
    55        get_local $p0
    6         i32.add))
     6        i32.add)
     7    (global (export "answer") i32 i32.const 42))
  • trunk/JSTests/wasm/modules/wasm-imports-wasm-exports.js

    r230759 r230763  
    1 import { addOne } from "./wasm-imports-js-exports/imports.wasm"
     1import { addOne, getAnswer, getAnswer1, getAnswer2, getAnswer3, getAnswer4 } from "./wasm-imports-wasm-exports/imports.wasm"
    22import * as assert from '../assert.js';
    33
    … …  
    66assert.eq(addOne(-2), -1);
    77assert.eq(addOne(0x7fffffff), -2147483648);
     8
     9assert.eq(getAnswer(), 42);
     10assert.eq(getAnswer1(), 0.5);
     11assert.eq(getAnswer2(), 0.5);
     12
     13assert.truthy(isPureNaN(getAnswer3()));
     14assert.truthy(isPureNaN(getAnswer4()));
  • trunk/JSTests/wasm/modules/wasm-imports-wasm-exports/imports.wat

    r230759 r230763  
    11(module
    22    (import "./sum.wasm" "sum" (func $sum (param i32 i32) (result i32)))
     3    (import "./sum.wasm" "answer" (global i32))
     4    (import "./sum.wasm" "answer1" (global f32))
     5    (import "./sum.wasm" "answer2" (global f64))
     6    (import "./sum.wasm" "answer3" (global f32))
     7    (import "./sum.wasm" "answer4" (global f64))
    38    (type $t0 (func (param i32) (result i32)))
    49    (func $addOne (export "addOne") (type $t0) (param $p0 i32) (result i32)
    510        i32.const 1
    611        get_local $p0
    7         call $sum))
     12        call $sum)
     13    (type $t1 (func (result i32)))
     14    (func $getAnswer (export "getAnswer") (type $t1) (result i32)
     15        get_global 0)
     16    (type $t2 (func (result f32)))
     17    (func $getAnswer1 (export "getAnswer1") (type $t2) (result f32)
     18        get_global 1)
     19    (type $t3 (func (result f64)))
     20    (func $getAnswer2 (export "getAnswer2") (type $t3) (result f64)
     21        get_global 2)
     22    (func $getAnswer3 (export "getAnswer3") (type $t2) (result f32)
     23        get_global 3)
     24    (func $getAnswer4 (export "getAnswer4") (type $t3) (result f64)
     25        get_global 4)
     26    )
  • trunk/JSTests/wasm/modules/wasm-imports-wasm-exports/sum.wat

    r230759 r230763  
    44        get_local $p1
    55        get_local $p0
    6         i32.add))
     6        i32.add)
     7    (global (export "answer") i32 i32.const 42)
     8    (global (export "answer1") f32 f32.const 0.5)
     9    (global (export "answer2") f64 f64.const 0.5)
     10    (global (export "answer3") f32 f32.const nan)
     11    (global (export "answer4") f64 f64.const nan))
  • trunk/Source/JavaScriptCore/ChangeLog

    r230762 r230763  
     12018-04-18  Yusuke Suzuki  <utatane.tea@gmail.com>
     2
     3        [WebAssembly][Modules] Import globals from wasm modules
     4        https://bugs.webkit.org/show_bug.cgi?id=184736
     5
     6        Reviewed by JF Bastien.
     7
     8        This patch implements a feature importing globals to/from wasm modules.
     9        Since we are not supporting mutable globals now, we can just copy the
     10        global data when importing. Currently we do not support importing/exporting
     11        i64 globals. This will be supported once (1) mutable global bindings are
     12        specified and (2) BigInt based i64 importing/exporting is specified.
     13
     14        * wasm/js/JSWebAssemblyInstance.cpp:
     15        (JSC::JSWebAssemblyInstance::create):
     16        * wasm/js/WebAssemblyModuleRecord.cpp:
     17        (JSC::WebAssemblyModuleRecord::link):
     18
    1192018-04-18  Tomas Popela  <tpopela@redhat.com>
    220
  • trunk/Source/JavaScriptCore/jsc.cpp

    r230759 r230763  
    295295static EncodedJSValue JSC_HOST_CALL functionUndefined2(ExecState*);
    296296static EncodedJSValue JSC_HOST_CALL functionIsInt32(ExecState*);
     297static EncodedJSValue JSC_HOST_CALL functionIsPureNaN(ExecState*);
    297298static EncodedJSValue JSC_HOST_CALL functionEffectful42(ExecState*);
    298299static EncodedJSValue JSC_HOST_CALL functionIdentity(ExecState*);
    … …  
    521522        putDirectNativeFunction(vm, this, Identifier::fromString(&vm, "predictInt32"), 0, functionUndefined2, SetInt32HeapPredictionIntrinsic, static_cast<unsigned>(PropertyAttribute::DontEnum));
    522523        putDirectNativeFunction(vm, this, Identifier::fromString(&vm, "isInt32"), 0, functionIsInt32, CheckInt32Intrinsic, static_cast<unsigned>(PropertyAttribute::DontEnum));
     524        putDirectNativeFunction(vm, this, Identifier::fromString(&vm, "isPureNaN"), 0, functionIsPureNaN, CheckInt32Intrinsic, static_cast<unsigned>(PropertyAttribute::DontEnum));
    523525        putDirectNativeFunction(vm, this, Identifier::fromString(&vm, "fiatInt52"), 0, functionIdentity, FiatInt52Intrinsic, static_cast<unsigned>(PropertyAttribute::DontEnum));
    524526       
    … …  
    18801882}
    18811883
     1884EncodedJSValue JSC_HOST_CALL functionIsPureNaN(ExecState* exec)
     1885{
     1886    for (size_t i = 0; i < exec->argumentCount(); ++i) {
     1887        JSValue value = exec->argument(i);
     1888        if (!value.isNumber())
     1889            return JSValue::encode(jsBoolean(false));
     1890        double number = value.asNumber();
     1891        if (!std::isnan(number))
     1892            return JSValue::encode(jsBoolean(false));
     1893        if (isImpureNaN(number))
     1894            return JSValue::encode(jsBoolean(false));
     1895    }
     1896    return JSValue::encode(jsBoolean(true));
     1897}
     1898
    18821899EncodedJSValue JSC_HOST_CALL functionIdentity(ExecState* exec) { return JSValue::encode(exec->argument(0)); }
    18831900
  • trunk/Source/JavaScriptCore/wasm/js/JSWebAssemblyInstance.cpp

    r230759 r230763  
    181181    // Let funcs, memories and tables be initially-empty lists of callable JavaScript objects, WebAssembly.Memory objects and WebAssembly.Table objects, respectively.
    182182    // Let imports be an initially-empty list of external values.
    183     unsigned numImportGlobals = 0;
    184 
    185183    bool hasMemoryImport = false;
    186184    bool hasTableImport = false;
    … …  
    208206        switch (import.kind) {
    209207        case Wasm::ExternalKind::Function:
     208        case Wasm::ExternalKind::Global:
    210209            continue;
    211210        case Wasm::ExternalKind::Table:
    212211        case Wasm::ExternalKind::Memory:
    213         case Wasm::ExternalKind::Global:
    214212            break;
    215213        }
    … …  
    233231
    234232        switch (import.kind) {
    235         case Wasm::ExternalKind::Function: {
     233        case Wasm::ExternalKind::Function:
     234        case Wasm::ExternalKind::Global:
    236235            break;
    237         }
     236
    238237        case Wasm::ExternalKind::Table: {
    239238            RELEASE_ASSERT(!hasTableImport); // This should be guaranteed by a validation failure.
    … …  
    295294            break;
    296295        }
    297         case Wasm::ExternalKind::Global: {
    298             // 5. If i is a global import:
    299             // i. If i is not an immutable global, throw a TypeError.
    300             ASSERT(moduleInformation.globals[import.kindIndex].mutability == Wasm::Global::Immutable);
    301             // ii. If the global_type of i is i64 or Type(v) is not Number, throw a WebAssembly.LinkError.
    302             if (moduleInformation.globals[import.kindIndex].type == Wasm::I64)
    303                 return exception(createJSWebAssemblyLinkError(exec, vm, importFailMessage(import, "imported global", "cannot be an i64")));
    304             if (!value.isNumber())
    305                 return exception(createJSWebAssemblyLinkError(exec, vm, importFailMessage(import, "imported global", "must be a number")));
    306             // iii. Append ToWebAssemblyValue(v) to imports.
    307             ASSERT(numImportGlobals == import.kindIndex);
    308             switch (moduleInformation.globals[import.kindIndex].type) {
    309             case Wasm::I32:
    310                 jsInstance->instance().setGlobal(numImportGlobals++, value.toInt32(exec));
    311                 break;
    312             case Wasm::F32:
    313                 jsInstance->instance().setGlobal(numImportGlobals++, bitwise_cast<uint32_t>(value.toFloat(exec)));
    314                 break;
    315             case Wasm::F64:
    316                 jsInstance->instance().setGlobal(numImportGlobals++, bitwise_cast<uint64_t>(value.asNumber()));
    317                 break;
    318             default:
    319                 RELEASE_ASSERT_NOT_REACHED();
    320             }
    321             throwScope.assertNoException();
    322             break;
    323         }
    324296        }
    325297    }
    … …  
    336308            RELEASE_ASSERT(!moduleInformation.memory.isImport());
    337309
    338             auto* jsMemory = JSWebAssemblyMemory::create(exec, vm, exec->lexicalGlobalObject()->WebAssemblyMemoryStructure());
     310            auto* jsMemory = JSWebAssemblyMemory::create(exec, vm, globalObject->WebAssemblyMemoryStructure());
    339311            RETURN_IF_EXCEPTION(throwScope, nullptr);
    340312
    … …  
    364336            if (!wasmTable)
    365337                return exception(createJSWebAssemblyLinkError(exec, vm, "couldn't create Table"));
    366             JSWebAssemblyTable* table = JSWebAssemblyTable::create(exec, vm, exec->lexicalGlobalObject()->WebAssemblyTableStructure(), wasmTable.releaseNonNull());
     338            JSWebAssemblyTable* table = JSWebAssemblyTable::create(exec, vm, globalObject->WebAssemblyTableStructure(), wasmTable.releaseNonNull());
    367339            // We should always be able to allocate a JSWebAssemblyTable we've defined.
    368340            // If it's defined to be too large, we should have thrown a validation error.
    … …  
    376348    if (!jsInstance->memory()) {
    377349        // Make sure we have a dummy memory, so that wasm -> wasm thunks avoid checking for a nullptr Memory when trying to set pinned registers.
    378         auto* jsMemory = JSWebAssemblyMemory::create(exec, vm, exec->lexicalGlobalObject()->WebAssemblyMemoryStructure());
     350        auto* jsMemory = JSWebAssemblyMemory::create(exec, vm, globalObject->WebAssemblyMemoryStructure());
    379351        jsMemory->adopt(Wasm::Memory::create().releaseNonNull());
    380352        jsInstance->setMemory(vm, jsMemory);
    … …  
    382354    }
    383355   
    384     // Globals
    385     {
    386         ASSERT(numImportGlobals == moduleInformation.firstInternalGlobal);
    387         for (size_t globalIndex = numImportGlobals; globalIndex < moduleInformation.globals.size(); ++globalIndex) {
    388             const auto& global = moduleInformation.globals[globalIndex];
    389             ASSERT(global.initializationType != Wasm::Global::IsImport);
    390             if (global.initializationType == Wasm::Global::FromGlobalImport) {
    391                 ASSERT(global.initialBitsOrImportNumber < numImportGlobals);
    392                 jsInstance->instance().setGlobal(globalIndex, jsInstance->instance().loadI64Global(global.initialBitsOrImportNumber));
    393             } else
    394                 jsInstance->instance().setGlobal(globalIndex, global.initialBitsOrImportNumber);
    395         }
    396     }
    397 
    398356    return jsInstance;
    399357}
  • trunk/Source/JavaScriptCore/wasm/js/WebAssemblyModuleRecord.cpp

    r230759 r230763  
    119119        switch (import.kind) {
    120120        case Wasm::ExternalKind::Function:
     121        case Wasm::ExternalKind::Global:
    121122            break;
    122123        case Wasm::ExternalKind::Table:
    123124        case Wasm::ExternalKind::Memory:
    124         case Wasm::ExternalKind::Global:
    125125            continue;
    126126        }
    … …  
    226226            break;
    227227        }
     228
     229        case Wasm::ExternalKind::Global: {
     230            // 5. If i is a global import:
     231            // i. If i is not an immutable global, throw a TypeError.
     232            ASSERT(moduleInformation.globals[import.kindIndex].mutability == Wasm::Global::Immutable);
     233            // ii. If the global_type of i is i64 or Type(v) is not Number, throw a WebAssembly.LinkError.
     234            if (moduleInformation.globals[import.kindIndex].type == Wasm::I64)
     235                return exception(createJSWebAssemblyLinkError(exec, vm, importFailMessage(import, "imported global", "cannot be an i64")));
     236            if (!value.isNumber())
     237                return exception(createJSWebAssemblyLinkError(exec, vm, importFailMessage(import, "imported global", "must be a number")));
     238            // iii. Append ToWebAssemblyValue(v) to imports.
     239            switch (moduleInformation.globals[import.kindIndex].type) {
     240            case Wasm::I32:
     241                m_instance->instance().setGlobal(import.kindIndex, value.toInt32(exec));
     242                break;
     243            case Wasm::F32:
     244                m_instance->instance().setGlobal(import.kindIndex, bitwise_cast<uint32_t>(value.toFloat(exec)));
     245                break;
     246            case Wasm::F64:
     247                m_instance->instance().setGlobal(import.kindIndex, bitwise_cast<uint64_t>(value.asNumber()));
     248                break;
     249            default:
     250                RELEASE_ASSERT_NOT_REACHED();
     251            }
     252            scope.assertNoException();
     253            break;
     254        }
     255
    228256        case Wasm::ExternalKind::Table:
    229257        case Wasm::ExternalKind::Memory:
    230         case Wasm::ExternalKind::Global:
    231             break;
     258            break;
     259        }
     260    }
     261
     262    // Globals
     263    {
     264        for (size_t globalIndex = moduleInformation.firstInternalGlobal; globalIndex < moduleInformation.globals.size(); ++globalIndex) {
     265            const auto& global = moduleInformation.globals[globalIndex];
     266            ASSERT(global.initializationType != Wasm::Global::IsImport);
     267            if (global.initializationType == Wasm::Global::FromGlobalImport) {
     268                ASSERT(global.initialBitsOrImportNumber < moduleInformation.firstInternalGlobal);
     269                m_instance->instance().setGlobal(globalIndex, m_instance->instance().loadI64Global(global.initialBitsOrImportNumber));
     270            } else
     271                m_instance->instance().setGlobal(globalIndex, global.initialBitsOrImportNumber);
    232272        }
    233273    }
Note: See TracChangeset for help on using the changeset viewer.