Changeset 246504 in webkit


Ignore:
Timestamp:
Jun 17, 2019 11:44:18 AM (5 years ago)
Author:
Justin Michaud
Message:

[WASM-References] Add support for Funcref in parameters and return types
https://bugs.webkit.org/show_bug.cgi?id=198157

Reviewed by Yusuke Suzuki.

JSTests:

  • wasm/Builder.js:

(export.default.Builder.prototype._registerSectionBuilders.const.section.in.WASM.description.section.switch.section.case.string_appeared_here.this.section):

  • wasm/references/anyref_globals.js:
  • wasm/references/func_ref.js: Added.

(fullGC.gc.makeExportedFunction):
(makeExportedIdent):
(makeAnyfuncIdent):
(fun):
(assert.eq.instance.exports.fix.fun):
(assert.eq.instance.exports.fix):
(string_appeared_here.End.End.Function.End.Code.End.WebAssembly.imp.ref):
(string_appeared_here.End.End.Function.End.Code.End.WebAssembly):
(GetLocal.0.I32Const.0.TableSet.End.End.WebAssembly.fun):
(GetLocal.0.I32Const.0.TableSet.End.End.WebAssembly.assert.throws):
(GetLocal.0.I32Const.0.TableSet.End.End.WebAssembly):
(assert.throws):
(assert.throws.doTest):
(let.importedFun.of):
(makeAnyfuncIdent.fun):

  • wasm/references/validation.js:

(assert.throws):

  • wasm/wasm.json:

Source/JavaScriptCore:

Add support for funcref in parameters, globals, and in table.get/set. When converting a JSValue to
a funcref (nee anyfunc), we first make sure it is an exported wasm function or null.

We also add support for Ref.func. Anywhere a Ref.func is used, (statically) we construct a JS wrapper
for it so that we never need to construct JSValues when handling references. This should make threads
easier to implement.

Finally, we add some missing bounds checks for table.get/set.

  • wasm/WasmAirIRGenerator.cpp:

(JSC::Wasm::AirIRGenerator::tmpForType):
(JSC::Wasm::AirIRGenerator::moveOpForValueType):
(JSC::Wasm::AirIRGenerator::AirIRGenerator):
(JSC::Wasm::AirIRGenerator::addLocal):
(JSC::Wasm::AirIRGenerator::addConstant):
(JSC::Wasm::AirIRGenerator::addRefFunc):
(JSC::Wasm::AirIRGenerator::addTableSet):
(JSC::Wasm::AirIRGenerator::setGlobal):
(JSC::Wasm::AirIRGenerator::addReturn):

  • wasm/WasmB3IRGenerator.cpp:

(JSC::Wasm::B3IRGenerator::addLocal):
(JSC::Wasm::B3IRGenerator::addTableSet):
(JSC::Wasm::B3IRGenerator::addRefFunc):
(JSC::Wasm::B3IRGenerator::setGlobal):

  • wasm/WasmBBQPlan.cpp:

(JSC::Wasm::BBQPlan::compileFunctions):

  • wasm/WasmCallingConvention.h:

(JSC::Wasm::CallingConventionAir::marshallArgument const):
(JSC::Wasm::CallingConventionAir::setupCall const):

  • wasm/WasmExceptionType.h:
  • wasm/WasmFormat.h:

(JSC::Wasm::isValueType):
(JSC::Wasm::isSubtype):

  • wasm/WasmFunctionParser.h:

(JSC::Wasm::FunctionParser<Context>::parseExpression):
(JSC::Wasm::FunctionParser<Context>::parseUnreachableExpression):

  • wasm/WasmInstance.cpp:

(JSC::Wasm::Instance::Instance):
(JSC::Wasm::Instance::getFunctionWrapper const):
(JSC::Wasm::Instance::setFunctionWrapper):

  • wasm/WasmInstance.h:
  • wasm/WasmModuleInformation.h:

(JSC::Wasm::ModuleInformation::referencedFunctions const):
(JSC::Wasm::ModuleInformation::addReferencedFunction const):

  • wasm/WasmSectionParser.cpp:

(JSC::Wasm::SectionParser::parseGlobal):
(JSC::Wasm::SectionParser::parseInitExpr):

  • wasm/WasmValidate.cpp:

(JSC::Wasm::Validate::addTableGet):
(JSC::Wasm::Validate::addTableSet):
(JSC::Wasm::Validate::addRefIsNull):
(JSC::Wasm::Validate::addRefFunc):
(JSC::Wasm::Validate::setLocal):
(JSC::Wasm::Validate::addCall):
(JSC::Wasm::Validate::addCallIndirect):

  • wasm/js/JSToWasm.cpp:

(JSC::Wasm::createJSToWasmWrapper):

  • wasm/js/JSWebAssemblyHelpers.h:

(JSC::isWebAssemblyHostFunction):

  • wasm/js/JSWebAssemblyInstance.cpp:

(JSC::JSWebAssemblyInstance::visitChildren):

  • wasm/js/JSWebAssemblyRuntimeError.cpp:

(JSC::createJSWebAssemblyRuntimeError):

  • wasm/js/JSWebAssemblyRuntimeError.h:
  • wasm/js/WasmToJS.cpp:

(JSC::Wasm::handleBadI64Use):
(JSC::Wasm::wasmToJS):
(JSC::Wasm::emitWasmToJSException):

  • wasm/js/WasmToJS.h:
  • wasm/js/WebAssemblyFunction.cpp:

(JSC::callWebAssemblyFunction):
(JSC::WebAssemblyFunction::jsCallEntrypointSlow):

  • wasm/js/WebAssemblyModuleRecord.cpp:

(JSC::WebAssemblyModuleRecord::link):

  • wasm/wasm.json:
Location:
trunk
Files:
1 added
28 edited

Legend:

Unmodified
Added
Removed
  • trunk/JSTests/ChangeLog

    r246499 r246504  
     12019-06-17  Justin Michaud  <justin_michaud@apple.com>
     2
     3        [WASM-References] Add support for Funcref in parameters and return types
     4        https://bugs.webkit.org/show_bug.cgi?id=198157
     5
     6        Reviewed by Yusuke Suzuki.
     7
     8        * wasm/Builder.js:
     9        (export.default.Builder.prototype._registerSectionBuilders.const.section.in.WASM.description.section.switch.section.case.string_appeared_here.this.section):
     10        * wasm/references/anyref_globals.js:
     11        * wasm/references/func_ref.js: Added.
     12        (fullGC.gc.makeExportedFunction):
     13        (makeExportedIdent):
     14        (makeAnyfuncIdent):
     15        (fun):
     16        (assert.eq.instance.exports.fix.fun):
     17        (assert.eq.instance.exports.fix):
     18        (string_appeared_here.End.End.Function.End.Code.End.WebAssembly.imp.ref):
     19        (string_appeared_here.End.End.Function.End.Code.End.WebAssembly):
     20        (GetLocal.0.I32Const.0.TableSet.End.End.WebAssembly.fun):
     21        (GetLocal.0.I32Const.0.TableSet.End.End.WebAssembly.assert.throws):
     22        (GetLocal.0.I32Const.0.TableSet.End.End.WebAssembly):
     23        (assert.throws):
     24        (assert.throws.doTest):
     25        (let.importedFun.of):
     26        (makeAnyfuncIdent.fun):
     27        * wasm/references/validation.js:
     28        (assert.throws):
     29        * wasm/wasm.json:
     30
    1312019-06-17  Ross Kirsling  <ross.kirsling@sony.com>
    232
  • trunk/JSTests/wasm/Builder.js

    r245765 r246504  
    535535                        GetGlobal: (type, initValue, mutability) => {
    536536                            s.data.push({ type, op: "get_global", mutability: _normalizeMutability(mutability), initValue });
     537                            return _errorHandlingProxyFor(globalBuilder);
     538                        },
     539                        RefFunc: (type, initValue, mutability) => {
     540                            s.data.push({ type, op: "ref.func", mutability: _normalizeMutability(mutability), initValue });
    537541                            return _errorHandlingProxyFor(globalBuilder);
    538542                        },
  • trunk/JSTests/wasm/references/anyref_globals.js

    r245765 r246504  
    5757const obj = { test: "hi" }
    5858
    59 $1.exports.set_glob(obj); assert.eq($1.exports.get_glob(), obj);
     59assert.throws(() => $1.exports.expglob2 = null, TypeError, "Attempted to assign to readonly property.")
     60
     61$1.exports.set_glob(obj); assert.eq($1.exports.get_glob(), obj); assert.eq($1.exports.expglob2, "hi")
    6062$1.exports.set_glob(5); assert.eq($1.exports.get_glob(), 5)
    6163$1.exports.set_glob(null); assert.eq($1.exports.get_glob(), null)
  • trunk/JSTests/wasm/references/validation.js

    r246139 r246504  
    6464    bin.trim();
    6565
    66     assert.throws(() => new WebAssembly.Module(bin.get()), WebAssembly.CompileError, "WebAssembly.Module doesn't validate: table.set expects the table to have type Anyref, in function at index 0 (evaluating 'new WebAssembly.Module(bin.get())')");
     66    assert.throws(() => new WebAssembly.Module(bin.get()), WebAssembly.CompileError, "WebAssembly.Module doesn't validate: table.set value to type Anyref expected Anyfunc, in function at index 0 (evaluating 'new WebAssembly.Module(bin.get())')");
    6767}
    6868
     
    8787    bin.trim();
    8888
    89     assert.throws(() => new WebAssembly.Module(bin.get()), WebAssembly.CompileError, "WebAssembly.Module doesn't validate: table.get expects the table to have type Anyref, in function at index 0 (evaluating 'new WebAssembly.Module(bin.get())')");
     89    assert.throws(() => new WebAssembly.Module(bin.get()), WebAssembly.CompileError, "WebAssembly.Module doesn't validate: control flow returns with unexpected type, in function at index 0 (evaluating 'new WebAssembly.Module(bin.get())')");
    9090}
    9191
  • trunk/JSTests/wasm/wasm.json

    r246139 r246504  
    1212        "f32":     { "type": "varint7", "value":  -3, "b3type": "B3::Float" },
    1313        "f64":     { "type": "varint7", "value":  -4, "b3type": "B3::Double" },
    14         "anyfunc": { "type": "varint7", "value": -16, "b3type": "B3::Void" },
     14        "anyfunc": { "type": "varint7", "value": -16, "b3type": "B3::Int64" },
    1515        "anyref":  { "type": "varint7", "value": -17, "b3type": "B3::Int64" },
    1616        "func":    { "type": "varint7", "value": -32, "b3type": "B3::Void" },
    1717        "void":    { "type": "varint7", "value": -64, "b3type": "B3::Void" }
    1818    },
    19     "value_type": ["i32", "i64", "f32", "f64", "anyref"],
    20     "block_type": ["i32", "i64", "f32", "f64", "void", "anyref"],
     19    "value_type": ["i32", "i64", "f32", "f64", "anyref", "anyfunc"],
     20    "block_type": ["i32", "i64", "f32", "f64", "void", "anyref", "anyfunc"],
    2121    "elem_type": ["anyfunc","anyref"],
    2222    "external_kind": {
     
    6060        "f64.const":           { "category": "special",    "value":  68, "return": ["f64"],      "parameter": [],                       "immediate": [{"name": "value",          "type": "double"}],                                               "description": "a constant value interpreted as f64" },
    6161        "f32.const":           { "category": "special",    "value":  67, "return": ["f32"],      "parameter": [],                       "immediate": [{"name": "value",          "type": "float"}],                                                "description": "a constant value interpreted as f32" },
    62         "ref.null":            { "category": "special",    "value": 208, "return": ["anyref"],   "parameter": [],                       "immediate": [],                                                                                           "description": "a constant null reference" },
     62        "ref.null":            { "category": "special",    "value": 208, "return": ["anyfunc"],  "parameter": [],                       "immediate": [],                                                                                           "description": "a constant null reference" },
    6363        "ref.is_null":         { "category": "special",    "value": 209, "return": ["i32"],      "parameter": ["anyref"],               "immediate": [],                                                                                           "description": "determine if a reference is null" },
     64        "ref.func":            { "category": "special",    "value": 210, "return": ["anyfunc"],  "parameter": [],                       "immediate": [{"name": "function_index",  "type": "varuint32"}],                                           "description": "return a reference to the function at the given index" },
    6465        "get_local":           { "category": "special",    "value":  32, "return": ["any"],      "parameter": [],                       "immediate": [{"name": "local_index",    "type": "varuint32"}],                                            "description": "read a local variable or parameter" },
    6566        "set_local":           { "category": "special",    "value":  33, "return": [],           "parameter": ["any"],                  "immediate": [{"name": "local_index",    "type": "varuint32"}],                                            "description": "write a local variable or parameter" },
  • trunk/Source/JavaScriptCore/ChangeLog

    r246490 r246504  
     12019-06-17  Justin Michaud  <justin_michaud@apple.com>
     2
     3        [WASM-References] Add support for Funcref in parameters and return types
     4        https://bugs.webkit.org/show_bug.cgi?id=198157
     5
     6        Reviewed by Yusuke Suzuki.
     7
     8        Add support for funcref in parameters, globals, and in table.get/set. When converting a JSValue to
     9        a funcref (nee anyfunc), we first make sure it is an exported wasm function or null.
     10
     11        We also add support for Ref.func. Anywhere a Ref.func is used, (statically) we construct a JS wrapper
     12        for it so that we never need to construct JSValues when handling references. This should make threads
     13        easier to implement.
     14
     15        Finally, we add some missing bounds checks for table.get/set.
     16
     17        * wasm/WasmAirIRGenerator.cpp:
     18        (JSC::Wasm::AirIRGenerator::tmpForType):
     19        (JSC::Wasm::AirIRGenerator::moveOpForValueType):
     20        (JSC::Wasm::AirIRGenerator::AirIRGenerator):
     21        (JSC::Wasm::AirIRGenerator::addLocal):
     22        (JSC::Wasm::AirIRGenerator::addConstant):
     23        (JSC::Wasm::AirIRGenerator::addRefFunc):
     24        (JSC::Wasm::AirIRGenerator::addTableSet):
     25        (JSC::Wasm::AirIRGenerator::setGlobal):
     26        (JSC::Wasm::AirIRGenerator::addReturn):
     27        * wasm/WasmB3IRGenerator.cpp:
     28        (JSC::Wasm::B3IRGenerator::addLocal):
     29        (JSC::Wasm::B3IRGenerator::addTableSet):
     30        (JSC::Wasm::B3IRGenerator::addRefFunc):
     31        (JSC::Wasm::B3IRGenerator::setGlobal):
     32        * wasm/WasmBBQPlan.cpp:
     33        (JSC::Wasm::BBQPlan::compileFunctions):
     34        * wasm/WasmCallingConvention.h:
     35        (JSC::Wasm::CallingConventionAir::marshallArgument const):
     36        (JSC::Wasm::CallingConventionAir::setupCall const):
     37        * wasm/WasmExceptionType.h:
     38        * wasm/WasmFormat.h:
     39        (JSC::Wasm::isValueType):
     40        (JSC::Wasm::isSubtype):
     41        * wasm/WasmFunctionParser.h:
     42        (JSC::Wasm::FunctionParser<Context>::parseExpression):
     43        (JSC::Wasm::FunctionParser<Context>::parseUnreachableExpression):
     44        * wasm/WasmInstance.cpp:
     45        (JSC::Wasm::Instance::Instance):
     46        (JSC::Wasm::Instance::getFunctionWrapper const):
     47        (JSC::Wasm::Instance::setFunctionWrapper):
     48        * wasm/WasmInstance.h:
     49        * wasm/WasmModuleInformation.h:
     50        (JSC::Wasm::ModuleInformation::referencedFunctions const):
     51        (JSC::Wasm::ModuleInformation::addReferencedFunction const):
     52        * wasm/WasmSectionParser.cpp:
     53        (JSC::Wasm::SectionParser::parseGlobal):
     54        (JSC::Wasm::SectionParser::parseInitExpr):
     55        * wasm/WasmValidate.cpp:
     56        (JSC::Wasm::Validate::addTableGet):
     57        (JSC::Wasm::Validate::addTableSet):
     58        (JSC::Wasm::Validate::addRefIsNull):
     59        (JSC::Wasm::Validate::addRefFunc):
     60        (JSC::Wasm::Validate::setLocal):
     61        (JSC::Wasm::Validate::addCall):
     62        (JSC::Wasm::Validate::addCallIndirect):
     63        * wasm/js/JSToWasm.cpp:
     64        (JSC::Wasm::createJSToWasmWrapper):
     65        * wasm/js/JSWebAssemblyHelpers.h:
     66        (JSC::isWebAssemblyHostFunction):
     67        * wasm/js/JSWebAssemblyInstance.cpp:
     68        (JSC::JSWebAssemblyInstance::visitChildren):
     69        * wasm/js/JSWebAssemblyRuntimeError.cpp:
     70        (JSC::createJSWebAssemblyRuntimeError):
     71        * wasm/js/JSWebAssemblyRuntimeError.h:
     72        * wasm/js/WasmToJS.cpp:
     73        (JSC::Wasm::handleBadI64Use):
     74        (JSC::Wasm::wasmToJS):
     75        (JSC::Wasm::emitWasmToJSException):
     76        * wasm/js/WasmToJS.h:
     77        * wasm/js/WebAssemblyFunction.cpp:
     78        (JSC::callWebAssemblyFunction):
     79        (JSC::WebAssemblyFunction::jsCallEntrypointSlow):
     80        * wasm/js/WebAssemblyModuleRecord.cpp:
     81        (JSC::WebAssemblyModuleRecord::link):
     82        * wasm/wasm.json:
     83
    1842019-06-16  Darin Adler  <darin@apple.com>
    285
  • trunk/Source/JavaScriptCore/wasm/WasmAirIRGenerator.cpp

    r246451 r246504  
    235235    // References
    236236    PartialResult WARN_UNUSED_RETURN addRefIsNull(ExpressionType& value, ExpressionType& result);
     237    PartialResult WARN_UNUSED_RETURN addRefFunc(uint32_t index, ExpressionType& result);
    237238
    238239    // Tables
    239     PartialResult WARN_UNUSED_RETURN addTableGet(ExpressionType& idx, ExpressionType& result);
    240     PartialResult WARN_UNUSED_RETURN addTableSet(ExpressionType& idx, ExpressionType& value);
     240    PartialResult WARN_UNUSED_RETURN addTableGet(ExpressionType& index, ExpressionType& result);
     241    PartialResult WARN_UNUSED_RETURN addTableSet(ExpressionType& index, ExpressionType& value);
    241242
    242243    // Locals
     
    371372        case Type::I64:
    372373        case Type::Anyref:
     374        case Type::Anyfunc:
    373375            return g64();
    374376        case Type::F32:
     
    555557        case Type::I64:
    556558        case Type::Anyref:
     559        case Type::Anyfunc:
    557560            return Move;
    558561        case Type::F32:
     
    800803        case Type::I64:
    801804        case Type::Anyref:
     805        case Type::Anyfunc:
    802806            append(Move, arg, m_locals[i]);
    803807            break;
     
    885889        switch (type) {
    886890        case Type::Anyref:
     891        case Type::Anyfunc:
    887892            append(Move, Arg::imm(JSValue::encode(jsNull())), local);
    888893            break;
     
    919924    case Type::I64:
    920925    case Type::Anyref:
     926    case Type::Anyfunc:
    921927        append(block, Move, Arg::bigImm(value), result);
    922928        break;
     
    954960}
    955961
    956 auto AirIRGenerator::addTableGet(ExpressionType& idx, ExpressionType& result) -> PartialResult
     962auto AirIRGenerator::addRefFunc(uint32_t index, ExpressionType& result) -> PartialResult
    957963{
    958964    // FIXME: Emit this inline <https://bugs.webkit.org/show_bug.cgi?id=198506>.
    959     ASSERT(idx.tmp());
    960     ASSERT(idx.type() == Type::I32);
     965    result = tmpForType(Type::Anyfunc);
     966    emitCCall(&doWasmRefFunc, result, instanceValue(), addConstant(Type::I32, index));
     967
     968    return { };
     969}
     970
     971auto AirIRGenerator::addTableGet(ExpressionType& index, ExpressionType& result) -> PartialResult
     972{
     973    // FIXME: Emit this inline <https://bugs.webkit.org/show_bug.cgi?id=198506>.
     974    ASSERT(index.tmp());
     975    ASSERT(index.type() == Type::I32);
    961976    result = tmpForType(Type::Anyref);
    962977
    963     uint64_t (*doGet)(Instance*, int32_t) = [] (Instance* instance, int32_t idx) -> uint64_t {
    964         return JSValue::encode(instance->table()->get(idx));
    965     };
    966 
    967     emitCCall(doGet, result, instanceValue(), idx);
    968 
    969     return { };
    970 }
    971 
    972 auto AirIRGenerator::addTableSet(ExpressionType& idx, ExpressionType& value) -> PartialResult
     978    emitCCall(&getWasmTableElement, result, instanceValue(), index);
     979    emitCheck([&] {
     980        return Inst(BranchTest32, nullptr, Arg::resCond(MacroAssembler::Zero), result, result);
     981    }, [=] (CCallHelpers& jit, const B3::StackmapGenerationParams&) {
     982        this->emitThrowException(jit, ExceptionType::OutOfBoundsTableAccess);
     983    });
     984
     985    return { };
     986}
     987
     988auto AirIRGenerator::addTableSet(ExpressionType& index, ExpressionType& value) -> PartialResult
    973989{
    974990    // FIXME: Emit this inline <https://bugs.webkit.org/show_bug.cgi?id=198506>.
    975     ASSERT(idx.tmp());
    976     ASSERT(idx.type() == Type::I32);
     991    ASSERT(index.tmp());
     992    ASSERT(index.type() == Type::I32);
    977993    ASSERT(value.tmp());
    978994
    979     void (*doSet)(Instance*, int32_t, uint64_t value) = [] (Instance* instance, int32_t idx, uint64_t value) -> void {
    980         // FIXME: We need to box wasm Funcrefs once they are supported here.
    981         // <https://bugs.webkit.org/show_bug.cgi?id=198157>
    982         instance->table()->set(idx, JSValue::decode(value));
    983     };
    984 
    985     emitCCall(doSet, TypedTmp(), instanceValue(), idx, value);
     995    auto shouldThrow = g32();
     996    emitCCall(&setWasmTableElement, shouldThrow, instanceValue(), index, value);
     997
     998    emitCheck([&] {
     999        return Inst(BranchTest32, nullptr, Arg::resCond(MacroAssembler::Zero), shouldThrow, shouldThrow);
     1000    }, [=] (CCallHelpers& jit, const B3::StackmapGenerationParams&) {
     1001        this->emitThrowException(jit, ExceptionType::OutOfBoundsTableAccess);
     1002    });
    9861003
    9871004    return { };
     
    11041121    }
    11051122
    1106     if (type == Anyref)
     1123    if (isSubtype(type, Anyref))
    11071124        emitWriteBarrierForJSWrapper();
    11081125
     
    16241641        case Type::I64:
    16251642        case Type::Anyref:
     1643        case Type::Anyfunc:
    16261644            append(Move, returnValues[0], returnValueGPR);
    16271645            append(Ret64, returnValueGPR);
  • trunk/Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp

    r246451 r246504  
    188188    // References
    189189    PartialResult WARN_UNUSED_RETURN addRefIsNull(ExpressionType& value, ExpressionType& result);
     190    PartialResult WARN_UNUSED_RETURN addRefFunc(uint32_t index, ExpressionType& result);
    190191
    191192    // Tables
    192     PartialResult WARN_UNUSED_RETURN addTableGet(ExpressionType& idx, ExpressionType& result);
    193     PartialResult WARN_UNUSED_RETURN addTableSet(ExpressionType& idx, ExpressionType& value);
     193    PartialResult WARN_UNUSED_RETURN addTableGet(ExpressionType& index, ExpressionType& result);
     194    PartialResult WARN_UNUSED_RETURN addTableSet(ExpressionType& index, ExpressionType& value);
    194195
    195196    // Locals
     
    539540        Variable* local = m_proc.addVariable(toB3Type(type));
    540541        m_locals.uncheckedAppend(local);
    541         auto val = type == Anyref ? JSValue::encode(jsNull()) : 0;
     542        auto val = isSubtype(type, Anyref) ? JSValue::encode(jsNull()) : 0;
    542543        m_currentBlock->appendNew<VariableValue>(m_proc, Set, Origin(), local, constant(toB3Type(type), val, Origin()));
    543544    }
     
    566567}
    567568
    568 auto B3IRGenerator::addTableGet(ExpressionType& idx, ExpressionType& result) -> PartialResult
     569auto B3IRGenerator::addTableGet(ExpressionType& index, ExpressionType& result) -> PartialResult
    569570{
    570571    // FIXME: Emit this inline <https://bugs.webkit.org/show_bug.cgi?id=198506>.
    571     uint64_t (*doGet)(Instance*, int32_t) = [] (Instance* instance, int32_t idx) -> uint64_t {
    572         return JSValue::encode(instance->table()->get(idx));
    573     };
    574 
    575572    result = m_currentBlock->appendNew<CCallValue>(m_proc, toB3Type(Anyref), origin(),
    576         m_currentBlock->appendNew<ConstPtrValue>(m_proc, origin(), tagCFunctionPtr<void*>(doGet, B3CCallPtrTag)),
    577         instanceValue(), idx);
    578 
    579     return { };
    580 }
    581 
    582 auto B3IRGenerator::addTableSet(ExpressionType& idx, ExpressionType& value) -> PartialResult
     573        m_currentBlock->appendNew<ConstPtrValue>(m_proc, origin(), tagCFunctionPtr<void*>(&getWasmTableElement, B3CCallPtrTag)),
     574        instanceValue(), index);
     575
     576    {
     577        CheckValue* check = m_currentBlock->appendNew<CheckValue>(m_proc, Check, origin(),
     578            m_currentBlock->appendNew<Value>(m_proc, Equal, origin(), result, m_currentBlock->appendNew<Const64Value>(m_proc, origin(), 0)));
     579
     580        check->setGenerator([=] (CCallHelpers& jit, const B3::StackmapGenerationParams&) {
     581            this->emitExceptionCheck(jit, ExceptionType::OutOfBoundsTableAccess);
     582        });
     583    }
     584
     585    return { };
     586}
     587
     588auto B3IRGenerator::addTableSet(ExpressionType& index, ExpressionType& value) -> PartialResult
    583589{
    584590    // FIXME: Emit this inline <https://bugs.webkit.org/show_bug.cgi?id=198506>.
    585     void (*doSet)(Instance*, int32_t, uint64_t value) = [] (Instance* instance, int32_t idx, uint64_t value) -> void {
    586         // FIXME: We need to box wasm Funcrefs once they are supported here.
    587         // <https://bugs.webkit.org/show_bug.cgi?id=198157>
    588         instance->table()->set(idx, JSValue::decode(value));
    589     };
    590 
    591     m_currentBlock->appendNew<CCallValue>(m_proc, B3::Void, origin(),
    592         m_currentBlock->appendNew<ConstPtrValue>(m_proc, origin(), tagCFunctionPtr<void*>(doSet, B3CCallPtrTag)),
    593         instanceValue(), idx, value);
     591    auto shouldThrow = m_currentBlock->appendNew<CCallValue>(m_proc, B3::Int32, origin(),
     592        m_currentBlock->appendNew<ConstPtrValue>(m_proc, origin(), tagCFunctionPtr<void*>(&setWasmTableElement, B3CCallPtrTag)),
     593        instanceValue(), index, value);
     594
     595    {
     596        CheckValue* check = m_currentBlock->appendNew<CheckValue>(m_proc, Check, origin(),
     597            m_currentBlock->appendNew<Value>(m_proc, Equal, origin(), shouldThrow, m_currentBlock->appendNew<Const32Value>(m_proc, origin(), 0)));
     598
     599        check->setGenerator([=] (CCallHelpers& jit, const B3::StackmapGenerationParams&) {
     600            this->emitExceptionCheck(jit, ExceptionType::OutOfBoundsTableAccess);
     601        });
     602    }
     603
     604    return { };
     605}
     606
     607auto B3IRGenerator::addRefFunc(uint32_t index, ExpressionType& result) -> PartialResult
     608{
     609    // FIXME: Emit this inline <https://bugs.webkit.org/show_bug.cgi?id=198506>.
     610
     611    result = m_currentBlock->appendNew<CCallValue>(m_proc, B3::Int64, origin(),
     612        m_currentBlock->appendNew<ConstPtrValue>(m_proc, origin(), tagCFunctionPtr<void*>(&doWasmRefFunc, B3CCallPtrTag)),
     613        instanceValue(), addConstant(Type::I32, index));
    594614
    595615    return { };
     
    680700    m_currentBlock->appendNew<MemoryValue>(m_proc, Store, origin(), value, globalsArray, safeCast<int32_t>(index * sizeof(Register)));
    681701
    682     if (m_info.globals[index].type == Anyref)
     702    if (isSubtype(m_info.globals[index].type, Anyref))
    683703        emitWriteBarrierForJSWrapper();
    684704
  • trunk/Source/JavaScriptCore/wasm/WasmBBQPlan.cpp

    r246368 r246504  
    287287        m_wasmInternalFunctions[functionIndex] = WTFMove(*parseAndCompileResult);
    288288
    289         if (m_exportedFunctionIndices.contains(functionIndex)) {
     289        if (m_exportedFunctionIndices.contains(functionIndex) || m_moduleInformation->referencedFunctions().contains(functionIndex)) {
    290290            auto locker = holdLock(m_lock);
    291291            auto result = m_embedderToWasmInternalFunctions.add(functionIndex, m_createEmbedderWrapper(m_compilationContexts[functionIndex], signature, &m_unlinkedWasmToWasmCalls[functionIndex], m_moduleInformation.get(), m_mode, functionIndex));
  • trunk/Source/JavaScriptCore/wasm/WasmCallingConvention.h

    r245496 r246504  
    237237        case Type::I64:
    238238        case Type::Anyref:
     239        case Wasm::Anyfunc:
    239240            marshallArgumentImpl(m_gprArgs, gpArgumentCount, stackOffset, regFunc, stackFunc);
    240241            break;
     
    302303        case Type::I64:
    303304        case Type::Anyref:
     305        case Wasm::Anyfunc:
    304306            patchpoint->resultConstraint = B3::ValueRep::reg(GPRInfo::returnValueGPR);
    305307            break;
  • trunk/Source/JavaScriptCore/wasm/WasmExceptionType.h

    r238376 r246504  
    3434#define FOR_EACH_EXCEPTION(macro) \
    3535    macro(OutOfBoundsMemoryAccess,  "Out of bounds memory access") \
     36    macro(OutOfBoundsTableAccess,  "Out of bounds table access") \
    3637    macro(OutOfBoundsCallIndirect, "Out of bounds call_indirect") \
    3738    macro(NullTableEntry,  "call_indirect to a null table entry") \
     
    4344    macro(StackOverflow, "Stack overflow") \
    4445    macro(I64ArgumentType, "WebAssembly function with an i64 argument can't be called from JavaScript") \
    45     macro(I64ReturnType, "WebAssembly function that returns i64 can't be called from JavaScript")
     46    macro(I64ReturnType, "WebAssembly function that returns i64 can't be called from JavaScript") \
     47    macro(FuncrefNotWasm, "Anyfunc must be an exported wasm function")
    4648
    4749enum class ExceptionType : uint32_t {
  • trunk/Source/JavaScriptCore/wasm/WasmFormat.h

    r246139 r246504  
    6969        return true;
    7070    case Anyref:
     71    case Anyfunc:
    7172        return Options::useWebAssemblyReferences();
    7273    default:
     
    7475    }
    7576    return false;
     77}
     78
     79inline bool isSubtype(Type sub, Type parent)
     80{
     81    if (sub == parent)
     82        return true;
     83    return sub == Anyfunc && parent == Anyref;
    7684}
    7785   
     
    139147        IsImport,
    140148        FromGlobalImport,
     149        FromRefFunc,
    141150        FromExpression
    142151    };
     
    235244    Optional<uint32_t> maximum() const { return m_maximum; }
    236245    TableElementType type() const { return m_type; }
     246    Wasm::Type wasmType() const { return m_type == TableElementType::Funcref ? Type::Anyfunc : Type::Anyref; }
    237247
    238248private:
  • trunk/Source/JavaScriptCore/wasm/WasmFunctionParser.h

    r246139 r246504  
    284284    case TableGet: {
    285285        WASM_PARSER_FAIL_IF(!Options::useWebAssemblyReferences(), "references are not enabled");
    286         ExpressionType result, idx;
    287         WASM_TRY_POP_EXPRESSION_STACK_INTO(idx, "table.get");
    288         WASM_TRY_ADD_TO_CONTEXT(addTableGet(idx, result));
     286        ExpressionType result, index;
     287        WASM_TRY_POP_EXPRESSION_STACK_INTO(index, "table.get");
     288        WASM_TRY_ADD_TO_CONTEXT(addTableGet(index, result));
    289289        m_expressionStack.append(result);
    290290        return { };
     
    293293    case TableSet: {
    294294        WASM_PARSER_FAIL_IF(!Options::useWebAssemblyReferences(), "references are not enabled");
    295         ExpressionType val, idx;
     295        ExpressionType val, index;
    296296        WASM_TRY_POP_EXPRESSION_STACK_INTO(val, "table.set");
    297         WASM_TRY_POP_EXPRESSION_STACK_INTO(idx, "table.set");
    298         WASM_TRY_ADD_TO_CONTEXT(addTableSet(idx, val));
     297        WASM_TRY_POP_EXPRESSION_STACK_INTO(index, "table.set");
     298        WASM_TRY_ADD_TO_CONTEXT(addTableSet(index, val));
    299299        return { };
    300300    }
     
    302302    case RefNull: {
    303303        WASM_PARSER_FAIL_IF(!Options::useWebAssemblyReferences(), "references are not enabled");
    304         m_expressionStack.append(m_context.addConstant(Anyref, JSValue::encode(jsNull())));
     304        m_expressionStack.append(m_context.addConstant(Anyfunc, JSValue::encode(jsNull())));
    305305        return { };
    306306    }
     
    311311        WASM_TRY_POP_EXPRESSION_STACK_INTO(value, "ref.is_null");
    312312        WASM_TRY_ADD_TO_CONTEXT(addRefIsNull(value, result));
     313        m_expressionStack.append(result);
     314        return { };
     315    }
     316
     317    case RefFunc: {
     318        uint32_t index;
     319        ExpressionType result;
     320        WASM_PARSER_FAIL_IF(!Options::useWebAssemblyReferences(), "references are not enabled");
     321        WASM_PARSER_FAIL_IF(!parseVarUInt32(index), "can't get index for ref.func");
     322
     323        WASM_TRY_ADD_TO_CONTEXT(addRefFunc(index, result));
    313324        m_expressionStack.append(result);
    314325        return { };
     
    682693    }
    683694
     695    case RefFunc: {
     696        uint32_t unused;
     697        WASM_PARSER_FAIL_IF(!parseVarUInt32(unused), "can't get immediate for ", m_currentOpcode, " in unreachable context");
     698        WASM_PARSER_FAIL_IF(!Options::useWebAssemblyReferences(), "references are not enabled");
     699        return { };
     700    }
     701
    684702    case GrowMemory:
    685703    case CurrentMemory: {
  • trunk/Source/JavaScriptCore/wasm/WasmInstance.cpp

    r246095 r246504  
    3030
    3131#include "JSCInlines.h"
     32#include "JSWebAssemblyHelpers.h"
    3233#include "JSWebAssemblyInstance.h"
    3334#include "Register.h"
     
    5859    memset(static_cast<void*>(m_globals.get()), 0, globalMemoryByteSize(m_module.get()));
    5960    for (unsigned i = 0; i < m_module->moduleInformation().globals.size(); ++i) {
    60         if (m_module.get().moduleInformation().globals[i].type == Anyref)
     61        if (isSubtype(m_module.get().moduleInformation().globals[i].type, Anyref))
    6162            m_globalsToMark.set(i);
    6263    }
     
    8182}
    8283
     84JSValue Instance::getFunctionWrapper(unsigned i) const
     85{
     86    JSValue value = m_functionWrappers.get(i).get();
     87    if (value.isEmpty())
     88        return jsNull();
     89    return value;
     90}
     91
     92void Instance::setFunctionWrapper(unsigned i, JSValue value)
     93{
     94    ASSERT(m_owner);
     95    ASSERT(value.isFunction(*owner<JSWebAssemblyInstance>()->vm()));
     96    ASSERT(!m_functionWrappers.contains(i));
     97    auto locker = holdLock(owner<JSWebAssemblyInstance>()->cellLock());
     98    m_functionWrappers.set(i, WriteBarrier<Unknown>(*owner<JSWebAssemblyInstance>()->vm(), owner<JSWebAssemblyInstance>(), value));
     99    ASSERT(getFunctionWrapper(i) == value);
     100}
     101
     102EncodedJSValue getWasmTableElement(Instance* instance, int32_t signedIndex)
     103{
     104    if (signedIndex < 0)
     105        return 0;
     106
     107    uint32_t index = signedIndex;
     108    if (index >= instance->table()->length())
     109        return 0;
     110
     111    return JSValue::encode(instance->table()->get(index));
     112}
     113
     114bool setWasmTableElement(Instance* instance, int32_t signedIndex, EncodedJSValue encValue)
     115{
     116    if (signedIndex < 0)
     117        return false;
     118
     119    uint32_t index = signedIndex;
     120    if (index >= instance->table()->length())
     121        return false;
     122
     123    JSValue value = JSValue::decode(encValue);
     124    if (instance->table()->type() == Wasm::TableElementType::Anyref)
     125        instance->table()->set(index, value);
     126    else if (instance->table()->type() == Wasm::TableElementType::Funcref) {
     127        WebAssemblyFunction* wasmFunction;
     128        WebAssemblyWrapperFunction* wasmWrapperFunction;
     129
     130        if (isWebAssemblyHostFunction(*instance->owner<JSObject>()->vm(), value, wasmFunction, wasmWrapperFunction)) {
     131            ASSERT(!!wasmFunction || !!wasmWrapperFunction);
     132            if (wasmFunction)
     133                instance->table()->asFuncrefTable()->setFunction(index, jsCast<JSObject*>(value), wasmFunction->importableFunction(), &wasmFunction->instance()->instance());
     134            else
     135                instance->table()->asFuncrefTable()->setFunction(index, jsCast<JSObject*>(value), wasmWrapperFunction->importableFunction(), &wasmWrapperFunction->instance()->instance());
     136        } else if (value.isNull())
     137            instance->table()->clear(index);
     138        else
     139            ASSERT_NOT_REACHED();
     140    } else
     141        ASSERT_NOT_REACHED();
     142
     143    return true;
     144}
     145
     146EncodedJSValue doWasmRefFunc(Instance* instance, uint32_t index)
     147{
     148    JSValue value = instance->getFunctionWrapper(index);
     149    ASSERT(value.isFunction(*instance->owner<JSObject>()->vm()));
     150    return JSValue::encode(value);
     151}
     152
    83153} } // namespace JSC::Wasm
    84154
  • trunk/Source/JavaScriptCore/wasm/WasmInstance.h

    r246368 r246504  
    4040
    4141struct Context;
     42class Instance;
     43
     44EncodedJSValue getWasmTableElement(Instance*, int32_t);
     45bool setWasmTableElement(Instance*, int32_t, EncodedJSValue encValue);
     46EncodedJSValue doWasmRefFunc(Instance*, uint32_t);
    4247
    4348class Instance : public ThreadSafeRefCounted<Instance>, public CanMakeWeakPtr<Instance> {
    4449public:
    4550    using StoreTopCallFrameCallback = WTF::Function<void(void*)>;
     51    using FunctionWrapperMap = HashMap<uint32_t, WriteBarrier<Unknown>, IntHash<uint32_t>, WTF::UnsignedWithZeroKeyHashTraits<uint32_t>>;
    4652
    4753    static Ref<Instance> create(Context*, Ref<Module>&&, EntryFrame** pointerToTopEntryFrame, void** pointerToActualStackLimit, StoreTopCallFrameCallback&&);
     
    9298    void setGlobal(unsigned, JSValue);
    9399    const BitVector& globalsToMark() { return m_globalsToMark; }
     100    JSValue getFunctionWrapper(unsigned) const;
     101    typename FunctionWrapperMap::ValuesConstIteratorRange functionWrappers() const { return m_functionWrappers.values(); }
     102    void setFunctionWrapper(unsigned, JSValue);
    94103
    95104    static ptrdiff_t offsetOfMemory() { return OBJECT_OFFSETOF(Instance, m_memory); }
     
    160169    };
    161170    MallocPtr<GlobalValue> m_globals;
     171    FunctionWrapperMap m_functionWrappers;
    162172    BitVector m_globalsToMark;
    163173    EntryFrame** m_pointerToTopEntryFrame { nullptr };
  • trunk/Source/JavaScriptCore/wasm/WasmModuleInformation.h

    r239427 r246504  
    3030#include "WasmFormat.h"
    3131
     32#include <wtf/BitVector.h>
    3233#include <wtf/Optional.h>
    3334
     
    6768    uint32_t tableCount() const { return tableInformation ? 1 : 0; }
    6869
     70    const BitVector& referencedFunctions() const { return m_referencedFunctions; }
     71    void addReferencedFunction(unsigned index) const { m_referencedFunctions.set(index); }
     72
    6973    Vector<Import> imports;
    7074    Vector<SignatureIndex> importFunctionSignatureIndices;
     
    8589    Vector<CustomSection> customSections;
    8690    Ref<NameSection> nameSection;
     91   
     92    mutable BitVector m_referencedFunctions;
    8793};
    8894
  • trunk/Source/JavaScriptCore/wasm/WasmSectionParser.cpp

    r246266 r246504  
    292292        if (initOpcode == GetGlobal)
    293293            global.initializationType = Global::FromGlobalImport;
     294        else if (initOpcode == RefFunc)
     295            global.initializationType = Global::FromRefFunc;
    294296        else
    295297            global.initializationType = Global::FromExpression;
    296         WASM_PARSER_FAIL_IF(typeForInitOpcode != global.type, "Global init_expr opcode of type ", typeForInitOpcode, " doesn't match global's type ", global.type);
     298        WASM_PARSER_FAIL_IF(!isSubtype(typeForInitOpcode, global.type), "Global init_expr opcode of type ", typeForInitOpcode, " doesn't match global's type ", global.type);
    297299
    298300        m_info->globals.uncheckedAppend(WTFMove(global));
     
    480482
    481483    case RefNull: {
    482         resultType = Anyref;
     484        resultType = Anyfunc;
    483485        bitsOrImportNumber = JSValue::encode(jsNull());
     486        break;
     487    }
     488
     489    case RefFunc: {
     490        uint32_t index;
     491        WASM_PARSER_FAIL_IF(!parseVarUInt32(index), "can't get ref.func index");
     492        WASM_PARSER_FAIL_IF(index >= m_info->functions.size(), "ref.func index", index, " exceeds the number of functions ", m_info->functions.size());
     493
     494        resultType = Anyfunc;
     495        bitsOrImportNumber = index;
    484496        break;
    485497    }
  • trunk/Source/JavaScriptCore/wasm/WasmValidate.cpp

    r246266 r246504  
    104104    // References
    105105    Result WARN_UNUSED_RETURN addRefIsNull(ExpressionType& value, ExpressionType& result);
     106    Result WARN_UNUSED_RETURN addRefFunc(uint32_t index, ExpressionType& result);
    106107
    107108    // Tables
    108     Result WARN_UNUSED_RETURN addTableGet(ExpressionType& idx, ExpressionType& result);
    109     Result WARN_UNUSED_RETURN addTableSet(ExpressionType& idx, ExpressionType& value);
     109    Result WARN_UNUSED_RETURN addTableGet(ExpressionType& index, ExpressionType& result);
     110    Result WARN_UNUSED_RETURN addTableSet(ExpressionType& index, ExpressionType& value);
    110111
    111112    // Locals
     
    178179}
    179180
    180 auto Validate::addTableGet(ExpressionType& idx, ExpressionType& result) -> Result
    181 {
    182     result = Type::Anyref;
    183     WASM_VALIDATOR_FAIL_IF(Type::I32 != idx, "table.get index to type ", idx, " expected ", Type::I32);
    184     WASM_VALIDATOR_FAIL_IF(TableElementType::Anyref != m_module.tableInformation.type(), "table.get expects the table to have type ", Type::Anyref);
    185 
    186     return { };
    187 }
    188 
    189 auto Validate::addTableSet(ExpressionType& idx, ExpressionType& value) -> Result
    190 {
    191     WASM_VALIDATOR_FAIL_IF(Type::I32 != idx, "table.set index to type ", idx, " expected ", Type::I32);
    192     WASM_VALIDATOR_FAIL_IF(Type::Anyref != value, "table.set value to type ", value, " expected ", Type::Anyref);
    193     WASM_VALIDATOR_FAIL_IF(TableElementType::Anyref != m_module.tableInformation.type(), "table.set expects the table to have type ", Type::Anyref);
     181auto Validate::addTableGet(ExpressionType& index, ExpressionType& result) -> Result
     182{
     183    result = m_module.tableInformation.wasmType();
     184    WASM_VALIDATOR_FAIL_IF(Type::I32 != index, "table.get index to type ", index, " expected ", Type::I32);
     185
     186    return { };
     187}
     188
     189auto Validate::addTableSet(ExpressionType& index, ExpressionType& value) -> Result
     190{
     191    auto type = m_module.tableInformation.wasmType();
     192    WASM_VALIDATOR_FAIL_IF(Type::I32 != index, "table.set index to type ", index, " expected ", Type::I32);
     193    WASM_VALIDATOR_FAIL_IF(!isSubtype(value, type), "table.set value to type ", value, " expected ", type);
     194    WASM_VALIDATOR_FAIL_IF(m_module.tableInformation.type() != TableElementType::Anyref
     195        && m_module.tableInformation.type() != TableElementType::Funcref, "table.set expects the table to have type anyref or anyfunc");
    194196
    195197    return { };
     
    199201{
    200202    result = Type::I32;
    201     WASM_VALIDATOR_FAIL_IF(Type::Anyref != value, "ref.is_null to type ", value, " expected ", Type::Anyref);
     203    WASM_VALIDATOR_FAIL_IF(!isSubtype(value, Type::Anyref), "ref.is_null to type ", value, " expected ", Type::Anyref);
     204
     205    return { };
     206}
     207
     208auto Validate::addRefFunc(uint32_t index, ExpressionType& result) -> Result
     209{
     210    result = Type::Anyfunc;
     211    WASM_VALIDATOR_FAIL_IF(index >= m_module.functionIndexSpaceSize(), "ref.func index ", index, " is too large, max is ", m_module.functionIndexSpaceSize());
     212    m_module.addReferencedFunction(index);
    202213
    203214    return { };
     
    225236    ExpressionType localType;
    226237    WASM_FAIL_IF_HELPER_FAILS(getLocal(index, localType));
    227     WASM_VALIDATOR_FAIL_IF(localType != value, "set_local to type ", value, " expected ", localType);
     238    WASM_VALIDATOR_FAIL_IF(!isSubtype(value, localType), "set_local to type ", value, " expected ", localType);
    228239    return { };
    229240}
     
    363374
    364375    for (unsigned i = 0; i < args.size(); ++i)
    365         WASM_VALIDATOR_FAIL_IF(args[i] != signature.argument(i), "argument type mismatch in call, got ", args[i], ", expected ", signature.argument(i));
     376        WASM_VALIDATOR_FAIL_IF(!isSubtype(args[i], signature.argument(i)), "argument type mismatch in call, got ", args[i], ", expected ", signature.argument(i));
    366377
    367378    result = signature.returnType();
     
    376387
    377388    for (unsigned i = 0; i < argumentCount; ++i)
    378         WASM_VALIDATOR_FAIL_IF(args[i] != signature.argument(i), "argument type mismatch in call_indirect, got ", args[i], ", expected ", signature.argument(i));
     389        WASM_VALIDATOR_FAIL_IF(!isSubtype(args[i], signature.argument(i)), "argument type mismatch in call_indirect, got ", args[i], ", expected ", signature.argument(i));
    379390
    380391    WASM_VALIDATOR_FAIL_IF(args.last() != I32, "non-i32 call_indirect index ", args.last());
  • trunk/Source/JavaScriptCore/wasm/js/JSToWasm.cpp

    r246451 r246504  
    3232#include "DisallowMacroScratchRegisterUsage.h"
    3333#include "JSCInlines.h"
     34#include "JSWebAssemblyHelpers.h"
    3435#include "JSWebAssemblyInstance.h"
    3536#include "JSWebAssemblyRuntimeError.h"
     
    8485        case Wasm::I32:
    8586        case Wasm::Anyref:
     87        case Wasm::Anyfunc:
    8688            if (numGPRs >= wasmCallingConvention().m_gprArgs.size())
    8789                totalFrameSize += sizeof(void*);
     
    123125        }
    124126
    125         jit.loadPtr(CCallHelpers::Address(GPRInfo::argumentGPR2, Instance::offsetOfPointerToTopEntryFrame()), GPRInfo::argumentGPR0);
    126         jit.loadPtr(CCallHelpers::Address(GPRInfo::argumentGPR0), GPRInfo::argumentGPR0);
    127         jit.copyCalleeSavesToEntryFrameCalleeSavesBuffer(GPRInfo::argumentGPR0);
    128         jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
    129         jit.move(CCallHelpers::TrustedImm32(static_cast<int32_t>(argumentsIncludeI64 ? ExceptionType::I64ArgumentType : ExceptionType::I64ReturnType)), GPRInfo::argumentGPR1);
    130 
    131         CCallHelpers::Call call = jit.call(OperationPtrTag);
    132 
    133         jit.jump(GPRInfo::returnValueGPR, ExceptionHandlerPtrTag);
    134         jit.breakpoint(); // We should not reach this.
    135 
    136         jit.addLinkTask([=] (LinkBuffer& linkBuffer) {
    137             linkBuffer.link(call, FunctionPtr<OperationPtrTag>(wasmToJSException));
    138         });
     127        emitThrowWasmToJSException(jit, GPRInfo::argumentGPR2, argumentsIncludeI64 ? ExceptionType::I64ArgumentType : ExceptionType::I64ReturnType);
    139128        return result;
    140129    }
     
    166155            case Wasm::I32:
    167156            case Wasm::I64:
     157            case Wasm::Anyfunc:
    168158            case Wasm::Anyref:
    169159                if (numGPRs >= wasmCallingConvention().m_gprArgs.size()) {
     
    251241        break;
    252242    case Wasm::Anyref:
    253         // FIXME: We need to box wasm Funcrefs once they are supported here.
     243    case Wasm::Anyfunc:
    254244        break;
    255245    case Wasm::I32:
     
    269259    case Wasm::I64:
    270260    case Wasm::Func:
    271     case Wasm::Anyfunc:
    272261        jit.breakpoint();
    273262        break;
  • trunk/Source/JavaScriptCore/wasm/js/JSWebAssemblyHelpers.h

    r233122 r246504  
    123123
    124124
    125 ALWAYS_INLINE bool isWebAssemblyHostFunction(VM& vm, JSObject* object)
     125ALWAYS_INLINE bool isWebAssemblyHostFunction(VM& vm, JSValue object)
    126126{
    127127    WebAssemblyFunction* unused;
  • trunk/Source/JavaScriptCore/wasm/js/JSWebAssemblyInstance.cpp

    r245765 r246504  
    9292        visitor.append(*thisObject->instance().importFunction<WriteBarrier<JSObject>>(i)); // This also keeps the functions' JSWebAssemblyInstance alive.
    9393
    94     for (size_t i : thisObject->instance().globalsToMark()) {
    95         // FIXME: We need to box wasm Funcrefs once they are supported here.
    96         // <https://bugs.webkit.org/show_bug.cgi?id=198157>
     94    for (size_t i : thisObject->instance().globalsToMark())
    9795        visitor.appendUnbarriered(JSValue::decode(thisObject->instance().loadI64Global(i)));
    98     }
     96
     97    auto locker = holdLock(cell->cellLock());
     98    for (auto& wrapper : thisObject->instance().functionWrappers())
     99        visitor.appendUnbarriered(wrapper.get());
    99100}
    100101
  • trunk/Source/JavaScriptCore/wasm/js/JSWebAssemblyRuntimeError.cpp

    r217108 r246504  
    4949const ClassInfo JSWebAssemblyRuntimeError::s_info = { "WebAssembly.RuntimeError", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSWebAssemblyRuntimeError) };
    5050
     51JSObject* createJSWebAssemblyRuntimeError(ExecState* exec, VM& vm, const String& message)
     52{
     53    ASSERT(!message.isEmpty());
     54    JSGlobalObject* globalObject = exec->lexicalGlobalObject();
     55    return JSWebAssemblyRuntimeError::create(exec, vm, globalObject->webAssemblyRuntimeErrorStructure(), message);
     56}
    5157   
    5258} // namespace JSC
  • trunk/Source/JavaScriptCore/wasm/js/JSWebAssemblyRuntimeError.h

    r244040 r246504  
    4444};
    4545
     46JSObject* createJSWebAssemblyRuntimeError(ExecState*, VM&, const String&);
     47
    4648} // namespace JSC
    4749
  • trunk/Source/JavaScriptCore/wasm/js/WasmToJS.cpp

    r245496 r246504  
    3333#include "JITExceptions.h"
    3434#include "JSCInlines.h"
     35#include "JSWebAssemblyHelpers.h"
    3536#include "JSWebAssemblyInstance.h"
    3637#include "JSWebAssemblyRuntimeError.h"
     
    6667        case Void:
    6768        case Func:
    68         case Anyfunc:
    6969            RELEASE_ASSERT_NOT_REACHED();
    7070
     
    163163            case Void:
    164164            case Func:
    165             case Anyfunc:
    166165            case I64:
    167166                RELEASE_ASSERT_NOT_REACHED();
    168167            case Anyref:
     168            case Anyfunc:
    169169            case I32: {
    170170                GPRReg gprReg;
     
    238238                    case Void:
    239239                    case Func:
    240                     case Anyfunc:
    241240                    case I64:
    242241                        RELEASE_ASSERT_NOT_REACHED();
     
    244243                        arg = jsNumber(static_cast<int32_t>(buffer[argNum]));
    245244                        break;
     245                    case Anyfunc: {
     246                        arg = JSValue::decode(buffer[argNum]);
     247                        ASSERT(isWebAssemblyHostFunction(*vm, arg) || arg.isNull());
     248                        break;
     249                    }
    246250                    case Anyref:
    247                         // FIXME: We need to box wasm Funcrefs once they are supported here.
    248251                        arg = JSValue::decode(buffer[argNum]);
    249252                        break;
     
    269272                switch (signature.returnType()) {
    270273                case Func:
    271                 case Anyfunc:
    272274                case I64:
    273275                    RELEASE_ASSERT_NOT_REACHED();
     
    277279                case I32: {
    278280                    realResult = static_cast<uint64_t>(static_cast<uint32_t>(result.toInt32(exec)));
     281                    break;
     282                }
     283                case Anyfunc: {
     284                    realResult = JSValue::encode(result);
     285                    ASSERT(result.isFunction(*vm) || result.isNull());
    279286                    break;
    280287                }
     
    372379            case Void:
    373380            case Func:
    374             case Anyfunc:
    375381            case I64:
    376382                RELEASE_ASSERT_NOT_REACHED(); // Handled above.
    377383            case Anyref:
     384            case Anyfunc:
    378385            case I32: {
    379386                GPRReg gprReg;
     
    391398                    jit.boxInt32(gprReg, JSValueRegs(gprReg), DoNotHaveTagRegisters);
    392399                }
    393                 // FIXME: We need to box wasm Funcrefs once they are supported here.
    394400                jit.store64(gprReg, calleeFrame.withOffset(calleeFrameOffset));
    395401                calleeFrameOffset += sizeof(Register);
     
    442448            case Void:
    443449            case Func:
    444             case Anyfunc:
    445450            case I64:
    446451                RELEASE_ASSERT_NOT_REACHED(); // Handled above.
    447452            case Anyref:
     453            case Anyfunc:
    448454            case I32:
    449455                // Skipped: handled above.
     
    520526        break;
    521527    case Func:
    522     case Anyfunc:
    523528        // For the JavaScript embedding, imports with these types in their signature return are a WebAssembly.Module validation error.
    524529        RELEASE_ASSERT_NOT_REACHED();
     
    554559        break;
    555560    }
     561    case Anyfunc:
    556562    case Anyref:
    557563        break;
     
    696702}
    697703
     704void emitThrowWasmToJSException(CCallHelpers& jit, GPRReg wasmInstance, Wasm::ExceptionType type)
     705{
     706    ASSERT(wasmInstance != GPRInfo::argumentGPR0);
     707    jit.loadPtr(CCallHelpers::Address(wasmInstance, Wasm::Instance::offsetOfPointerToTopEntryFrame()), GPRInfo::argumentGPR0);
     708    jit.loadPtr(CCallHelpers::Address(GPRInfo::argumentGPR0), GPRInfo::argumentGPR0);
     709    jit.copyCalleeSavesToEntryFrameCalleeSavesBuffer(GPRInfo::argumentGPR0);
     710    jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
     711    jit.move(CCallHelpers::TrustedImm32(static_cast<int32_t>(type)), GPRInfo::argumentGPR1);
     712
     713    CCallHelpers::Call call = jit.call(OperationPtrTag);
     714
     715    jit.jump(GPRInfo::returnValueGPR, ExceptionHandlerPtrTag);
     716    jit.breakpoint(); // We should not reach this.
     717
     718    jit.addLinkTask([=] (LinkBuffer& linkBuffer) {
     719        linkBuffer.link(call, FunctionPtr<OperationPtrTag>(Wasm::wasmToJSException));
     720    });
     721}
     722
    698723} } // namespace JSC::Wasm
    699724
  • trunk/Source/JavaScriptCore/wasm/js/WasmToJS.h

    r230748 r246504  
    4646
    4747void* wasmToJSException(ExecState*, Wasm::ExceptionType, Instance*);
     48void emitThrowWasmToJSException(CCallHelpers&, GPRReg wasmInstance, Wasm::ExceptionType);
    4849
    4950} } // namespace JSC::Wasm
  • trunk/Source/JavaScriptCore/wasm/js/WebAssemblyFunction.cpp

    r246451 r246504  
    8585            arg = JSValue::decode(arg.toInt32(exec));
    8686            break;
     87        case Wasm::Anyfunc: {
     88            if (!isWebAssemblyHostFunction(vm, arg) && !arg.isNull())
     89                return JSValue::encode(throwException(exec, scope, createJSWebAssemblyRuntimeError(exec, vm, "Anyfunc must be an exported wasm function")));
     90            break;
     91        }
    8792        case Wasm::Anyref:
    8893            break;
     
    98103        case Wasm::Void:
    99104        case Wasm::Func:
    100         case Wasm::Anyfunc:
    101105            RELEASE_ASSERT_NOT_REACHED();
    102106        }
     
    229233            break;
    230234        case Wasm::Anyref:
     235        case Wasm::Anyfunc:
    231236        case Wasm::I32:
    232237            if (numGPRs >= Wasm::wasmCallingConvention().m_gprArgs.size())
     
    304309                }
    305310                break;
     311            case Wasm::Anyfunc: {
     312                // FIXME: Emit this inline <https://bugs.webkit.org/show_bug.cgi?id=198506>.
     313                bool (*shouldThrow)(Wasm::Instance*, JSValue) = [] (Wasm::Instance* wasmInstance, JSValue arg) -> bool {
     314                    JSWebAssemblyInstance* instance = wasmInstance->owner<JSWebAssemblyInstance>();
     315                    JSGlobalObject* globalObject = instance->globalObject();
     316                    VM& vm = globalObject->vm();
     317                    return !isWebAssemblyHostFunction(vm, arg) && !arg.isNull();
     318                };
     319                jit.move(CCallHelpers::TrustedImmPtr(&instance()->instance()), GPRInfo::argumentGPR0);
     320                jit.load64(CCallHelpers::Address(GPRInfo::callFrameRegister, jsOffset), GPRInfo::argumentGPR1);
     321                jit.setupArguments<decltype(shouldThrow)>(GPRInfo::argumentGPR0, GPRInfo::argumentGPR1);
     322                auto call = jit.call(OperationPtrTag);
     323
     324                jit.addLinkTask([=] (LinkBuffer& linkBuffer) {
     325                    linkBuffer.link(call, FunctionPtr<OperationPtrTag>(shouldThrow));
     326                });
     327
     328                slowPath.append(jit.branchTest32(CCallHelpers::NonZero, GPRInfo::returnValueGPR));
     329
     330                FALLTHROUGH;
     331            }
    306332            case Wasm::Anyref: {
    307333                jit.load64(CCallHelpers::Address(GPRInfo::callFrameRegister, jsOffset), scratchGPR);
     
    467493        break;
    468494    }
    469     case Wasm::Anyref: {
    470         // FIXME: We need to box wasm Funcrefs once they are supported here.
     495    case Wasm::Anyfunc:
     496    case Wasm::Anyref:
    471497        break;
    472     }
    473498    case Wasm::I64:
    474499    case Wasm::Func:
    475     case Wasm::Anyfunc:
    476500        return nullptr;
    477501    default:
  • trunk/Source/JavaScriptCore/wasm/js/WebAssemblyModuleRecord.cpp

    r246139 r246504  
    236236            if (moduleInformation.globals[import.kindIndex].type == Wasm::I64)
    237237                return exception(createJSWebAssemblyLinkError(exec, vm, importFailMessage(import, "imported global", "cannot be an i64")));
    238             if (moduleInformation.globals[import.kindIndex].type != Wasm::Anyref && !value.isNumber())
     238            if (!isSubtype(moduleInformation.globals[import.kindIndex].type, Wasm::Anyref) && !value.isNumber())
    239239                return exception(createJSWebAssemblyLinkError(exec, vm, importFailMessage(import, "imported global", "must be a number")));
    240240            // iii. Append ToWebAssemblyValue(v) to imports.
    241241            switch (moduleInformation.globals[import.kindIndex].type) {
     242            case Wasm::Anyfunc:
     243                if (!isWebAssemblyHostFunction(vm, value) && !value.isNull())
     244                    return exception(createJSWebAssemblyLinkError(exec, vm, importFailMessage(import, "imported global", "must be a wasm exported function or null")));
     245                m_instance->instance().setGlobal(import.kindIndex, value);
     246                break;
    242247            case Wasm::Anyref:
    243248                m_instance->instance().setGlobal(import.kindIndex, value);
     
    320325    }
    321326
     327    unsigned functionImportCount = codeBlock->functionImportCount();
     328    auto makeFunctionWrapper = [&] (const String& field, uint32_t index) -> JSValue {
     329        // If we already made a wrapper, do not make a new one.
     330        JSValue wrapper = m_instance->instance().getFunctionWrapper(index);
     331
     332        if (!wrapper.isNull())
     333            return wrapper;
     334
     335        // 1. If e is a closure c:
     336        //   i. If there is an Exported Function Exotic Object func in funcs whose func.[[Closure]] equals c, then return func.
     337        //   ii. (Note: At most one wrapper is created for any closure, so func is unique, even if there are multiple occurrances in the list. Moreover, if the item was an import that is already an Exported Function Exotic Object, then the original function object will be found. For imports that are regular JS functions, a new wrapper will be created.)
     338        if (index < functionImportCount) {
     339            JSObject* functionImport = m_instance->instance().importFunction<WriteBarrier<JSObject>>(index)->get();
     340            if (isWebAssemblyHostFunction(vm, functionImport))
     341                wrapper = functionImport;
     342            else {
     343                Wasm::SignatureIndex signatureIndex = module->signatureIndexFromFunctionIndexSpace(index);
     344                wrapper = WebAssemblyWrapperFunction::create(vm, globalObject, globalObject->webAssemblyWrapperFunctionStructure(), functionImport, index, m_instance.get(), signatureIndex);
     345            }
     346        } else {
     347            //   iii. Otherwise:
     348            //     a. Let func be an Exported Function Exotic Object created from c.
     349            //     b. Append func to funcs.
     350            //     c. Return func.
     351            Wasm::Callee& embedderEntrypointCallee = codeBlock->embedderEntrypointCalleeFromFunctionIndexSpace(index);
     352            Wasm::WasmToWasmImportableFunction::LoadLocation entrypointLoadLocation = codeBlock->entrypointLoadLocationFromFunctionIndexSpace(index);
     353            Wasm::SignatureIndex signatureIndex = module->signatureIndexFromFunctionIndexSpace(index);
     354            const Wasm::Signature& signature = Wasm::SignatureInformation::get(signatureIndex);
     355            WebAssemblyFunction* function = WebAssemblyFunction::create(vm, globalObject, globalObject->webAssemblyFunctionStructure(), signature.argumentCount(), field, m_instance.get(), embedderEntrypointCallee, entrypointLoadLocation, signatureIndex);
     356            wrapper = function;
     357        }
     358
     359        ASSERT(wrapper.isFunction(vm));
     360        m_instance->instance().setFunctionWrapper(index, wrapper);
     361
     362        return wrapper;
     363    };
     364
     365    for (auto index : moduleInformation.referencedFunctions())
     366        makeFunctionWrapper("Referenced function", index);
     367
    322368    // Globals
    323369    {
     
    328374                ASSERT(global.initialBitsOrImportNumber < moduleInformation.firstInternalGlobal);
    329375                m_instance->instance().setGlobal(globalIndex, m_instance->instance().loadI64Global(global.initialBitsOrImportNumber));
     376            } else if (global.initializationType == Wasm::Global::FromRefFunc) {
     377                ASSERT(global.initialBitsOrImportNumber < moduleInformation.functionIndexSpaceSize());
     378                ASSERT(makeFunctionWrapper("Global init expr", global.initialBitsOrImportNumber).isFunction(vm));
     379                m_instance->instance().setGlobal(globalIndex, JSValue::encode(makeFunctionWrapper("Global init expr", global.initialBitsOrImportNumber)));
    330380            } else
    331381                m_instance->instance().setGlobal(globalIndex, global.initialBitsOrImportNumber);
     
    334384
    335385    SymbolTable* exportSymbolTable = module->exportSymbolTable();
    336     unsigned functionImportCount = codeBlock->functionImportCount();
    337386
    338387    // Let exports be a list of (string, JS value) pairs that is mapped from each external value e in instance.exports as follows:
     
    342391        switch (exp.kind) {
    343392        case Wasm::ExternalKind::Function: {
    344             // 1. If e is a closure c:
    345             //   i. If there is an Exported Function Exotic Object func in funcs whose func.[[Closure]] equals c, then return func.
    346             //   ii. (Note: At most one wrapper is created for any closure, so func is unique, even if there are multiple occurrances in the list. Moreover, if the item was an import that is already an Exported Function Exotic Object, then the original function object will be found. For imports that are regular JS functions, a new wrapper will be created.)
    347             if (exp.kindIndex < functionImportCount) {
    348                 unsigned functionIndex = exp.kindIndex;
    349                 JSObject* functionImport = m_instance->instance().importFunction<WriteBarrier<JSObject>>(functionIndex)->get();
    350                 if (isWebAssemblyHostFunction(vm, functionImport))
    351                     exportedValue = functionImport;
    352                 else {
    353                     Wasm::SignatureIndex signatureIndex = module->signatureIndexFromFunctionIndexSpace(functionIndex);
    354                     exportedValue = WebAssemblyWrapperFunction::create(vm, globalObject, globalObject->webAssemblyWrapperFunctionStructure(), functionImport, functionIndex, m_instance.get(), signatureIndex);
    355                 }
    356             } else {
    357                 //   iii. Otherwise:
    358                 //     a. Let func be an Exported Function Exotic Object created from c.
    359                 //     b. Append func to funcs.
    360                 //     c. Return func.
    361                 Wasm::Callee& embedderEntrypointCallee = codeBlock->embedderEntrypointCalleeFromFunctionIndexSpace(exp.kindIndex);
    362                 Wasm::WasmToWasmImportableFunction::LoadLocation entrypointLoadLocation = codeBlock->entrypointLoadLocationFromFunctionIndexSpace(exp.kindIndex);
    363                 Wasm::SignatureIndex signatureIndex = module->signatureIndexFromFunctionIndexSpace(exp.kindIndex);
    364                 const Wasm::Signature& signature = Wasm::SignatureInformation::get(signatureIndex);
    365                 WebAssemblyFunction* function = WebAssemblyFunction::create(vm, globalObject, globalObject->webAssemblyFunctionStructure(), signature.argumentCount(), String::fromUTF8(exp.field), m_instance.get(), embedderEntrypointCallee, entrypointLoadLocation, signatureIndex);
    366                 exportedValue = function;
    367             }
     393            exportedValue = makeFunctionWrapper(String::fromUTF8(exp.field), exp.kindIndex);
     394            ASSERT(exportedValue.isFunction(vm));
     395            ASSERT(makeFunctionWrapper(String::fromUTF8(exp.field), exp.kindIndex) == exportedValue);
    368396            break;
    369397        }
     
    389417            switch (global.type) {
    390418            case Wasm::Anyref:
    391                 // FIXME: We need to box wasm Funcrefs once they are supported here.
    392                 // <https://bugs.webkit.org/show_bug.cgi?id=198157>
     419            case Wasm::Anyfunc:
    393420                exportedValue = JSValue::decode(m_instance->instance().loadI64Global(exp.kindIndex));
    394421                break;
  • trunk/Source/JavaScriptCore/wasm/wasm.json

    r246139 r246504  
    1212        "f32":     { "type": "varint7", "value":  -3, "b3type": "B3::Float" },
    1313        "f64":     { "type": "varint7", "value":  -4, "b3type": "B3::Double" },
    14         "anyfunc": { "type": "varint7", "value": -16, "b3type": "B3::Void" },
     14        "anyfunc": { "type": "varint7", "value": -16, "b3type": "B3::Int64" },
    1515        "anyref":  { "type": "varint7", "value": -17, "b3type": "B3::Int64" },
    1616        "func":    { "type": "varint7", "value": -32, "b3type": "B3::Void" },
    1717        "void":    { "type": "varint7", "value": -64, "b3type": "B3::Void" }
    1818    },
    19     "value_type": ["i32", "i64", "f32", "f64", "anyref"],
    20     "block_type": ["i32", "i64", "f32", "f64", "void", "anyref"],
     19    "value_type": ["i32", "i64", "f32", "f64", "anyref", "anyfunc"],
     20    "block_type": ["i32", "i64", "f32", "f64", "void", "anyref", "anyfunc"],
    2121    "elem_type": ["anyfunc","anyref"],
    2222    "external_kind": {
     
    6060        "f64.const":           { "category": "special",    "value":  68, "return": ["f64"],      "parameter": [],                       "immediate": [{"name": "value",          "type": "double"}],                                               "description": "a constant value interpreted as f64" },
    6161        "f32.const":           { "category": "special",    "value":  67, "return": ["f32"],      "parameter": [],                       "immediate": [{"name": "value",          "type": "float"}],                                                "description": "a constant value interpreted as f32" },
    62         "ref.null":            { "category": "special",    "value": 208, "return": ["anyref"],   "parameter": [],                       "immediate": [],                                                                                           "description": "a constant null reference" },
     62        "ref.null":            { "category": "special",    "value": 208, "return": ["anyfunc"],  "parameter": [],                       "immediate": [],                                                                                           "description": "a constant null reference" },
    6363        "ref.is_null":         { "category": "special",    "value": 209, "return": ["i32"],      "parameter": ["anyref"],               "immediate": [],                                                                                           "description": "determine if a reference is null" },
     64        "ref.func":            { "category": "special",    "value": 210, "return": ["anyfunc"],  "parameter": [],                       "immediate": [{"name": "function_index", "type": "varuint32"}],                                            "description": "return a reference to the function at the given index" },
    6465        "get_local":           { "category": "special",    "value":  32, "return": ["any"],      "parameter": [],                       "immediate": [{"name": "local_index",    "type": "varuint32"}],                                            "description": "read a local variable or parameter" },
    6566        "set_local":           { "category": "special",    "value":  33, "return": [],           "parameter": ["any"],                  "immediate": [{"name": "local_index",    "type": "varuint32"}],                                            "description": "write a local variable or parameter" },
Note: See TracChangeset for help on using the changeset viewer.