[JSC] LLIntEntryPoint creates same DirectJITCode for all functions
authorticaiolima@gmail.com <ticaiolima@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 19 Mar 2019 13:36:05 +0000 (13:36 +0000)
committerticaiolima@gmail.com <ticaiolima@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 19 Mar 2019 13:36:05 +0000 (13:36 +0000)
https://bugs.webkit.org/show_bug.cgi?id=194648

Reviewed by Keith Miller.

JSTests:

* microbenchmarks/generate-multiple-llint-entrypoints.js: Added.

Source/JavaScriptCore:

1. Making LLIntThunks singleton.

Motivation: Former implementation has one LLIntThunk per type per VM.
However, the generated code for every kind of thunk is essentially the
same and we end up wasting memory (right now jitAllocationGranule = 32 bytes)
when we have 2 or more VM instantiated. Turn these thunks into
singleton will avoid such wasting.

Tradeoff: This change comes with a price, because we will keep thunks
allocated even when there is no VM instantiated. Considering WebCore use case,
the situation of having no VM instantiated is uncommon, since once a
VM is created through `commomVM()`, it will never be destroyed. Given
that, this change does not impact the overall memory comsumption of
WebCore/JSC. It also doesn't impact memory footprint, since thunks are
generated lazily (see results below).

Since we are keeping a static `MacroAssemblerCodeRef<JITThunkPtrTag>`,
we have the assurance that JITed code will never be deallocated,
given it is being pointed by `RefPtr<ExecutableMemoryHandle> m_executableMemory`.
To understand why we decided to make LLIntThunks singleton instead of
removing them, please see the comment on `llint/LLIntThunks.cpp`.

2. Making all LLIntEntrypoints singleton

Motivation: With singleton LLIntThunks, we also can have singleton
DirectJITCodes and NativeJITCodes for each LLIntEntrypoint type and
avoid multiple allocations of objects with the same content.

Tradeoff: As explained before, once we allocate an entrypoint, it
will be alive until the program exits. However, the gains we can
achieve in some use cases justifies such allocations.

As DirectJITCode and NativeJITCode are ThreadSafeRefCounted and we are using
`codeBlock->setJITCode(makeRef(*jitCode))`, their reference counter
will never be less than 1.

3. Memory usage analysis

This change reduces memory usage on stress/generate-multiple-llint-entrypoints.js
by 2% and is neutral on JetStream 2. Following results were generated
running each benchmark 6 times and using 95% Student's t distribution
confidence interval.

microbenchmarks/generate-multiple-llint-entrypoints.js (Changes uses less memory):
    Mean of memory peak on ToT: 122576896 bytes (confidence interval: 67747.2316)
    Mean of memory peak on Changes: 119248213.33 bytes (confidence interval: 50251.2718)

JetStream2 (Neutral):
    Mean of memory peak on ToT: 5442742272 bytes (confidence interval: 134381565.9117)
    Mean of memory peak on Changes: 5384949760 bytes (confidence interval: 158413904.8352)

4. Performance Analysis

This change is performance neutral on JetStream 2 and Speedometer 2.
See results below.:

JetStream 2 (Neutral):
    Mean of score on ToT: 139.58 (confidence interval: 2.44)
    Mean of score on Changes: 141.46 (confidence interval: 4.24)

Speedometer run #1
   ToT: 110 +- 2.9
   Changes: 110 +- 1.8

Speedometer run #2
   ToT: 110 +- 1.6
   Changes: 108 +- 2.3

Speedometer run #3
   ToT: 110 +- 3.0
   Changes: 110 +- 1.4

* jit/JSInterfaceJIT.h:
(JSC::JSInterfaceJIT::JSInterfaceJIT):
* llint/LLIntEntrypoint.cpp:

Here we are changing the usage or DirectJITCode by NativeJITCode on cases
where there is no difference from address of calls with and without
ArithCheck.

(JSC::LLInt::setFunctionEntrypoint):
(JSC::LLInt::setEvalEntrypoint):
(JSC::LLInt::setProgramEntrypoint):
(JSC::LLInt::setModuleProgramEntrypoint):
(JSC::LLInt::setEntrypoint):
* llint/LLIntEntrypoint.h:
* llint/LLIntThunks.cpp:
(JSC::LLInt::generateThunkWithJumpTo):
(JSC::LLInt::functionForCallEntryThunk):
(JSC::LLInt::functionForConstructEntryThunk):
(JSC::LLInt::functionForCallArityCheckThunk):
(JSC::LLInt::functionForConstructArityCheckThunk):
(JSC::LLInt::evalEntryThunk):
(JSC::LLInt::programEntryThunk):
(JSC::LLInt::moduleProgramEntryThunk):
(JSC::LLInt::functionForCallEntryThunkGenerator): Deleted.
(JSC::LLInt::functionForConstructEntryThunkGenerator): Deleted.
(JSC::LLInt::functionForCallArityCheckThunkGenerator): Deleted.
(JSC::LLInt::functionForConstructArityCheckThunkGenerator): Deleted.
(JSC::LLInt::evalEntryThunkGenerator): Deleted.
(JSC::LLInt::programEntryThunkGenerator): Deleted.
(JSC::LLInt::moduleProgramEntryThunkGenerator): Deleted.
* llint/LLIntThunks.h:
* runtime/ScriptExecutable.cpp:
(JSC::setupLLInt):
(JSC::ScriptExecutable::prepareForExecutionImpl):

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

JSTests/ChangeLog
JSTests/microbenchmarks/generate-multiple-llint-entrypoints.js [new file with mode: 0644]
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/jit/JSInterfaceJIT.h
Source/JavaScriptCore/llint/LLIntEntrypoint.cpp
Source/JavaScriptCore/llint/LLIntEntrypoint.h
Source/JavaScriptCore/llint/LLIntThunks.cpp
Source/JavaScriptCore/llint/LLIntThunks.h
Source/JavaScriptCore/runtime/ScriptExecutable.cpp

index 1707a06..a58a4b0 100644 (file)
@@ -1,3 +1,12 @@
+2019-03-19  Caio Lima  <ticaiolima@gmail.com>
+
+        [JSC] LLIntEntryPoint creates same DirectJITCode for all functions
+        https://bugs.webkit.org/show_bug.cgi?id=194648
+
+        Reviewed by Keith Miller.
+
+        * microbenchmarks/generate-multiple-llint-entrypoints.js: Added.
+
 2019-03-18  Mark Lam  <mark.lam@apple.com>
 
         Missing a ThrowScope release in JSObject::toString().
diff --git a/JSTests/microbenchmarks/generate-multiple-llint-entrypoints.js b/JSTests/microbenchmarks/generate-multiple-llint-entrypoints.js
new file mode 100644 (file)
index 0000000..f7f2bc9
--- /dev/null
@@ -0,0 +1,17 @@
+function assert(a, e) {
+    if (a !== e)
+        throw new Error("Expected: " + e + " but got: " + a);
+}
+
+let n = 40000;
+let arr = Array(n);
+
+for(let i = 0; i < n; i++) {
+    arr[i] = eval(`() => ${i}`);
+    assert(arr[i](), i);
+}
+
+for(let i = 0; i < n; i++) {
+    assert(arr[i](), i);
+}
+
index 3484740..0fc72f8 100644 (file)
@@ -1,3 +1,117 @@
+2019-03-19  Caio Lima  <ticaiolima@gmail.com>
+
+        [JSC] LLIntEntryPoint creates same DirectJITCode for all functions
+        https://bugs.webkit.org/show_bug.cgi?id=194648
+
+        Reviewed by Keith Miller.
+
+        1. Making LLIntThunks singleton. 
+
+        Motivation: Former implementation has one LLIntThunk per type per VM.
+        However, the generated code for every kind of thunk is essentially the
+        same and we end up wasting memory (right now jitAllocationGranule = 32 bytes)
+        when we have 2 or more VM instantiated. Turn these thunks into
+        singleton will avoid such wasting.
+
+        Tradeoff: This change comes with a price, because we will keep thunks
+        allocated even when there is no VM instantiated. Considering WebCore use case,
+        the situation of having no VM instantiated is uncommon, since once a
+        VM is created through `commomVM()`, it will never be destroyed. Given
+        that, this change does not impact the overall memory comsumption of
+        WebCore/JSC. It also doesn't impact memory footprint, since thunks are
+        generated lazily (see results below).
+
+        Since we are keeping a static `MacroAssemblerCodeRef<JITThunkPtrTag>`,
+        we have the assurance that JITed code will never be deallocated,
+        given it is being pointed by `RefPtr<ExecutableMemoryHandle> m_executableMemory`.
+        To understand why we decided to make LLIntThunks singleton instead of
+        removing them, please see the comment on `llint/LLIntThunks.cpp`.
+
+        2. Making all LLIntEntrypoints singleton
+
+        Motivation: With singleton LLIntThunks, we also can have singleton
+        DirectJITCodes and NativeJITCodes for each LLIntEntrypoint type and
+        avoid multiple allocations of objects with the same content.
+
+        Tradeoff: As explained before, once we allocate an entrypoint, it
+        will be alive until the program exits. However, the gains we can
+        achieve in some use cases justifies such allocations.
+
+        As DirectJITCode and NativeJITCode are ThreadSafeRefCounted and we are using
+        `codeBlock->setJITCode(makeRef(*jitCode))`, their reference counter
+        will never be less than 1.
+
+        3. Memory usage analysis
+
+        This change reduces memory usage on stress/generate-multiple-llint-entrypoints.js
+        by 2% and is neutral on JetStream 2. Following results were generated
+        running each benchmark 6 times and using 95% Student's t distribution
+        confidence interval.
+
+        microbenchmarks/generate-multiple-llint-entrypoints.js (Changes uses less memory): 
+            Mean of memory peak on ToT: 122576896 bytes (confidence interval: 67747.2316)
+            Mean of memory peak on Changes: 119248213.33 bytes (confidence interval: 50251.2718)
+
+        JetStream2 (Neutral):
+            Mean of memory peak on ToT: 5442742272 bytes (confidence interval: 134381565.9117)
+            Mean of memory peak on Changes: 5384949760 bytes (confidence interval: 158413904.8352)
+
+        4. Performance Analysis
+
+        This change is performance neutral on JetStream 2 and Speedometer 2.
+        See results below.:
+
+        JetStream 2 (Neutral):
+            Mean of score on ToT: 139.58 (confidence interval: 2.44)
+            Mean of score on Changes: 141.46 (confidence interval: 4.24)
+
+        Speedometer run #1
+           ToT: 110 +- 2.9
+           Changes: 110 +- 1.8
+
+        Speedometer run #2
+           ToT: 110 +- 1.6
+           Changes: 108 +- 2.3
+
+        Speedometer run #3
+           ToT: 110 +- 3.0
+           Changes: 110 +- 1.4
+
+        * jit/JSInterfaceJIT.h:
+        (JSC::JSInterfaceJIT::JSInterfaceJIT):
+        * llint/LLIntEntrypoint.cpp:
+
+        Here we are changing the usage or DirectJITCode by NativeJITCode on cases
+        where there is no difference from address of calls with and without
+        ArithCheck.
+
+        (JSC::LLInt::setFunctionEntrypoint):
+        (JSC::LLInt::setEvalEntrypoint):
+        (JSC::LLInt::setProgramEntrypoint):
+        (JSC::LLInt::setModuleProgramEntrypoint):
+        (JSC::LLInt::setEntrypoint):
+        * llint/LLIntEntrypoint.h:
+        * llint/LLIntThunks.cpp:
+        (JSC::LLInt::generateThunkWithJumpTo):
+        (JSC::LLInt::functionForCallEntryThunk):
+        (JSC::LLInt::functionForConstructEntryThunk):
+        (JSC::LLInt::functionForCallArityCheckThunk):
+        (JSC::LLInt::functionForConstructArityCheckThunk):
+        (JSC::LLInt::evalEntryThunk):
+        (JSC::LLInt::programEntryThunk):
+        (JSC::LLInt::moduleProgramEntryThunk):
+        (JSC::LLInt::functionForCallEntryThunkGenerator): Deleted.
+        (JSC::LLInt::functionForConstructEntryThunkGenerator): Deleted.
+        (JSC::LLInt::functionForCallArityCheckThunkGenerator): Deleted.
+        (JSC::LLInt::functionForConstructArityCheckThunkGenerator): Deleted.
+        (JSC::LLInt::evalEntryThunkGenerator): Deleted.
+        (JSC::LLInt::programEntryThunkGenerator): Deleted.
+        (JSC::LLInt::moduleProgramEntryThunkGenerator): Deleted.
+        * llint/LLIntThunks.h:
+        * runtime/ScriptExecutable.cpp:
+        (JSC::setupLLInt):
+        (JSC::ScriptExecutable::prepareForExecutionImpl):
+
 2019-03-18  Yusuke Suzuki  <ysuzuki@apple.com>
 
         [JSC] Add missing exception checks revealed by newly added exception checks, follow-up after r243081
index 5c3e323..2cf9198 100644 (file)
@@ -38,7 +38,8 @@
 namespace JSC {
     class JSInterfaceJIT : public CCallHelpers, public GPRInfo, public FPRInfo {
     public:
-        JSInterfaceJIT(VM* vm, CodeBlock* codeBlock = 0)
+
+        JSInterfaceJIT(VM* vm = nullptr, CodeBlock* codeBlock = nullptr)
             : CCallHelpers(codeBlock)
             , m_vm(vm)
         {
index 3ebb8a6..5d65fb4 100644 (file)
 
 namespace JSC { namespace LLInt {
 
-static void setFunctionEntrypoint(VM& vm, CodeBlock* codeBlock)
+static void setFunctionEntrypoint(CodeBlock* codeBlock)
 {
     CodeSpecializationKind kind = codeBlock->specializationKind();
     
 #if ENABLE(JIT)
     if (VM::canUseJIT()) {
         if (kind == CodeForCall) {
-            codeBlock->setJITCode(
-                adoptRef(*new DirectJITCode(vm.getCTIStub(functionForCallEntryThunkGenerator).retagged<JSEntryPtrTag>(), vm.getCTIStub(functionForCallArityCheckThunkGenerator).retaggedCode<JSEntryPtrTag>(), JITCode::InterpreterThunk)));
+            static DirectJITCode* jitCode;
+            static std::once_flag onceKey;
+            std::call_once(onceKey, [&] {
+                auto callRef = functionForCallEntryThunk().retagged<JSEntryPtrTag>();
+                auto callArityCheckRef = functionForCallArityCheckThunk().retaggedCode<JSEntryPtrTag>();
+                jitCode = new DirectJITCode(callRef, callArityCheckRef, JITCode::InterpreterThunk, JITCode::ShareAttribute::Shared);
+            });
+
+            codeBlock->setJITCode(makeRef(*jitCode));
             return;
         }
         ASSERT(kind == CodeForConstruct);
-        codeBlock->setJITCode(
-            adoptRef(*new DirectJITCode(vm.getCTIStub(functionForConstructEntryThunkGenerator).retagged<JSEntryPtrTag>(), vm.getCTIStub(functionForConstructArityCheckThunkGenerator).retaggedCode<JSEntryPtrTag>(), JITCode::InterpreterThunk)));
+
+        static DirectJITCode* jitCode;
+        static std::once_flag onceKey;
+        std::call_once(onceKey, [&] {
+            auto constructRef = functionForConstructEntryThunk().retagged<JSEntryPtrTag>();
+            auto constructArityCheckRef = functionForConstructArityCheckThunk().retaggedCode<JSEntryPtrTag>();
+            jitCode = new DirectJITCode(constructRef, constructArityCheckRef, JITCode::InterpreterThunk, JITCode::ShareAttribute::Shared);
+        });
+
+        codeBlock->setJITCode(makeRef(*jitCode));
         return;
     }
 #endif // ENABLE(JIT)
 
-    UNUSED_PARAM(vm);
     if (kind == CodeForCall) {
         static DirectJITCode* jitCode;
         static std::once_flag onceKey;
@@ -74,18 +88,21 @@ static void setFunctionEntrypoint(VM& vm, CodeBlock* codeBlock)
     }
 }
 
-static void setEvalEntrypoint(VM& vm, CodeBlock* codeBlock)
+static void setEvalEntrypoint(CodeBlock* codeBlock)
 {
 #if ENABLE(JIT)
     if (VM::canUseJIT()) {
-        MacroAssemblerCodeRef<JSEntryPtrTag> codeRef = vm.getCTIStub(evalEntryThunkGenerator).retagged<JSEntryPtrTag>();
-        codeBlock->setJITCode(
-            adoptRef(*new DirectJITCode(codeRef, codeRef.code(), JITCode::InterpreterThunk)));
+        static NativeJITCode* jitCode;
+        static std::once_flag onceKey;
+        std::call_once(onceKey, [&] {
+            MacroAssemblerCodeRef<JSEntryPtrTag> codeRef = evalEntryThunk().retagged<JSEntryPtrTag>();
+            jitCode = new NativeJITCode(codeRef, JITCode::InterpreterThunk, Intrinsic::NoIntrinsic, JITCode::ShareAttribute::Shared);
+        });
+        codeBlock->setJITCode(makeRef(*jitCode));
         return;
     }
 #endif // ENABLE(JIT)
 
-    UNUSED_PARAM(vm);
     static NativeJITCode* jitCode;
     static std::once_flag onceKey;
     std::call_once(onceKey, [&] {
@@ -94,18 +111,21 @@ static void setEvalEntrypoint(VM& vm, CodeBlock* codeBlock)
     codeBlock->setJITCode(makeRef(*jitCode));
 }
 
-static void setProgramEntrypoint(VM& vm, CodeBlock* codeBlock)
+static void setProgramEntrypoint(CodeBlock* codeBlock)
 {
 #if ENABLE(JIT)
     if (VM::canUseJIT()) {
-        MacroAssemblerCodeRef<JSEntryPtrTag> codeRef = vm.getCTIStub(programEntryThunkGenerator).retagged<JSEntryPtrTag>();
-        codeBlock->setJITCode(
-            adoptRef(*new DirectJITCode(codeRef, codeRef.code(), JITCode::InterpreterThunk)));
+        static NativeJITCode* jitCode;
+        static std::once_flag onceKey;
+        std::call_once(onceKey, [&] {
+            MacroAssemblerCodeRef<JSEntryPtrTag> codeRef = programEntryThunk().retagged<JSEntryPtrTag>();
+            jitCode = new NativeJITCode(codeRef, JITCode::InterpreterThunk, Intrinsic::NoIntrinsic, JITCode::ShareAttribute::Shared);
+        });
+        codeBlock->setJITCode(makeRef(*jitCode));
         return;
     }
 #endif // ENABLE(JIT)
 
-    UNUSED_PARAM(vm);
     static NativeJITCode* jitCode;
     static std::once_flag onceKey;
     std::call_once(onceKey, [&] {
@@ -114,18 +134,21 @@ static void setProgramEntrypoint(VM& vm, CodeBlock* codeBlock)
     codeBlock->setJITCode(makeRef(*jitCode));
 }
 
-static void setModuleProgramEntrypoint(VM& vm, CodeBlock* codeBlock)
+static void setModuleProgramEntrypoint(CodeBlock* codeBlock)
 {
 #if ENABLE(JIT)
     if (VM::canUseJIT()) {
-        MacroAssemblerCodeRef<JSEntryPtrTag> codeRef = vm.getCTIStub(moduleProgramEntryThunkGenerator).retagged<JSEntryPtrTag>();
-        codeBlock->setJITCode(
-            adoptRef(*new DirectJITCode(codeRef, codeRef.code(), JITCode::InterpreterThunk)));
+        static NativeJITCode* jitCode;
+        static std::once_flag onceKey;
+        std::call_once(onceKey, [&] {
+            MacroAssemblerCodeRef<JSEntryPtrTag> codeRef = moduleProgramEntryThunk().retagged<JSEntryPtrTag>();
+            jitCode = new NativeJITCode(codeRef, JITCode::InterpreterThunk, Intrinsic::NoIntrinsic, JITCode::ShareAttribute::Shared);
+        });
+        codeBlock->setJITCode(makeRef(*jitCode));
         return;
     }
 #endif // ENABLE(JIT)
 
-    UNUSED_PARAM(vm);
     static NativeJITCode* jitCode;
     static std::once_flag onceKey;
     std::call_once(onceKey, [&] {
@@ -134,20 +157,20 @@ static void setModuleProgramEntrypoint(VM& vm, CodeBlock* codeBlock)
     codeBlock->setJITCode(makeRef(*jitCode));
 }
 
-void setEntrypoint(VM& vm, CodeBlock* codeBlock)
+void setEntrypoint(CodeBlock* codeBlock)
 {
     switch (codeBlock->codeType()) {
     case GlobalCode:
-        setProgramEntrypoint(vm, codeBlock);
+        setProgramEntrypoint(codeBlock);
         return;
     case ModuleCode:
-        setModuleProgramEntrypoint(vm, codeBlock);
+        setModuleProgramEntrypoint(codeBlock);
         return;
     case EvalCode:
-        setEvalEntrypoint(vm, codeBlock);
+        setEvalEntrypoint(codeBlock);
         return;
     case FunctionCode:
-        setFunctionEntrypoint(vm, codeBlock);
+        setFunctionEntrypoint(codeBlock);
         return;
     }
     
index 3e81720..e100fb8 100644 (file)
@@ -33,7 +33,7 @@ class VM;
 
 namespace LLInt {
 
-void setEntrypoint(VM&, CodeBlock*);
+void setEntrypoint(CodeBlock*);
 
 unsigned frameRegisterCountFor(CodeBlock*);
 
index 5c194cf..12e64fc 100644 (file)
@@ -39,6 +39,7 @@
 #include "ProtoCallFrame.h"
 #include "StackAlignment.h"
 #include "VM.h"
+#include <wtf/NeverDestroyed.h>
 
 namespace JSC {
 
@@ -46,9 +47,14 @@ namespace JSC {
 
 namespace LLInt {
 
-static MacroAssemblerCodeRef<JITThunkPtrTag> generateThunkWithJumpTo(VM* vm, OpcodeID opcodeID, const char *thunkKind)
+// These thunks are necessary because of nearCall used on JITed code.
+// It requires that the distance from nearCall address to the destination address
+// fits on 32-bits, and that's not the case of getCodeRef(llint_function_for_call_prologue)
+// and others LLIntEntrypoints.
+
+static MacroAssemblerCodeRef<JITThunkPtrTag> generateThunkWithJumpTo(OpcodeID opcodeID, const char *thunkKind)
 {
-    JSInterfaceJIT jit(vm);
+    JSInterfaceJIT jit;
 
     // FIXME: there's probably a better way to do it on X86, but I'm not sure I care.
     LLIntCode target = LLInt::getCodeFunctionPtr<JSEntryPtrTag>(opcodeID);
@@ -61,39 +67,74 @@ static MacroAssemblerCodeRef<JITThunkPtrTag> generateThunkWithJumpTo(VM* vm, Opc
     return FINALIZE_CODE(patchBuffer, JITThunkPtrTag, "LLInt %s prologue thunk", thunkKind);
 }
 
-MacroAssemblerCodeRef<JITThunkPtrTag> functionForCallEntryThunkGenerator(VM* vm)
+MacroAssemblerCodeRef<JITThunkPtrTag> functionForCallEntryThunk()
 {
-    return generateThunkWithJumpTo(vm, llint_function_for_call_prologue, "function for call");
+    static LazyNeverDestroyed<MacroAssemblerCodeRef<JITThunkPtrTag>> codeRef;
+    static std::once_flag onceKey;
+    std::call_once(onceKey, [&] {
+        codeRef.construct(generateThunkWithJumpTo(llint_function_for_call_prologue, "function for call"));
+    });
+    return codeRef;
 }
 
-MacroAssemblerCodeRef<JITThunkPtrTag> functionForConstructEntryThunkGenerator(VM* vm)
+MacroAssemblerCodeRef<JITThunkPtrTag> functionForConstructEntryThunk()
 {
-    return generateThunkWithJumpTo(vm, llint_function_for_construct_prologue, "function for construct");
+    static LazyNeverDestroyed<MacroAssemblerCodeRef<JITThunkPtrTag>> codeRef;
+    static std::once_flag onceKey;
+    std::call_once(onceKey, [&] {
+        codeRef.construct(generateThunkWithJumpTo(llint_function_for_construct_prologue, "function for construct"));
+    });
+    return codeRef;
 }
 
-MacroAssemblerCodeRef<JITThunkPtrTag> functionForCallArityCheckThunkGenerator(VM* vm)
+MacroAssemblerCodeRef<JITThunkPtrTag> functionForCallArityCheckThunk()
 {
-    return generateThunkWithJumpTo(vm, llint_function_for_call_arity_check, "function for call with arity check");
+    static LazyNeverDestroyed<MacroAssemblerCodeRef<JITThunkPtrTag>> codeRef;
+    static std::once_flag onceKey;
+    std::call_once(onceKey, [&] {
+        codeRef.construct(generateThunkWithJumpTo(llint_function_for_call_arity_check, "function for call with arity check"));
+    });
+    return codeRef;
 }
 
-MacroAssemblerCodeRef<JITThunkPtrTag> functionForConstructArityCheckThunkGenerator(VM* vm)
+MacroAssemblerCodeRef<JITThunkPtrTag> functionForConstructArityCheckThunk()
 {
-    return generateThunkWithJumpTo(vm, llint_function_for_construct_arity_check, "function for construct with arity check");
+    static LazyNeverDestroyed<MacroAssemblerCodeRef<JITThunkPtrTag>> codeRef;
+    static std::once_flag onceKey;
+    std::call_once(onceKey, [&] {
+        codeRef.construct(generateThunkWithJumpTo(llint_function_for_construct_arity_check, "function for construct with arity check"));
+    });
+    return codeRef;
 }
 
-MacroAssemblerCodeRef<JITThunkPtrTag> evalEntryThunkGenerator(VM* vm)
+MacroAssemblerCodeRef<JITThunkPtrTag> evalEntryThunk()
 {
-    return generateThunkWithJumpTo(vm, llint_eval_prologue, "eval");
+    static LazyNeverDestroyed<MacroAssemblerCodeRef<JITThunkPtrTag>> codeRef;
+    static std::once_flag onceKey;
+    std::call_once(onceKey, [&] {
+        codeRef.construct(generateThunkWithJumpTo(llint_eval_prologue, "eval"));
+    });
+    return codeRef;
 }
 
-MacroAssemblerCodeRef<JITThunkPtrTag> programEntryThunkGenerator(VM* vm)
+MacroAssemblerCodeRef<JITThunkPtrTag> programEntryThunk()
 {
-    return generateThunkWithJumpTo(vm, llint_program_prologue, "program");
+    static LazyNeverDestroyed<MacroAssemblerCodeRef<JITThunkPtrTag>> codeRef;
+    static std::once_flag onceKey;
+    std::call_once(onceKey, [&] {
+        codeRef.construct(generateThunkWithJumpTo(llint_program_prologue, "program"));
+    });
+    return codeRef;
 }
 
-MacroAssemblerCodeRef<JITThunkPtrTag> moduleProgramEntryThunkGenerator(VM* vm)
+MacroAssemblerCodeRef<JITThunkPtrTag> moduleProgramEntryThunk()
 {
-    return generateThunkWithJumpTo(vm, llint_module_program_prologue, "module_program");
+    static LazyNeverDestroyed<MacroAssemblerCodeRef<JITThunkPtrTag>> codeRef;
+    static std::once_flag onceKey;
+    std::call_once(onceKey, [&] {
+        codeRef.construct(generateThunkWithJumpTo(llint_module_program_prologue, "module_program"));
+    });
+    return codeRef;
 }
 
 } // namespace LLInt
index 839ff1e..e2293df 100644 (file)
@@ -46,12 +46,12 @@ inline EncodedJSValue vmEntryToWasm(void* code, VM* vm, ProtoCallFrame* frame)
 
 namespace LLInt {
 
-MacroAssemblerCodeRef<JITThunkPtrTag> functionForCallEntryThunkGenerator(VM*);
-MacroAssemblerCodeRef<JITThunkPtrTag> functionForConstructEntryThunkGenerator(VM*);
-MacroAssemblerCodeRef<JITThunkPtrTag> functionForCallArityCheckThunkGenerator(VM*);
-MacroAssemblerCodeRef<JITThunkPtrTag> functionForConstructArityCheckThunkGenerator(VM*);
-MacroAssemblerCodeRef<JITThunkPtrTag> evalEntryThunkGenerator(VM*);
-MacroAssemblerCodeRef<JITThunkPtrTag> programEntryThunkGenerator(VM*);
-MacroAssemblerCodeRef<JITThunkPtrTag> moduleProgramEntryThunkGenerator(VM*);
+MacroAssemblerCodeRef<JITThunkPtrTag> functionForCallEntryThunk();
+MacroAssemblerCodeRef<JITThunkPtrTag> functionForConstructEntryThunk();
+MacroAssemblerCodeRef<JITThunkPtrTag> functionForCallArityCheckThunk();
+MacroAssemblerCodeRef<JITThunkPtrTag> functionForConstructArityCheckThunk();
+MacroAssemblerCodeRef<JITThunkPtrTag> evalEntryThunk();
+MacroAssemblerCodeRef<JITThunkPtrTag> programEntryThunk();
+MacroAssemblerCodeRef<JITThunkPtrTag> moduleProgramEntryThunk();
 
 } } // namespace JSC::LLInt
index 65e872d..4e1ef9a 100644 (file)
@@ -385,9 +385,9 @@ CodeBlock* ScriptExecutable::newReplacementCodeBlockFor(
     return result;
 }
 
-static void setupLLInt(VM& vm, CodeBlock* codeBlock)
+static void setupLLInt(CodeBlock* codeBlock)
 {
-    LLInt::setEntrypoint(vm, codeBlock);
+    LLInt::setEntrypoint(codeBlock);
 }
 
 static void setupJIT(VM& vm, CodeBlock* codeBlock)
@@ -424,7 +424,7 @@ Exception* ScriptExecutable::prepareForExecutionImpl(
         codeBlock->validate();
     
     if (Options::useLLInt())
-        setupLLInt(vm, codeBlock);
+        setupLLInt(codeBlock);
     else
         setupJIT(vm, codeBlock);