|
Lines 58-63
Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp_sec1
|
| 58 |
#include "ScopedArguments.h" |
58 |
#include "ScopedArguments.h" |
| 59 |
#include "ScopedArgumentsTable.h" |
59 |
#include "ScopedArgumentsTable.h" |
| 60 |
#include "ScratchRegisterAllocator.h" |
60 |
#include "ScratchRegisterAllocator.h" |
|
|
61 |
#include "SetupVarargsFrame.h" |
| 61 |
#include "VirtualRegister.h" |
62 |
#include "VirtualRegister.h" |
| 62 |
#include "Watchdog.h" |
63 |
#include "Watchdog.h" |
| 63 |
#include <atomic> |
64 |
#include <atomic> |
|
Lines 205-212
public:
Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp_sec2
|
| 205 |
#endif // FTL_USE_B3 |
206 |
#endif // FTL_USE_B3 |
| 206 |
|
207 |
|
| 207 |
auto preOrder = m_graph.blocksInPreOrder(); |
208 |
auto preOrder = m_graph.blocksInPreOrder(); |
| 208 |
|
209 |
|
| 209 |
// If we have any CallVarargs then we need to have a spill slot for it. |
210 |
#if !FTL_USES_B3 |
| 210 |
bool hasVarargs = false; |
211 |
bool hasVarargs = false; |
| 211 |
size_t maxNumberOfCatchSpills = 0; |
212 |
size_t maxNumberOfCatchSpills = 0; |
| 212 |
for (DFG::BasicBlock* block : preOrder) { |
213 |
for (DFG::BasicBlock* block : preOrder) { |
|
Lines 270-279
public:
Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp_sec3
|
| 270 |
} |
271 |
} |
| 271 |
} |
272 |
} |
| 272 |
|
273 |
|
| 273 |
#if FTL_USES_B3 |
274 |
// B3 doesn't need the varargs spill slot because we just use call arg area size as a way to |
| 274 |
UNUSED_PARAM(hasVarargs); |
275 |
// request spill slots. |
| 275 |
// FIXME |
|
|
| 276 |
#else |
| 277 |
if (hasVarargs) { |
276 |
if (hasVarargs) { |
| 278 |
LValue varargsSpillSlots = m_out.alloca( |
277 |
LValue varargsSpillSlots = m_out.alloca( |
| 279 |
arrayType(m_out.int64, JSCallVarargs::numSpillSlotsNeeded())); |
278 |
arrayType(m_out.int64, JSCallVarargs::numSpillSlotsNeeded())); |
|
Lines 284-289
public:
Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp_sec4
|
| 284 |
m_out.int32Zero, varargsSpillSlots); |
283 |
m_out.int32Zero, varargsSpillSlots); |
| 285 |
} |
284 |
} |
| 286 |
|
285 |
|
|
|
286 |
// B3 doesn't need the exception spill slot because we just use the |
| 287 |
if (m_graph.m_hasExceptionHandlers && maxNumberOfCatchSpills) { |
287 |
if (m_graph.m_hasExceptionHandlers && maxNumberOfCatchSpills) { |
| 288 |
RegisterSet volatileRegisters = RegisterSet::volatileRegistersForJSCall(); |
288 |
RegisterSet volatileRegisters = RegisterSet::volatileRegistersForJSCall(); |
| 289 |
maxNumberOfCatchSpills = std::min(volatileRegisters.numberOfSetRegisters(), maxNumberOfCatchSpills); |
289 |
maxNumberOfCatchSpills = std::min(volatileRegisters.numberOfSetRegisters(), maxNumberOfCatchSpills); |
|
Lines 296-302
public:
Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp_sec5
|
| 296 |
m_out.constInt64(m_ftlState.exceptionHandlingSpillSlotStackmapID), |
296 |
m_out.constInt64(m_ftlState.exceptionHandlingSpillSlotStackmapID), |
| 297 |
m_out.int32Zero, exceptionHandlingVolatileRegistersSpillSlots); |
297 |
m_out.int32Zero, exceptionHandlingVolatileRegistersSpillSlots); |
| 298 |
} |
298 |
} |
| 299 |
#endif |
299 |
#endif // !FTL_USES_B3 |
| 300 |
|
300 |
|
| 301 |
// We should not create any alloca's after this point, since they will cease to |
301 |
// We should not create any alloca's after this point, since they will cease to |
| 302 |
// be mem2reg candidates. |
302 |
// be mem2reg candidates. |
|
Lines 5069-5100
private:
Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp_sec6
|
| 5069 |
|
5069 |
|
| 5070 |
void compileCallOrConstructVarargs() |
5070 |
void compileCallOrConstructVarargs() |
| 5071 |
{ |
5071 |
{ |
| 5072 |
#if FTL_USES_B3 |
5072 |
Node* node = m_node; |
| 5073 |
if (verboseCompilationEnabled() || !verboseCompilationEnabled()) |
|
|
| 5074 |
CRASH(); |
| 5075 |
#else |
| 5076 |
LValue jsCallee = lowJSValue(m_node->child1()); |
5073 |
LValue jsCallee = lowJSValue(m_node->child1()); |
| 5077 |
LValue thisArg = lowJSValue(m_node->child3()); |
5074 |
LValue thisArg = lowJSValue(m_node->child3()); |
| 5078 |
|
5075 |
|
| 5079 |
LValue jsArguments = nullptr; |
5076 |
LValue jsArguments = nullptr; |
|
|
5077 |
bool forwarding = false; |
| 5080 |
|
5078 |
|
| 5081 |
switch (m_node->op()) { |
5079 |
switch (node->op()) { |
| 5082 |
case CallVarargs: |
5080 |
case CallVarargs: |
| 5083 |
case TailCallVarargs: |
5081 |
case TailCallVarargs: |
| 5084 |
case TailCallVarargsInlinedCaller: |
5082 |
case TailCallVarargsInlinedCaller: |
| 5085 |
case ConstructVarargs: |
5083 |
case ConstructVarargs: |
| 5086 |
jsArguments = lowJSValue(m_node->child2()); |
5084 |
jsArguments = lowJSValue(node->child2()); |
| 5087 |
break; |
5085 |
break; |
| 5088 |
case CallForwardVarargs: |
5086 |
case CallForwardVarargs: |
| 5089 |
case TailCallForwardVarargs: |
5087 |
case TailCallForwardVarargs: |
| 5090 |
case TailCallForwardVarargsInlinedCaller: |
5088 |
case TailCallForwardVarargsInlinedCaller: |
| 5091 |
case ConstructForwardVarargs: |
5089 |
case ConstructForwardVarargs: |
|
|
5090 |
forwarding = true; |
| 5092 |
break; |
5091 |
break; |
| 5093 |
default: |
5092 |
default: |
| 5094 |
DFG_CRASH(m_graph, m_node, "bad node type"); |
5093 |
DFG_CRASH(m_graph, node, "bad node type"); |
| 5095 |
break; |
5094 |
break; |
| 5096 |
} |
5095 |
} |
| 5097 |
|
5096 |
|
|
|
5097 |
#if FTL_USES_B3 |
| 5098 |
// FIXME: Need a story for exceptions. |
| 5099 |
// https://bugs.webkit.org/show_bug.cgi?id=151686 |
| 5100 |
|
| 5101 |
PatchpointValue* patchpoint = m_out.patchpoint(Int64); |
| 5102 |
|
| 5103 |
// Append the forms of the arguments that we will use before any clobbering happens. |
| 5104 |
patchpoint->append(jsCallee, ValueRep::reg(GPRInfo::regT0)); |
| 5105 |
if (jsArguments) |
| 5106 |
patchpoint->append(jsArguments, ValueRep::SomeRegister); |
| 5107 |
patchpoint->append(thisArg, ValueRep::SomeRegister); |
| 5108 |
|
| 5109 |
if (!forwarding) { |
| 5110 |
// Now append them again for after clobbering. Note that the compiler may ask us to use a |
| 5111 |
// different register for the late for the post-clobbering version of the value. This gives |
| 5112 |
// the compiler to spill these values without having to burn any callee-saves. |
| 5113 |
patchpoint->append(jsCallee, ValueRep::LateColdAny); |
| 5114 |
patchpoint->append(jsArguments, ValueRep::LateColdAny); |
| 5115 |
patchpoint->append(thisArg, ValueRep::LateColdAny); |
| 5116 |
} |
| 5117 |
|
| 5118 |
patchpoint->clobber(RegisterSet::macroScratchRegisters()); |
| 5119 |
patchpoint->clobberLate(RegisterSet::volatileRegistersForJSCall()); |
| 5120 |
patchpoint->resultConstraint = ValueRep::reg(GPRInfo::returnValueGPR); |
| 5121 |
|
| 5122 |
// This is the minimum amount of call arg area stack space that all JS->JS calls always have. |
| 5123 |
unsigned minimumJSCallAreaSize = |
| 5124 |
sizeof(CallerFrameAndPC) + |
| 5125 |
WTF::roundUpToMultipleOf(stackAlignmentBytes(), 5 * sizeof(EncodedJSValue)); |
| 5126 |
|
| 5127 |
m_proc.requestCallArgAreaSize(minimumJSCallAreaSize); |
| 5128 |
|
| 5129 |
CodeOrigin codeOrigin = codeOriginDescriptionOfCallSite(); |
| 5130 |
State* state = &m_ftlState; |
| 5131 |
patchpoint->setGenerator( |
| 5132 |
[=] (CCallHelpers& jit, const StackmapGenerationParams& params) { |
| 5133 |
AllowMacroScratchRegisterUsage allowScratch(jit); |
| 5134 |
CallSiteIndex callSiteIndex = |
| 5135 |
state->jitCode->common.addUniqueCallSiteIndex(codeOrigin); |
| 5136 |
|
| 5137 |
// FIXME: We would ask the OSR exit descriptor to prepare and then we would modify |
| 5138 |
// the OSRExit data structure inside the OSRExitHandle to link it up to this call. |
| 5139 |
// Also, the exception checks JumpList should be linked to somewhere. |
| 5140 |
// https://bugs.webkit.org/show_bug.cgi?id=151686 |
| 5141 |
CCallHelpers::JumpList exceptions; |
| 5142 |
|
| 5143 |
jit.store32( |
| 5144 |
CCallHelpers::TrustedImm32(callSiteIndex.bits()), |
| 5145 |
CCallHelpers::tagFor(VirtualRegister(JSStack::ArgumentCount))); |
| 5146 |
|
| 5147 |
CallLinkInfo* callLinkInfo = jit.codeBlock()->addCallLinkInfo(); |
| 5148 |
CallVarargsData* data = node->callVarargsData(); |
| 5149 |
|
| 5150 |
unsigned argIndex = 1; |
| 5151 |
GPRReg calleeGPR = params[argIndex++].gpr(); |
| 5152 |
ASSERT(calleeGPR == GPRInfo::regT0); |
| 5153 |
GPRReg argumentsGPR = jsArguments ? params[argIndex++].gpr() : InvalidGPRReg; |
| 5154 |
GPRReg thisGPR = params[argIndex++].gpr(); |
| 5155 |
|
| 5156 |
B3::ValueRep calleeLateRep; |
| 5157 |
B3::ValueRep argumentsLateRep; |
| 5158 |
B3::ValueRep thisLateRep; |
| 5159 |
if (!forwarding) { |
| 5160 |
calleeLateRep = params[argIndex++]; |
| 5161 |
argumentsLateRep = params[argIndex++]; |
| 5162 |
thisLateRep = params[argIndex++]; |
| 5163 |
} |
| 5164 |
|
| 5165 |
// Get some scratch registers. |
| 5166 |
RegisterSet usedRegisters; |
| 5167 |
usedRegisters.merge(RegisterSet::stackRegisters()); |
| 5168 |
usedRegisters.merge(RegisterSet::reservedHardwareRegisters()); |
| 5169 |
usedRegisters.merge(RegisterSet::calleeSaveRegisters()); |
| 5170 |
usedRegisters.set(calleeGPR); |
| 5171 |
if (argumentsGPR != InvalidGPRReg) |
| 5172 |
usedRegisters.set(argumentsGPR); |
| 5173 |
usedRegisters.set(thisGPR); |
| 5174 |
if (calleeLateRep.isReg()) |
| 5175 |
usedRegisters.set(calleeLateRep.reg()); |
| 5176 |
if (argumentsLateRep.isReg()) |
| 5177 |
usedRegisters.set(argumentsLateRep.reg()); |
| 5178 |
if (thisLateRep.isReg()) |
| 5179 |
usedRegisters.set(thisLateRep.reg()); |
| 5180 |
ScratchRegisterAllocator allocator(usedRegisters); |
| 5181 |
GPRReg scratchGPR1 = allocator.allocateScratchGPR(); |
| 5182 |
GPRReg scratchGPR2 = allocator.allocateScratchGPR(); |
| 5183 |
GPRReg scratchGPR3 = forwarding ? allocator.allocateScratchGPR() : InvalidGPRReg; |
| 5184 |
RELEASE_ASSERT(!allocator.numberOfReusedRegisters()); |
| 5185 |
|
| 5186 |
auto callWithExceptionCheck = [&] (void* callee) { |
| 5187 |
jit.move(CCallHelpers::TrustedImmPtr(callee), GPRInfo::nonPreservedNonArgumentGPR); |
| 5188 |
jit.call(GPRInfo::nonPreservedNonArgumentGPR); |
| 5189 |
exceptions.append(jit.emitExceptionCheck(AssemblyHelpers::NormalExceptionCheck, AssemblyHelpers::FarJumpWidth)); |
| 5190 |
}; |
| 5191 |
|
| 5192 |
auto adjustStack = [&] (GPRReg amount) { |
| 5193 |
jit.addPtr(CCallHelpers::TrustedImm32(sizeof(CallerFrameAndPC)), amount, CCallHelpers::stackPointerRegister); |
| 5194 |
}; |
| 5195 |
|
| 5196 |
unsigned originalStackHeight = params.proc().frameSize(); |
| 5197 |
|
| 5198 |
if (forwarding) { |
| 5199 |
jit.move(CCallHelpers::TrustedImm32(originalStackHeight / sizeof(EncodedJSValue)), scratchGPR2); |
| 5200 |
|
| 5201 |
CCallHelpers::JumpList slowCase; |
| 5202 |
emitSetupVarargsFrameFastCase(jit, scratchGPR2, scratchGPR1, scratchGPR2, scratchGPR3, node->child2()->origin.semantic.inlineCallFrame, data->firstVarArgOffset, slowCase); |
| 5203 |
|
| 5204 |
CCallHelpers::Jump done = jit.jump(); |
| 5205 |
slowCase.link(&jit); |
| 5206 |
jit.setupArgumentsExecState(); |
| 5207 |
callWithExceptionCheck(bitwise_cast<void*>(operationThrowStackOverflowForVarargs)); |
| 5208 |
jit.abortWithReason(DFGVarargsThrowingPathDidNotThrow); |
| 5209 |
|
| 5210 |
done.link(&jit); |
| 5211 |
|
| 5212 |
adjustStack(scratchGPR2); |
| 5213 |
} else { |
| 5214 |
jit.move(CCallHelpers::TrustedImm32(originalStackHeight / sizeof(EncodedJSValue)), scratchGPR1); |
| 5215 |
jit.setupArgumentsWithExecState(argumentsGPR, scratchGPR1, CCallHelpers::TrustedImm32(data->firstVarArgOffset)); |
| 5216 |
callWithExceptionCheck(bitwise_cast<void*>(operationSizeFrameForVarargs)); |
| 5217 |
|
| 5218 |
jit.move(GPRInfo::returnValueGPR, scratchGPR1); |
| 5219 |
jit.move(CCallHelpers::TrustedImm32(originalStackHeight / sizeof(EncodedJSValue)), scratchGPR2); |
| 5220 |
argumentsLateRep.emitRestore(jit, argumentsGPR); |
| 5221 |
emitSetVarargsFrame(jit, scratchGPR1, false, scratchGPR2, scratchGPR2); |
| 5222 |
jit.addPtr(CCallHelpers::TrustedImm32(-minimumJSCallAreaSize), scratchGPR2, CCallHelpers::stackPointerRegister); |
| 5223 |
jit.setupArgumentsWithExecState(scratchGPR2, argumentsGPR, CCallHelpers::TrustedImm32(data->firstVarArgOffset), scratchGPR1); |
| 5224 |
callWithExceptionCheck(bitwise_cast<void*>(operationSetupVarargsFrame)); |
| 5225 |
|
| 5226 |
adjustStack(GPRInfo::returnValueGPR); |
| 5227 |
|
| 5228 |
calleeLateRep.emitRestore(jit, GPRInfo::regT0); |
| 5229 |
|
| 5230 |
// This may not emit code if thisGPR got a callee-save. Also, we're guaranteed |
| 5231 |
// that thisGPR != GPRInfo::regT0 because regT0 interferes with it. |
| 5232 |
thisLateRep.emitRestore(jit, thisGPR); |
| 5233 |
} |
| 5234 |
|
| 5235 |
jit.store64(GPRInfo::regT0, CCallHelpers::calleeFrameSlot(JSStack::Callee)); |
| 5236 |
jit.store64(thisGPR, CCallHelpers::calleeArgumentSlot(0)); |
| 5237 |
|
| 5238 |
CallLinkInfo::CallType callType; |
| 5239 |
if (node->op() == ConstructVarargs || node->op() == ConstructForwardVarargs) |
| 5240 |
callType = CallLinkInfo::ConstructVarargs; |
| 5241 |
else if (node->op() == TailCallVarargs || node->op() == TailCallForwardVarargs) |
| 5242 |
callType = CallLinkInfo::TailCallVarargs; |
| 5243 |
else |
| 5244 |
callType = CallLinkInfo::CallVarargs; |
| 5245 |
|
| 5246 |
bool isTailCall = CallLinkInfo::callModeFor(callType) == CallMode::Tail; |
| 5247 |
|
| 5248 |
CCallHelpers::DataLabelPtr targetToCheck; |
| 5249 |
CCallHelpers::Jump slowPath = jit.branchPtrWithPatch( |
| 5250 |
CCallHelpers::NotEqual, GPRInfo::regT0, targetToCheck, |
| 5251 |
CCallHelpers::TrustedImmPtr(0)); |
| 5252 |
|
| 5253 |
CCallHelpers::Call fastCall; |
| 5254 |
CCallHelpers::Jump done; |
| 5255 |
|
| 5256 |
if (isTailCall) { |
| 5257 |
jit.prepareForTailCallSlow(); |
| 5258 |
fastCall = jit.nearTailCall(); |
| 5259 |
} else { |
| 5260 |
fastCall = jit.nearCall(); |
| 5261 |
done = jit.jump(); |
| 5262 |
} |
| 5263 |
|
| 5264 |
slowPath.link(&jit); |
| 5265 |
|
| 5266 |
jit.move(CCallHelpers::TrustedImmPtr(callLinkInfo), GPRInfo::regT2); |
| 5267 |
CCallHelpers::Call slowCall = jit.nearCall(); |
| 5268 |
|
| 5269 |
if (isTailCall) |
| 5270 |
jit.abortWithReason(JITDidReturnFromTailCall); |
| 5271 |
else |
| 5272 |
done.link(&jit); |
| 5273 |
|
| 5274 |
callLinkInfo->setUpCall(callType, node->origin.semantic, GPRInfo::regT0); |
| 5275 |
|
| 5276 |
jit.addPtr( |
| 5277 |
CCallHelpers::TrustedImm32(-originalStackHeight), |
| 5278 |
GPRInfo::callFrameRegister, CCallHelpers::stackPointerRegister); |
| 5279 |
|
| 5280 |
jit.addLinkTask( |
| 5281 |
[=] (LinkBuffer& linkBuffer) { |
| 5282 |
MacroAssemblerCodePtr linkCall = |
| 5283 |
linkBuffer.vm().getCTIStub(linkCallThunkGenerator).code(); |
| 5284 |
linkBuffer.link(slowCall, FunctionPtr(linkCall.executableAddress())); |
| 5285 |
|
| 5286 |
callLinkInfo->setCallLocations( |
| 5287 |
linkBuffer.locationOfNearCall(slowCall), |
| 5288 |
linkBuffer.locationOf(targetToCheck), |
| 5289 |
linkBuffer.locationOfNearCall(fastCall)); |
| 5290 |
}); |
| 5291 |
}); |
| 5292 |
|
| 5293 |
setJSValue(patchpoint); |
| 5294 |
#else |
| 5098 |
unsigned stackmapID = m_stackmapIDs++; |
5295 |
unsigned stackmapID = m_stackmapIDs++; |
| 5099 |
|
5296 |
|
| 5100 |
StackmapArgumentList arguments; |
5297 |
StackmapArgumentList arguments; |
|
Lines 5108-5122
private:
Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp_sec7
|
| 5108 |
|
5305 |
|
| 5109 |
arguments.insert(0, m_out.constInt32(2 + !!jsArguments)); |
5306 |
arguments.insert(0, m_out.constInt32(2 + !!jsArguments)); |
| 5110 |
arguments.insert(0, constNull(m_out.ref8)); |
5307 |
arguments.insert(0, constNull(m_out.ref8)); |
| 5111 |
arguments.insert(0, m_out.constInt32(sizeOfICFor(m_node))); |
5308 |
arguments.insert(0, m_out.constInt32(sizeOfICFor(node))); |
| 5112 |
arguments.insert(0, m_out.constInt64(stackmapID)); |
5309 |
arguments.insert(0, m_out.constInt64(stackmapID)); |
| 5113 |
|
5310 |
|
| 5114 |
LValue call = m_out.call(m_out.int64, m_out.patchpointInt64Intrinsic(), arguments); |
5311 |
LValue call = m_out.call(m_out.int64, m_out.patchpointInt64Intrinsic(), arguments); |
| 5115 |
setInstructionCallingConvention(call, LLVMCCallConv); |
5312 |
setInstructionCallingConvention(call, LLVMCCallConv); |
| 5116 |
|
5313 |
|
| 5117 |
m_ftlState.jsCallVarargses.append(JSCallVarargs(stackmapID, m_node, codeOriginDescriptionOfCallSite())); |
5314 |
m_ftlState.jsCallVarargses.append(JSCallVarargs(stackmapID, node, codeOriginDescriptionOfCallSite())); |
| 5118 |
|
5315 |
|
| 5119 |
switch (m_node->op()) { |
5316 |
switch (node->op()) { |
| 5120 |
case TailCallVarargs: |
5317 |
case TailCallVarargs: |
| 5121 |
case TailCallForwardVarargs: |
5318 |
case TailCallForwardVarargs: |
| 5122 |
m_out.unreachable(); |
5319 |
m_out.unreachable(); |
|
Lines 5488-5494
private:
Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp_sec8
|
| 5488 |
DFG_ASSERT(m_graph, m_node, m_origin.exitOK); |
5685 |
DFG_ASSERT(m_graph, m_node, m_origin.exitOK); |
| 5489 |
|
5686 |
|
| 5490 |
#if FTL_USES_B3 |
5687 |
#if FTL_USES_B3 |
| 5491 |
B3::PatchpointValue* patchpoint = m_out.patchpoint(Void); |
5688 |
PatchpointValue* patchpoint = m_out.patchpoint(Void); |
| 5492 |
OSRExitDescriptor* descriptor = appendOSRExitDescriptor(noValue(), nullptr); |
5689 |
OSRExitDescriptor* descriptor = appendOSRExitDescriptor(noValue(), nullptr); |
| 5493 |
NodeOrigin origin = m_origin; |
5690 |
NodeOrigin origin = m_origin; |
| 5494 |
patchpoint->appendColdAnys(buildExitArguments(descriptor, origin.forExit, noValue())); |
5691 |
patchpoint->appendColdAnys(buildExitArguments(descriptor, origin.forExit, noValue())); |