Changeset 122392 in webkit
- Timestamp:
- Jul 11, 2012 5:12:03 PM (12 years ago)
- Location:
- trunk
- Files:
-
- 21 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r122386 r122392 1 2012-07-11 Filip Pizlo <fpizlo@apple.com> 2 3 DFG should have fast virtual calls 4 https://bugs.webkit.org/show_bug.cgi?id=90924 5 6 Rubber stamped by Oliver Hunt. 7 8 This changes which piece of code appears on top of the stack at the point of a stack 9 overflow. As far as Oliver and I can tell, it doesn't matter, so I just rebased the 10 test. 11 12 * fast/js/stack-trace-expected.txt: 13 1 14 2012-07-11 Adam Barth <abarth@webkit.org> 2 15 -
trunk/LayoutTests/fast/js/stack-trace-expected.txt
r115861 r122392 152 152 153 153 --> Stack Trace: 154 0 selfRecursive2 at stack-trace.js: 58154 0 selfRecursive2 at stack-trace.js:62 155 155 1 selfRecursive2 at stack-trace.js:62 156 156 2 selfRecursive2 at stack-trace.js:62 -
trunk/Source/JavaScriptCore/ChangeLog
r122388 r122392 1 2012-07-11 Filip Pizlo <fpizlo@apple.com> 2 3 DFG should have fast virtual calls 4 https://bugs.webkit.org/show_bug.cgi?id=90924 5 6 Reviewed by Gavin Barraclough. 7 8 Implements virtual call support in the style of the old JIT, with the 9 caveat that we still use the same slow path for both InternalFunction 10 calls and JSFunction calls. Also rationalized the way that our 11 CodeOrigin indices tie into exception checks (previously it was a 12 strange one-to-one mapping with fairly limited assertions; now it's a 13 one-to-many mapping for CodeOrigins to exception checks, respectively). 14 I also took the opportunity to clean up 15 CallLinkInfo::callReturnLocation, which previously was either a Call or 16 a NearCall. Now it's just a NearCall. As well, exceptions during slow 17 path call resolution are now handled by returning an exception throwing 18 thunk rather than returning null. And finally, I made a few things 19 public that were previously private-with-lots-of-friends, because I 20 truly despise the thought of listing each thunk generating function as 21 a friend of JSValue and friends. 22 23 * bytecode/CallLinkInfo.cpp: 24 (JSC::CallLinkInfo::unlink): 25 * bytecode/CallLinkInfo.h: 26 (CallLinkInfo): 27 * bytecode/CodeOrigin.h: 28 (JSC::CodeOrigin::CodeOrigin): 29 (JSC::CodeOrigin::isSet): 30 * dfg/DFGAssemblyHelpers.h: 31 (JSC::DFG::AssemblyHelpers::AssemblyHelpers): 32 * dfg/DFGCCallHelpers.h: 33 (JSC::DFG::CCallHelpers::CCallHelpers): 34 * dfg/DFGGPRInfo.h: 35 (GPRInfo): 36 * dfg/DFGJITCompiler.cpp: 37 (JSC::DFG::JITCompiler::link): 38 (JSC::DFG::JITCompiler::compileFunction): 39 * dfg/DFGJITCompiler.h: 40 (JSC::DFG::CallBeginToken::CallBeginToken): 41 (JSC::DFG::CallBeginToken::~CallBeginToken): 42 (CallBeginToken): 43 (JSC::DFG::CallBeginToken::set): 44 (JSC::DFG::CallBeginToken::registerWithExceptionCheck): 45 (JSC::DFG::CallBeginToken::codeOrigin): 46 (JSC::DFG::CallExceptionRecord::CallExceptionRecord): 47 (CallExceptionRecord): 48 (JSC::DFG::JITCompiler::currentCodeOriginIndex): 49 (JITCompiler): 50 (JSC::DFG::JITCompiler::beginCall): 51 (JSC::DFG::JITCompiler::notifyCall): 52 (JSC::DFG::JITCompiler::prepareForExceptionCheck): 53 (JSC::DFG::JITCompiler::addExceptionCheck): 54 (JSC::DFG::JITCompiler::addFastExceptionCheck): 55 * dfg/DFGOperations.cpp: 56 * dfg/DFGRepatch.cpp: 57 (JSC::DFG::dfgLinkFor): 58 * dfg/DFGSpeculativeJIT.h: 59 (JSC::DFG::SpeculativeJIT::appendCallWithExceptionCheck): 60 * dfg/DFGSpeculativeJIT32_64.cpp: 61 (JSC::DFG::SpeculativeJIT::emitCall): 62 * dfg/DFGSpeculativeJIT64.cpp: 63 (JSC::DFG::SpeculativeJIT::emitCall): 64 * dfg/DFGThunks.cpp: 65 (JSC::DFG::emitPointerValidation): 66 (DFG): 67 (JSC::DFG::throwExceptionFromCallSlowPathGenerator): 68 (JSC::DFG::slowPathFor): 69 (JSC::DFG::linkForThunkGenerator): 70 (JSC::DFG::linkCallThunkGenerator): 71 (JSC::DFG::linkConstructThunkGenerator): 72 (JSC::DFG::virtualForThunkGenerator): 73 (JSC::DFG::virtualCallThunkGenerator): 74 (JSC::DFG::virtualConstructThunkGenerator): 75 * dfg/DFGThunks.h: 76 (DFG): 77 * jit/JIT.cpp: 78 (JSC::JIT::privateCompile): 79 (JSC::JIT::linkFor): 80 * runtime/Executable.h: 81 (ExecutableBase): 82 (JSC::ExecutableBase::offsetOfJITCodeFor): 83 (JSC::ExecutableBase::offsetOfNumParametersFor): 84 * runtime/JSValue.h: 85 (JSValue): 86 1 87 2012-07-11 Filip Pizlo <fpizlo@apple.com> 2 88 -
trunk/Source/JavaScriptCore/bytecode/CallLinkInfo.cpp
r104646 r122392 28 28 29 29 #include "DFGOperations.h" 30 #include "DFGThunks.h" 30 31 #include "RepatchBuffer.h" 31 32 … … 39 40 if (isDFG) { 40 41 #if ENABLE(DFG_JIT) 41 repatchBuffer.relink( CodeLocationCall(callReturnLocation), callType == Construct ? DFG::operationLinkConstruct : DFG::operationLinkCall);42 repatchBuffer.relink(callReturnLocation, (callType == Construct ? globalData.getCTIStub(DFG::linkConstructThunkGenerator) : globalData.getCTIStub(DFG::linkCallThunkGenerator)).code()); 42 43 #else 43 44 ASSERT_NOT_REACHED(); 44 45 #endif 45 46 } else 46 repatchBuffer.relink( CodeLocationNearCall(callReturnLocation), callType == Construct ? globalData.jitStubs->ctiVirtualConstructLink() : globalData.jitStubs->ctiVirtualCallLink());47 repatchBuffer.relink(callReturnLocation, callType == Construct ? globalData.jitStubs->ctiVirtualConstructLink() : globalData.jitStubs->ctiVirtualCallLink()); 47 48 hasSeenShouldRepatch = false; 48 49 callee.clear(); -
trunk/Source/JavaScriptCore/bytecode/CallLinkInfo.h
r106075 r122392 66 66 } 67 67 68 CodeLocation Label callReturnLocation; // it's a near call in the old JIT, or a normal call in DFG68 CodeLocationNearCall callReturnLocation; 69 69 CodeLocationDataLabelPtr hotPathBegin; 70 70 CodeLocationNearCall hotPathOther; -
trunk/Source/JavaScriptCore/bytecode/CodeOrigin.h
r118136 r122392 40 40 41 41 struct CodeOrigin { 42 static const unsigned maximumBytecodeIndex = (1u << 29) - 1; 43 42 44 // Bytecode offset that you'd use to re-execute this instruction. 43 45 unsigned bytecodeIndex : 29; … … 49 51 50 52 CodeOrigin() 51 : bytecodeIndex( std::numeric_limits<uint32_t>::max())53 : bytecodeIndex(maximumBytecodeIndex) 52 54 , valueProfileOffset(0) 53 55 , inlineCallFrame(0) … … 60 62 , inlineCallFrame(inlineCallFrame) 61 63 { 62 ASSERT(bytecodeIndex < (1u << 29));64 ASSERT(bytecodeIndex <= maximumBytecodeIndex); 63 65 ASSERT(valueProfileOffset < (1u << 3)); 64 66 } 65 67 66 bool isSet() const { return bytecodeIndex != std::numeric_limits<uint32_t>::max(); }68 bool isSet() const { return bytecodeIndex != maximumBytecodeIndex; } 67 69 68 70 unsigned bytecodeIndexForValueProfile() const -
trunk/Source/JavaScriptCore/dfg/DFGAssemblyHelpers.h
r121885 r122392 47 47 : m_globalData(globalData) 48 48 , m_codeBlock(codeBlock) 49 , m_baselineCodeBlock(codeBlock->baselineVersion()) 50 { 51 ASSERT(m_codeBlock); 52 ASSERT(m_baselineCodeBlock); 53 ASSERT(!m_baselineCodeBlock->alternative()); 54 ASSERT(m_baselineCodeBlock->getJITType() == JITCode::BaselineJIT); 49 , m_baselineCodeBlock(codeBlock ? codeBlock->baselineVersion() : 0) 50 { 51 if (m_codeBlock) { 52 ASSERT(m_baselineCodeBlock); 53 ASSERT(!m_baselineCodeBlock->alternative()); 54 ASSERT(m_baselineCodeBlock->getJITType() == JITCode::BaselineJIT); 55 } 55 56 } 56 57 -
trunk/Source/JavaScriptCore/dfg/DFGCCallHelpers.h
r121885 r122392 38 38 class CCallHelpers : public AssemblyHelpers { 39 39 public: 40 CCallHelpers(JSGlobalData* globalData, CodeBlock* codeBlock )40 CCallHelpers(JSGlobalData* globalData, CodeBlock* codeBlock = 0) 41 41 : AssemblyHelpers(globalData, codeBlock) 42 42 { -
trunk/Source/JavaScriptCore/dfg/DFGGPRInfo.h
r121885 r122392 274 274 static const GPRReg nonArgGPR0 = X86Registers::eax; // regT0 275 275 static const GPRReg nonArgGPR1 = X86Registers::ebx; // regT3 276 static const GPRReg nonArgGPR2 = X86Registers::esi; // regT4 276 277 static const GPRReg returnValueGPR = X86Registers::eax; // regT0 277 278 static const GPRReg returnValueGPR2 = X86Registers::edx; // regT1 … … 345 346 static const GPRReg nonArgGPR0 = X86Registers::eax; // regT0 346 347 static const GPRReg nonArgGPR1 = X86Registers::ebx; // regT3 348 static const GPRReg nonArgGPR2 = X86Registers::r10; // regT8 347 349 static const GPRReg returnValueGPR = X86Registers::eax; // regT0 348 350 static const GPRReg returnValueGPR2 = X86Registers::edx; // regT1 … … 417 419 static const GPRReg nonArgGPR0 = ARMRegisters::r4; // regT3 418 420 static const GPRReg nonArgGPR1 = ARMRegisters::r8; // regT4 421 static const GPRReg nonArgGPR2 = ARMRegisters::r9; // regT5 419 422 static const GPRReg returnValueGPR = ARMRegisters::r0; // regT0 420 423 static const GPRReg returnValueGPR2 = ARMRegisters::r1; // regT1 -
trunk/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp
r122206 r122392 154 154 codeOrigins[i].codeOrigin = record.m_codeOrigin; 155 155 codeOrigins[i].callReturnOffset = returnAddressOffset; 156 record.m_token.assertCodeOriginIndex(i);157 156 } 158 157 … … 190 189 info.callType = m_jsCalls[i].m_callType; 191 190 info.isDFG = true; 192 info.callReturnLocation = CodeLocationLabel(linkBuffer.locationOf(m_jsCalls[i].m_slowCall)); 191 linkBuffer.link(m_jsCalls[i].m_slowCall, FunctionPtr((m_globalData->getCTIStub(info.callType == CallLinkInfo::Construct ? linkConstructThunkGenerator : linkCallThunkGenerator)).code().executableAddress())); 192 info.callReturnLocation = linkBuffer.locationOfNearCall(m_jsCalls[i].m_slowCall); 193 193 info.hotPathBegin = linkBuffer.locationOf(m_jsCalls[i].m_targetToCheck); 194 194 info.hotPathOther = linkBuffer.locationOfNearCall(m_jsCalls[i].m_fastCall); … … 281 281 poke(GPRInfo::callFrameRegister, OBJECT_OFFSETOF(struct JITStackFrame, callFrame) / sizeof(void*)); 282 282 283 CallBeginToken token = beginCall(); 283 CallBeginToken token; 284 beginCall(CodeOrigin(0), token); 284 285 Call callRegisterFileCheck = call(); 285 286 notifyCall(callRegisterFileCheck, CodeOrigin(0), token); … … 298 299 move(stackPointerRegister, GPRInfo::argumentGPR0); 299 300 poke(GPRInfo::callFrameRegister, OBJECT_OFFSETOF(struct JITStackFrame, callFrame) / sizeof(void*)); 300 token = beginCall();301 beginCall(CodeOrigin(0), token); 301 302 Call callArityCheck = call(); 302 303 notifyCall(callArityCheck, CodeOrigin(0), token); -
trunk/Source/JavaScriptCore/dfg/DFGJITCompiler.h
r121925 r122392 77 77 CallBeginToken() 78 78 #if !ASSERT_DISABLED 79 : m_codeOriginIndex(UINT_MAX) 80 #endif 81 { 82 } 83 84 explicit CallBeginToken(unsigned codeOriginIndex) 79 : m_registered(false) 80 , m_exceptionCheckIndex(std::numeric_limits<unsigned>::max()) 81 #endif 82 { 83 } 84 85 ~CallBeginToken() 86 { 87 ASSERT(m_registered || !m_codeOrigin.isSet()); 88 ASSERT(m_codeOrigin.isSet() == (m_exceptionCheckIndex != std::numeric_limits<unsigned>::max())); 89 } 90 91 void set(CodeOrigin codeOrigin, unsigned index) 92 { 85 93 #if !ASSERT_DISABLED 86 : m_codeOriginIndex(codeOriginIndex) 87 #endif 88 { 89 UNUSED_PARAM(codeOriginIndex); 90 } 91 92 void assertCodeOriginIndex(unsigned codeOriginIndex) const 93 { 94 ASSERT_UNUSED(codeOriginIndex, codeOriginIndex < UINT_MAX); 95 ASSERT_UNUSED(codeOriginIndex, codeOriginIndex == m_codeOriginIndex); 96 } 97 94 ASSERT(m_registered || !m_codeOrigin.isSet()); 95 ASSERT(m_codeOrigin.isSet() == (m_exceptionCheckIndex != std::numeric_limits<unsigned>::max())); 96 m_codeOrigin = codeOrigin; 97 m_registered = false; 98 m_exceptionCheckIndex = index; 99 #else 100 UNUSED_PARAM(codeOrigin); 101 UNUSED_PARAM(index); 102 #endif 103 } 104 105 void registerWithExceptionCheck(CodeOrigin codeOrigin, unsigned index) 106 { 107 #if !ASSERT_DISABLED 108 ASSERT(m_codeOrigin == codeOrigin); 109 if (m_registered) 110 return; 111 ASSERT(m_exceptionCheckIndex == index); 112 m_registered = true; 113 #else 114 UNUSED_PARAM(codeOrigin); 115 UNUSED_PARAM(index); 116 #endif 117 } 118 119 #if !ASSERT_DISABLED 120 const CodeOrigin& codeOrigin() const 121 { 122 return m_codeOrigin; 123 } 124 #endif 125 98 126 private: 99 127 #if !ASSERT_DISABLED 100 unsigned m_codeOriginIndex; 128 CodeOrigin m_codeOrigin; 129 bool m_registered; 130 unsigned m_exceptionCheckIndex; 101 131 #endif 102 132 }; … … 108 138 // (unset if not present) and code origin used to recover handler/source info. 109 139 struct CallExceptionRecord { 110 CallExceptionRecord(MacroAssembler::Call call, CodeOrigin codeOrigin , CallBeginToken token)140 CallExceptionRecord(MacroAssembler::Call call, CodeOrigin codeOrigin) 111 141 : m_call(call) 112 142 , m_codeOrigin(codeOrigin) 113 , m_token(token) 114 { 115 } 116 117 CallExceptionRecord(MacroAssembler::Call call, MacroAssembler::Jump exceptionCheck, CodeOrigin codeOrigin, CallBeginToken token) 143 { 144 } 145 146 CallExceptionRecord(MacroAssembler::Call call, MacroAssembler::Jump exceptionCheck, CodeOrigin codeOrigin) 118 147 : m_call(call) 119 148 , m_exceptionCheck(exceptionCheck) 120 149 , m_codeOrigin(codeOrigin) 121 , m_token(token)122 150 { 123 151 } … … 126 154 MacroAssembler::Jump m_exceptionCheck; 127 155 CodeOrigin m_codeOrigin; 128 CallBeginToken m_token;129 156 }; 130 157 … … 258 285 } 259 286 287 unsigned currentCodeOriginIndex() const 288 { 289 return m_currentCodeOriginIndex; 290 } 291 260 292 // Get a token for beginning a call, and set the current code origin index in 261 // the call frame. 262 CallBeginToken beginCall() 263 { 264 unsigned codeOriginIndex = m_currentCodeOriginIndex++; 265 store32(TrustedImm32(codeOriginIndex), tagFor(static_cast<VirtualRegister>(RegisterFile::ArgumentCount))); 266 return CallBeginToken(codeOriginIndex); 293 // the call frame. For each beginCall() there must be at least one exception 294 // check, and all of the exception checks must have the same CodeOrigin as the 295 // beginCall(). 296 void beginCall(CodeOrigin codeOrigin, CallBeginToken& token) 297 { 298 unsigned index = m_exceptionChecks.size(); 299 store32(TrustedImm32(index), tagFor(static_cast<VirtualRegister>(RegisterFile::ArgumentCount))); 300 token.set(codeOrigin, index); 267 301 } 268 302 269 303 // Notify the JIT of a call that does not require linking. 270 void notifyCall(Call functionCall, CodeOrigin codeOrigin, CallBeginToken token) 271 { 272 m_exceptionChecks.append(CallExceptionRecord(functionCall, codeOrigin, token)); 304 void notifyCall(Call functionCall, CodeOrigin codeOrigin, CallBeginToken& token) 305 { 306 token.registerWithExceptionCheck(codeOrigin, m_exceptionChecks.size()); 307 m_exceptionChecks.append(CallExceptionRecord(functionCall, codeOrigin)); 273 308 } 274 309 … … 280 315 return functionCall; 281 316 } 317 318 void prepareForExceptionCheck() 319 { 320 move(TrustedImm32(m_exceptionChecks.size()), GPRInfo::nonPreservedNonReturnGPR); 321 } 282 322 283 323 // Add a call out from JIT code, with an exception check. 284 void addExceptionCheck(Call functionCall, CodeOrigin codeOrigin, CallBeginToken token) 285 { 286 move(TrustedImm32(m_exceptionChecks.size()), GPRInfo::nonPreservedNonReturnGPR); 287 m_exceptionChecks.append(CallExceptionRecord(functionCall, emitExceptionCheck(), codeOrigin, token)); 324 void addExceptionCheck(Call functionCall, CodeOrigin codeOrigin, CallBeginToken& token) 325 { 326 prepareForExceptionCheck(); 327 token.registerWithExceptionCheck(codeOrigin, m_exceptionChecks.size()); 328 m_exceptionChecks.append(CallExceptionRecord(functionCall, emitExceptionCheck(), codeOrigin)); 288 329 } 289 330 290 331 // Add a call out from JIT code, with a fast exception check that tests if the return value is zero. 291 void addFastExceptionCheck(Call functionCall, CodeOrigin codeOrigin, CallBeginToken token)292 { 293 move(TrustedImm32(m_exceptionChecks.size()), GPRInfo::nonPreservedNonReturnGPR);332 void addFastExceptionCheck(Call functionCall, CodeOrigin codeOrigin, CallBeginToken& token) 333 { 334 prepareForExceptionCheck(); 294 335 Jump exceptionCheck = branchTestPtr(Zero, GPRInfo::returnValueGPR); 295 m_exceptionChecks.append(CallExceptionRecord(functionCall, exceptionCheck, codeOrigin, token)); 336 token.registerWithExceptionCheck(codeOrigin, m_exceptionChecks.size()); 337 m_exceptionChecks.append(CallExceptionRecord(functionCall, exceptionCheck, codeOrigin)); 296 338 } 297 339 -
trunk/Source/JavaScriptCore/dfg/DFGOperations.cpp
r122206 r122392 31 31 #include "DFGOSRExit.h" 32 32 #include "DFGRepatch.h" 33 #include "DFGThunks.h" 33 34 #include "HostCallReturnValue.h" 34 35 #include "GetterSetter.h" … … 850 851 execCallee->setScopeChain(exec->scopeChain()); 851 852 execCallee->setCodeBlock(0); 852 execCallee->clearReturnPC();853 853 854 854 if (kind == CodeForCall) { … … 863 863 globalData->hostCallReturnValue = JSValue::decode(callData.native.function(execCallee)); 864 864 if (globalData->exception) 865 return 0;865 return globalData->getCTIStub(throwExceptionFromCallSlowPathGenerator).code().executableAddress(); 866 866 867 867 return reinterpret_cast<void*>(getHostCallReturnValue); … … 870 870 ASSERT(callType == CallTypeNone); 871 871 exec->globalData().exception = createNotAFunctionError(exec, callee); 872 return 0;872 return globalData->getCTIStub(throwExceptionFromCallSlowPathGenerator).code().executableAddress(); 873 873 } 874 874 … … 885 885 globalData->hostCallReturnValue = JSValue::decode(constructData.native.function(execCallee)); 886 886 if (globalData->exception) 887 return 0;887 return globalData->getCTIStub(throwExceptionFromCallSlowPathGenerator).code().executableAddress(); 888 888 889 889 return reinterpret_cast<void*>(getHostCallReturnValue); … … 892 892 ASSERT(constructType == ConstructTypeNone); 893 893 exec->globalData().exception = createNotAConstructorError(exec, callee); 894 return 0;895 } 896 897 inline void* linkFor(ExecState* execCallee, ReturnAddressPtr returnAddress,CodeSpecializationKind kind)894 return globalData->getCTIStub(throwExceptionFromCallSlowPathGenerator).code().executableAddress(); 895 } 896 897 inline void* linkFor(ExecState* execCallee, CodeSpecializationKind kind) 898 898 { 899 899 ExecState* exec = execCallee->callerFrame(); … … 919 919 if (error) { 920 920 globalData->exception = createStackOverflowError(exec); 921 return 0;921 return globalData->getCTIStub(throwExceptionFromCallSlowPathGenerator).code().executableAddress(); 922 922 } 923 923 codeBlock = &functionExecutable->generatedBytecodeFor(kind); … … 927 927 codePtr = functionExecutable->generatedJITCodeFor(kind).addressForCall(); 928 928 } 929 CallLinkInfo& callLinkInfo = exec->codeBlock()->getCallLinkInfo( returnAddress);929 CallLinkInfo& callLinkInfo = exec->codeBlock()->getCallLinkInfo(execCallee->returnPC()); 930 930 if (!callLinkInfo.seenOnce()) 931 931 callLinkInfo.setSeen(); … … 935 935 } 936 936 937 P_FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_E(operationLinkCall); 938 void* DFG_OPERATION operationLinkCallWithReturnAddress(ExecState* execCallee, ReturnAddressPtr returnAddress) 939 { 940 return linkFor(execCallee, returnAddress, CodeForCall); 941 } 942 943 P_FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_E(operationLinkConstruct); 944 void* DFG_OPERATION operationLinkConstructWithReturnAddress(ExecState* execCallee, ReturnAddressPtr returnAddress) 945 { 946 return linkFor(execCallee, returnAddress, CodeForConstruct); 937 void* DFG_OPERATION operationLinkCall(ExecState* execCallee) 938 { 939 return linkFor(execCallee, CodeForCall); 940 } 941 942 void* DFG_OPERATION operationLinkConstruct(ExecState* execCallee) 943 { 944 return linkFor(execCallee, CodeForConstruct); 947 945 } 948 946 … … 966 964 if (error) { 967 965 exec->globalData().exception = error; 968 return 0;966 return globalData->getCTIStub(throwExceptionFromCallSlowPathGenerator).code().executableAddress(); 969 967 } 970 968 } -
trunk/Source/JavaScriptCore/dfg/DFGRepatch.cpp
r122166 r122392 31 31 #include "DFGCCallHelpers.h" 32 32 #include "DFGSpeculativeJIT.h" 33 #include "DFGThunks.h" 33 34 #include "GCAwareJITStubRoutine.h" 34 35 #include "LinkBuffer.h" … … 917 918 { 918 919 CodeBlock* callerCodeBlock = exec->callerFrame()->codeBlock(); 920 JSGlobalData* globalData = callerCodeBlock->globalData(); 919 921 920 922 RepatchBuffer repatchBuffer(callerCodeBlock); … … 929 931 930 932 if (kind == CodeForCall) { 931 repatchBuffer.relink( CodeLocationCall(callLinkInfo.callReturnLocation), operationVirtualCall);933 repatchBuffer.relink(callLinkInfo.callReturnLocation, globalData->getCTIStub(virtualCallThunkGenerator).code()); 932 934 return; 933 935 } 934 936 ASSERT(kind == CodeForConstruct); 935 repatchBuffer.relink( CodeLocationCall(callLinkInfo.callReturnLocation), operationVirtualConstruct);937 repatchBuffer.relink(callLinkInfo.callReturnLocation, globalData->getCTIStub(virtualConstructThunkGenerator).code()); 936 938 } 937 939 -
trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
r122385 r122392 1739 1739 prepareForExternalCall(); 1740 1740 CodeOrigin codeOrigin = at(m_compileIndex).codeOrigin; 1741 CallBeginToken token = m_jit.beginCall(); 1741 CallBeginToken token; 1742 m_jit.beginCall(codeOrigin, token); 1742 1743 JITCompiler::Call call = m_jit.appendCall(function); 1743 1744 m_jit.addExceptionCheck(call, codeOrigin, token); -
trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
r121946 r122392 1008 1008 JITCompiler::JumpList slowPath; 1009 1009 1010 CallBeginToken token; 1011 m_jit.beginCall(node.codeOrigin, token); 1012 1013 m_jit.addPtr(TrustedImm32(m_jit.codeBlock()->m_numCalleeRegisters * sizeof(Register)), GPRInfo::callFrameRegister); 1014 1010 1015 slowPath.append(m_jit.branchPtrWithPatch(MacroAssembler::NotEqual, calleePayloadGPR, targetToCheck)); 1011 1016 slowPath.append(m_jit.branch32(MacroAssembler::NotEqual, calleeTagGPR, TrustedImm32(JSValue::CellTag))); 1012 1017 m_jit.loadPtr(MacroAssembler::Address(calleePayloadGPR, OBJECT_OFFSETOF(JSFunction, m_scopeChain)), resultPayloadGPR); 1013 m_jit.storePtr(resultPayloadGPR, callFramePayloadSlot(RegisterFile::ScopeChain)); 1014 m_jit.store32(MacroAssembler::TrustedImm32(JSValue::CellTag), callFrameTagSlot(RegisterFile::ScopeChain)); 1015 1016 m_jit.addPtr(TrustedImm32(m_jit.codeBlock()->m_numCalleeRegisters * sizeof(Register)), GPRInfo::callFrameRegister); 1018 m_jit.storePtr(resultPayloadGPR, MacroAssembler::Address(GPRInfo::callFrameRegister, static_cast<ptrdiff_t>(sizeof(Register)) * RegisterFile::ScopeChain + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload))); 1019 m_jit.store32(MacroAssembler::TrustedImm32(JSValue::CellTag), MacroAssembler::Address(GPRInfo::callFrameRegister, static_cast<ptrdiff_t>(sizeof(Register)) * RegisterFile::ScopeChain + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag))); 1017 1020 1018 1021 CodeOrigin codeOrigin = at(m_compileIndex).codeOrigin; 1019 CallBeginToken token = m_jit.beginCall();1020 1022 JITCompiler::Call fastCall = m_jit.nearCall(); 1021 1023 m_jit.notifyCall(fastCall, codeOrigin, token); … … 1025 1027 slowPath.link(&m_jit); 1026 1028 1027 m_jit.addPtr(TrustedImm32(m_jit.codeBlock()->m_numCalleeRegisters * sizeof(Register)), GPRInfo::callFrameRegister, GPRInfo::argumentGPR0); 1028 m_jit.poke(GPRInfo::argumentGPR0); 1029 token = m_jit.beginCall(); 1030 JITCompiler::Call slowCall = m_jit.appendCall(slowCallFunction); 1031 m_jit.addFastExceptionCheck(slowCall, codeOrigin, token); 1032 m_jit.addPtr(TrustedImm32(m_jit.codeBlock()->m_numCalleeRegisters * sizeof(Register)), GPRInfo::callFrameRegister); 1033 token = m_jit.beginCall(); 1034 JITCompiler::Call theCall = m_jit.call(GPRInfo::returnValueGPR); 1035 m_jit.notifyCall(theCall, codeOrigin, token); 1029 if (calleeTagGPR == GPRInfo::nonArgGPR0) { 1030 if (calleePayloadGPR == GPRInfo::nonArgGPR1) 1031 m_jit.swap(GPRInfo::nonArgGPR1, GPRInfo::nonArgGPR0); 1032 else { 1033 m_jit.move(calleeTagGPR, GPRInfo::nonArgGPR1); 1034 m_jit.move(calleePayloadGPR, GPRInfo::nonArgGPR0); 1035 } 1036 } else { 1037 m_jit.move(calleePayloadGPR, GPRInfo::nonArgGPR0); 1038 m_jit.move(calleeTagGPR, GPRInfo::nonArgGPR1); 1039 } 1040 m_jit.prepareForExceptionCheck(); 1041 JITCompiler::Call slowCall = m_jit.nearCall(); 1042 m_jit.notifyCall(slowCall, codeOrigin, token); 1036 1043 1037 1044 done.link(&m_jit); -
trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
r121925 r122392 999 999 JITCompiler::Jump slowPath; 1000 1000 1001 CallBeginToken token; 1002 m_jit.beginCall(node.codeOrigin, token); 1003 1004 m_jit.addPtr(TrustedImm32(m_jit.codeBlock()->m_numCalleeRegisters * sizeof(Register)), GPRInfo::callFrameRegister); 1005 1001 1006 slowPath = m_jit.branchPtrWithPatch(MacroAssembler::NotEqual, calleeGPR, targetToCheck, MacroAssembler::TrustedImmPtr(JSValue::encode(JSValue()))); 1002 1007 m_jit.loadPtr(MacroAssembler::Address(calleeGPR, OBJECT_OFFSETOF(JSFunction, m_scopeChain)), resultGPR); 1003 m_jit.storePtr(resultGPR, callFrameSlot(RegisterFile::ScopeChain)); 1004 1005 m_jit.addPtr(TrustedImm32(m_jit.codeBlock()->m_numCalleeRegisters * sizeof(Register)), GPRInfo::callFrameRegister); 1006 1008 m_jit.storePtr(resultGPR, MacroAssembler::Address(GPRInfo::callFrameRegister, static_cast<ptrdiff_t>(sizeof(Register)) * RegisterFile::ScopeChain)); 1009 1007 1010 CodeOrigin codeOrigin = at(m_compileIndex).codeOrigin; 1008 CallBeginToken token = m_jit.beginCall();1009 1011 JITCompiler::Call fastCall = m_jit.nearCall(); 1010 1012 m_jit.notifyCall(fastCall, codeOrigin, token); … … 1014 1016 slowPath.link(&m_jit); 1015 1017 1016 m_jit.addPtr(TrustedImm32(m_jit.codeBlock()->m_numCalleeRegisters * sizeof(Register)), GPRInfo::callFrameRegister, GPRInfo::argumentGPR0); 1017 token = m_jit.beginCall(); 1018 JITCompiler::Call slowCall = m_jit.appendCall(slowCallFunction); 1019 m_jit.addFastExceptionCheck(slowCall, codeOrigin, token); 1020 m_jit.addPtr(TrustedImm32(m_jit.codeBlock()->m_numCalleeRegisters * sizeof(Register)), GPRInfo::callFrameRegister); 1021 token = m_jit.beginCall(); 1022 JITCompiler::Call theCall = m_jit.call(GPRInfo::returnValueGPR); 1023 m_jit.notifyCall(theCall, codeOrigin, token); 1018 m_jit.move(calleeGPR, GPRInfo::nonArgGPR0); 1019 m_jit.prepareForExceptionCheck(); 1020 JITCompiler::Call slowCall = m_jit.nearCall(); 1021 m_jit.notifyCall(slowCall, codeOrigin, token); 1024 1022 1025 1023 done.link(&m_jit); -
trunk/Source/JavaScriptCore/dfg/DFGThunks.cpp
r120786 r122392 29 29 #if ENABLE(DFG_JIT) 30 30 31 #include "DFGCCallHelpers.h" 31 32 #include "DFGFPRInfo.h" 32 33 #include "DFGGPRInfo.h" … … 83 84 } 84 85 86 inline void emitPointerValidation(CCallHelpers& jit, GPRReg pointerGPR) 87 { 88 #if !ASSERT_DISABLED 89 CCallHelpers::Jump isNonZero = jit.branchTestPtr(CCallHelpers::NonZero, pointerGPR); 90 jit.breakpoint(); 91 isNonZero.link(&jit); 92 jit.push(pointerGPR); 93 jit.load8(pointerGPR, pointerGPR); 94 jit.pop(pointerGPR); 95 #else 96 UNUSED_PARAM(jit); 97 UNUSED_PARAM(pointerGPR); 98 #endif 99 } 100 101 MacroAssemblerCodeRef throwExceptionFromCallSlowPathGenerator(JSGlobalData* globalData) 102 { 103 CCallHelpers jit(globalData); 104 105 // We will jump to here if the JIT code thinks it's making a call, but the 106 // linking helper (C++ code) decided to throw an exception instead. We will 107 // have saved the callReturnIndex in the first arguments of JITStackFrame. 108 // Note that the return address will be on the stack at this point, so we 109 // need to remove it and drop it on the floor, since we don't care about it. 110 // Finally note that the call frame register points at the callee frame, so 111 // we need to pop it. 112 jit.preserveReturnAddressAfterCall(GPRInfo::nonPreservedNonReturnGPR); 113 jit.loadPtr( 114 CCallHelpers::Address( 115 GPRInfo::callFrameRegister, 116 static_cast<ptrdiff_t>(sizeof(Register)) * RegisterFile::CallerFrame), 117 GPRInfo::callFrameRegister); 118 jit.peek(GPRInfo::nonPreservedNonReturnGPR, JITSTACKFRAME_ARGS_INDEX); 119 jit.setupArgumentsWithExecState(GPRInfo::nonPreservedNonReturnGPR); 120 jit.move(CCallHelpers::TrustedImmPtr(bitwise_cast<void*>(lookupExceptionHandler)), GPRInfo::nonArgGPR0); 121 emitPointerValidation(jit, GPRInfo::nonArgGPR0); 122 jit.call(GPRInfo::nonArgGPR0); 123 emitPointerValidation(jit, GPRInfo::returnValueGPR2); 124 jit.jump(GPRInfo::returnValueGPR2); 125 126 LinkBuffer patchBuffer(*globalData, &jit, GLOBAL_THUNK_ID); 127 return FINALIZE_CODE(patchBuffer, ("DFG throw exception from call slow path thunk")); 128 } 129 130 static void slowPathFor( 131 CCallHelpers& jit, JSGlobalData* globalData, P_DFGOperation_E slowPathFunction) 132 { 133 jit.preserveReturnAddressAfterCall(GPRInfo::nonArgGPR2); 134 emitPointerValidation(jit, GPRInfo::nonArgGPR2); 135 jit.storePtr( 136 GPRInfo::nonArgGPR2, 137 CCallHelpers::Address( 138 GPRInfo::callFrameRegister, 139 static_cast<ptrdiff_t>(sizeof(Register)) * RegisterFile::ReturnPC)); 140 jit.storePtr(GPRInfo::callFrameRegister, &globalData->topCallFrame); 141 jit.poke(GPRInfo::nonPreservedNonReturnGPR, JITSTACKFRAME_ARGS_INDEX); 142 jit.setupArgumentsExecState(); 143 jit.move(CCallHelpers::TrustedImmPtr(bitwise_cast<void*>(slowPathFunction)), GPRInfo::nonArgGPR0); 144 emitPointerValidation(jit, GPRInfo::nonArgGPR0); 145 jit.call(GPRInfo::nonArgGPR0); 146 147 // This slow call will return the address of one of the following: 148 // 1) Exception throwing thunk. 149 // 2) Host call return value returner thingy. 150 // 3) The function to call. 151 jit.loadPtr( 152 CCallHelpers::Address( 153 GPRInfo::callFrameRegister, 154 static_cast<ptrdiff_t>(sizeof(Register)) * RegisterFile::ReturnPC), 155 GPRInfo::nonPreservedNonReturnGPR); 156 jit.storePtr( 157 CCallHelpers::TrustedImmPtr(0), 158 CCallHelpers::Address( 159 GPRInfo::callFrameRegister, 160 static_cast<ptrdiff_t>(sizeof(Register)) * RegisterFile::ReturnPC)); 161 emitPointerValidation(jit, GPRInfo::nonPreservedNonReturnGPR); 162 jit.restoreReturnAddressBeforeReturn(GPRInfo::nonPreservedNonReturnGPR); 163 emitPointerValidation(jit, GPRInfo::returnValueGPR); 164 jit.jump(GPRInfo::returnValueGPR); 165 } 166 167 static MacroAssemblerCodeRef linkForThunkGenerator( 168 JSGlobalData* globalData, CodeSpecializationKind kind) 169 { 170 // The return address is on the stack or in the link register. We will hence 171 // save the return address to the call frame while we make a C++ function call 172 // to perform linking and lazy compilation if necessary. We expect the callee 173 // to be in nonArgGPR0/nonArgGPR1 (payload/tag), the call frame to have already 174 // been adjusted, nonPreservedNonReturnGPR holds the exception handler index, 175 // and all other registers to be available for use. We use JITStackFrame::args 176 // to save important information across calls. 177 178 CCallHelpers jit(globalData); 179 180 slowPathFor(jit, globalData, kind == CodeForCall ? operationLinkCall : operationLinkConstruct); 181 182 LinkBuffer patchBuffer(*globalData, &jit, GLOBAL_THUNK_ID); 183 return FINALIZE_CODE( 184 patchBuffer, 185 ("DFG link %s slow path thunk", kind == CodeForCall ? "call" : "construct")); 186 } 187 188 MacroAssemblerCodeRef linkCallThunkGenerator(JSGlobalData* globalData) 189 { 190 return linkForThunkGenerator(globalData, CodeForCall); 191 } 192 193 MacroAssemblerCodeRef linkConstructThunkGenerator(JSGlobalData* globalData) 194 { 195 return linkForThunkGenerator(globalData, CodeForConstruct); 196 } 197 198 static MacroAssemblerCodeRef virtualForThunkGenerator( 199 JSGlobalData* globalData, CodeSpecializationKind kind) 200 { 201 // The return address is on the stack, or in the link register. We will hence 202 // jump to the callee, or save the return address to the call frame while we 203 // make a C++ function call to the appropriate DFG operation. 204 205 CCallHelpers jit(globalData); 206 207 CCallHelpers::JumpList slowCase; 208 209 // FIXME: we should have a story for eliminating these checks. In many cases, 210 // the DFG knows that the value is definitely a cell, or definitely a function. 211 212 #if USE(JSVALUE64) 213 slowCase.append( 214 jit.branchTestPtr( 215 CCallHelpers::NonZero, GPRInfo::nonArgGPR0, GPRInfo::tagMaskRegister)); 216 #else 217 slowCase.append( 218 jit.branch32( 219 CCallHelpers::NotEqual, GPRInfo::nonArgGPR1, 220 CCallHelpers::TrustedImm32(JSValue::CellTag))); 221 #endif 222 slowCase.append( 223 jit.branchPtr( 224 CCallHelpers::NotEqual, 225 CCallHelpers::Address(GPRInfo::nonArgGPR0, JSCell::classInfoOffset()), 226 CCallHelpers::TrustedImmPtr(&JSFunction::s_info))); 227 228 // Now we know we have a JSFunction. 229 230 jit.loadPtr( 231 CCallHelpers::Address(GPRInfo::nonArgGPR0, JSFunction::offsetOfExecutable()), 232 GPRInfo::nonArgGPR2); 233 slowCase.append( 234 jit.branch32( 235 CCallHelpers::LessThan, 236 CCallHelpers::Address( 237 GPRInfo::nonArgGPR2, ExecutableBase::offsetOfNumParametersFor(kind)), 238 CCallHelpers::TrustedImm32(0))); 239 240 // Now we know that we have a CodeBlock, and we're committed to making a fast 241 // call. 242 243 jit.loadPtr( 244 CCallHelpers::Address(GPRInfo::nonArgGPR0, JSFunction::offsetOfScopeChain()), 245 GPRInfo::nonArgGPR1); 246 #if USE(JSVALUE64) 247 jit.storePtr( 248 GPRInfo::nonArgGPR1, 249 CCallHelpers::Address( 250 GPRInfo::callFrameRegister, 251 static_cast<ptrdiff_t>(sizeof(Register)) * RegisterFile::ScopeChain)); 252 #else 253 jit.storePtr( 254 GPRInfo::nonArgGPR1, 255 CCallHelpers::Address( 256 GPRInfo::callFrameRegister, 257 static_cast<ptrdiff_t>(sizeof(Register)) * RegisterFile::ScopeChain + 258 OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload))); 259 jit.store32( 260 CCallHelpers::TrustedImm32(JSValue::CellTag), 261 CCallHelpers::Address( 262 GPRInfo::callFrameRegister, 263 static_cast<ptrdiff_t>(sizeof(Register)) * RegisterFile::ScopeChain + 264 OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag))); 265 #endif 266 267 jit.loadPtr( 268 CCallHelpers::Address(GPRInfo::nonArgGPR2, ExecutableBase::offsetOfJITCodeWithArityCheckFor(kind)), 269 GPRInfo::regT0); 270 271 // Make a tail call. This will return back to DFG code. 272 emitPointerValidation(jit, GPRInfo::regT0); 273 jit.jump(GPRInfo::regT0); 274 275 slowCase.link(&jit); 276 277 // Here we don't know anything, so revert to the full slow path. 278 279 slowPathFor(jit, globalData, kind == CodeForCall ? operationVirtualCall : operationVirtualConstruct); 280 281 LinkBuffer patchBuffer(*globalData, &jit, GLOBAL_THUNK_ID); 282 return FINALIZE_CODE( 283 patchBuffer, 284 ("DFG virtual %s slow path thunk", kind == CodeForCall ? "call" : "construct")); 285 } 286 287 MacroAssemblerCodeRef virtualCallThunkGenerator(JSGlobalData* globalData) 288 { 289 return virtualForThunkGenerator(globalData, CodeForCall); 290 } 291 292 MacroAssemblerCodeRef virtualConstructThunkGenerator(JSGlobalData* globalData) 293 { 294 return virtualForThunkGenerator(globalData, CodeForConstruct); 295 } 296 85 297 } } // namespace JSC::DFG 86 298 -
trunk/Source/JavaScriptCore/dfg/DFGThunks.h
r99787 r122392 41 41 MacroAssemblerCodeRef osrExitGenerationThunkGenerator(JSGlobalData*); 42 42 43 MacroAssemblerCodeRef throwExceptionFromCallSlowPathGenerator(JSGlobalData*); 44 45 MacroAssemblerCodeRef linkCallThunkGenerator(JSGlobalData*); 46 MacroAssemblerCodeRef linkConstructThunkGenerator(JSGlobalData*); 47 48 MacroAssemblerCodeRef virtualCallThunkGenerator(JSGlobalData*); 49 MacroAssemblerCodeRef virtualConstructThunkGenerator(JSGlobalData*); 50 43 51 } } // namespace JSC::DFG 44 52 -
trunk/Source/JavaScriptCore/jit/JIT.cpp
r121925 r122392 740 740 info.callType = m_callStructureStubCompilationInfo[i].callType; 741 741 info.bytecodeIndex = m_callStructureStubCompilationInfo[i].bytecodeIndex; 742 info.callReturnLocation = CodeLocationLabel(patchBuffer.locationOfNearCall(m_callStructureStubCompilationInfo[i].callReturnLocation));742 info.callReturnLocation = patchBuffer.locationOfNearCall(m_callStructureStubCompilationInfo[i].callReturnLocation); 743 743 info.hotPathBegin = patchBuffer.locationOf(m_callStructureStubCompilationInfo[i].hotPathBegin); 744 744 info.hotPathOther = patchBuffer.locationOfNearCall(m_callStructureStubCompilationInfo[i].hotPathOther); … … 803 803 // Patch the slow patch so we do not continue to try to link. 804 804 if (kind == CodeForCall) { 805 repatchBuffer.relink( CodeLocationNearCall(callLinkInfo->callReturnLocation), globalData->jitStubs->ctiVirtualCall());805 repatchBuffer.relink(callLinkInfo->callReturnLocation, globalData->jitStubs->ctiVirtualCall()); 806 806 return; 807 807 } 808 808 809 809 ASSERT(kind == CodeForConstruct); 810 repatchBuffer.relink( CodeLocationNearCall(callLinkInfo->callReturnLocation), globalData->jitStubs->ctiVirtualConstruct());810 repatchBuffer.relink(callLinkInfo->callReturnLocation, globalData->jitStubs->ctiVirtualConstruct()); 811 811 } 812 812 -
trunk/Source/JavaScriptCore/runtime/Executable.h
r119926 r122392 177 177 return NoIntrinsic; 178 178 } 179 180 static ptrdiff_t offsetOfJITCodeFor(CodeSpecializationKind kind) 181 { 182 if (kind == CodeForCall) 183 return OBJECT_OFFSETOF(ExecutableBase, m_jitCodeForCall); 184 ASSERT(kind == CodeForConstruct); 185 return OBJECT_OFFSETOF(ExecutableBase, m_jitCodeForConstruct); 186 } 187 188 static ptrdiff_t offsetOfJITCodeWithArityCheckFor(CodeSpecializationKind kind) 189 { 190 if (kind == CodeForCall) 191 return OBJECT_OFFSETOF(ExecutableBase, m_jitCodeForCallWithArityCheck); 192 ASSERT(kind == CodeForConstruct); 193 return OBJECT_OFFSETOF(ExecutableBase, m_jitCodeForConstructWithArityCheck); 194 } 195 196 static ptrdiff_t offsetOfNumParametersFor(CodeSpecializationKind kind) 197 { 198 if (kind == CodeForCall) 199 return OBJECT_OFFSETOF(ExecutableBase, m_numParametersForCall); 200 ASSERT(kind == CodeForConstruct); 201 return OBJECT_OFFSETOF(ExecutableBase, m_numParametersForConstruct); 202 } 179 203 #endif 180 204 -
trunk/Source/JavaScriptCore/runtime/JSValue.h
r118555 r122392 125 125 126 126 public: 127 #if USE(JSVALUE32_64) 128 enum { Int32Tag = 0xffffffff }; 129 enum { BooleanTag = 0xfffffffe }; 130 enum { NullTag = 0xfffffffd }; 131 enum { UndefinedTag = 0xfffffffc }; 132 enum { CellTag = 0xfffffffb }; 133 enum { EmptyValueTag = 0xfffffffa }; 134 enum { DeletedValueTag = 0xfffffff9 }; 135 136 enum { LowestTag = DeletedValueTag }; 137 #endif 138 127 139 static EncodedJSValue encode(JSValue); 128 140 static JSValue decode(EncodedJSValue); … … 279 291 * integer or boolean value; in the case of all other tags the payload is 0. 280 292 */ 281 enum { Int32Tag = 0xffffffff };282 enum { BooleanTag = 0xfffffffe };283 enum { NullTag = 0xfffffffd };284 enum { UndefinedTag = 0xfffffffc };285 enum { CellTag = 0xfffffffb };286 enum { EmptyValueTag = 0xfffffffa };287 enum { DeletedValueTag = 0xfffffff9 };288 289 enum { LowestTag = DeletedValueTag };290 291 293 uint32_t tag() const; 292 294 int32_t payload() const;
Note: See TracChangeset
for help on using the changeset viewer.