Changeset 243136 in webkit
- Timestamp:
- Mar 19, 2019 6:36:05 AM (5 years ago)
- Location:
- trunk
- Files:
-
- 1 added
- 8 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/JSTests/ChangeLog
r243079 r243136 1 2019-03-19 Caio Lima <ticaiolima@gmail.com> 2 3 [JSC] LLIntEntryPoint creates same DirectJITCode for all functions 4 https://bugs.webkit.org/show_bug.cgi?id=194648 5 6 Reviewed by Keith Miller. 7 8 * microbenchmarks/generate-multiple-llint-entrypoints.js: Added. 9 1 10 2019-03-18 Mark Lam <mark.lam@apple.com> 2 11 -
trunk/Source/JavaScriptCore/ChangeLog
r243128 r243136 1 2019-03-19 Caio Lima <ticaiolima@gmail.com> 2 3 [JSC] LLIntEntryPoint creates same DirectJITCode for all functions 4 https://bugs.webkit.org/show_bug.cgi?id=194648 5 6 Reviewed by Keith Miller. 7 8 1. Making LLIntThunks singleton. 9 10 Motivation: Former implementation has one LLIntThunk per type per VM. 11 However, the generated code for every kind of thunk is essentially the 12 same and we end up wasting memory (right now jitAllocationGranule = 32 bytes) 13 when we have 2 or more VM instantiated. Turn these thunks into 14 singleton will avoid such wasting. 15 16 Tradeoff: This change comes with a price, because we will keep thunks 17 allocated even when there is no VM instantiated. Considering WebCore use case, 18 the situation of having no VM instantiated is uncommon, since once a 19 VM is created through `commomVM()`, it will never be destroyed. Given 20 that, this change does not impact the overall memory comsumption of 21 WebCore/JSC. It also doesn't impact memory footprint, since thunks are 22 generated lazily (see results below). 23 24 Since we are keeping a static `MacroAssemblerCodeRef<JITThunkPtrTag>`, 25 we have the assurance that JITed code will never be deallocated, 26 given it is being pointed by `RefPtr<ExecutableMemoryHandle> m_executableMemory`. 27 To understand why we decided to make LLIntThunks singleton instead of 28 removing them, please see the comment on `llint/LLIntThunks.cpp`. 29 30 2. Making all LLIntEntrypoints singleton 31 32 Motivation: With singleton LLIntThunks, we also can have singleton 33 DirectJITCodes and NativeJITCodes for each LLIntEntrypoint type and 34 avoid multiple allocations of objects with the same content. 35 36 Tradeoff: As explained before, once we allocate an entrypoint, it 37 will be alive until the program exits. However, the gains we can 38 achieve in some use cases justifies such allocations. 39 40 As DirectJITCode and NativeJITCode are ThreadSafeRefCounted and we are using 41 `codeBlock->setJITCode(makeRef(*jitCode))`, their reference counter 42 will never be less than 1. 43 44 3. Memory usage analysis 45 46 This change reduces memory usage on stress/generate-multiple-llint-entrypoints.js 47 by 2% and is neutral on JetStream 2. Following results were generated 48 running each benchmark 6 times and using 95% Student's t distribution 49 confidence interval. 50 51 microbenchmarks/generate-multiple-llint-entrypoints.js (Changes uses less memory): 52 Mean of memory peak on ToT: 122576896 bytes (confidence interval: 67747.2316) 53 Mean of memory peak on Changes: 119248213.33 bytes (confidence interval: 50251.2718) 54 55 JetStream2 (Neutral): 56 Mean of memory peak on ToT: 5442742272 bytes (confidence interval: 134381565.9117) 57 Mean of memory peak on Changes: 5384949760 bytes (confidence interval: 158413904.8352) 58 59 4. Performance Analysis 60 61 This change is performance neutral on JetStream 2 and Speedometer 2. 62 See results below.: 63 64 JetStream 2 (Neutral): 65 Mean of score on ToT: 139.58 (confidence interval: 2.44) 66 Mean of score on Changes: 141.46 (confidence interval: 4.24) 67 68 Speedometer run #1 69 ToT: 110 +- 2.9 70 Changes: 110 +- 1.8 71 72 Speedometer run #2 73 ToT: 110 +- 1.6 74 Changes: 108 +- 2.3 75 76 Speedometer run #3 77 ToT: 110 +- 3.0 78 Changes: 110 +- 1.4 79 80 * jit/JSInterfaceJIT.h: 81 (JSC::JSInterfaceJIT::JSInterfaceJIT): 82 * llint/LLIntEntrypoint.cpp: 83 84 Here we are changing the usage or DirectJITCode by NativeJITCode on cases 85 where there is no difference from address of calls with and without 86 ArithCheck. 87 88 (JSC::LLInt::setFunctionEntrypoint): 89 (JSC::LLInt::setEvalEntrypoint): 90 (JSC::LLInt::setProgramEntrypoint): 91 (JSC::LLInt::setModuleProgramEntrypoint): 92 (JSC::LLInt::setEntrypoint): 93 * llint/LLIntEntrypoint.h: 94 * llint/LLIntThunks.cpp: 95 (JSC::LLInt::generateThunkWithJumpTo): 96 (JSC::LLInt::functionForCallEntryThunk): 97 (JSC::LLInt::functionForConstructEntryThunk): 98 (JSC::LLInt::functionForCallArityCheckThunk): 99 (JSC::LLInt::functionForConstructArityCheckThunk): 100 (JSC::LLInt::evalEntryThunk): 101 (JSC::LLInt::programEntryThunk): 102 (JSC::LLInt::moduleProgramEntryThunk): 103 (JSC::LLInt::functionForCallEntryThunkGenerator): Deleted. 104 (JSC::LLInt::functionForConstructEntryThunkGenerator): Deleted. 105 (JSC::LLInt::functionForCallArityCheckThunkGenerator): Deleted. 106 (JSC::LLInt::functionForConstructArityCheckThunkGenerator): Deleted. 107 (JSC::LLInt::evalEntryThunkGenerator): Deleted. 108 (JSC::LLInt::programEntryThunkGenerator): Deleted. 109 (JSC::LLInt::moduleProgramEntryThunkGenerator): Deleted. 110 * llint/LLIntThunks.h: 111 * runtime/ScriptExecutable.cpp: 112 (JSC::setupLLInt): 113 (JSC::ScriptExecutable::prepareForExecutionImpl): 114 1 115 2019-03-18 Yusuke Suzuki <ysuzuki@apple.com> 2 116 -
trunk/Source/JavaScriptCore/jit/JSInterfaceJIT.h
r232105 r243136 39 39 class JSInterfaceJIT : public CCallHelpers, public GPRInfo, public FPRInfo { 40 40 public: 41 JSInterfaceJIT(VM* vm, CodeBlock* codeBlock = 0) 41 42 JSInterfaceJIT(VM* vm = nullptr, CodeBlock* codeBlock = nullptr) 42 43 : CCallHelpers(codeBlock) 43 44 , m_vm(vm) -
trunk/Source/JavaScriptCore/llint/LLIntEntrypoint.cpp
r242928 r243136 39 39 namespace JSC { namespace LLInt { 40 40 41 static void setFunctionEntrypoint( VM& vm,CodeBlock* codeBlock)41 static void setFunctionEntrypoint(CodeBlock* codeBlock) 42 42 { 43 43 CodeSpecializationKind kind = codeBlock->specializationKind(); … … 46 46 if (VM::canUseJIT()) { 47 47 if (kind == CodeForCall) { 48 codeBlock->setJITCode( 49 adoptRef(*new DirectJITCode(vm.getCTIStub(functionForCallEntryThunkGenerator).retagged<JSEntryPtrTag>(), vm.getCTIStub(functionForCallArityCheckThunkGenerator).retaggedCode<JSEntryPtrTag>(), JITCode::InterpreterThunk))); 48 static DirectJITCode* jitCode; 49 static std::once_flag onceKey; 50 std::call_once(onceKey, [&] { 51 auto callRef = functionForCallEntryThunk().retagged<JSEntryPtrTag>(); 52 auto callArityCheckRef = functionForCallArityCheckThunk().retaggedCode<JSEntryPtrTag>(); 53 jitCode = new DirectJITCode(callRef, callArityCheckRef, JITCode::InterpreterThunk, JITCode::ShareAttribute::Shared); 54 }); 55 56 codeBlock->setJITCode(makeRef(*jitCode)); 50 57 return; 51 58 } 52 59 ASSERT(kind == CodeForConstruct); 53 codeBlock->setJITCode( 54 adoptRef(*new DirectJITCode(vm.getCTIStub(functionForConstructEntryThunkGenerator).retagged<JSEntryPtrTag>(), vm.getCTIStub(functionForConstructArityCheckThunkGenerator).retaggedCode<JSEntryPtrTag>(), JITCode::InterpreterThunk))); 60 61 static DirectJITCode* jitCode; 62 static std::once_flag onceKey; 63 std::call_once(onceKey, [&] { 64 auto constructRef = functionForConstructEntryThunk().retagged<JSEntryPtrTag>(); 65 auto constructArityCheckRef = functionForConstructArityCheckThunk().retaggedCode<JSEntryPtrTag>(); 66 jitCode = new DirectJITCode(constructRef, constructArityCheckRef, JITCode::InterpreterThunk, JITCode::ShareAttribute::Shared); 67 }); 68 69 codeBlock->setJITCode(makeRef(*jitCode)); 55 70 return; 56 71 } 57 72 #endif // ENABLE(JIT) 58 73 59 UNUSED_PARAM(vm);60 74 if (kind == CodeForCall) { 61 75 static DirectJITCode* jitCode; … … 75 89 } 76 90 77 static void setEvalEntrypoint( VM& vm,CodeBlock* codeBlock)91 static void setEvalEntrypoint(CodeBlock* codeBlock) 78 92 { 79 93 #if ENABLE(JIT) 80 94 if (VM::canUseJIT()) { 81 MacroAssemblerCodeRef<JSEntryPtrTag> codeRef = vm.getCTIStub(evalEntryThunkGenerator).retagged<JSEntryPtrTag>(); 82 codeBlock->setJITCode( 83 adoptRef(*new DirectJITCode(codeRef, codeRef.code(), JITCode::InterpreterThunk))); 95 static NativeJITCode* jitCode; 96 static std::once_flag onceKey; 97 std::call_once(onceKey, [&] { 98 MacroAssemblerCodeRef<JSEntryPtrTag> codeRef = evalEntryThunk().retagged<JSEntryPtrTag>(); 99 jitCode = new NativeJITCode(codeRef, JITCode::InterpreterThunk, Intrinsic::NoIntrinsic, JITCode::ShareAttribute::Shared); 100 }); 101 codeBlock->setJITCode(makeRef(*jitCode)); 84 102 return; 85 103 } 86 104 #endif // ENABLE(JIT) 87 105 88 UNUSED_PARAM(vm);89 106 static NativeJITCode* jitCode; 90 107 static std::once_flag onceKey; … … 95 112 } 96 113 97 static void setProgramEntrypoint( VM& vm,CodeBlock* codeBlock)114 static void setProgramEntrypoint(CodeBlock* codeBlock) 98 115 { 99 116 #if ENABLE(JIT) 100 117 if (VM::canUseJIT()) { 101 MacroAssemblerCodeRef<JSEntryPtrTag> codeRef = vm.getCTIStub(programEntryThunkGenerator).retagged<JSEntryPtrTag>(); 102 codeBlock->setJITCode( 103 adoptRef(*new DirectJITCode(codeRef, codeRef.code(), JITCode::InterpreterThunk))); 118 static NativeJITCode* jitCode; 119 static std::once_flag onceKey; 120 std::call_once(onceKey, [&] { 121 MacroAssemblerCodeRef<JSEntryPtrTag> codeRef = programEntryThunk().retagged<JSEntryPtrTag>(); 122 jitCode = new NativeJITCode(codeRef, JITCode::InterpreterThunk, Intrinsic::NoIntrinsic, JITCode::ShareAttribute::Shared); 123 }); 124 codeBlock->setJITCode(makeRef(*jitCode)); 104 125 return; 105 126 } 106 127 #endif // ENABLE(JIT) 107 128 108 UNUSED_PARAM(vm);109 129 static NativeJITCode* jitCode; 110 130 static std::once_flag onceKey; … … 115 135 } 116 136 117 static void setModuleProgramEntrypoint( VM& vm,CodeBlock* codeBlock)137 static void setModuleProgramEntrypoint(CodeBlock* codeBlock) 118 138 { 119 139 #if ENABLE(JIT) 120 140 if (VM::canUseJIT()) { 121 MacroAssemblerCodeRef<JSEntryPtrTag> codeRef = vm.getCTIStub(moduleProgramEntryThunkGenerator).retagged<JSEntryPtrTag>(); 122 codeBlock->setJITCode( 123 adoptRef(*new DirectJITCode(codeRef, codeRef.code(), JITCode::InterpreterThunk))); 141 static NativeJITCode* jitCode; 142 static std::once_flag onceKey; 143 std::call_once(onceKey, [&] { 144 MacroAssemblerCodeRef<JSEntryPtrTag> codeRef = moduleProgramEntryThunk().retagged<JSEntryPtrTag>(); 145 jitCode = new NativeJITCode(codeRef, JITCode::InterpreterThunk, Intrinsic::NoIntrinsic, JITCode::ShareAttribute::Shared); 146 }); 147 codeBlock->setJITCode(makeRef(*jitCode)); 124 148 return; 125 149 } 126 150 #endif // ENABLE(JIT) 127 151 128 UNUSED_PARAM(vm);129 152 static NativeJITCode* jitCode; 130 153 static std::once_flag onceKey; … … 135 158 } 136 159 137 void setEntrypoint( VM& vm,CodeBlock* codeBlock)160 void setEntrypoint(CodeBlock* codeBlock) 138 161 { 139 162 switch (codeBlock->codeType()) { 140 163 case GlobalCode: 141 setProgramEntrypoint( vm,codeBlock);164 setProgramEntrypoint(codeBlock); 142 165 return; 143 166 case ModuleCode: 144 setModuleProgramEntrypoint( vm,codeBlock);167 setModuleProgramEntrypoint(codeBlock); 145 168 return; 146 169 case EvalCode: 147 setEvalEntrypoint( vm,codeBlock);170 setEvalEntrypoint(codeBlock); 148 171 return; 149 172 case FunctionCode: 150 setFunctionEntrypoint( vm,codeBlock);173 setFunctionEntrypoint(codeBlock); 151 174 return; 152 175 } -
trunk/Source/JavaScriptCore/llint/LLIntEntrypoint.h
r218794 r243136 34 34 namespace LLInt { 35 35 36 void setEntrypoint( VM&,CodeBlock*);36 void setEntrypoint(CodeBlock*); 37 37 38 38 unsigned frameRegisterCountFor(CodeBlock*); -
trunk/Source/JavaScriptCore/llint/LLIntThunks.cpp
r236381 r243136 40 40 #include "StackAlignment.h" 41 41 #include "VM.h" 42 #include <wtf/NeverDestroyed.h> 42 43 43 44 namespace JSC { … … 47 48 namespace LLInt { 48 49 49 static MacroAssemblerCodeRef<JITThunkPtrTag> generateThunkWithJumpTo(VM* vm, OpcodeID opcodeID, const char *thunkKind) 50 // These thunks are necessary because of nearCall used on JITed code. 51 // It requires that the distance from nearCall address to the destination address 52 // fits on 32-bits, and that's not the case of getCodeRef(llint_function_for_call_prologue) 53 // and others LLIntEntrypoints. 54 55 static MacroAssemblerCodeRef<JITThunkPtrTag> generateThunkWithJumpTo(OpcodeID opcodeID, const char *thunkKind) 50 56 { 51 JSInterfaceJIT jit (vm);57 JSInterfaceJIT jit; 52 58 53 59 // FIXME: there's probably a better way to do it on X86, but I'm not sure I care. … … 62 68 } 63 69 64 MacroAssemblerCodeRef<JITThunkPtrTag> functionForCallEntryThunk Generator(VM* vm)70 MacroAssemblerCodeRef<JITThunkPtrTag> functionForCallEntryThunk() 65 71 { 66 return generateThunkWithJumpTo(vm, llint_function_for_call_prologue, "function for call"); 72 static LazyNeverDestroyed<MacroAssemblerCodeRef<JITThunkPtrTag>> codeRef; 73 static std::once_flag onceKey; 74 std::call_once(onceKey, [&] { 75 codeRef.construct(generateThunkWithJumpTo(llint_function_for_call_prologue, "function for call")); 76 }); 77 return codeRef; 67 78 } 68 79 69 MacroAssemblerCodeRef<JITThunkPtrTag> functionForConstructEntryThunk Generator(VM* vm)80 MacroAssemblerCodeRef<JITThunkPtrTag> functionForConstructEntryThunk() 70 81 { 71 return generateThunkWithJumpTo(vm, llint_function_for_construct_prologue, "function for construct"); 82 static LazyNeverDestroyed<MacroAssemblerCodeRef<JITThunkPtrTag>> codeRef; 83 static std::once_flag onceKey; 84 std::call_once(onceKey, [&] { 85 codeRef.construct(generateThunkWithJumpTo(llint_function_for_construct_prologue, "function for construct")); 86 }); 87 return codeRef; 72 88 } 73 89 74 MacroAssemblerCodeRef<JITThunkPtrTag> functionForCallArityCheckThunk Generator(VM* vm)90 MacroAssemblerCodeRef<JITThunkPtrTag> functionForCallArityCheckThunk() 75 91 { 76 return generateThunkWithJumpTo(vm, llint_function_for_call_arity_check, "function for call with arity check"); 92 static LazyNeverDestroyed<MacroAssemblerCodeRef<JITThunkPtrTag>> codeRef; 93 static std::once_flag onceKey; 94 std::call_once(onceKey, [&] { 95 codeRef.construct(generateThunkWithJumpTo(llint_function_for_call_arity_check, "function for call with arity check")); 96 }); 97 return codeRef; 77 98 } 78 99 79 MacroAssemblerCodeRef<JITThunkPtrTag> functionForConstructArityCheckThunk Generator(VM* vm)100 MacroAssemblerCodeRef<JITThunkPtrTag> functionForConstructArityCheckThunk() 80 101 { 81 return generateThunkWithJumpTo(vm, llint_function_for_construct_arity_check, "function for construct with arity check"); 102 static LazyNeverDestroyed<MacroAssemblerCodeRef<JITThunkPtrTag>> codeRef; 103 static std::once_flag onceKey; 104 std::call_once(onceKey, [&] { 105 codeRef.construct(generateThunkWithJumpTo(llint_function_for_construct_arity_check, "function for construct with arity check")); 106 }); 107 return codeRef; 82 108 } 83 109 84 MacroAssemblerCodeRef<JITThunkPtrTag> evalEntryThunk Generator(VM* vm)110 MacroAssemblerCodeRef<JITThunkPtrTag> evalEntryThunk() 85 111 { 86 return generateThunkWithJumpTo(vm, llint_eval_prologue, "eval"); 112 static LazyNeverDestroyed<MacroAssemblerCodeRef<JITThunkPtrTag>> codeRef; 113 static std::once_flag onceKey; 114 std::call_once(onceKey, [&] { 115 codeRef.construct(generateThunkWithJumpTo(llint_eval_prologue, "eval")); 116 }); 117 return codeRef; 87 118 } 88 119 89 MacroAssemblerCodeRef<JITThunkPtrTag> programEntryThunk Generator(VM* vm)120 MacroAssemblerCodeRef<JITThunkPtrTag> programEntryThunk() 90 121 { 91 return generateThunkWithJumpTo(vm, llint_program_prologue, "program"); 122 static LazyNeverDestroyed<MacroAssemblerCodeRef<JITThunkPtrTag>> codeRef; 123 static std::once_flag onceKey; 124 std::call_once(onceKey, [&] { 125 codeRef.construct(generateThunkWithJumpTo(llint_program_prologue, "program")); 126 }); 127 return codeRef; 92 128 } 93 129 94 MacroAssemblerCodeRef<JITThunkPtrTag> moduleProgramEntryThunk Generator(VM* vm)130 MacroAssemblerCodeRef<JITThunkPtrTag> moduleProgramEntryThunk() 95 131 { 96 return generateThunkWithJumpTo(vm, llint_module_program_prologue, "module_program"); 132 static LazyNeverDestroyed<MacroAssemblerCodeRef<JITThunkPtrTag>> codeRef; 133 static std::once_flag onceKey; 134 std::call_once(onceKey, [&] { 135 codeRef.construct(generateThunkWithJumpTo(llint_module_program_prologue, "module_program")); 136 }); 137 return codeRef; 97 138 } 98 139 -
trunk/Source/JavaScriptCore/llint/LLIntThunks.h
r235785 r243136 47 47 namespace LLInt { 48 48 49 MacroAssemblerCodeRef<JITThunkPtrTag> functionForCallEntryThunk Generator(VM*);50 MacroAssemblerCodeRef<JITThunkPtrTag> functionForConstructEntryThunk Generator(VM*);51 MacroAssemblerCodeRef<JITThunkPtrTag> functionForCallArityCheckThunk Generator(VM*);52 MacroAssemblerCodeRef<JITThunkPtrTag> functionForConstructArityCheckThunk Generator(VM*);53 MacroAssemblerCodeRef<JITThunkPtrTag> evalEntryThunk Generator(VM*);54 MacroAssemblerCodeRef<JITThunkPtrTag> programEntryThunk Generator(VM*);55 MacroAssemblerCodeRef<JITThunkPtrTag> moduleProgramEntryThunk Generator(VM*);49 MacroAssemblerCodeRef<JITThunkPtrTag> functionForCallEntryThunk(); 50 MacroAssemblerCodeRef<JITThunkPtrTag> functionForConstructEntryThunk(); 51 MacroAssemblerCodeRef<JITThunkPtrTag> functionForCallArityCheckThunk(); 52 MacroAssemblerCodeRef<JITThunkPtrTag> functionForConstructArityCheckThunk(); 53 MacroAssemblerCodeRef<JITThunkPtrTag> evalEntryThunk(); 54 MacroAssemblerCodeRef<JITThunkPtrTag> programEntryThunk(); 55 MacroAssemblerCodeRef<JITThunkPtrTag> moduleProgramEntryThunk(); 56 56 57 57 } } // namespace JSC::LLInt -
trunk/Source/JavaScriptCore/runtime/ScriptExecutable.cpp
r242596 r243136 386 386 } 387 387 388 static void setupLLInt( VM& vm,CodeBlock* codeBlock)389 { 390 LLInt::setEntrypoint( vm,codeBlock);388 static void setupLLInt(CodeBlock* codeBlock) 389 { 390 LLInt::setEntrypoint(codeBlock); 391 391 } 392 392 … … 425 425 426 426 if (Options::useLLInt()) 427 setupLLInt( vm,codeBlock);427 setupLLInt(codeBlock); 428 428 else 429 429 setupJIT(vm, codeBlock);
Note: See TracChangeset
for help on using the changeset viewer.