WebAssembly: add fallback to use pinned register to load/store state
authorutatane.tea@gmail.com <utatane.tea@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 28 Mar 2017 22:16:01 +0000 (22:16 +0000)
committerutatane.tea@gmail.com <utatane.tea@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 28 Mar 2017 22:16:01 +0000 (22:16 +0000)
https://bugs.webkit.org/show_bug.cgi?id=169773

Reviewed by Saam Barati.

This patch adds a new pinned register to hold JSWebAssemblyInstance,
which is used to represent the context of running Wasm code.
While we use fast TLS to hold the context in macOS, we do not have
any system reserved fast TLS slot in the other systems. This pinned
register approach is used in these systems. These changes decouple
VM from Wasm module to make Wasm module position independent code.

While using fast TLS could be beneficial in x64 systems which number of
registers is relatively small, pinned register approach could be
beneficial in ARM64 which has plenty of registers. In macOS, we can
switch the implementation with the runtime flag. Thus macOS port can
compare the performance and decide which implementation is used after
landing this patch.

* heap/MarkedBlock.h:
(JSC::MarkedBlock::offsetOfVM):
* jit/AssemblyHelpers.cpp:
(JSC::AssemblyHelpers::loadWasmContext):
(JSC::AssemblyHelpers::storeWasmContext):
(JSC::AssemblyHelpers::loadWasmContextNeedsMacroScratchRegister):
(JSC::AssemblyHelpers::storeWasmContextNeedsMacroScratchRegister):
* jit/AssemblyHelpers.h:
(JSC::AssemblyHelpers::loadWasmContext): Deleted.
(JSC::AssemblyHelpers::storeWasmContext): Deleted.
(JSC::AssemblyHelpers::loadWasmContextNeedsMacroScratchRegister): Deleted.
(JSC::AssemblyHelpers::storeWasmContextNeedsMacroScratchRegister): Deleted.
* jit/Repatch.cpp:
(JSC::webAssemblyOwner):
(JSC::linkFor):
(JSC::linkPolymorphicCall):
(JSC::isWebAssemblyToJSCallee): Deleted.
* jit/ThunkGenerators.cpp:
(JSC::throwExceptionFromWasmThunkGenerator):
* llint/LLIntData.cpp:
(JSC::LLInt::Data::performAssertions):
* llint/LowLevelInterpreter.asm:
* runtime/JSCell.cpp:
(JSC::JSCell::isAnyWasmCallee):
* runtime/JSCellInlines.h:
(JSC::isWebAssemblyToJSCallee):
* runtime/JSType.h:
* runtime/StackFrame.cpp:
(JSC::StackFrame::functionName):
* runtime/VM.cpp:
(JSC::VM::VM):
* runtime/VM.h:
(JSC::VM::wasmContextOffset):
* wasm/WasmB3IRGenerator.cpp:
(JSC::Wasm::B3IRGenerator::materializeWasmContext):
(JSC::Wasm::B3IRGenerator::restoreWasmContext):
(JSC::Wasm::B3IRGenerator::B3IRGenerator):
(JSC::Wasm::getMemoryBaseAndSize):
(JSC::Wasm::B3IRGenerator::restoreWebAssemblyGlobalState):
(JSC::Wasm::createJSToWasmWrapper):
(JSC::Wasm::loadWasmContext): Deleted.
(JSC::Wasm::storeWasmContext): Deleted.
(JSC::Wasm::restoreWebAssemblyGlobalState): Deleted.
* wasm/WasmBinding.cpp:
(JSC::Wasm::wasmToJs):
* wasm/WasmContext.cpp:
(JSC::loadWasmContext):
(JSC::storeWasmContext):
* wasm/WasmContext.h:
* wasm/WasmMemoryInformation.cpp:
(JSC::Wasm::getPinnedRegisters):
(JSC::Wasm::PinnedRegisterInfo::get):
(JSC::Wasm::PinnedRegisterInfo::PinnedRegisterInfo):
* wasm/WasmMemoryInformation.h:
(JSC::Wasm::PinnedRegisterInfo::toSave):
(JSC::Wasm::useFastTLS):
(JSC::Wasm::useFastTLSForWasmContext):
* wasm/js/JSWebAssemblyInstance.cpp:
(JSC::JSWebAssemblyInstance::finishCreation):
(JSC::JSWebAssemblyInstance::visitChildren):
* wasm/js/JSWebAssemblyInstance.h:
(JSC::JSWebAssemblyInstance::offsetOfCallee):
* wasm/js/JSWebAssemblyModule.cpp:
(JSC::JSWebAssemblyModule::finishCreation):
(JSC::JSWebAssemblyModule::visitChildren):
* wasm/js/JSWebAssemblyModule.h:
(JSC::JSWebAssemblyModule::callee):
* wasm/js/WebAssemblyFunction.cpp:
(JSC::callWebAssemblyFunction):
(JSC::WebAssemblyFunction::create):
* wasm/js/WebAssemblyToJSCallee.cpp:
(JSC::WebAssemblyToJSCallee::create):
(JSC::WebAssemblyToJSCallee::createStructure):
(JSC::WebAssemblyToJSCallee::finishCreation):
(JSC::WebAssemblyToJSCallee::visitChildren):
(JSC::WebAssemblyToJSCallee::destroy): Deleted.
* wasm/js/WebAssemblyToJSCallee.h:

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@214498 268f45cc-cd09-0410-ab3c-d52691b4dbfc

27 files changed:
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/heap/MarkedBlock.h
Source/JavaScriptCore/jit/AssemblyHelpers.cpp
Source/JavaScriptCore/jit/AssemblyHelpers.h
Source/JavaScriptCore/jit/Repatch.cpp
Source/JavaScriptCore/jit/ThunkGenerators.cpp
Source/JavaScriptCore/llint/LLIntData.cpp
Source/JavaScriptCore/llint/LowLevelInterpreter.asm
Source/JavaScriptCore/runtime/JSCell.cpp
Source/JavaScriptCore/runtime/JSCellInlines.h
Source/JavaScriptCore/runtime/JSType.h
Source/JavaScriptCore/runtime/StackFrame.cpp
Source/JavaScriptCore/runtime/VM.cpp
Source/JavaScriptCore/runtime/VM.h
Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp
Source/JavaScriptCore/wasm/WasmBinding.cpp
Source/JavaScriptCore/wasm/WasmContext.cpp
Source/JavaScriptCore/wasm/WasmContext.h
Source/JavaScriptCore/wasm/WasmMemoryInformation.cpp
Source/JavaScriptCore/wasm/WasmMemoryInformation.h
Source/JavaScriptCore/wasm/js/JSWebAssemblyInstance.cpp
Source/JavaScriptCore/wasm/js/JSWebAssemblyInstance.h
Source/JavaScriptCore/wasm/js/JSWebAssemblyModule.cpp
Source/JavaScriptCore/wasm/js/JSWebAssemblyModule.h
Source/JavaScriptCore/wasm/js/WebAssemblyFunction.cpp
Source/JavaScriptCore/wasm/js/WebAssemblyToJSCallee.cpp
Source/JavaScriptCore/wasm/js/WebAssemblyToJSCallee.h

index 70ecfc8..46f0932 100644 (file)
@@ -1,3 +1,102 @@
+2017-03-28  Yusuke Suzuki  <utatane.tea@gmail.com>
+
+        WebAssembly: add fallback to use pinned register to load/store state
+        https://bugs.webkit.org/show_bug.cgi?id=169773
+
+        Reviewed by Saam Barati.
+
+        This patch adds a new pinned register to hold JSWebAssemblyInstance,
+        which is used to represent the context of running Wasm code.
+        While we use fast TLS to hold the context in macOS, we do not have
+        any system reserved fast TLS slot in the other systems. This pinned
+        register approach is used in these systems. These changes decouple
+        VM from Wasm module to make Wasm module position independent code.
+
+        While using fast TLS could be beneficial in x64 systems which number of
+        registers is relatively small, pinned register approach could be
+        beneficial in ARM64 which has plenty of registers. In macOS, we can
+        switch the implementation with the runtime flag. Thus macOS port can
+        compare the performance and decide which implementation is used after
+        landing this patch.
+
+        * heap/MarkedBlock.h:
+        (JSC::MarkedBlock::offsetOfVM):
+        * jit/AssemblyHelpers.cpp:
+        (JSC::AssemblyHelpers::loadWasmContext):
+        (JSC::AssemblyHelpers::storeWasmContext):
+        (JSC::AssemblyHelpers::loadWasmContextNeedsMacroScratchRegister):
+        (JSC::AssemblyHelpers::storeWasmContextNeedsMacroScratchRegister):
+        * jit/AssemblyHelpers.h:
+        (JSC::AssemblyHelpers::loadWasmContext): Deleted.
+        (JSC::AssemblyHelpers::storeWasmContext): Deleted.
+        (JSC::AssemblyHelpers::loadWasmContextNeedsMacroScratchRegister): Deleted.
+        (JSC::AssemblyHelpers::storeWasmContextNeedsMacroScratchRegister): Deleted.
+        * jit/Repatch.cpp:
+        (JSC::webAssemblyOwner):
+        (JSC::linkFor):
+        (JSC::linkPolymorphicCall):
+        (JSC::isWebAssemblyToJSCallee): Deleted.
+        * jit/ThunkGenerators.cpp:
+        (JSC::throwExceptionFromWasmThunkGenerator):
+        * llint/LLIntData.cpp:
+        (JSC::LLInt::Data::performAssertions):
+        * llint/LowLevelInterpreter.asm:
+        * runtime/JSCell.cpp:
+        (JSC::JSCell::isAnyWasmCallee):
+        * runtime/JSCellInlines.h:
+        (JSC::isWebAssemblyToJSCallee):
+        * runtime/JSType.h:
+        * runtime/StackFrame.cpp:
+        (JSC::StackFrame::functionName):
+        * runtime/VM.cpp:
+        (JSC::VM::VM):
+        * runtime/VM.h:
+        (JSC::VM::wasmContextOffset):
+        * wasm/WasmB3IRGenerator.cpp:
+        (JSC::Wasm::B3IRGenerator::materializeWasmContext):
+        (JSC::Wasm::B3IRGenerator::restoreWasmContext):
+        (JSC::Wasm::B3IRGenerator::B3IRGenerator):
+        (JSC::Wasm::getMemoryBaseAndSize):
+        (JSC::Wasm::B3IRGenerator::restoreWebAssemblyGlobalState):
+        (JSC::Wasm::createJSToWasmWrapper):
+        (JSC::Wasm::loadWasmContext): Deleted.
+        (JSC::Wasm::storeWasmContext): Deleted.
+        (JSC::Wasm::restoreWebAssemblyGlobalState): Deleted.
+        * wasm/WasmBinding.cpp:
+        (JSC::Wasm::wasmToJs):
+        * wasm/WasmContext.cpp:
+        (JSC::loadWasmContext):
+        (JSC::storeWasmContext):
+        * wasm/WasmContext.h:
+        * wasm/WasmMemoryInformation.cpp:
+        (JSC::Wasm::getPinnedRegisters):
+        (JSC::Wasm::PinnedRegisterInfo::get):
+        (JSC::Wasm::PinnedRegisterInfo::PinnedRegisterInfo):
+        * wasm/WasmMemoryInformation.h:
+        (JSC::Wasm::PinnedRegisterInfo::toSave):
+        (JSC::Wasm::useFastTLS):
+        (JSC::Wasm::useFastTLSForWasmContext):
+        * wasm/js/JSWebAssemblyInstance.cpp:
+        (JSC::JSWebAssemblyInstance::finishCreation):
+        (JSC::JSWebAssemblyInstance::visitChildren):
+        * wasm/js/JSWebAssemblyInstance.h:
+        (JSC::JSWebAssemblyInstance::offsetOfCallee):
+        * wasm/js/JSWebAssemblyModule.cpp:
+        (JSC::JSWebAssemblyModule::finishCreation):
+        (JSC::JSWebAssemblyModule::visitChildren):
+        * wasm/js/JSWebAssemblyModule.h:
+        (JSC::JSWebAssemblyModule::callee):
+        * wasm/js/WebAssemblyFunction.cpp:
+        (JSC::callWebAssemblyFunction):
+        (JSC::WebAssemblyFunction::create):
+        * wasm/js/WebAssemblyToJSCallee.cpp:
+        (JSC::WebAssemblyToJSCallee::create):
+        (JSC::WebAssemblyToJSCallee::createStructure):
+        (JSC::WebAssemblyToJSCallee::finishCreation):
+        (JSC::WebAssemblyToJSCallee::visitChildren):
+        (JSC::WebAssemblyToJSCallee::destroy): Deleted.
+        * wasm/js/WebAssemblyToJSCallee.h:
+
 2017-03-28  Brian Burg  <bburg@apple.com>
 
         Web Inspector: Add "Disable Caches" option that only applies to the inspected page while Web Inspector is open
index 22a7ba7..56d5cbe 100644 (file)
@@ -298,6 +298,11 @@ public:
     
     bool isMarkedRaw(const void* p);
     HeapVersion markingVersion() const { return m_markingVersion; }
+
+    static ptrdiff_t offsetOfVM()
+    {
+        return OBJECT_OFFSETOF(MarkedBlock, m_vm);
+    }
     
 private:
     static const size_t atomAlignmentMask = atomSize - 1;
index 7832047..de1fb21 100644 (file)
 #include "JSCInlines.h"
 #include "LinkBuffer.h"
 
+#if ENABLE(WEBASSEMBLY)
+#include "WasmMemoryInformation.h"
+#endif
+
 namespace JSC {
 
 ExecutableBase* AssemblyHelpers::executableFor(const CodeOrigin& codeOrigin)
@@ -766,6 +770,49 @@ void AssemblyHelpers::emitConvertValueToBoolean(JSValueRegs value, GPRReg result
     done.link(this);
 }
 
+#if ENABLE(WEBASSEMBLY)
+void AssemblyHelpers::loadWasmContext(GPRReg dst)
+{
+#if ENABLE(FAST_TLS_JIT)
+    if (Wasm::useFastTLSForWasmContext()) {
+        loadFromTLSPtr(fastTLSOffsetForKey(WTF_WASM_CONTEXT_KEY), dst);
+        return;
+    }
+#endif
+    move(Wasm::PinnedRegisterInfo::get().wasmContextPointer, dst);
+}
+
+void AssemblyHelpers::storeWasmContext(GPRReg src)
+{
+#if ENABLE(FAST_TLS_JIT)
+    if (Wasm::useFastTLSForWasmContext()) {
+        storeToTLSPtr(src, fastTLSOffsetForKey(WTF_WASM_CONTEXT_KEY));
+        return;
+    }
+#endif
+    move(src, Wasm::PinnedRegisterInfo::get().wasmContextPointer);
+}
+
+bool AssemblyHelpers::loadWasmContextNeedsMacroScratchRegister()
+{
+#if ENABLE(FAST_TLS_JIT)
+    if (Wasm::useFastTLSForWasmContext())
+        return loadFromTLSPtrNeedsMacroScratchRegister();
+#endif
+    return false;
+}
+
+bool AssemblyHelpers::storeWasmContextNeedsMacroScratchRegister()
+{
+#if ENABLE(FAST_TLS_JIT)
+    if (Wasm::useFastTLSForWasmContext())
+        return storeToTLSPtrNeedsMacroScratchRegister();
+#endif
+    return false;
+}
+
+#endif
+
 } // namespace JSC
 
 #endif // ENABLE(JIT)
index 500d688..a78cc69 100644 (file)
@@ -1636,45 +1636,12 @@ public:
     void wangsInt64Hash(GPRReg inputAndResult, GPRReg scratch);
 #endif
 
-    void loadWasmContext(GPRReg dst)
-    {
-#if ENABLE(FAST_TLS_JIT)
-        if (Options::useWebAssemblyFastTLS()) {
-            loadFromTLSPtr(fastTLSOffsetForKey(WTF_WASM_CONTEXT_KEY), dst);
-            return;
-        }
-#endif
-        // FIXME: Save this state elsewhere to allow PIC. https://bugs.webkit.org/show_bug.cgi?id=169773
-        loadPtr(&m_vm->wasmContext, dst);
-    }
-
-    void storeWasmContext(GPRReg src)
-    {
-#if ENABLE(FAST_TLS_JIT)
-        if (Options::useWebAssemblyFastTLS())
-            return storeToTLSPtr(src, fastTLSOffsetForKey(WTF_WASM_CONTEXT_KEY));
-#endif
-        // FIXME: Save this state elsewhere to allow PIC. https://bugs.webkit.org/show_bug.cgi?id=169773
-        storePtr(src, &m_vm->wasmContext);
-    }
-
-    static bool loadWasmContextNeedsMacroScratchRegister()
-    {
-#if ENABLE(FAST_TLS_JIT)
-        if (Options::useWebAssemblyFastTLS())
-            return loadFromTLSPtrNeedsMacroScratchRegister();
-#endif
-        return true;
-    }
-
-    static bool storeWasmContextNeedsMacroScratchRegister()
-    {
-#if ENABLE(FAST_TLS_JIT)
-        if (Options::useWebAssemblyFastTLS())
-            return storeToTLSPtrNeedsMacroScratchRegister();
+#if ENABLE(WEBASSEMBLY)
+    void loadWasmContext(GPRReg dst);
+    void storeWasmContext(GPRReg src);
+    static bool loadWasmContextNeedsMacroScratchRegister();
+    static bool storeWasmContextNeedsMacroScratchRegister();
 #endif
-        return true;
-    }
 
 protected:
     VM* m_vm;
index 7ddc6ba..1978480 100644 (file)
@@ -59,7 +59,6 @@
 #include "StructureStubClearingWatchpoint.h"
 #include "StructureStubInfo.h"
 #include "ThunkGenerators.h"
-#include "WasmContext.h"
 #include <wtf/CommaPrinter.h>
 #include <wtf/ListDump.h>
 #include <wtf/StringPrintStream.h>
@@ -577,25 +576,13 @@ static void linkSlowFor(VM* vm, CallLinkInfo& callLinkInfo)
     callLinkInfo.setSlowStub(createJITStubRoutine(virtualThunk, *vm, nullptr, true));
 }
 
-static bool isWebAssemblyToJSCallee(VM& vm, JSCell* callee)
-{
-#if ENABLE(WEBASSEMBLY)
-    // The WebAssembly -> JS stub sets it caller frame's callee to a singleton which lives on the VM.
-    return callee == vm.webAssemblyToJSCallee.get();
-#else
-    UNUSED_PARAM(vm);
-    UNUSED_PARAM(callee);
-    return false;
-#endif // ENABLE(WEBASSEMBLY)
-}
-
-static JSCell* webAssemblyOwner(VM& vm)
+static JSCell* webAssemblyOwner(JSCell* callee)
 {
 #if ENABLE(WEBASSEMBLY)
     // Each WebAssembly.Instance shares the stubs from their WebAssembly.Module, which are therefore the appropriate owner.
-    return loadWasmContext(vm)->module();
+    return jsCast<WebAssemblyToJSCallee*>(callee)->module();
 #else
-    UNUSED_PARAM(vm);
+    UNUSED_PARAM(callee);
     RELEASE_ASSERT_NOT_REACHED();
     return nullptr;
 #endif // ENABLE(WEBASSEMBLY)
@@ -612,7 +599,7 @@ void linkFor(
     CodeBlock* callerCodeBlock = callerFrame->codeBlock();
 
     // WebAssembly -> JS stubs don't have a valid CodeBlock.
-    JSCell* owner = isWebAssemblyToJSCallee(vm, callerFrame->callee()) ? webAssemblyOwner(vm) : callerCodeBlock;
+    JSCell* owner = isWebAssemblyToJSCallee(callerFrame->callee()) ? webAssemblyOwner(callerFrame->callee()) : callerCodeBlock;
     ASSERT(owner);
 
     ASSERT(!callLinkInfo.isLinked());
@@ -732,10 +719,10 @@ void linkPolymorphicCall(
     CallFrame* callerFrame = exec->callerFrame();
     VM& vm = callerFrame->vm();
     CodeBlock* callerCodeBlock = callerFrame->codeBlock();
-    bool isWebAssembly = isWebAssemblyToJSCallee(vm, callerFrame->callee());
+    bool isWebAssembly = isWebAssemblyToJSCallee(callerFrame->callee());
 
     // WebAssembly -> JS stubs don't have a valid CodeBlock.
-    JSCell* owner = isWebAssembly ? webAssemblyOwner(vm) : callerCodeBlock;
+    JSCell* owner = isWebAssembly ? webAssemblyOwner(callerFrame->callee()) : callerCodeBlock;
     ASSERT(owner);
 
     CallVariantList list;
index 0857e34..5217b82 100644 (file)
@@ -38,7 +38,6 @@
 #include "MathCommon.h"
 #include "MaxFrameExtentForSlowPathCall.h"
 #include "SpecializedThunkJIT.h"
-#include "WasmContext.h"
 #include "WasmExceptionType.h"
 #include <wtf/InlineASM.h>
 #include <wtf/StringPrintStream.h>
@@ -1148,16 +1147,17 @@ MacroAssemblerCodeRef throwExceptionFromWasmThunkGenerator(VM* vm)
     }
 
     jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
+    jit.loadWasmContext(GPRInfo::argumentGPR2);
     CCallHelpers::Call call = jit.call();
     jit.jumpToExceptionHandler();
 
-    void (*throwWasmException)(ExecState*, Wasm::ExceptionType) = [] (ExecState* exec, Wasm::ExceptionType type) {
+    void (*throwWasmException)(ExecState*, Wasm::ExceptionType, JSWebAssemblyInstance*) = [] (ExecState* exec, Wasm::ExceptionType type, JSWebAssemblyInstance* wasmContext) {
         VM* vm = &exec->vm();
         NativeCallFrameTracer tracer(vm, exec);
 
         {
             auto throwScope = DECLARE_THROW_SCOPE(*vm);
-            JSGlobalObject* globalObject = loadWasmContext(*vm)->globalObject();
+            JSGlobalObject* globalObject = wasmContext->globalObject();
 
             JSWebAssemblyRuntimeError* error = JSWebAssemblyRuntimeError::create(exec, *vm, globalObject->WebAssemblyRuntimeErrorStructure(), Wasm::errorMessageForExceptionType(type));
             throwException(exec, throwScope, error);
index 8b615a1..0aff108 100644 (file)
@@ -156,21 +156,21 @@ void Data::performAssertions(VM& vm)
     
     STATIC_ASSERT(StringType == 6);
     STATIC_ASSERT(SymbolType == 7);
-    STATIC_ASSERT(ObjectType == 23);
-    STATIC_ASSERT(FinalObjectType == 24);
-    STATIC_ASSERT(JSFunctionType == 26);
-    STATIC_ASSERT(ArrayType == 34);
-    STATIC_ASSERT(DerivedArrayType == 35);
-    STATIC_ASSERT(ProxyObjectType == 53);
-    STATIC_ASSERT(Int8ArrayType == 36);
-    STATIC_ASSERT(Int16ArrayType == 37);
-    STATIC_ASSERT(Int32ArrayType == 38);
-    STATIC_ASSERT(Uint8ArrayType == 39);
-    STATIC_ASSERT(Uint8ClampedArrayType == 40);
-    STATIC_ASSERT(Uint16ArrayType == 41);
-    STATIC_ASSERT(Uint32ArrayType == 42);
-    STATIC_ASSERT(Float32ArrayType == 43);
-    STATIC_ASSERT(Float64ArrayType == 44);
+    STATIC_ASSERT(ObjectType == 24);
+    STATIC_ASSERT(FinalObjectType == 25);
+    STATIC_ASSERT(JSFunctionType == 27);
+    STATIC_ASSERT(ArrayType == 35);
+    STATIC_ASSERT(DerivedArrayType == 36);
+    STATIC_ASSERT(ProxyObjectType == 54);
+    STATIC_ASSERT(Int8ArrayType == 37);
+    STATIC_ASSERT(Int16ArrayType == 38);
+    STATIC_ASSERT(Int32ArrayType == 39);
+    STATIC_ASSERT(Uint8ArrayType == 40);
+    STATIC_ASSERT(Uint8ClampedArrayType == 41);
+    STATIC_ASSERT(Uint16ArrayType == 42);
+    STATIC_ASSERT(Uint32ArrayType == 43);
+    STATIC_ASSERT(Float32ArrayType == 44);
+    STATIC_ASSERT(Float64ArrayType == 45);
     STATIC_ASSERT(MasqueradesAsUndefined == 1);
     STATIC_ASSERT(ImplementsDefaultHasInstance == 2);
     STATIC_ASSERT(FirstConstantRegisterIndex == 0x40000000);
index e8e2db8..ab3c0c8 100644 (file)
@@ -345,24 +345,24 @@ const SlowPutArrayStorageShape = 0x0C
 # Type constants.
 const StringType = 6
 const SymbolType = 7
-const ObjectType = 23
-const FinalObjectType = 24
-const JSFunctionType = 26
-const ArrayType = 34
-const DerivedArrayType = 35
-const ProxyObjectType = 53
+const ObjectType = 24
+const FinalObjectType = 25
+const JSFunctionType = 27
+const ArrayType = 35
+const DerivedArrayType = 36
+const ProxyObjectType = 54
 
 # The typed array types need to be numbered in a particular order because of the manually written
 # switch statement in get_by_val and put_by_val.
-const Int8ArrayType = 36
-const Int16ArrayType = 37
-const Int32ArrayType = 38
-const Uint8ArrayType = 39
-const Uint8ClampedArrayType = 40
-const Uint16ArrayType = 41
-const Uint32ArrayType = 42
-const Float32ArrayType = 43
-const Float64ArrayType = 44
+const Int8ArrayType = 37
+const Int16ArrayType = 38
+const Int32ArrayType = 39
+const Uint8ArrayType = 40
+const Uint8ClampedArrayType = 41
+const Uint16ArrayType = 42
+const Uint32ArrayType = 43
+const Float32ArrayType = 44
+const Float64ArrayType = 45
 
 const FirstArrayType = Int8ArrayType
 const LastArrayType = Float64ArrayType
index acdd4e8..3dfc285 100644 (file)
@@ -298,7 +298,7 @@ JSValue JSCell::getPrototype(JSObject*, ExecState*)
 bool JSCell::isAnyWasmCallee(VM& vm) const
 {
 #if ENABLE(WEBASSEMBLY)
-    return inherits(vm, JSWebAssemblyCallee::info()) || inherits(vm, WebAssemblyToJSCallee::info());
+    return inherits(vm, JSWebAssemblyCallee::info()) || isWebAssemblyToJSCallee(this);
 #else
     UNUSED_PARAM(vm);
     return false;
index 6a980a8..9509356 100644 (file)
@@ -346,4 +346,9 @@ inline JSObject* JSCell::toObject(ExecState* exec, JSGlobalObject* globalObject)
     return toObjectSlow(exec, globalObject);
 }
 
+inline bool isWebAssemblyToJSCallee(const JSCell* cell)
+{
+    return cell->type() == WebAssemblyToJSCalleeType;
+}
+
 } // namespace JSC
index 4d7ee49..62e3772 100644 (file)
@@ -53,6 +53,8 @@ enum JSType : uint8_t {
     JSSourceCodeType,
     JSScriptFetcherType,
 
+    WebAssemblyToJSCalleeType,
+
     // The ObjectType value must come before any JSType that is a subclass of JSObject.
     ObjectType,
     FinalObjectType,
index 6d47864..164c4f5 100644 (file)
@@ -72,10 +72,10 @@ String StackFrame::functionName(VM& vm) const
     }
     String name;
     if (m_callee) {
+        if (m_callee->isAnyWasmCallee(*m_callee->vm()))
+            return ASCIILiteral("<wasm>");
         if (m_callee->isObject())
             name = getCalculatedDisplayName(vm, jsCast<JSObject*>(m_callee.get())).impl();
-        else if (m_callee->isAnyWasmCallee(*m_callee->vm()))
-            return ASCIILiteral("<wasm>");
     }
     return name.isNull() ? emptyString() : name;
 }
index 8511542..d108153 100644 (file)
@@ -240,7 +240,6 @@ VM::VM(VMType vmType, HeapType heapType)
     webAssemblyCalleeStructure.set(*this, JSWebAssemblyCallee::createStructure(*this, 0, jsNull()));
     webAssemblyToJSCalleeStructure.set(*this, WebAssemblyToJSCallee::createStructure(*this, 0, jsNull()));
     webAssemblyCodeBlockStructure.set(*this, JSWebAssemblyCodeBlock::createStructure(*this, 0, jsNull()));
-    webAssemblyToJSCallee.set(*this, WebAssemblyToJSCallee::create(*this, webAssemblyToJSCalleeStructure.get()));
 #endif
     moduleProgramExecutableStructure.set(*this, ModuleProgramExecutable::createStructure(*this, 0, jsNull()));
     regExpStructure.set(*this, RegExp::createStructure(*this, 0, jsNull()));
index 1ec87f9..d67e71b 100644 (file)
@@ -336,7 +336,6 @@ public:
     Strong<Structure> webAssemblyCalleeStructure;
     Strong<Structure> webAssemblyToJSCalleeStructure;
     Strong<Structure> webAssemblyCodeBlockStructure;
-    Strong<JSCell> webAssemblyToJSCallee;
 #endif
     Strong<Structure> moduleProgramExecutableStructure;
     Strong<Structure> regExpStructure;
@@ -490,6 +489,11 @@ public:
         return OBJECT_OFFSETOF(VM, targetMachinePCForThrow);
     }
 
+    static ptrdiff_t wasmContextOffset()
+    {
+        return OBJECT_OFFSETOF(VM, wasmContext);
+    }
+
     void restorePreviousException(Exception* exception) { setException(exception); }
 
     void clearLastException() { m_lastException = nullptr; }
index fac57ad..0b02ec3 100644 (file)
@@ -35,6 +35,7 @@
 #include "B3ConstPtrValue.h"
 #include "B3FixSSA.h"
 #include "B3Generate.h"
+#include "B3SlotBaseValue.h"
 #include "B3StackmapGenerationParams.h"
 #include "B3SwitchValue.h"
 #include "B3Validate.h"
@@ -49,7 +50,6 @@
 #include "JSWebAssemblyRuntimeError.h"
 #include "VirtualRegister.h"
 #include "WasmCallingConvention.h"
-#include "WasmContext.h"
 #include "WasmExceptionType.h"
 #include "WasmFunctionParser.h"
 #include "WasmMemory.h"
@@ -219,6 +219,10 @@ private:
 
     void emitChecksForModOrDiv(B3::Opcode, ExpressionType left, ExpressionType right);
 
+    Value* materializeWasmContext(Procedure&, BasicBlock*);
+    void restoreWasmContext(Procedure&, BasicBlock*, Value*);
+    void restoreWebAssemblyGlobalState(const MemoryInformation&, Value* instance, Procedure&, BasicBlock*);
+
     VM& m_vm;
     const ModuleInformation& m_info;
     Procedure& m_proc;
@@ -227,35 +231,63 @@ private:
     Vector<UnlinkedWasmToWasmCall>& m_unlinkedWasmToWasmCalls; // List each call site and the function index whose address it should be patched with.
     GPRReg m_memoryBaseGPR;
     GPRReg m_memorySizeGPR;
+    GPRReg m_wasmContextGPR;
     Value* m_zeroValues[numTypes];
     Value* m_instanceValue; // FIXME: make this lazy https://bugs.webkit.org/show_bug.cgi?id=169792
 };
 
-static Value* loadWasmContext(Procedure& proc, BasicBlock* block)
+Value* B3IRGenerator::materializeWasmContext(Procedure& proc, BasicBlock* block)
 {
-    PatchpointValue* patchpoint = block->appendNew<PatchpointValue>(proc, pointerType(), Origin());
-    if (CCallHelpers::loadWasmContextNeedsMacroScratchRegister())
-        patchpoint->clobber(RegisterSet::macroScratchRegisters());
-    patchpoint->setGenerator(
-        [&] (CCallHelpers& jit, const StackmapGenerationParams& params) {
-            AllowMacroScratchRegisterUsageIf allowScratch(jit, CCallHelpers::loadWasmContextNeedsMacroScratchRegister());
-            jit.loadWasmContext(params[0].gpr());
-        });
+    if (useFastTLSForWasmContext()) {
+        PatchpointValue* patchpoint = block->appendNew<PatchpointValue>(proc, pointerType(), Origin());
+        if (CCallHelpers::loadWasmContextNeedsMacroScratchRegister())
+            patchpoint->clobber(RegisterSet::macroScratchRegisters());
+        patchpoint->setGenerator(
+            [=] (CCallHelpers& jit, const StackmapGenerationParams& params) {
+                AllowMacroScratchRegisterUsageIf allowScratch(jit, CCallHelpers::loadWasmContextNeedsMacroScratchRegister());
+                jit.loadWasmContext(params[0].gpr());
+            });
+        return patchpoint;
+    }
 
-    return block->appendNew<Value>(proc, Identity, Origin(), patchpoint);
-}
+    // FIXME: Because WasmToWasm call clobbers wasmContext register and does not restore it, we need to restore it in the caller side.
+    // This prevents us from using ArgumentReg to this (logically) immutable pinned register.
+    PatchpointValue* patchpoint = block->appendNew<PatchpointValue>(proc, pointerType(), Origin());
+    patchpoint->effects.writesPinned = false;
+    patchpoint->effects.readsPinned = true;
+    patchpoint->resultConstraint = ValueRep::reg(m_wasmContextGPR);
+    patchpoint->setGenerator([] (CCallHelpers&, const StackmapGenerationParams&) { });
+    return patchpoint;
+}
+
+void B3IRGenerator::restoreWasmContext(Procedure& proc, BasicBlock* block, Value* arg)
+{
+    if (useFastTLSForWasmContext()) {
+        PatchpointValue* patchpoint = block->appendNew<PatchpointValue>(proc, B3::Void, Origin());
+        if (CCallHelpers::storeWasmContextNeedsMacroScratchRegister())
+            patchpoint->clobber(RegisterSet::macroScratchRegisters());
+        patchpoint->append(ConstrainedValue(arg, ValueRep::SomeRegister));
+        patchpoint->setGenerator(
+            [=] (CCallHelpers& jit, const StackmapGenerationParams& params) {
+                AllowMacroScratchRegisterUsageIf allowScratch(jit, CCallHelpers::storeWasmContextNeedsMacroScratchRegister());
+                jit.storeWasmContext(params[0].gpr());
+            });
+        return;
+    }
 
-static void storeWasmContext(Procedure& proc, BasicBlock* block, Value* arg)
-{
+    // FIXME: Because WasmToWasm call clobbers wasmContext register and does not restore it, we need to restore it in the caller side.
+    // This prevents us from using ArgumentReg to this (logically) immutable pinned register.
     PatchpointValue* patchpoint = block->appendNew<PatchpointValue>(proc, B3::Void, Origin());
-    if (CCallHelpers::storeWasmContextNeedsMacroScratchRegister())
-        patchpoint->clobber(RegisterSet::macroScratchRegisters());
-    patchpoint->append(ConstrainedValue(arg, ValueRep::SomeRegister));
-    patchpoint->setGenerator(
-        [&] (CCallHelpers& jit, const StackmapGenerationParams& params) {
-            AllowMacroScratchRegisterUsageIf allowScratch(jit, CCallHelpers::storeWasmContextNeedsMacroScratchRegister());
-            jit.storeWasmContext(params[0].gpr());
-        });
+    Effects effects = Effects::none();
+    effects.writesPinned = true;
+    effects.reads = B3::HeapRange::top();
+    patchpoint->effects = effects;
+    patchpoint->clobberLate(RegisterSet(m_wasmContextGPR));
+    patchpoint->append(m_instanceValue, ValueRep::SomeRegister);
+    GPRReg wasmContextGPR = m_wasmContextGPR;
+    patchpoint->setGenerator([=] (CCallHelpers& jit, const StackmapGenerationParams& param) {
+        jit.move(param[0].gpr(), wasmContextGPR);
+    });
 }
 
 B3IRGenerator::B3IRGenerator(VM& vm, const ModuleInformation& info, Procedure& procedure, WasmInternalFunction* compilation, Vector<UnlinkedWasmToWasmCall>& unlinkedWasmToWasmCalls)
@@ -283,7 +315,10 @@ B3IRGenerator::B3IRGenerator(VM& vm, const ModuleInformation& info, Procedure& p
     // FIXME we don't really need to pin registers here if there's no memory. It makes wasm -> wasm thunks simpler for now. https://bugs.webkit.org/show_bug.cgi?id=166623
     const PinnedRegisterInfo& pinnedRegs = PinnedRegisterInfo::get();
     m_memoryBaseGPR = pinnedRegs.baseMemoryPointer;
+    m_wasmContextGPR = pinnedRegs.wasmContextPointer;
     m_proc.pinRegister(m_memoryBaseGPR);
+    if (!useFastTLSForWasmContext())
+        m_proc.pinRegister(m_wasmContextGPR);
     ASSERT(!pinnedRegs.sizeRegisters[0].sizeOffset);
     m_memorySizeGPR = pinnedRegs.sizeRegisters[0].sizeRegister;
     for (const PinnedSizeRegisterInfo& regInfo : pinnedRegs.sizeRegisters)
@@ -299,7 +334,7 @@ B3IRGenerator::B3IRGenerator(VM& vm, const ModuleInformation& info, Procedure& p
 
     wasmCallingConvention().setupFrameInPrologue(&compilation->wasmCalleeMoveLocation, m_proc, Origin(), m_currentBlock);
 
-    m_instanceValue = loadWasmContext(m_proc, m_currentBlock);
+    m_instanceValue = materializeWasmContext(m_proc, m_currentBlock);
 }
 
 struct MemoryBaseAndSize {
@@ -307,12 +342,12 @@ struct MemoryBaseAndSize {
     Value* size;
 };
 
-static MemoryBaseAndSize getMemoryBaseAndSize(VM& vm, Value* instance, Procedure& proc, BasicBlock* block)
+static MemoryBaseAndSize getMemoryBaseAndSize(Value* instance, Procedure& proc, BasicBlock* block)
 {
     Value* memoryObject = block->appendNew<MemoryValue>(proc, Load, pointerType(), Origin(), instance, JSWebAssemblyInstance::offsetOfMemory());
 
-    static_assert(sizeof(decltype(loadWasmContext(vm)->memory()->memory().memory())) == sizeof(void*), "codegen relies on this size");
-    static_assert(sizeof(decltype(loadWasmContext(vm)->memory()->memory().size())) == sizeof(uint64_t), "codegen relies on this size");
+    static_assert(sizeof(decltype(static_cast<JSWebAssemblyInstance*>(nullptr)->memory()->memory().memory())) == sizeof(void*), "codegen relies on this size");
+    static_assert(sizeof(decltype(static_cast<JSWebAssemblyInstance*>(nullptr)->memory()->memory().size())) == sizeof(uint64_t), "codegen relies on this size");
     MemoryBaseAndSize result;
     result.base = block->appendNew<MemoryValue>(proc, Load, pointerType(), Origin(), memoryObject, JSWebAssemblyMemory::offsetOfMemory());
     result.size = block->appendNew<MemoryValue>(proc, Load, Int64, Origin(), memoryObject, JSWebAssemblyMemory::offsetOfSize());
@@ -320,9 +355,9 @@ static MemoryBaseAndSize getMemoryBaseAndSize(VM& vm, Value* instance, Procedure
     return result;
 }
 
-static void restoreWebAssemblyGlobalState(const MemoryInformation& memory, Value* instance, Procedure& proc, BasicBlock* block)
+void B3IRGenerator::restoreWebAssemblyGlobalState(const MemoryInformation& memory, Value* instance, Procedure& proc, BasicBlock* block)
 {
-    storeWasmContext(proc, block, instance);
+    restoreWasmContext(proc, block, instance);
 
     if (!!memory) {
         const PinnedRegisterInfo* pinnedRegs = &PinnedRegisterInfo::get();
@@ -392,7 +427,7 @@ auto B3IRGenerator::addArguments(const Signature* signature) -> PartialResult
 
     m_locals.grow(signature->argumentCount());
     wasmCallingConvention().loadArguments(signature, m_proc, m_currentBlock, Origin(),
-        [&] (ExpressionType argument, unsigned i) {
+        [=] (ExpressionType argument, unsigned i) {
             Variable* argumentVariable = m_proc.addVariable(argument->type());
             m_locals[i] = argumentVariable;
             m_currentBlock->appendNew<VariableValue>(m_proc, Set, Origin(), argumentVariable, argument);
@@ -419,12 +454,11 @@ auto B3IRGenerator::addUnreachable() -> PartialResult
 
 auto B3IRGenerator::addGrowMemory(ExpressionType delta, ExpressionType& result) -> PartialResult
 {
-    int32_t (*growMemory) (ExecState*, int32_t) = [] (ExecState* exec, int32_t delta) -> int32_t {
+    int32_t (*growMemory) (ExecState*, JSWebAssemblyInstance*, int32_t) = [] (ExecState* exec, JSWebAssemblyInstance* wasmContext, int32_t delta) -> int32_t {
         VM& vm = exec->vm();
         auto scope = DECLARE_THROW_SCOPE(vm);
 
-        JSWebAssemblyInstance* instance = loadWasmContext(vm);
-        JSWebAssemblyMemory* wasmMemory = instance->memory();
+        JSWebAssemblyMemory* wasmMemory = wasmContext->memory();
 
         if (delta < 0)
             return -1;
@@ -440,7 +474,7 @@ auto B3IRGenerator::addGrowMemory(ExpressionType delta, ExpressionType& result)
 
     result = m_currentBlock->appendNew<CCallValue>(m_proc, Int32, Origin(),
         m_currentBlock->appendNew<ConstPtrValue>(m_proc, Origin(), bitwise_cast<void*>(growMemory)),
-        m_currentBlock->appendNew<B3::Value>(m_proc, B3::FramePointer, Origin()), delta);
+        m_currentBlock->appendNew<B3::Value>(m_proc, B3::FramePointer, Origin()), m_instanceValue, delta);
 
     restoreWebAssemblyGlobalState(m_info.memory, m_instanceValue, m_proc, m_currentBlock);
 
@@ -449,7 +483,7 @@ auto B3IRGenerator::addGrowMemory(ExpressionType delta, ExpressionType& result)
 
 auto B3IRGenerator::addCurrentMemory(ExpressionType& result) -> PartialResult
 {
-    auto memoryValue = getMemoryBaseAndSize(m_vm, m_instanceValue, m_proc, m_currentBlock);
+    auto memoryValue = getMemoryBaseAndSize(m_instanceValue, m_proc, m_currentBlock);
 
     constexpr uint32_t shiftValue = 16;
     static_assert(PageCount::pageSize == 1 << shiftValue, "This must hold for the code below to be correct.");
@@ -889,9 +923,10 @@ auto B3IRGenerator::addCall(uint32_t functionIndex, const Signature* signature,
         m_currentBlock->appendNewControlValue(m_proc, B3::Branch, Origin(), isWasmCall, FrequentedBlock(isWasmBlock), FrequentedBlock(isJSBlock));
 
         Value* wasmCallResult = wasmCallingConvention().setupCall(m_proc, isWasmBlock, Origin(), args, toB3Type(returnType),
-            [&] (PatchpointValue* patchpoint) {
+            [=] (PatchpointValue* patchpoint) {
                 patchpoint->effects.writesPinned = true;
                 patchpoint->effects.readsPinned = true;
+                patchpoint->clobberLate(PinnedRegisterInfo::get().toSave());
                 patchpoint->setGenerator([unlinkedWasmToWasmCalls, functionIndex] (CCallHelpers& jit, const B3::StackmapGenerationParams&) {
                     AllowMacroScratchRegisterUsage allowScratch(jit);
                     CCallHelpers::Call call = jit.call();
@@ -904,9 +939,10 @@ auto B3IRGenerator::addCall(uint32_t functionIndex, const Signature* signature,
         isWasmBlock->appendNewControlValue(m_proc, Jump, Origin(), continuation);
 
         Value* jsCallResult = wasmCallingConvention().setupCall(m_proc, isJSBlock, Origin(), args, toB3Type(returnType),
-            [&] (PatchpointValue* patchpoint) {
+            [=] (PatchpointValue* patchpoint) {
                 patchpoint->effects.writesPinned = true;
                 patchpoint->effects.readsPinned = true;
+                patchpoint->clobberLate(PinnedRegisterInfo::get().toSave());
                 patchpoint->setGenerator([unlinkedWasmToWasmCalls, functionIndex] (CCallHelpers& jit, const B3::StackmapGenerationParams&) {
                     AllowMacroScratchRegisterUsage allowScratch(jit);
                     CCallHelpers::Call call = jit.call();
@@ -932,9 +968,10 @@ auto B3IRGenerator::addCall(uint32_t functionIndex, const Signature* signature,
         restoreWebAssemblyGlobalState(m_info.memory, m_instanceValue, m_proc, continuation);
     } else {
         result = wasmCallingConvention().setupCall(m_proc, m_currentBlock, Origin(), args, toB3Type(returnType),
-            [&] (PatchpointValue* patchpoint) {
+            [=] (PatchpointValue* patchpoint) {
                 patchpoint->effects.writesPinned = true;
                 patchpoint->effects.readsPinned = true;
+
                 patchpoint->setGenerator([unlinkedWasmToWasmCalls, functionIndex] (CCallHelpers& jit, const B3::StackmapGenerationParams&) {
                     AllowMacroScratchRegisterUsage allowScratch(jit);
                     CCallHelpers::Call call = jit.call();
@@ -1010,12 +1047,12 @@ auto B3IRGenerator::addCallIndirect(const Signature* signature, SignatureIndex s
 
     Type returnType = signature->returnType();
     result = wasmCallingConvention().setupCall(m_proc, m_currentBlock, Origin(), args, toB3Type(returnType),
-        [&] (PatchpointValue* patchpoint) {
+        [=] (PatchpointValue* patchpoint) {
             patchpoint->effects.writesPinned = true;
             patchpoint->effects.readsPinned = true;
+            patchpoint->clobberLate(PinnedRegisterInfo::get().toSave());
 
             patchpoint->append(calleeCode, ValueRep::SomeRegister);
-
             patchpoint->setGenerator([=] (CCallHelpers& jit, const B3::StackmapGenerationParams& params) {
                 AllowMacroScratchRegisterUsage allowScratch(jit);
                 jit.call(params[returnType == Void ? 0 : 1].gpr());
@@ -1080,11 +1117,8 @@ static void createJSToWasmWrapper(CompilationContext& compilationContext, WasmIn
         *linkedCalleeMove = linkBuffer.locationOf(calleeMoveLocation);
     });
 
-    RegisterSet toSave;
     const PinnedRegisterInfo& pinnedRegs = PinnedRegisterInfo::get();
-    toSave.set(pinnedRegs.baseMemoryPointer);
-    for (const PinnedSizeRegisterInfo& regInfo : pinnedRegs.sizeRegisters)
-        toSave.set(regInfo.sizeRegister);
+    RegisterSet toSave = pinnedRegs.toSave();
 
 #if !ASSERT_DISABLED
     unsigned toSaveSize = toSave.numberOfSetGPRs();
@@ -1191,10 +1225,25 @@ static void createJSToWasmWrapper(CompilationContext& compilationContext, WasmIn
         }
     }
 
+    // FIXME: JStoWasm wrapper should take JSWebAssemblyInstance pointer as an argument directly.
+    // https://bugs.webkit.org/show_bug.cgi?id=170182
+    GPRReg wasmContext = pinnedRegs.wasmContextPointer;
+    if (!useFastTLSForWasmContext()) {
+        jit.loadPtr(CCallHelpers::Address(GPRInfo::callFrameRegister, CallFrameSlot::callee * static_cast<int>(sizeof(Register))), wasmContext);
+        jit.andPtr(CCallHelpers::TrustedImmPtr(MarkedBlock::blockMask), wasmContext);
+        jit.loadPtr(CCallHelpers::Address(wasmContext, MarkedBlock::offsetOfVM()), wasmContext);
+        jit.loadPtr(CCallHelpers::Address(wasmContext, VM::wasmContextOffset()), wasmContext);
+    }
+
     if (!!info.memory) {
         GPRReg baseMemory = pinnedRegs.baseMemoryPointer;
-        jit.loadWasmContext(baseMemory);
-        jit.loadPtr(CCallHelpers::Address(baseMemory, JSWebAssemblyInstance::offsetOfMemory()), baseMemory);
+
+        if (!useFastTLSForWasmContext())
+            jit.loadPtr(CCallHelpers::Address(wasmContext, JSWebAssemblyInstance::offsetOfMemory()), baseMemory);
+        else {
+            jit.loadWasmContext(baseMemory);
+            jit.loadPtr(CCallHelpers::Address(baseMemory, JSWebAssemblyInstance::offsetOfMemory()), baseMemory);
+        }
         const auto& sizeRegs = pinnedRegs.sizeRegisters;
         ASSERT(sizeRegs.size() >= 1);
         ASSERT(!sizeRegs[0].sizeOffset); // The following code assumes we start at 0, and calculates subsequent size registers relative to 0.
index fb67657..e0cab1f 100644 (file)
@@ -36,7 +36,6 @@
 #include "LinkBuffer.h"
 #include "NativeErrorConstructor.h"
 #include "WasmCallingConvention.h"
-#include "WasmContext.h"
 #include "WasmExceptionType.h"
 
 namespace JSC { namespace Wasm {
@@ -66,8 +65,6 @@ static MacroAssemblerCodeRef wasmToJs(VM* vm, Bag<CallLinkInfo>& callLinkInfos,
 
     jit.emitFunctionPrologue();
     jit.store64(JIT::TrustedImm32(0), JIT::Address(GPRInfo::callFrameRegister, CallFrameSlot::codeBlock * static_cast<int>(sizeof(Register)))); // FIXME Stop using 0 as codeBlocks. https://bugs.webkit.org/show_bug.cgi?id=165321
-    jit.storePtr(JIT::TrustedImmPtr(vm->webAssemblyToJSCallee.get()), JIT::Address(GPRInfo::callFrameRegister, CallFrameSlot::callee * static_cast<int>(sizeof(Register))));
-
 
     {
         bool hasBadI64Use = false;
@@ -93,16 +90,22 @@ static MacroAssemblerCodeRef wasmToJs(VM* vm, Bag<CallLinkInfo>& callLinkInfos,
         if (hasBadI64Use) {
             jit.copyCalleeSavesToVMEntryFrameCalleeSavesBuffer();
             jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
+            jit.loadWasmContext(GPRInfo::argumentGPR1);
+
+            // Store Callee.
+            jit.loadPtr(CCallHelpers::Address(GPRInfo::argumentGPR1, JSWebAssemblyInstance::offsetOfCallee()), GPRInfo::argumentGPR2);
+            jit.storePtr(GPRInfo::argumentGPR2, JIT::Address(GPRInfo::callFrameRegister, CallFrameSlot::callee * static_cast<int>(sizeof(Register))));
+
             auto call = jit.call();
             jit.jumpToExceptionHandler();
 
-            void (*throwBadI64)(ExecState*) = [] (ExecState* exec) -> void {
+            void (*throwBadI64)(ExecState*, JSWebAssemblyInstance*) = [] (ExecState* exec, JSWebAssemblyInstance* wasmContext) -> void {
                 VM* vm = &exec->vm();
                 NativeCallFrameTracer tracer(vm, exec);
 
                 {
                     auto throwScope = DECLARE_THROW_SCOPE(*vm);
-                    JSGlobalObject* globalObject = loadWasmContext(*vm)->globalObject();
+                    JSGlobalObject* globalObject = wasmContext->globalObject();
                     auto* error = ErrorInstance::create(exec, *vm, globalObject->typeErrorConstructor()->errorStructure(), ASCIILiteral("i64 not allowed as return type or argument to an imported function"));
                     throwException(exec, throwScope, error);
                 }
@@ -252,6 +255,10 @@ static MacroAssemblerCodeRef wasmToJs(VM* vm, Bag<CallLinkInfo>& callLinkInfos,
         }
     }
 
+    jit.loadWasmContext(GPRInfo::argumentGPR0);
+    jit.loadPtr(CCallHelpers::Address(GPRInfo::argumentGPR0, JSWebAssemblyInstance::offsetOfCallee()), GPRInfo::argumentGPR0);
+    jit.storePtr(GPRInfo::argumentGPR0, JIT::Address(GPRInfo::callFrameRegister, CallFrameSlot::callee * static_cast<int>(sizeof(Register))));
+
     GPRReg importJSCellGPRReg = GPRInfo::regT0; // Callee needs to be in regT0 for slow path below.
     ASSERT(!wasmCC.m_calleeSaveRegisters.get(importJSCellGPRReg));
 
index 6484cd4..217ce1e 100644 (file)
 
 namespace JSC {
 
-JSWebAssemblyInstance* loadWasmContext(VM& vm)
+WasmContext* loadWasmContext(VM& vm)
 {
 #if ENABLE(FAST_TLS_JIT)
     if (Options::useWebAssemblyFastTLS())
-        return bitwise_cast<JSWebAssemblyInstance*>(_pthread_getspecific_direct(WTF_WASM_CONTEXT_KEY));
+        return bitwise_cast<WasmContext*>(_pthread_getspecific_direct(WTF_WASM_CONTEXT_KEY));
 #endif
     // FIXME: Save this state elsewhere to allow PIC. https://bugs.webkit.org/show_bug.cgi?id=169773
     return vm.wasmContext;
 }
 
-void storeWasmContext(VM& vm, JSWebAssemblyInstance* instance)
+void storeWasmContext(VM& vm, WasmContext* instance)
 {
 #if ENABLE(FAST_TLS_JIT)
     if (Options::useWebAssemblyFastTLS())
index 1c5e8a1..afe7835 100644 (file)
@@ -32,8 +32,10 @@ namespace JSC {
 class JSWebAssemblyInstance;
 class VM;
 
-JSWebAssemblyInstance* loadWasmContext(VM&);
-void storeWasmContext(VM&, JSWebAssemblyInstance*);
+using WasmContext = JSWebAssemblyInstance;
+
+WasmContext* loadWasmContext(VM&);
+void storeWasmContext(VM&, WasmContext*);
 
 } // namespace JSC
 
index 8ac0866..58ad07a 100644 (file)
 
 namespace JSC { namespace Wasm {
 
+static Vector<GPRReg> getPinnedRegisters(unsigned remainingPinnedRegisters)
+{
+    Vector<GPRReg> registers;
+    jscCallingConvention().m_calleeSaveRegisters.forEach([&] (Reg reg) {
+        if (!reg.isGPR())
+            return;
+        GPRReg gpr = reg.gpr();
+        if (!remainingPinnedRegisters || RegisterSet::stackRegisters().get(reg))
+            return;
+        --remainingPinnedRegisters;
+        registers.append(gpr);
+    });
+    return registers;
+}
+
 const PinnedRegisterInfo& PinnedRegisterInfo::get()
 {
     static LazyNeverDestroyed<PinnedRegisterInfo> staticPinnedRegisterInfo;
     static std::once_flag staticPinnedRegisterInfoFlag;
     std::call_once(staticPinnedRegisterInfoFlag, [] () {
         Vector<PinnedSizeRegisterInfo> sizeRegisters;
-        GPRReg baseMemoryPointer;
+        GPRReg baseMemoryPointer = InvalidGPRReg;
+        GPRReg wasmContextPointer = InvalidGPRReg;
 
         // FIXME: We should support more than one memory size register, and we should allow different
         //        WebAssembly.Instance to have different pins. Right now we take a vector with only one entry.
         //        If we have more than one size register, we can have one for each load size class.
         //        see: https://bugs.webkit.org/show_bug.cgi?id=162952
         Vector<unsigned> pinnedSizes = { 0 };
-        unsigned remainingPinnedRegisters = pinnedSizes.size() + 1;
-        jscCallingConvention().m_calleeSaveRegisters.forEach([&] (Reg reg) {
-            if (!reg.isGPR())
-                return;
-            GPRReg gpr = reg.gpr();
-            if (!remainingPinnedRegisters || RegisterSet::stackRegisters().get(reg))
-                return;
-            if (remainingPinnedRegisters == 1) {
-                baseMemoryPointer = gpr;
-                remainingPinnedRegisters--;
-            } else
-                sizeRegisters.append({ gpr, pinnedSizes[--remainingPinnedRegisters - 1] });
-        });
-
-        ASSERT(!remainingPinnedRegisters);
-        staticPinnedRegisterInfo.construct(WTFMove(sizeRegisters), baseMemoryPointer);
+        unsigned numberOfPinnedRegisters = pinnedSizes.size() + 1;
+        if (!useFastTLSForWasmContext())
+            ++numberOfPinnedRegisters;
+        Vector<GPRReg> pinnedRegs = getPinnedRegisters(numberOfPinnedRegisters);
+
+        baseMemoryPointer = pinnedRegs.takeLast();
+        if (!useFastTLSForWasmContext())
+            wasmContextPointer = pinnedRegs.takeLast();
+
+        ASSERT(pinnedSizes.size() == pinnedRegs.size());
+        for (unsigned i = 0; i < pinnedSizes.size(); ++i)
+            sizeRegisters.append({ pinnedRegs[i], pinnedSizes[i] });
+        staticPinnedRegisterInfo.construct(WTFMove(sizeRegisters), baseMemoryPointer, wasmContextPointer);
     });
 
     return staticPinnedRegisterInfo.get();
 }
 
-PinnedRegisterInfo::PinnedRegisterInfo(Vector<PinnedSizeRegisterInfo>&& sizeRegisters, GPRReg baseMemoryPointer)
+PinnedRegisterInfo::PinnedRegisterInfo(Vector<PinnedSizeRegisterInfo>&& sizeRegisters, GPRReg baseMemoryPointer, GPRReg wasmContextPointer)
     : sizeRegisters(WTFMove(sizeRegisters))
     , baseMemoryPointer(baseMemoryPointer)
+    , wasmContextPointer(wasmContextPointer)
 {
 }
 
index 6de070a..248796d 100644 (file)
@@ -28,6 +28,7 @@
 #if ENABLE(WEBASSEMBLY)
 
 #include "GPRInfo.h"
+#include "RegisterSet.h"
 #include "WasmMemory.h"
 #include "WasmPageCount.h"
 #include <wtf/Ref.h>
@@ -43,8 +44,20 @@ struct PinnedSizeRegisterInfo {
 struct PinnedRegisterInfo {
     Vector<PinnedSizeRegisterInfo> sizeRegisters;
     GPRReg baseMemoryPointer;
+    GPRReg wasmContextPointer;
     static const PinnedRegisterInfo& get();
-    PinnedRegisterInfo(Vector<PinnedSizeRegisterInfo>&&, GPRReg);
+    PinnedRegisterInfo(Vector<PinnedSizeRegisterInfo>&&, GPRReg, GPRReg);
+
+    RegisterSet toSave() const
+    {
+        RegisterSet result;
+        result.set(baseMemoryPointer);
+        if (wasmContextPointer != InvalidGPRReg)
+            result.set(wasmContextPointer);
+        for (const auto& info : sizeRegisters)
+            result.set(info.sizeRegister);
+        return result;
+    }
 };
 
 class MemoryInformation {
@@ -73,6 +86,20 @@ private:
     bool m_isImport { false };
 };
 
+inline bool useFastTLS()
+{
+#if ENABLE(FAST_TLS_JIT)
+    return Options::useWebAssemblyFastTLS();
+#else
+    return false;
+#endif
+}
+
+inline bool useFastTLSForWasmContext()
+{
+    return useFastTLS();
+}
+
 } } // namespace JSC::Wasm
 
 #endif // ENABLE(WASM)
index 1c11b0c..e3bd740 100644 (file)
@@ -34,6 +34,7 @@
 #include "JSModuleNamespaceObject.h"
 #include "JSWebAssemblyMemory.h"
 #include "JSWebAssemblyModule.h"
+#include "WebAssemblyToJSCallee.h"
 #include <wtf/StdLibExtras.h>
 
 namespace JSC {
@@ -81,6 +82,7 @@ void JSWebAssemblyInstance::finishCreation(VM& vm, JSWebAssemblyModule* module,
 
     m_codeBlock.set(vm, this, module->codeBlock());
     m_moduleNamespaceObject.set(vm, this, moduleNamespaceObject);
+    m_callee.set(vm, this, module->callee());
     putDirect(vm, Identifier::fromString(&vm, "exports"), moduleNamespaceObject, None);
 }
 
@@ -99,6 +101,7 @@ void JSWebAssemblyInstance::visitChildren(JSCell* cell, SlotVisitor& visitor)
     visitor.append(thisObject->m_moduleNamespaceObject);
     visitor.append(thisObject->m_memory);
     visitor.append(thisObject->m_table);
+    visitor.append(thisObject->m_callee);
     visitor.reportExtraMemoryVisited(thisObject->module()->moduleInformation().globals.size());
     for (unsigned i = 0; i < thisObject->m_numImportFunctions; ++i)
         visitor.append(*thisObject->importFunction(i));
index e228496..42aa1b3 100644 (file)
@@ -37,6 +37,7 @@ namespace JSC {
 
 class JSModuleNamespaceObject;
 class JSWebAssemblyModule;
+class WebAssemblyToJSCallee;
 
 class JSWebAssemblyInstance : public JSDestructibleObject {
 public:
@@ -97,6 +98,7 @@ public:
 
     static ptrdiff_t offsetOfMemory() { return OBJECT_OFFSETOF(JSWebAssemblyInstance, m_memory); }
     static ptrdiff_t offsetOfTable() { return OBJECT_OFFSETOF(JSWebAssemblyInstance, m_table); }
+    static ptrdiff_t offsetOfCallee() { return OBJECT_OFFSETOF(JSWebAssemblyInstance, m_callee); }
     static ptrdiff_t offsetOfGlobals() { return OBJECT_OFFSETOF(JSWebAssemblyInstance, m_globals); }
     static size_t offsetOfImportFunctions() { return WTF::roundUpToMultipleOf<sizeof(WriteBarrier<JSCell>)>(sizeof(JSWebAssemblyInstance)); }
     static size_t offsetOfImportFunction(size_t importFunctionNum) { return offsetOfImportFunctions() + importFunctionNum * sizeof(sizeof(WriteBarrier<JSCell>)); }
@@ -117,6 +119,7 @@ private:
     WriteBarrier<JSModuleNamespaceObject> m_moduleNamespaceObject;
     WriteBarrier<JSWebAssemblyMemory> m_memory;
     WriteBarrier<JSWebAssemblyTable> m_table;
+    WriteBarrier<WebAssemblyToJSCallee> m_callee;
     MallocPtr<uint64_t> m_globals;
     unsigned m_numImportFunctions;
 };
index f41467f..939437e 100644 (file)
@@ -36,6 +36,7 @@
 #include "WasmFormat.h"
 #include "WasmMemory.h"
 #include "WasmPlan.h"
+#include "WebAssemblyToJSCallee.h"
 #include <wtf/StdLibExtras.h>
 
 namespace JSC {
@@ -132,6 +133,7 @@ void JSWebAssemblyModule::finishCreation(VM& vm, ExecState* exec, uint8_t* sourc
     m_sourceBuffer = ArrayBuffer::create(source, byteSize);
     m_moduleInformation = plan.takeModuleInformation();
     m_exportSymbolTable.set(vm, this, exportSymbolTable);
+    m_callee.set(vm, this, WebAssemblyToJSCallee::create(vm, vm.webAssemblyToJSCalleeStructure.get(), this));
     codeBlockFor(codeBlock->mode()).set(vm, this, codeBlock);
 }
 
@@ -147,6 +149,7 @@ void JSWebAssemblyModule::visitChildren(JSCell* cell, SlotVisitor& visitor)
 
     Base::visitChildren(thisObject, visitor);
     visitor.append(thisObject->m_exportSymbolTable);
+    visitor.append(thisObject->m_callee);
     for (unsigned i = 0; i < Wasm::NumberOfMemoryModes; ++i)
         visitor.append(thisObject->m_codeBlocks[i]);
 }
index 389e63a..0414104 100644 (file)
@@ -43,6 +43,7 @@ class Plan;
 
 class SymbolTable;
 class JSWebAssemblyMemory;
+class WebAssemblyToJSCallee;
 
 class JSWebAssemblyModule : public JSDestructibleObject {
 public:
@@ -60,6 +61,7 @@ public:
     {
         return m_moduleInformation->signatureIndexFromFunctionIndexSpace(functionIndexSpace);
     }
+    WebAssemblyToJSCallee* callee() const { return m_callee.get(); }
 
     // Returns the code block that this module was originally compiled expecting to use. This won't need to recompile.
     JSWebAssemblyCodeBlock* codeBlock() { return codeBlockFor(m_moduleInformation->memory.mode()).get(); }
@@ -79,6 +81,7 @@ private:
     std::unique_ptr<Wasm::ModuleInformation> m_moduleInformation;
     WriteBarrier<SymbolTable> m_exportSymbolTable;
     WriteBarrier<JSWebAssemblyCodeBlock> m_codeBlocks[Wasm::NumberOfMemoryModes];
+    WriteBarrier<WebAssemblyToJSCallee> m_callee;
 };
 
 } // namespace JSC
index d1a801c..89edd94 100644 (file)
@@ -42,6 +42,7 @@
 #include "WasmContext.h"
 #include "WasmFormat.h"
 #include "WasmMemory.h"
+#include <wtf/FastTLS.h>
 #include <wtf/SystemTracing.h>
 
 namespace JSC {
@@ -121,6 +122,10 @@ static EncodedJSValue JSC_HOST_CALL callWebAssemblyFunction(ExecState* exec)
     protoCallFrame.init(nullptr, wasmFunction, firstArgument, argCount, remainingArgs);
 
     // FIXME Do away with this entire function, and only use the entrypoint generated by B3. https://bugs.webkit.org/show_bug.cgi?id=166486
+    // FIXME: We would like to make loadWasmContext and storeWasmContext no-op if we use pinned registers.
+    // However, we use VM.wasmContext field to pass instance to wasm function's JS glue code.
+    // We should pass JSWebAssemblyInstance directly to vmEntryToWasm.
+    // https://bugs.webkit.org/show_bug.cgi?id=170182
     JSWebAssemblyInstance* prevJSWebAssemblyInstance = loadWasmContext(vm);
     storeWasmContext(vm, wasmFunction->instance());
     ASSERT(wasmFunction->instance());
@@ -153,6 +158,7 @@ WebAssemblyFunction* WebAssemblyFunction::create(VM& vm, JSGlobalObject* globalO
     Structure* structure = globalObject->webAssemblyFunctionStructure();
     WebAssemblyFunction* function = new (NotNull, allocateCell<WebAssemblyFunction>(vm.heap)) WebAssemblyFunction(vm, globalObject, structure, wasmEntrypoint, signatureIndex);
     function->finishCreation(vm, executable, length, name, instance, jsEntrypoint, wasmEntrypoint);
+    ASSERT_WITH_MESSAGE(!function->isLargeAllocation(), "WebAssemblyFunction should be allocated not in large allocation since it is JSCallee.");
     return function;
 }
 
index 4e891a0..4b9c86f 100644 (file)
 #if ENABLE(WEBASSEMBLY)
 
 #include "JSCInlines.h"
+#include "JSWebAssemblyModule.h"
 
 namespace JSC {
 
 const ClassInfo WebAssemblyToJSCallee::s_info = { "WebAssemblyToJSCallee", nullptr, 0, CREATE_METHOD_TABLE(WebAssemblyToJSCallee) };
 
-WebAssemblyToJSCallee* WebAssemblyToJSCallee::create(VM& vm, Structure* structure)
+WebAssemblyToJSCallee* WebAssemblyToJSCallee::create(VM& vm, Structure* structure, JSWebAssemblyModule* module)
 {
     WebAssemblyToJSCallee* callee = new (NotNull, allocateCell<WebAssemblyToJSCallee>(vm.heap)) WebAssemblyToJSCallee(vm, structure);
-    callee->finishCreation(vm);
+    callee->finishCreation(vm, module);
     return callee;
 }
 
 Structure* WebAssemblyToJSCallee::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
 {
-    return Structure::create(vm, globalObject, prototype, TypeInfo(CellType, StructureFlags), info());
+    return Structure::create(vm, globalObject, prototype, TypeInfo(WebAssemblyToJSCalleeType, StructureFlags), info());
 }
 
 WebAssemblyToJSCallee::WebAssemblyToJSCallee(VM& vm, Structure* structure)
@@ -51,15 +52,19 @@ WebAssemblyToJSCallee::WebAssemblyToJSCallee(VM& vm, Structure* structure)
 {
 }
 
-void WebAssemblyToJSCallee::finishCreation(VM& vm)
+void WebAssemblyToJSCallee::finishCreation(VM& vm, JSWebAssemblyModule* module)
 {
     Base::finishCreation(vm);
+    m_module.set(vm, this, module);
 }
 
-void WebAssemblyToJSCallee::destroy(JSCell* cell)
+void WebAssemblyToJSCallee::visitChildren(JSCell* cell, SlotVisitor& visitor)
 {
-    WebAssemblyToJSCallee* thisObject = static_cast<WebAssemblyToJSCallee*>(cell);
-    thisObject->WebAssemblyToJSCallee::~WebAssemblyToJSCallee();
+    auto* thisObject = jsCast<WebAssemblyToJSCallee*>(cell);
+    ASSERT_GC_OBJECT_INHERITS(thisObject, info());
+
+    Base::visitChildren(thisObject, visitor);
+    visitor.append(thisObject->m_module);
 }
 
 } // namespace JSC
index 496c885..19f4795 100644 (file)
 
 namespace JSC {
 
-class WebAssemblyToJSCallee : public JSCell {
+class JSWebAssemblyModule;
+
+class WebAssemblyToJSCallee final : public JSCell {
 public:
     typedef JSCell Base;
     static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal;
 
-    static WebAssemblyToJSCallee* create(VM&, Structure*);
+    static WebAssemblyToJSCallee* create(VM&, Structure*, JSWebAssemblyModule*);
     static Structure* createStructure(VM&, JSGlobalObject*, JSValue);
 
     DECLARE_EXPORT_INFO;
-    static const bool needsDestruction = true;
-    static void destroy(JSCell*);
+
+    static void visitChildren(JSCell*, SlotVisitor&);
+
+    JSWebAssemblyModule* module() { return m_module.get(); }
 
 private:
-    void finishCreation(VM&);
+    void finishCreation(VM&, JSWebAssemblyModule*);
     WebAssemblyToJSCallee(VM&, Structure*);
+
+    WriteBarrier<JSWebAssemblyModule> m_module;
 };
 
 } // namespace JSC