Title: [276896] trunk
Revision
276896
Author
[email protected]
Date
2021-05-03 04:00:43 -0700 (Mon, 03 May 2021)

Log Message

[WASM-Function-References] Add call_ref instruction
https://bugs.webkit.org/show_bug.cgi?id=222903

Patch by Dmitry Bezhetskov <[email protected]> on 2021-05-03
Reviewed by Yusuke Suzuki.

JSTests:

Add basic tests for new call_ref instruction:
https://github.com/WebAssembly/function-references/blob/master/proposals/function-references/Overview.md.
Add tests for calling same-instance wasm function, foreign-instance
wasm function and for calling imported js function.

* wasm.yaml:
* wasm/function-references/call_ref.js: Added.
(module):
(async basics):
(async indirectCall):
(async importHostCall):
* wasm/wasm.json:

Source/_javascript_Core:

Add support for call_ref instruction from the typed function
references proposal: https://github.com/WebAssembly/function-references/blob/master/proposals/function-references/Overview.md.
call_ref calls the given function references from the stack
and it does almost the same stuff as call_indirect but
it doesn't check signatures because wasm types system guaranties
correctness.

* bytecode/BytecodeList.rb:
* dfg/DFGCapabilities.cpp:
(JSC::DFG::capabilityLevel):
* llint/LowLevelInterpreter.asm:
* llint/WebAssembly.asm:
* runtime/Gate.h:
* wasm/WasmAirIRGenerator.cpp:
(JSC::Wasm::AirIRGenerator::addCallIndirect):
(JSC::Wasm::AirIRGenerator::addCallRef):
(JSC::Wasm::AirIRGenerator::emitIndirectCall):
* wasm/WasmB3IRGenerator.cpp:
(JSC::Wasm::B3IRGenerator::emitIndirectCall):
(JSC::Wasm::B3IRGenerator::addCallIndirect):
(JSC::Wasm::B3IRGenerator::addCallRef):
* wasm/WasmFunctionParser.h:
(JSC::Wasm::FunctionParser<Context>::parseExpression):
(JSC::Wasm::FunctionParser<Context>::parseUnreachableExpression):
* wasm/WasmLLIntGenerator.cpp:
(JSC::Wasm::LLIntGenerator::addCallRef):
* wasm/WasmSlowPaths.cpp:
(JSC::LLInt::doWasmCallRef):
(JSC::LLInt::WASM_SLOW_PATH_DECL):
* wasm/WasmSlowPaths.h:
* wasm/js/JSWebAssemblyTable.cpp:
* wasm/js/WebAssemblyFunction.cpp:
(JSC::WebAssemblyFunction::WebAssemblyFunction):
* wasm/js/WebAssemblyFunction.h:
* wasm/js/WebAssemblyFunctionBase.cpp:
(JSC::WebAssemblyFunctionBase::WebAssemblyFunctionBase):
* wasm/js/WebAssemblyFunctionBase.h:
(JSC::WebAssemblyFunctionBase::offsetOfEntrypointLoadLocation):
* wasm/js/WebAssemblyWrapperFunction.cpp:
(JSC::WebAssemblyWrapperFunction::WebAssemblyWrapperFunction):
* wasm/js/WebAssemblyWrapperFunction.h:
* wasm/wasm.json:

Modified Paths

Added Paths

Diff

Modified: trunk/JSTests/ChangeLog (276895 => 276896)


--- trunk/JSTests/ChangeLog	2021-05-03 09:29:48 UTC (rev 276895)
+++ trunk/JSTests/ChangeLog	2021-05-03 11:00:43 UTC (rev 276896)
@@ -1,3 +1,23 @@
+2021-05-03  Dmitry Bezhetskov  <[email protected]>
+
+        [WASM-Function-References] Add call_ref instruction
+        https://bugs.webkit.org/show_bug.cgi?id=222903
+
+        Reviewed by Yusuke Suzuki.
+
+        Add basic tests for new call_ref instruction:
+        https://github.com/WebAssembly/function-references/blob/master/proposals/function-references/Overview.md.
+        Add tests for calling same-instance wasm function, foreign-instance
+        wasm function and for calling imported js function.
+
+        * wasm.yaml:
+        * wasm/function-references/call_ref.js: Added.
+        (module):
+        (async basics):
+        (async indirectCall):
+        (async importHostCall):
+        * wasm/wasm.json:
+
 2021-04-28  Mark Lam  <[email protected]>
 
         Fix exception assertions in light of the TerminationException.

Added: trunk/JSTests/wasm/function-references/call_ref.js (0 => 276896)


--- trunk/JSTests/wasm/function-references/call_ref.js	                        (rev 0)
+++ trunk/JSTests/wasm/function-references/call_ref.js	2021-05-03 11:00:43 UTC (rev 276896)
@@ -0,0 +1,75 @@
+//@ runWebAssemblySuite("--useWebAssemblyTypedFunctionReferences=true")
+import * as assert from '../assert.js';
+import { instantiate } from "../wabt-wrapper.js";
+
+function module(bytes, valid = true) {
+  let buffer = new ArrayBuffer(bytes.length);
+  let view = new Uint8Array(buffer);
+  for (let i = 0; i < bytes.length; ++i) {
+    view[i] = bytes.charCodeAt(i);
+  }
+  return new WebAssembly.Module(buffer);
+}
+
+async function callFunctionFromTheSameInstance() {
+  /*
+  (module
+    (elem declare funcref (ref.func $foo))
+    (func $foo (param $x i32) (result i32)
+      (i32.add (local.get $x)
+               (i32.const 19)
+      )
+    )
+    (func (export "main") (result i32)
+      (call_ref (i32.const 10) (ref.func $foo))
+    )
+  )
+  */
+  let instance = new WebAssembly.Instance(module("\x00\x61\x73\x6d\x01\x00\x00\x00\x01\x0a\x02\x60\x01\x7f\x01\x7f\x60\x00\x01\x7f\x03\x03\x02\x00\x01\x07\x08\x01\x04\x6d\x61\x69\x6e\x00\x01\x09\x05\x01\x03\x00\x01\x00\x0a\x11\x02\x07\x00\x20\x00\x41\x13\x6a\x0b\x07\x00\x41\x0a\xd2\x00\x14\x0b"));
+  assert.eq(instance.exports.main(), 29);
+}
+
+async function callFunctionFromTheDifferentInstance() {
+  let wat = `
+  (module
+    (func (export "bar") (param $x i32) (result i32)
+      (i32.add (local.get $x)
+               (i32.const 19))
+    )
+  )`;
+  const barProvider = await instantiate(wat, {}, {reference_types: true});
+
+  /*
+  (module
+    (import "exports" "bar" (func $bar (param i32) (result i32)))
+    (elem declare funcref (ref.func $bar))
+    (func (export "main") (result i32)
+      (call_ref (i32.const 10) (ref.func $bar))
+    )
+  )
+  */
+  let instance = new WebAssembly.Instance(
+    module("\x00\x61\x73\x6d\x01\x00\x00\x00\x01\x0a\x02\x60\x01\x7f\x01\x7f\x60\x00\x01\x7f\x02\x0f\x01\x07\x65\x78\x70\x6f\x72\x74\x73\x03\x62\x61\x72\x00\x00\x03\x02\x01\x01\x07\x08\x01\x04\x6d\x61\x69\x6e\x00\x01\x09\x05\x01\x03\x00\x01\x00\x0a\x09\x01\x07\x00\x41\x0a\xd2\x00\x14\x0b"),
+    barProvider);
+  assert.eq(instance.exports.main(), 29);
+}
+
+async function callFunctionFromJS() {
+  /*
+  (module
+    (import "exports" "bar" (func $bar (param i32) (result i32)))
+    (elem declare funcref (ref.func $bar))
+    (func (export "main") (result i32)
+      (call_ref (i32.const 10) (ref.func $bar))
+    )
+  )
+  */
+  let instance = new WebAssembly.Instance(
+    module("\x00\x61\x73\x6d\x01\x00\x00\x00\x01\x0a\x02\x60\x01\x7f\x01\x7f\x60\x00\x01\x7f\x02\x0f\x01\x07\x65\x78\x70\x6f\x72\x74\x73\x03\x62\x61\x72\x00\x00\x03\x02\x01\x01\x07\x08\x01\x04\x6d\x61\x69\x6e\x00\x01\x09\x05\x01\x03\x00\x01\x00\x0a\x09\x01\x07\x00\x41\x0a\xd2\x00\x14\x0b"),
+    {exports: {bar : x => x + 19}});
+  assert.eq(instance.exports.main(), 29);
+}
+
+assert.asyncTest(callFunctionFromTheSameInstance());
+assert.asyncTest(callFunctionFromTheDifferentInstance());
+assert.asyncTest(callFunctionFromJS());

Modified: trunk/JSTests/wasm/wasm.json (276895 => 276896)


--- trunk/JSTests/wasm/wasm.json	2021-05-03 09:29:48 UTC (rev 276895)
+++ trunk/JSTests/wasm/wasm.json	2021-05-03 11:00:43 UTC (rev 276896)
@@ -85,6 +85,7 @@
         "data.drop":           { "category": "exttable",   "value":  252, "return": [],                              "parameter": [],                             "immediate": [{"name": "segment_index",  "type": "varuint32"}],                                             "description": "shrinks the size of the segment to zero", "extendedOp": 9 },
         "call":                { "category": "call",       "value":  16, "return": ["call"],                         "parameter": ["call"],                       "immediate": [{"name": "function_index", "type": "varuint32"}],                                             "description": "call a function by its index" },
         "call_indirect":       { "category": "call",       "value":  17, "return": ["call"],                         "parameter": ["call"],                       "immediate": [{"name": "type_index",     "type": "varuint32"}, {"name": "table_index","type": "varuint32"}],"description": "call a function indirect with an expected signature" },
+        "call_ref":            { "category": "call",       "value":  20, "return": ["call"],                         "parameter": ["call"],                       "immediate": [],                                                                                            "description": "call a function reference" },
         "i32.load8_s":         { "category": "memory",     "value":  44, "return": ["i32"],                          "parameter": ["addr"],                       "immediate": [{"name": "flags",          "type": "varuint32"}, {"name": "offset",   "type": "varuint32"}], "description": "load from memory" },
         "i32.load8_u":         { "category": "memory",     "value":  45, "return": ["i32"],                          "parameter": ["addr"],                       "immediate": [{"name": "flags",          "type": "varuint32"}, {"name": "offset",   "type": "varuint32"}], "description": "load from memory" },
         "i32.load16_s":        { "category": "memory",     "value":  46, "return": ["i32"],                          "parameter": ["addr"],                       "immediate": [{"name": "flags",          "type": "varuint32"}, {"name": "offset",   "type": "varuint32"}], "description": "load from memory" },

Modified: trunk/JSTests/wasm.yaml (276895 => 276896)


--- trunk/JSTests/wasm.yaml	2021-05-03 09:29:48 UTC (rev 276895)
+++ trunk/JSTests/wasm.yaml	2021-05-03 11:00:43 UTC (rev 276896)
@@ -33,6 +33,8 @@
   cmd: runWebAssemblySuite unless parseRunCommands
 - path: wasm/references
   cmd: runWebAssemblySuite unless parseRunCommands
+- path: wasm/function-references
+  cmd: runWebAssemblySuite unless parseRunCommands
 - path: wasm/fuzz
   cmd: runWebAssemblySuite unless parseRunCommands
 - path: wasm/lowExecutableMemory

Modified: trunk/Source/_javascript_Core/ChangeLog (276895 => 276896)


--- trunk/Source/_javascript_Core/ChangeLog	2021-05-03 09:29:48 UTC (rev 276895)
+++ trunk/Source/_javascript_Core/ChangeLog	2021-05-03 11:00:43 UTC (rev 276896)
@@ -1,3 +1,53 @@
+2021-05-03  Dmitry Bezhetskov  <[email protected]>
+
+        [WASM-Function-References] Add call_ref instruction
+        https://bugs.webkit.org/show_bug.cgi?id=222903
+
+        Reviewed by Yusuke Suzuki.
+
+        Add support for call_ref instruction from the typed function
+        references proposal: https://github.com/WebAssembly/function-references/blob/master/proposals/function-references/Overview.md.
+        call_ref calls the given function references from the stack 
+        and it does almost the same stuff as call_indirect but
+        it doesn't check signatures because wasm types system guaranties
+        correctness.
+
+        * bytecode/BytecodeList.rb:
+        * dfg/DFGCapabilities.cpp:
+        (JSC::DFG::capabilityLevel):
+        * llint/LowLevelInterpreter.asm:
+        * llint/WebAssembly.asm:
+        * runtime/Gate.h:
+        * wasm/WasmAirIRGenerator.cpp:
+        (JSC::Wasm::AirIRGenerator::addCallIndirect):
+        (JSC::Wasm::AirIRGenerator::addCallRef):
+        (JSC::Wasm::AirIRGenerator::emitIndirectCall):
+        * wasm/WasmB3IRGenerator.cpp:
+        (JSC::Wasm::B3IRGenerator::emitIndirectCall):
+        (JSC::Wasm::B3IRGenerator::addCallIndirect):
+        (JSC::Wasm::B3IRGenerator::addCallRef):
+        * wasm/WasmFunctionParser.h:
+        (JSC::Wasm::FunctionParser<Context>::parseExpression):
+        (JSC::Wasm::FunctionParser<Context>::parseUnreachableExpression):
+        * wasm/WasmLLIntGenerator.cpp:
+        (JSC::Wasm::LLIntGenerator::addCallRef):
+        * wasm/WasmSlowPaths.cpp:
+        (JSC::LLInt::doWasmCallRef):
+        (JSC::LLInt::WASM_SLOW_PATH_DECL):
+        * wasm/WasmSlowPaths.h:
+        * wasm/js/JSWebAssemblyTable.cpp:
+        * wasm/js/WebAssemblyFunction.cpp:
+        (JSC::WebAssemblyFunction::WebAssemblyFunction):
+        * wasm/js/WebAssemblyFunction.h:
+        * wasm/js/WebAssemblyFunctionBase.cpp:
+        (JSC::WebAssemblyFunctionBase::WebAssemblyFunctionBase):
+        * wasm/js/WebAssemblyFunctionBase.h:
+        (JSC::WebAssemblyFunctionBase::offsetOfEntrypointLoadLocation):
+        * wasm/js/WebAssemblyWrapperFunction.cpp:
+        (JSC::WebAssemblyWrapperFunction::WebAssemblyWrapperFunction):
+        * wasm/js/WebAssemblyWrapperFunction.h:
+        * wasm/wasm.json:
+
 2021-05-01  Chris Dumez  <[email protected]>
 
         Start leveraging std::filesystem in WTF::FileSystem

Modified: trunk/Source/_javascript_Core/bytecode/BytecodeList.rb (276895 => 276896)


--- trunk/Source/_javascript_Core/bytecode/BytecodeList.rb	2021-05-03 09:29:48 UTC (rev 276895)
+++ trunk/Source/_javascript_Core/bytecode/BytecodeList.rb	2021-05-03 11:00:43 UTC (rev 276896)
@@ -1474,6 +1474,8 @@
 op :wasm_trampoline_wasm_call_no_tls
 op :wasm_trampoline_wasm_call_indirect
 op :wasm_trampoline_wasm_call_indirect_no_tls
+op :wasm_trampoline_wasm_call_ref
+op :wasm_trampoline_wasm_call_ref_no_tls
 
 end_section :NativeHelpers
 
@@ -1495,6 +1497,8 @@
 op :call_no_tls_return_location
 op :call_indirect_return_location
 op :call_indirect_no_tls_return_location
+op :call_ref_return_location
+op :call_ref_no_tls_return_location
 
 # FIXME: Wasm and JS LLInt should share common opcodes
 # https://bugs.webkit.org/show_bug.cgi?id=203656
@@ -1686,6 +1690,22 @@
         tableIndex: unsigned,
     }
 
+op :call_ref,
+    args: {
+        functionReference: VirtualRegister,
+        signatureIndex: unsigned,
+        stackOffset: unsigned,
+        numberOfStackArgs: unsigned,
+    }
+
+op :call_ref_no_tls,
+    args: {
+        functionReference: VirtualRegister,
+        signatureIndex: unsigned,
+        stackOffset: unsigned,
+        numberOfStackArgs: unsigned,
+    }
+
 op :current_memory,
     args: {
         dst: VirtualRegister,

Modified: trunk/Source/_javascript_Core/dfg/DFGCapabilities.cpp (276895 => 276896)


--- trunk/Source/_javascript_Core/dfg/DFGCapabilities.cpp	2021-05-03 09:29:48 UTC (rev 276895)
+++ trunk/Source/_javascript_Core/dfg/DFGCapabilities.cpp	2021-05-03 11:00:43 UTC (rev 276896)
@@ -368,6 +368,8 @@
     case wasm_trampoline_wasm_call_no_tls:
     case wasm_trampoline_wasm_call_indirect:
     case wasm_trampoline_wasm_call_indirect_no_tls:
+    case wasm_trampoline_wasm_call_ref:
+    case wasm_trampoline_wasm_call_ref_no_tls:
         return CannotCompile;
     }
     return CannotCompile;

Modified: trunk/Source/_javascript_Core/llint/LowLevelInterpreter.asm (276895 => 276896)


--- trunk/Source/_javascript_Core/llint/LowLevelInterpreter.asm	2021-05-03 09:29:48 UTC (rev 276895)
+++ trunk/Source/_javascript_Core/llint/LowLevelInterpreter.asm	2021-05-03 11:00:43 UTC (rev 276896)
@@ -2530,14 +2530,20 @@
 _wasm_trampoline_wasm_call_no_tls:
 _wasm_trampoline_wasm_call_indirect:
 _wasm_trampoline_wasm_call_indirect_no_tls:
+_wasm_trampoline_wasm_call_ref:
+_wasm_trampoline_wasm_call_ref_no_tls:
 _wasm_trampoline_wasm_call_wide16:
 _wasm_trampoline_wasm_call_no_tls_wide16:
 _wasm_trampoline_wasm_call_indirect_wide16:
 _wasm_trampoline_wasm_call_indirect_no_tls_wide16:
+_wasm_trampoline_wasm_call_ref_wide16:
+_wasm_trampoline_wasm_call_ref_no_tls_wide16:
 _wasm_trampoline_wasm_call_wide32:
 _wasm_trampoline_wasm_call_no_tls_wide32:
 _wasm_trampoline_wasm_call_indirect_wide32:
 _wasm_trampoline_wasm_call_indirect_no_tls_wide32:
+_wasm_trampoline_wasm_call_ref_wide32:
+_wasm_trampoline_wasm_call_ref_no_tls_wide32:
     crash()
 
 end

Modified: trunk/Source/_javascript_Core/llint/WebAssembly.asm (276895 => 276896)


--- trunk/Source/_javascript_Core/llint/WebAssembly.asm	2021-05-03 09:29:48 UTC (rev 276895)
+++ trunk/Source/_javascript_Core/llint/WebAssembly.asm	2021-05-03 11:00:43 UTC (rev 276896)
@@ -877,6 +877,14 @@
     slowPathForWasmCall(ctx, _slow_path_wasm_call_indirect_no_tls, macro(targetInstance) move targetInstance, wasmInstance end)
 end)
 
+wasmOp(call_ref, WasmCallRef, macro(ctx)
+    slowPathForWasmCall(ctx, _slow_path_wasm_call_ref, storeWasmInstanceToTLS)
+end)
+
+wasmOp(call_ref_no_tls, WasmCallRefNoTls, macro(ctx)
+    slowPathForWasmCall(ctx, _slow_path_wasm_call_ref_no_tls, macro(targetInstance) move targetInstance, wasmInstance end)
+end)
+
 wasmOp(current_memory, WasmCurrentMemory, macro(ctx)
     loadp Wasm::Instance::m_memory[wasmInstance], t0
     loadp Wasm::Memory::m_handle[t0], t0

Modified: trunk/Source/_javascript_Core/runtime/Gate.h (276895 => 276896)


--- trunk/Source/_javascript_Core/runtime/Gate.h	2021-05-03 09:29:48 UTC (rev 276895)
+++ trunk/Source/_javascript_Core/runtime/Gate.h	2021-05-03 11:00:43 UTC (rev 276896)
@@ -68,6 +68,8 @@
     v(wasm_call_no_tls, JSEntrySlowPathPtrTag) \
     v(wasm_call_indirect, JSEntrySlowPathPtrTag) \
     v(wasm_call_indirect_no_tls, JSEntrySlowPathPtrTag) \
+    v(wasm_call_ref, JSEntrySlowPathPtrTag) \
+    v(wasm_call_ref_no_tls, JSEntrySlowPathPtrTag) \
 
 #else
 #define JSC_WASM_GATE_OPCODES(v)

Modified: trunk/Source/_javascript_Core/wasm/WasmAirIRGenerator.cpp (276895 => 276896)


--- trunk/Source/_javascript_Core/wasm/WasmAirIRGenerator.cpp	2021-05-03 09:29:48 UTC (rev 276895)
+++ trunk/Source/_javascript_Core/wasm/WasmAirIRGenerator.cpp	2021-05-03 11:00:43 UTC (rev 276896)
@@ -325,7 +325,9 @@
     // Calls
     PartialResult WARN_UNUSED_RETURN addCall(uint32_t calleeIndex, const Signature&, Vector<ExpressionType>& args, ResultList& results);
     PartialResult WARN_UNUSED_RETURN addCallIndirect(unsigned tableIndex, const Signature&, Vector<ExpressionType>& args, ResultList& results);
+    PartialResult WARN_UNUSED_RETURN addCallRef(const Signature&, Vector<ExpressionType>& args, ResultList& results);
     PartialResult WARN_UNUSED_RETURN addUnreachable();
+    PartialResult WARN_UNUSED_RETURN emitIndirectCall(TypedTmp calleeInstance, ExpressionType calleeCode, const Signature&, const Vector<ExpressionType>& args, ResultList&);
     B3::PatchpointValue* WARN_UNUSED_RETURN emitCallPatchpoint(BasicBlock*, const Signature&, const ResultList& results, const Vector<TypedTmp>& args, Vector<ConstrainedTmp>&& extraArgs = { });
 
     PartialResult addShift(Type, B3::Air::Opcode, ExpressionType value, ExpressionType shift, ExpressionType& result);
@@ -3273,9 +3275,6 @@
     // can be to the embedder for our stack check calculation.
     m_maxNumJSCallArguments = std::max(m_maxNumJSCallArguments, static_cast<uint32_t>(args.size()));
 
-    auto currentInstance = g64();
-    append(Move, instanceValue(), currentInstance);
-
     ExpressionType callableFunctionBuffer = g64();
     ExpressionType instancesBuffer = g64();
     ExpressionType callableFunctionBufferLength = g64();
@@ -3340,15 +3339,42 @@
         });
     }
 
+    auto calleeInstance = g64();
+    append(Move, Arg::index(instancesBuffer, calleeIndex, 8, 0), calleeInstance);
+
+    return emitIndirectCall(calleeInstance, calleeCode, signature, args, results);
+}
+
+auto AirIRGenerator::addCallRef(const Signature& signature, Vector<ExpressionType>& args, ResultList& results) -> PartialResult
+{
+    m_makesCalls = true;
+    // Note: call ref can call either WebAssemblyFunction or WebAssemblyWrapperFunction. Because
+    // WebAssemblyWrapperFunction is like calling into the embedder, we conservatively assume all call indirects
+    // can be to the embedder for our stack check calculation.
+    ExpressionType calleeFunction = args.takeLast();
+    m_maxNumJSCallArguments = std::max(m_maxNumJSCallArguments, static_cast<uint32_t>(args.size()));
+
+    ExpressionType calleeCode = g64();
+    append(Move, Arg::addr(calleeFunction, WebAssemblyFunctionBase::offsetOfEntrypointLoadLocation()), calleeCode); // Pointer to callee code.
+
+    auto calleeInstance = g64();
+    append(Move, Arg::addr(calleeFunction, WebAssemblyFunctionBase::offsetOfInstance()), calleeInstance);
+    append(Move, Arg::addr(calleeInstance, JSWebAssemblyInstance::offsetOfInstance()), calleeInstance);
+
+    return emitIndirectCall(calleeInstance, calleeCode, signature, args, results);
+}
+
+auto AirIRGenerator::emitIndirectCall(TypedTmp calleeInstance, ExpressionType calleeCode, const Signature& signature, const Vector<ExpressionType>& args, ResultList& results) -> PartialResult
+{
+    auto currentInstance = g64();
+    append(Move, instanceValue(), currentInstance);
+
     // Do a context switch if needed.
     {
-        auto newContextInstance = g64();
-        append(Move, Arg::index(instancesBuffer, calleeIndex, 8, 0), newContextInstance);
-
         BasicBlock* doContextSwitch = m_code.addBlock();
         BasicBlock* continuation = m_code.addBlock();
 
-        append(Branch64, Arg::relCond(MacroAssembler::Equal), newContextInstance, instanceValue());
+        append(Branch64, Arg::relCond(MacroAssembler::Equal), calleeInstance, currentInstance);
         m_currentBlock->setSuccessors(continuation, doContextSwitch);
 
         auto* patchpoint = addPatchpoint(B3::Void);
@@ -3361,26 +3387,26 @@
 
         patchpoint->setGenerator([=] (CCallHelpers& jit, const B3::StackmapGenerationParams& params) {
             AllowMacroScratchRegisterUsage allowScratch(jit);
-            GPRReg newContextInstance = params[0].gpr();
+            GPRReg calleeInstance = params[0].gpr();
             GPRReg oldContextInstance = params[1].gpr();
             const PinnedRegisterInfo& pinnedRegs = PinnedRegisterInfo::get();
             GPRReg baseMemory = pinnedRegs.baseMemoryPointer;
-            ASSERT(newContextInstance != baseMemory);
+            ASSERT(calleeInstance != baseMemory);
             jit.loadPtr(CCallHelpers::Address(oldContextInstance, Instance::offsetOfCachedStackLimit()), baseMemory);
-            jit.storePtr(baseMemory, CCallHelpers::Address(newContextInstance, Instance::offsetOfCachedStackLimit()));
-            jit.storeWasmContextInstance(newContextInstance);
+            jit.storePtr(baseMemory, CCallHelpers::Address(calleeInstance, Instance::offsetOfCachedStackLimit()));
+            jit.storeWasmContextInstance(calleeInstance);
             // FIXME: We should support more than one memory size register
             //   see: https://bugs.webkit.org/show_bug.cgi?id=162952
-            ASSERT(pinnedRegs.boundsCheckingSizeRegister != newContextInstance);
+            ASSERT(pinnedRegs.boundsCheckingSizeRegister != calleeInstance);
             GPRReg scratch = params.gpScratch(0);
 
-            jit.loadPtr(CCallHelpers::Address(newContextInstance, Instance::offsetOfCachedBoundsCheckingSize()), pinnedRegs.boundsCheckingSizeRegister); // Bound checking size.
-            jit.loadPtr(CCallHelpers::Address(newContextInstance, Instance::offsetOfCachedMemory()), baseMemory); // Memory::void*.
+            jit.loadPtr(CCallHelpers::Address(calleeInstance, Instance::offsetOfCachedBoundsCheckingSize()), pinnedRegs.boundsCheckingSizeRegister); // Bound checking size.
+            jit.loadPtr(CCallHelpers::Address(calleeInstance, Instance::offsetOfCachedMemory()), baseMemory); // Memory::void*.
 
             jit.cageConditionallyAndUntag(Gigacage::Primitive, baseMemory, pinnedRegs.boundsCheckingSizeRegister, scratch);
         });
 
-        emitPatchpoint(doContextSwitch, patchpoint, Tmp(), newContextInstance, instanceValue());
+        emitPatchpoint(doContextSwitch, patchpoint, Tmp(), calleeInstance, currentInstance);
         append(doContextSwitch, Jump);
         doContextSwitch->setSuccessors(continuation);
 

Modified: trunk/Source/_javascript_Core/wasm/WasmB3IRGenerator.cpp (276895 => 276896)


--- trunk/Source/_javascript_Core/wasm/WasmB3IRGenerator.cpp	2021-05-03 09:29:48 UTC (rev 276895)
+++ trunk/Source/_javascript_Core/wasm/WasmB3IRGenerator.cpp	2021-05-03 11:00:43 UTC (rev 276896)
@@ -285,7 +285,9 @@
     // Calls
     PartialResult WARN_UNUSED_RETURN addCall(uint32_t calleeIndex, const Signature&, Vector<ExpressionType>& args, ResultList& results);
     PartialResult WARN_UNUSED_RETURN addCallIndirect(unsigned tableIndex, const Signature&, Vector<ExpressionType>& args, ResultList& results);
+    PartialResult WARN_UNUSED_RETURN addCallRef(const Signature&, Vector<ExpressionType>& args, ResultList& results);
     PartialResult WARN_UNUSED_RETURN addUnreachable();
+    PartialResult WARN_UNUSED_RETURN emitIndirectCall(Value* calleeInstance, ExpressionType calleeCode, const Signature&, Vector<ExpressionType>& args, ResultList&);
     B3::Value* createCallPatchpoint(BasicBlock*, Origin, const Signature&, Vector<ExpressionType>& args, const ScopedLambda<void(PatchpointValue*)>& patchpointFunctor);
 
     void dump(const ControlStack&, const Stack* expressionStack);
@@ -866,6 +868,95 @@
     return { };
 }
 
+auto B3IRGenerator::emitIndirectCall(Value* calleeInstance, ExpressionType calleeCode, const Signature& signature, Vector<ExpressionType>& args, ResultList& results) -> PartialResult
+{
+    // Do a context switch if needed.
+    {
+        BasicBlock* continuation = m_proc.addBlock();
+        BasicBlock* doContextSwitch = m_proc.addBlock();
+
+        Value* isSameContextInstance = m_currentBlock->appendNew<Value>(m_proc, Equal, origin(),
+            calleeInstance, instanceValue());
+        m_currentBlock->appendNewControlValue(m_proc, B3::Branch, origin(),
+            isSameContextInstance, FrequentedBlock(continuation), FrequentedBlock(doContextSwitch));
+
+        PatchpointValue* patchpoint = doContextSwitch->appendNew<PatchpointValue>(m_proc, B3::Void, origin());
+        patchpoint->effects.writesPinned = true;
+        // We pessimistically assume we're calling something with BoundsChecking memory.
+        // FIXME: We shouldn't have to do this: https://bugs.webkit.org/show_bug.cgi?id=172181
+        patchpoint->clobber(PinnedRegisterInfo::get().toSave(MemoryMode::BoundsChecking));
+        patchpoint->clobber(RegisterSet::macroScratchRegisters());
+        patchpoint->append(calleeInstance, ValueRep::SomeRegister);
+        patchpoint->append(instanceValue(), ValueRep::SomeRegister);
+        patchpoint->numGPScratchRegisters = 1;
+
+        patchpoint->setGenerator([=] (CCallHelpers& jit, const B3::StackmapGenerationParams& params) {
+            AllowMacroScratchRegisterUsage allowScratch(jit);
+            GPRReg calleeInstance = params[0].gpr();
+            GPRReg oldContextInstance = params[1].gpr();
+            const PinnedRegisterInfo& pinnedRegs = PinnedRegisterInfo::get();
+            GPRReg baseMemory = pinnedRegs.baseMemoryPointer;
+            ASSERT(calleeInstance != baseMemory);
+            jit.loadPtr(CCallHelpers::Address(oldContextInstance, Instance::offsetOfCachedStackLimit()), baseMemory);
+            jit.storePtr(baseMemory, CCallHelpers::Address(calleeInstance, Instance::offsetOfCachedStackLimit()));
+            jit.storeWasmContextInstance(calleeInstance);
+            ASSERT(pinnedRegs.boundsCheckingSizeRegister != baseMemory);
+            // FIXME: We should support more than one memory size register
+            //   see: https://bugs.webkit.org/show_bug.cgi?id=162952
+            ASSERT(pinnedRegs.boundsCheckingSizeRegister != calleeInstance);
+            GPRReg scratch = params.gpScratch(0);
+
+            jit.loadPtr(CCallHelpers::Address(calleeInstance, Instance::offsetOfCachedBoundsCheckingSize()), pinnedRegs.boundsCheckingSizeRegister); // Memory size.
+            jit.loadPtr(CCallHelpers::Address(calleeInstance, Instance::offsetOfCachedMemory()), baseMemory); // Memory::void*.
+
+            jit.cageConditionallyAndUntag(Gigacage::Primitive, baseMemory, pinnedRegs.boundsCheckingSizeRegister, scratch);
+        });
+        doContextSwitch->appendNewControlValue(m_proc, Jump, origin(), continuation);
+
+        m_currentBlock = continuation;
+    }
+
+    B3::Type returnType = toB3ResultType(&signature);
+    ExpressionType callResult = createCallPatchpoint(m_currentBlock, origin(), signature, args,
+        scopedLambdaRef<void(PatchpointValue*)>([=] (PatchpointValue* patchpoint) -> void {
+            patchpoint->effects.writesPinned = true;
+            patchpoint->effects.readsPinned = true;
+            // We need to clobber all potential pinned registers since we might be leaving the instance.
+            // We pessimistically assume we're always calling something that is bounds checking so
+            // because the wasm->wasm thunk unconditionally overrides the size registers.
+            // FIXME: We should not have to do this, but the wasm->wasm stub assumes it can
+            // use all the pinned registers as scratch: https://bugs.webkit.org/show_bug.cgi?id=172181
+            patchpoint->clobberLate(PinnedRegisterInfo::get().toSave(MemoryMode::BoundsChecking));
+
+            patchpoint->append(calleeCode, ValueRep::SomeRegister);
+            patchpoint->setGenerator([=] (CCallHelpers& jit, const B3::StackmapGenerationParams& params) {
+                AllowMacroScratchRegisterUsage allowScratch(jit);
+                jit.call(params[params.proc().resultCount(returnType)].gpr(), WasmEntryPtrTag);
+            });
+        }));
+
+    switch (returnType.kind()) {
+    case B3::Void: {
+        break;
+    }
+    case B3::Tuple: {
+        const Vector<B3::Type>& tuple = m_proc.tupleForType(returnType);
+        for (unsigned i = 0; i < signature.returnCount(); ++i)
+            results.append(m_currentBlock->appendNew<ExtractValue>(m_proc, origin(), tuple[i], callResult, i));
+        break;
+    }
+    default: {
+        results.append(callResult);
+        break;
+    }
+    }
+
+    // The call could have been to another WebAssembly instance, and / or could have modified our Memory.
+    restoreWebAssemblyGlobalState(RestoreCachedStackLimit::Yes, m_info.memory, instanceValue(), m_proc, m_currentBlock);
+
+    return { };
+}
+
 auto B3IRGenerator::addGrowMemory(ExpressionType delta, ExpressionType& result) -> PartialResult
 {
     result = m_currentBlock->appendNew<CCallValue>(m_proc, Int32, origin(),
@@ -2521,100 +2612,41 @@
         }
     }
 
-    // Do a context switch if needed.
-    {
-        Value* offset = m_currentBlock->appendNew<Value>(m_proc, Mul, origin(),
-            calleeIndex, constant(pointerType(), sizeof(Instance*)));
-        Value* newContextInstance = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, pointerType(), origin(),
-            m_currentBlock->appendNew<Value>(m_proc, Add, origin(), instancesBuffer, offset));
+    Value* offset = m_currentBlock->appendNew<Value>(m_proc, Mul, origin(),
+        calleeIndex, constant(pointerType(), sizeof(Instance*)));
+    Value* calleeInstance = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, pointerType(), origin(),
+        m_currentBlock->appendNew<Value>(m_proc, Add, origin(), instancesBuffer, offset));
+    ExpressionType calleeCode = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, pointerType(), origin(),
+        m_currentBlock->appendNew<MemoryValue>(m_proc, Load, pointerType(), origin(), callableFunction,
+            safeCast<int32_t>(WasmToWasmImportableFunction::offsetOfEntrypointLoadLocation())));
 
-        BasicBlock* continuation = m_proc.addBlock();
-        BasicBlock* doContextSwitch = m_proc.addBlock();
+    return emitIndirectCall(calleeInstance, calleeCode, signature, args, results);
+}
 
-        Value* isSameContextInstance = m_currentBlock->appendNew<Value>(m_proc, Equal, origin(),
-            newContextInstance, instanceValue());
-        m_currentBlock->appendNewControlValue(m_proc, B3::Branch, origin(),
-            isSameContextInstance, FrequentedBlock(continuation), FrequentedBlock(doContextSwitch));
+auto B3IRGenerator::addCallRef(const Signature& signature, Vector<ExpressionType>& args, ResultList& results) -> PartialResult
+{
+    ExpressionType callee = args.takeLast();
+    ASSERT(signature.argumentCount() == args.size());
+    m_makesCalls = true;
 
-        PatchpointValue* patchpoint = doContextSwitch->appendNew<PatchpointValue>(m_proc, B3::Void, origin());
-        patchpoint->effects.writesPinned = true;
-        // We pessimistically assume we're calling something with BoundsChecking memory.
-        // FIXME: We shouldn't have to do this: https://bugs.webkit.org/show_bug.cgi?id=172181
-        patchpoint->clobber(PinnedRegisterInfo::get().toSave(MemoryMode::BoundsChecking));
-        patchpoint->clobber(RegisterSet::macroScratchRegisters());
-        patchpoint->append(newContextInstance, ValueRep::SomeRegister);
-        patchpoint->append(instanceValue(), ValueRep::SomeRegister);
-        patchpoint->numGPScratchRegisters = 1;
+    // Note: call ref can call either WebAssemblyFunction or WebAssemblyWrapperFunction. Because
+    // WebAssemblyWrapperFunction is like calling into the embedder, we conservatively assume all call indirects
+    // can be to the embedder for our stack check calculation.
+    m_maxNumJSCallArguments = std::max(m_maxNumJSCallArguments, static_cast<uint32_t>(args.size()));
 
-        patchpoint->setGenerator([=] (CCallHelpers& jit, const B3::StackmapGenerationParams& params) {
-            AllowMacroScratchRegisterUsage allowScratch(jit);
-            GPRReg newContextInstance = params[0].gpr();
-            GPRReg oldContextInstance = params[1].gpr();
-            const PinnedRegisterInfo& pinnedRegs = PinnedRegisterInfo::get();
-            GPRReg baseMemory = pinnedRegs.baseMemoryPointer;
-            ASSERT(newContextInstance != baseMemory);
-            jit.loadPtr(CCallHelpers::Address(oldContextInstance, Instance::offsetOfCachedStackLimit()), baseMemory);
-            jit.storePtr(baseMemory, CCallHelpers::Address(newContextInstance, Instance::offsetOfCachedStackLimit()));
-            jit.storeWasmContextInstance(newContextInstance);
-            ASSERT(pinnedRegs.boundsCheckingSizeRegister != baseMemory);
-            // FIXME: We should support more than one memory size register
-            //   see: https://bugs.webkit.org/show_bug.cgi?id=162952
-            ASSERT(pinnedRegs.boundsCheckingSizeRegister != newContextInstance);
-            GPRReg scratch = params.gpScratch(0);
+    Value* jsInstanceOffset = constant(pointerType(), safeCast<int32_t>(WebAssemblyFunctionBase::offsetOfInstance()));
+    Value* jsCalleeInstance = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, pointerType(), origin(),
+        m_currentBlock->appendNew<Value>(m_proc, Add, origin(), callee, jsInstanceOffset));
 
-            jit.loadPtr(CCallHelpers::Address(newContextInstance, Instance::offsetOfCachedBoundsCheckingSize()), pinnedRegs.boundsCheckingSizeRegister); // Memory size.
-            jit.loadPtr(CCallHelpers::Address(newContextInstance, Instance::offsetOfCachedMemory()), baseMemory); // Memory::void*.
+    Value* instanceOffset = constant(pointerType(), safeCast<int32_t>(JSWebAssemblyInstance::offsetOfInstance()));
+    Value* calleeInstance = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, pointerType(), origin(),
+        m_currentBlock->appendNew<Value>(m_proc, Add, origin(), jsCalleeInstance, instanceOffset));
 
-            jit.cageConditionallyAndUntag(Gigacage::Primitive, baseMemory, pinnedRegs.boundsCheckingSizeRegister, scratch);
-        });
-        doContextSwitch->appendNewControlValue(m_proc, Jump, origin(), continuation);
-
-        m_currentBlock = continuation;
-    }
-
     ExpressionType calleeCode = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, pointerType(), origin(),
-        m_currentBlock->appendNew<MemoryValue>(m_proc, Load, pointerType(), origin(), callableFunction,
-            safeCast<int32_t>(WasmToWasmImportableFunction::offsetOfEntrypointLoadLocation())));
+        m_currentBlock->appendNew<MemoryValue>(m_proc, Load, pointerType(), origin(), callee,
+            safeCast<int32_t>(WebAssemblyFunctionBase::offsetOfEntrypointLoadLocation())));
 
-    B3::Type returnType = toB3ResultType(&signature);
-    ExpressionType callResult = createCallPatchpoint(m_currentBlock, origin(), signature, args,
-        scopedLambdaRef<void(PatchpointValue*)>([=] (PatchpointValue* patchpoint) -> void {
-            patchpoint->effects.writesPinned = true;
-            patchpoint->effects.readsPinned = true;
-            // We need to clobber all potential pinned registers since we might be leaving the instance.
-            // We pessimistically assume we're always calling something that is bounds checking so
-            // because the wasm->wasm thunk unconditionally overrides the size registers.
-            // FIXME: We should not have to do this, but the wasm->wasm stub assumes it can
-            // use all the pinned registers as scratch: https://bugs.webkit.org/show_bug.cgi?id=172181
-            patchpoint->clobberLate(PinnedRegisterInfo::get().toSave(MemoryMode::BoundsChecking));
-
-            patchpoint->append(calleeCode, ValueRep::SomeRegister);
-            patchpoint->setGenerator([=] (CCallHelpers& jit, const B3::StackmapGenerationParams& params) {
-                AllowMacroScratchRegisterUsage allowScratch(jit);
-                jit.call(params[params.proc().resultCount(returnType)].gpr(), WasmEntryPtrTag);
-            });
-        }));
-
-    switch (returnType.kind()) {
-    case B3::Void: {
-        break;
-    }
-    case B3::Tuple: {
-        const Vector<B3::Type>& tuple = m_proc.tupleForType(returnType);
-        for (unsigned i = 0; i < signature.returnCount(); ++i)
-            results.append(m_currentBlock->appendNew<ExtractValue>(m_proc, origin(), tuple[i], callResult, i));
-        break;
-    }
-    default: {
-        results.append(callResult);
-        break;
-    }
-    }
-
-    // The call could have been to another WebAssembly instance, and / or could have modified our Memory.
-    restoreWebAssemblyGlobalState(RestoreCachedStackLimit::Yes, m_info.memory, instanceValue(), m_proc, m_currentBlock);
-
-    return { };
+    return emitIndirectCall(calleeInstance, calleeCode, signature, args, results);
 }
 
 void B3IRGenerator::unify(const ExpressionType phi, const ExpressionType source)

Modified: trunk/Source/_javascript_Core/wasm/WasmFunctionParser.h (276895 => 276896)


--- trunk/Source/_javascript_Core/wasm/WasmFunctionParser.h	2021-05-03 09:29:48 UTC (rev 276895)
+++ trunk/Source/_javascript_Core/wasm/WasmFunctionParser.h	2021-05-03 11:00:43 UTC (rev 276896)
@@ -1248,6 +1248,37 @@
 
         return { };
     }
+
+    case CallRef: {
+        WASM_PARSER_FAIL_IF(!Options::useWebAssemblyTypedFunctionReferences(), "function references are not enabled");
+        WASM_VALIDATOR_FAIL_IF(!m_expressionStack.last().type().isTypeIdx(), "non-funcref call_ref value ", m_expressionStack.last().type().kind);
+
+        const SignatureIndex calleeSignatureIndex = m_expressionStack.last().type().index;
+        const Signature& calleeSignature = SignatureInformation::get(calleeSignatureIndex);
+        size_t argumentCount = calleeSignature.argumentCount() + 1; // Add the callee's value.
+        WASM_PARSER_FAIL_IF(argumentCount > m_expressionStack.size(), "call_ref expects ", argumentCount, " arguments, but the _expression_ stack currently holds ", m_expressionStack.size(), " values");
+
+        Vector<ExpressionType> args;
+        WASM_PARSER_FAIL_IF(!args.tryReserveCapacity(argumentCount + 1), "can't allocate enough memory for ", argumentCount, " call_indirect arguments");
+        size_t firstArgumentIndex = m_expressionStack.size() - argumentCount;
+        for (size_t i = firstArgumentIndex; i < m_expressionStack.size(); ++i) {
+            TypedExpression arg = m_expressionStack.at(i);
+            if (i < m_expressionStack.size() - 1)
+                WASM_VALIDATOR_FAIL_IF(arg.type() != calleeSignature.argument(i - firstArgumentIndex), "argument type mismatch in call_indirect, got ", arg.type().kind, ", expected ", calleeSignature.argument(i - firstArgumentIndex).kind);
+            args.uncheckedAppend(arg);
+            m_context.didPopValueFromStack();
+        }
+        m_expressionStack.shrink(firstArgumentIndex);
+
+        ResultList results;
+        WASM_TRY_ADD_TO_CONTEXT(addCallRef(calleeSignature, args, results));
+
+        for (unsigned i = 0; i < calleeSignature.returnCount(); ++i)
+            m_expressionStack.constructAndAppend(calleeSignature.returnType(i), results[i]);
+
+        return { };
+    }
+
     case Block: {
         BlockSignature inlineSignature;
         WASM_PARSER_FAIL_IF(!parseBlockSignature(m_info, inlineSignature), "can't get block's signature");
@@ -1739,6 +1770,7 @@
     // no immediate cases
     FOR_EACH_WASM_BINARY_OP(CREATE_CASE)
     FOR_EACH_WASM_UNARY_OP(CREATE_CASE)
+    case CallRef:
     case Unreachable:
     case Nop:
     case Return:

Modified: trunk/Source/_javascript_Core/wasm/WasmLLIntGenerator.cpp (276895 => 276896)


--- trunk/Source/_javascript_Core/wasm/WasmLLIntGenerator.cpp	2021-05-03 09:29:48 UTC (rev 276895)
+++ trunk/Source/_javascript_Core/wasm/WasmLLIntGenerator.cpp	2021-05-03 11:00:43 UTC (rev 276896)
@@ -253,6 +253,7 @@
     // Calls
     PartialResult WARN_UNUSED_RETURN addCall(uint32_t calleeIndex, const Signature&, Vector<ExpressionType>& args, ResultList& results);
     PartialResult WARN_UNUSED_RETURN addCallIndirect(unsigned tableIndex, const Signature&, Vector<ExpressionType>& args, ResultList& results);
+    PartialResult WARN_UNUSED_RETURN addCallRef(const Signature&, Vector<ExpressionType>& args, ResultList& results);
     PartialResult WARN_UNUSED_RETURN addUnreachable();
 
     void didFinishParsingLocals();
@@ -1104,6 +1105,21 @@
     return { };
 }
 
+auto LLIntGenerator::addCallRef(const Signature& signature, Vector<ExpressionType>& args, ResultList& results) -> PartialResult
+{
+    ExpressionType callee = args.takeLast();
+
+    LLIntCallInformation info = callInformationForCaller(signature);
+    unifyValuesWithBlock(info.arguments, args);
+    if (Context::useFastTLS())
+        WasmCallRef::emit(this, callee, m_codeBlock->addSignature(signature), info.stackOffset, info.numberOfStackArguments);
+    else
+        WasmCallRefNoTls::emit(this, callee, m_codeBlock->addSignature(signature), info.stackOffset, info.numberOfStackArguments);
+    info.commitResults(results);
+
+    return { };
+}
+
 auto LLIntGenerator::addRefIsNull(ExpressionType value, ExpressionType& result) -> PartialResult
 {
     result = push();

Modified: trunk/Source/_javascript_Core/wasm/WasmSlowPaths.cpp (276895 => 276896)


--- trunk/Source/_javascript_Core/wasm/WasmSlowPaths.cpp	2021-05-03 09:29:48 UTC (rev 276895)
+++ trunk/Source/_javascript_Core/wasm/WasmSlowPaths.cpp	2021-05-03 11:00:43 UTC (rev 276896)
@@ -29,6 +29,7 @@
 #if ENABLE(WEBASSEMBLY)
 
 #include "BytecodeStructs.h"
+#include "JSWebAssemblyInstance.h"
 #include "LLIntData.h"
 #include "WasmBBQPlan.h"
 #include "WasmCallee.h"
@@ -40,6 +41,7 @@
 #include "WasmOperations.h"
 #include "WasmSignatureInlines.h"
 #include "WasmWorklist.h"
+#include "WebAssemblyFunction.h"
 
 namespace JSC { namespace LLInt {
 
@@ -498,6 +500,40 @@
     return doWasmCallIndirect(callFrame, instance, functionIndex, instruction.m_tableIndex, instruction.m_signatureIndex);
 }
 
+inline SlowPathReturnType doWasmCallRef(CallFrame* callFrame, Wasm::Instance* callerInstance, JSValue targetReference, unsigned signatureIndex)
+{
+    UNUSED_PARAM(callFrame);
+
+    ASSERT(targetReference.isObject());
+    JSObject* referenceAsObject = jsCast<JSObject*>(targetReference);
+
+    ASSERT(referenceAsObject->inherits<WebAssemblyFunctionBase>(callerInstance->owner<JSObject>()->vm()));
+    auto* wasmFunction = jsCast<WebAssemblyFunctionBase*>(referenceAsObject);
+    Wasm::WasmToWasmImportableFunction function = wasmFunction->importableFunction();
+    Wasm::Instance* calleeInstance = &wasmFunction->instance()->instance();
+
+    if (calleeInstance != callerInstance)
+        calleeInstance->setCachedStackLimit(callerInstance->cachedStackLimit());
+
+    ASSERT(function.signatureIndex == Wasm::SignatureInformation::get(CODE_BLOCK()->signature(signatureIndex)));
+    UNUSED_PARAM(signatureIndex);
+    WASM_CALL_RETURN(calleeInstance, function.entrypointLoadLocation->executableAddress(), WasmEntryPtrTag);
+}
+
+WASM_SLOW_PATH_DECL(call_ref)
+{
+    auto instruction = pc->as<WasmCallRef, WasmOpcodeTraits>();
+    JSValue reference = JSValue::decode(READ(instruction.m_functionReference).encodedJSValue());
+    return doWasmCallRef(callFrame, instance, reference, instruction.m_signatureIndex);
+}
+
+WASM_SLOW_PATH_DECL(call_ref_no_tls)
+{
+    auto instruction = pc->as<WasmCallRefNoTls, WasmOpcodeTraits>();
+    JSValue reference = JSValue::decode(READ(instruction.m_functionReference).encodedJSValue());
+    return doWasmCallRef(callFrame, instance, reference, instruction.m_signatureIndex);
+}
+
 WASM_SLOW_PATH_DECL(set_global_ref)
 {
     auto instruction = pc->as<WasmSetGlobalRef, WasmOpcodeTraits>();

Modified: trunk/Source/_javascript_Core/wasm/WasmSlowPaths.h (276895 => 276896)


--- trunk/Source/_javascript_Core/wasm/WasmSlowPaths.h	2021-05-03 09:29:48 UTC (rev 276895)
+++ trunk/Source/_javascript_Core/wasm/WasmSlowPaths.h	2021-05-03 11:00:43 UTC (rev 276896)
@@ -76,6 +76,8 @@
 WASM_SLOW_PATH_HIDDEN_DECL(call_no_tls);
 WASM_SLOW_PATH_HIDDEN_DECL(call_indirect);
 WASM_SLOW_PATH_HIDDEN_DECL(call_indirect_no_tls);
+WASM_SLOW_PATH_HIDDEN_DECL(call_ref);
+WASM_SLOW_PATH_HIDDEN_DECL(call_ref_no_tls);
 WASM_SLOW_PATH_HIDDEN_DECL(set_global_ref);
 WASM_SLOW_PATH_HIDDEN_DECL(set_global_ref_portable_binding);
 WASM_SLOW_PATH_HIDDEN_DECL(memory_atomic_wait32);

Modified: trunk/Source/_javascript_Core/wasm/js/JSWebAssemblyTable.cpp (276895 => 276896)


--- trunk/Source/_javascript_Core/wasm/js/JSWebAssemblyTable.cpp	2021-05-03 09:29:48 UTC (rev 276895)
+++ trunk/Source/_javascript_Core/wasm/js/JSWebAssemblyTable.cpp	2021-05-03 11:00:43 UTC (rev 276896)
@@ -105,7 +105,7 @@
     m_table->set(index, value);
 }
 
-void JSWebAssemblyTable::set(uint32_t index, WebAssemblyFunction* function)
+void JSWebAssemblyTable::set(uint32_t index, WebAssemblyFunctionBase* function)
 {
     RELEASE_ASSERT(index < length());
     RELEASE_ASSERT(m_table->asFuncrefTable());
@@ -113,14 +113,6 @@
     subThis.setFunction(index, function, function->importableFunction(), &function->instance()->instance());
 }
 
-void JSWebAssemblyTable::set(uint32_t index, WebAssemblyWrapperFunction* function)
-{
-    RELEASE_ASSERT(index < length());
-    RELEASE_ASSERT(m_table->asFuncrefTable());
-    auto& subThis = *static_cast<Wasm::FuncRefTable*>(&m_table.get());
-    subThis.setFunction(index, function, function->importableFunction(), &function->instance()->instance());
-}
-
 void JSWebAssemblyTable::clear(uint32_t index)
 {
     RELEASE_ASSERT(index < length());

Modified: trunk/Source/_javascript_Core/wasm/js/JSWebAssemblyTable.h (276895 => 276896)


--- trunk/Source/_javascript_Core/wasm/js/JSWebAssemblyTable.h	2021-05-03 09:29:48 UTC (rev 276895)
+++ trunk/Source/_javascript_Core/wasm/js/JSWebAssemblyTable.h	2021-05-03 11:00:43 UTC (rev 276896)
@@ -60,8 +60,7 @@
     uint32_t allocatedLength() const { return m_table->allocatedLength(length()); }
     bool grow(uint32_t delta, JSValue defaultValue) WARN_UNUSED_RETURN;
     JSValue get(uint32_t);
-    void set(uint32_t, WebAssemblyFunction*);
-    void set(uint32_t, WebAssemblyWrapperFunction*);
+    void set(uint32_t, WebAssemblyFunctionBase*);
     void set(uint32_t, JSValue);
     void clear(uint32_t);
     JSObject* type(JSGlobalObject*);

Modified: trunk/Source/_javascript_Core/wasm/js/WebAssemblyFunction.cpp (276895 => 276896)


--- trunk/Source/_javascript_Core/wasm/js/WebAssemblyFunction.cpp	2021-05-03 09:29:48 UTC (rev 276895)
+++ trunk/Source/_javascript_Core/wasm/js/WebAssemblyFunction.cpp	2021-05-03 11:00:43 UTC (rev 276896)
@@ -454,9 +454,8 @@
 }
 
 WebAssemblyFunction::WebAssemblyFunction(VM& vm, NativeExecutable* executable, JSGlobalObject* globalObject, Structure* structure, Wasm::Callee& jsEntrypoint, Wasm::WasmToWasmImportableFunction::LoadLocation wasmToWasmEntrypointLoadLocation, Wasm::SignatureIndex signatureIndex)
-    : Base { vm, executable, globalObject, structure }
+    : Base { vm, executable, globalObject, structure, Wasm::WasmToWasmImportableFunction { signatureIndex, wasmToWasmEntrypointLoadLocation } }
     , m_jsEntrypoint { jsEntrypoint.entrypoint() }
-    , m_importableFunction { signatureIndex, wasmToWasmEntrypointLoadLocation }
 { }
 
 template<typename Visitor>

Modified: trunk/Source/_javascript_Core/wasm/js/WebAssemblyFunction.h (276895 => 276896)


--- trunk/Source/_javascript_Core/wasm/js/WebAssemblyFunction.h	2021-05-03 09:29:48 UTC (rev 276895)
+++ trunk/Source/_javascript_Core/wasm/js/WebAssemblyFunction.h	2021-05-03 11:00:43 UTC (rev 276896)
@@ -39,7 +39,6 @@
 class JSGlobalObject;
 struct ProtoCallFrame;
 class WebAssemblyInstance;
-using Wasm::WasmToWasmImportableFunction;
 
 class WebAssemblyFunction final : public WebAssemblyFunctionBase {
 public:
@@ -61,10 +60,6 @@
     JS_EXPORT_PRIVATE static WebAssemblyFunction* create(VM&, JSGlobalObject*, Structure*, unsigned, const String&, JSWebAssemblyInstance*, Wasm::Callee& jsEntrypoint, WasmToWasmImportableFunction::LoadLocation, Wasm::SignatureIndex);
     static Structure* createStructure(VM&, JSGlobalObject*, JSValue);
 
-    Wasm::SignatureIndex signatureIndex() const { return m_importableFunction.signatureIndex; }
-    WasmToWasmImportableFunction::LoadLocation entrypointLoadLocation() const { return m_importableFunction.entrypointLoadLocation; }
-    WasmToWasmImportableFunction importableFunction() const { return m_importableFunction; }
-
     MacroAssemblerCodePtr<WasmEntryPtrTag> jsEntrypoint(ArityCheckMode arity)
     {
         if (arity == ArityCheckNotRequired)
@@ -73,8 +68,6 @@
         return m_jsEntrypoint;
     }
 
-    static ptrdiff_t offsetOfEntrypointLoadLocation() { return OBJECT_OFFSETOF(WebAssemblyFunction, m_importableFunction) + WasmToWasmImportableFunction::offsetOfEntrypointLoadLocation(); }
-
     MacroAssemblerCodePtr<JSEntryPtrTag> jsCallEntrypoint()
     {
         if (m_jsCallEntrypoint)
@@ -95,11 +88,10 @@
 
     RegisterSet calleeSaves() const;
 
-    // It's safe to just hold the raw WasmToWasmImportableFunction/jsEntrypoint because we have a reference
+    // It's safe to just hold the raw jsEntrypoint because we have a reference
     // to our Instance, which points to the Module that exported us, which
     // ensures that the actual Signature/code doesn't get deallocated.
     MacroAssemblerCodePtr<WasmEntryPtrTag> m_jsEntrypoint;
-    WasmToWasmImportableFunction m_importableFunction;
     WriteBarrier<JSToWasmICCallee> m_jsToWasmICCallee;
     // Used for JS calling into Wasm.
     MacroAssemblerCodeRef<JSEntryPtrTag> m_jsCallEntrypoint;

Modified: trunk/Source/_javascript_Core/wasm/js/WebAssemblyFunctionBase.cpp (276895 => 276896)


--- trunk/Source/_javascript_Core/wasm/js/WebAssemblyFunctionBase.cpp	2021-05-03 09:29:48 UTC (rev 276895)
+++ trunk/Source/_javascript_Core/wasm/js/WebAssemblyFunctionBase.cpp	2021-05-03 11:00:43 UTC (rev 276896)
@@ -37,8 +37,9 @@
 
 const ClassInfo WebAssemblyFunctionBase::s_info = { "WebAssemblyFunctionBase", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(WebAssemblyFunctionBase) };
 
-WebAssemblyFunctionBase::WebAssemblyFunctionBase(VM& vm, NativeExecutable* executable, JSGlobalObject* globalObject, Structure* structure)
+WebAssemblyFunctionBase::WebAssemblyFunctionBase(VM& vm, NativeExecutable* executable, JSGlobalObject* globalObject, Structure* structure, WasmToWasmImportableFunction importableFunction)
     : Base(vm, executable, globalObject, structure)
+    , m_importableFunction(importableFunction)
 { }
 
 template<typename Visitor>

Modified: trunk/Source/_javascript_Core/wasm/js/WebAssemblyFunctionBase.h (276895 => 276896)


--- trunk/Source/_javascript_Core/wasm/js/WebAssemblyFunctionBase.h	2021-05-03 09:29:48 UTC (rev 276895)
+++ trunk/Source/_javascript_Core/wasm/js/WebAssemblyFunctionBase.h	2021-05-03 11:00:43 UTC (rev 276896)
@@ -33,6 +33,7 @@
 
 class JSGlobalObject;
 class JSWebAssemblyInstance;
+using Wasm::WasmToWasmImportableFunction;
 
 class WebAssemblyFunctionBase : public JSFunction {
 public:
@@ -43,14 +44,26 @@
     DECLARE_INFO;
 
     JSWebAssemblyInstance* instance() const { return m_instance.get(); }
+
+    Wasm::SignatureIndex signatureIndex() const { return m_importableFunction.signatureIndex; }
+    WasmToWasmImportableFunction::LoadLocation entrypointLoadLocation() const { return m_importableFunction.entrypointLoadLocation; }
+    WasmToWasmImportableFunction importableFunction() const { return m_importableFunction; }
+
     static ptrdiff_t offsetOfInstance() { return OBJECT_OFFSETOF(WebAssemblyFunctionBase, m_instance); }
 
+    static ptrdiff_t offsetOfEntrypointLoadLocation() { return OBJECT_OFFSETOF(WebAssemblyFunctionBase, m_importableFunction) + WasmToWasmImportableFunction::offsetOfEntrypointLoadLocation(); }
+
 protected:
     DECLARE_VISIT_CHILDREN;
     void finishCreation(VM&, NativeExecutable*, unsigned length, const String& name, JSWebAssemblyInstance*);
-    WebAssemblyFunctionBase(VM&, NativeExecutable*, JSGlobalObject*, Structure*);
+    WebAssemblyFunctionBase(VM&, NativeExecutable*, JSGlobalObject*, Structure*, WasmToWasmImportableFunction);
 
     WriteBarrier<JSWebAssemblyInstance> m_instance;
+
+    // It's safe to just hold the raw WasmToWasmImportableFunction because we have a reference
+    // to our Instance, which points to the CodeBlock, which points to the Module
+    // that exported us, which ensures that the actual Signature/code doesn't get deallocated.
+    WasmToWasmImportableFunction m_importableFunction;
 };
 
 } // namespace JSC

Modified: trunk/Source/_javascript_Core/wasm/js/WebAssemblyWrapperFunction.cpp (276895 => 276896)


--- trunk/Source/_javascript_Core/wasm/js/WebAssemblyWrapperFunction.cpp	2021-05-03 09:29:48 UTC (rev 276895)
+++ trunk/Source/_javascript_Core/wasm/js/WebAssemblyWrapperFunction.cpp	2021-05-03 11:00:43 UTC (rev 276896)
@@ -39,8 +39,7 @@
 static JSC_DECLARE_HOST_FUNCTION(callWebAssemblyWrapperFunction);
 
 WebAssemblyWrapperFunction::WebAssemblyWrapperFunction(VM& vm, NativeExecutable* executable, JSGlobalObject* globalObject, Structure* structure, Wasm::WasmToWasmImportableFunction importableFunction)
-    : Base(vm, executable, globalObject, structure)
-    , m_importableFunction(importableFunction)
+    : Base(vm, executable, globalObject, structure, importableFunction)
 { }
 
 WebAssemblyWrapperFunction* WebAssemblyWrapperFunction::create(VM& vm, JSGlobalObject* globalObject, Structure* structure, JSObject* function, unsigned importIndex, JSWebAssemblyInstance* instance, Wasm::SignatureIndex signatureIndex)

Modified: trunk/Source/_javascript_Core/wasm/js/WebAssemblyWrapperFunction.h (276895 => 276896)


--- trunk/Source/_javascript_Core/wasm/js/WebAssemblyWrapperFunction.h	2021-05-03 09:29:48 UTC (rev 276895)
+++ trunk/Source/_javascript_Core/wasm/js/WebAssemblyWrapperFunction.h	2021-05-03 11:00:43 UTC (rev 276896)
@@ -32,8 +32,6 @@
 
 namespace JSC {
 
-using Wasm::WasmToWasmImportableFunction;
-
 class WebAssemblyWrapperFunction final : public WebAssemblyFunctionBase {
 public:
     using Base = WebAssemblyFunctionBase;
@@ -51,9 +49,6 @@
     static WebAssemblyWrapperFunction* create(VM&, JSGlobalObject*, Structure*, JSObject*, unsigned importIndex, JSWebAssemblyInstance*, Wasm::SignatureIndex);
     static Structure* createStructure(VM&, JSGlobalObject*, JSValue);
 
-    Wasm::SignatureIndex signatureIndex() const { return m_importableFunction.signatureIndex; }
-    WasmToWasmImportableFunction::LoadLocation  entrypointLoadLocation() const { return m_importableFunction.entrypointLoadLocation; }
-    WasmToWasmImportableFunction importableFunction() const { return m_importableFunction; }
     JSObject* function() { return m_function.get(); }
 
 private:
@@ -62,10 +57,6 @@
     DECLARE_VISIT_CHILDREN;
 
     WriteBarrier<JSObject> m_function;
-    // It's safe to just hold the raw WasmToWasmImportableFunction because we have a reference
-    // to our Instance, which points to the CodeBlock, which points to the Module
-    // that exported us, which ensures that the actual Signature/code doesn't get deallocated.
-    WasmToWasmImportableFunction m_importableFunction;
 };
 
 } // namespace JSC

Modified: trunk/Source/_javascript_Core/wasm/wasm.json (276895 => 276896)


--- trunk/Source/_javascript_Core/wasm/wasm.json	2021-05-03 09:29:48 UTC (rev 276895)
+++ trunk/Source/_javascript_Core/wasm/wasm.json	2021-05-03 11:00:43 UTC (rev 276896)
@@ -85,6 +85,7 @@
         "data.drop":           { "category": "exttable",   "value":  252, "return": [],                              "parameter": [],                             "immediate": [{"name": "segment_index",  "type": "varuint32"}],                                             "description": "shrinks the size of the segment to zero", "extendedOp": 9 },
         "call":                { "category": "call",       "value":  16, "return": ["call"],                         "parameter": ["call"],                       "immediate": [{"name": "function_index", "type": "varuint32"}],                                             "description": "call a function by its index" },
         "call_indirect":       { "category": "call",       "value":  17, "return": ["call"],                         "parameter": ["call"],                       "immediate": [{"name": "type_index",     "type": "varuint32"}, {"name": "table_index","type": "varuint32"}],"description": "call a function indirect with an expected signature" },
+        "call_ref":            { "category": "call",       "value":  20, "return": ["call"],                         "parameter": ["call"],                       "immediate": [],                                                                                            "description": "call a function reference" },
         "i32.load8_s":         { "category": "memory",     "value":  44, "return": ["i32"],                          "parameter": ["addr"],                       "immediate": [{"name": "flags",          "type": "varuint32"}, {"name": "offset",   "type": "varuint32"}], "description": "load from memory" },
         "i32.load8_u":         { "category": "memory",     "value":  45, "return": ["i32"],                          "parameter": ["addr"],                       "immediate": [{"name": "flags",          "type": "varuint32"}, {"name": "offset",   "type": "varuint32"}], "description": "load from memory" },
         "i32.load16_s":        { "category": "memory",     "value":  46, "return": ["i32"],                          "parameter": ["addr"],                       "immediate": [{"name": "flags",          "type": "varuint32"}, {"name": "offset",   "type": "varuint32"}], "description": "load from memory" },
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to