void JITCompiler::noticeOSREntry(BasicBlock& basicBlock, JITCompiler::Label blockHead, LinkBuffer& linkBuffer)
{
// OSR entry is not allowed into blocks deemed unreachable by control flow analysis.
if (!basicBlock.intersectionOfCFAHasVisited)
return;
OSREntryData* entry = m_jitCode->appendOSREntryData(basicBlock.bytecodeBegin, linkBuffer.offsetOf(blockHead));
entry->m_expectedValues = basicBlock.intersectionOfPastValuesAtHead;
// Fix the expected values: in our protocol, a dead variable will have an expected
// value of (None, []). But the old JIT may stash some values there. So we really
// need (Top, TOP).
for (size_t argument = 0; argument < basicBlock.variablesAtHead.numberOfArguments(); ++argument) {
Node* node = basicBlock.variablesAtHead.argument(argument);
if (!node || !node->shouldGenerate())
entry->m_expectedValues.argument(argument).makeHeapTop();
}
for (size_t local = 0; local < basicBlock.variablesAtHead.numberOfLocals(); ++local) {
Node* node = basicBlock.variablesAtHead.local(local);
if (!node || !node->shouldGenerate())
entry->m_expectedValues.local(local).makeHeapTop();
else {
VariableAccessData* variable = node->variableAccessData();
entry->m_machineStackUsed.set(variable->machineLocal().toLocal());
switch (variable->flushFormat()) {
case FlushedDouble:
entry->m_localsForcedDouble.set(local);
break;
case FlushedInt52:
entry->m_localsForcedMachineInt.set(local);
break;
default:
break;
}
if (variable->local() != variable->machineLocal()) {
entry->m_reshufflings.append(
OSREntryReshuffling(
variable->local().offset(), variable->machineLocal().offset()));
}
}
}
entry->m_reshufflings.shrinkToFit();
}
bool run()
{
RELEASE_ASSERT(m_graph.m_plan.mode == FTLForOSREntryMode);
RELEASE_ASSERT(m_graph.m_form == ThreadedCPS);
unsigned bytecodeIndex = m_graph.m_plan.osrEntryBytecodeIndex;
RELEASE_ASSERT(bytecodeIndex);
RELEASE_ASSERT(bytecodeIndex != UINT_MAX);
// Needed by createPreHeader().
m_graph.ensureDominators();
CodeBlock* baseline = m_graph.m_profiledBlock;
BasicBlock* target = 0;
for (unsigned blockIndex = m_graph.numBlocks(); blockIndex--;) {
BasicBlock* block = m_graph.block(blockIndex);
if (!block)
continue;
unsigned nodeIndex = 0;
Node* firstNode = block->at(0);
while (firstNode->isSemanticallySkippable())
firstNode = block->at(++nodeIndex);
if (firstNode->op() == LoopHint
&& firstNode->origin.semantic == CodeOrigin(bytecodeIndex)) {
target = block;
break;
}
}
if (!target) {
// This is a terrible outcome. It shouldn't often happen but it might
// happen and so we should defend against it. If it happens, then this
// compilation is a failure.
return false;
}
BlockInsertionSet insertionSet(m_graph);
// We say that the execution count of the entry block is 1, because we know for sure
// that this must be the case. Under our definition of executionCount, "1" means "once
// per invocation". We could have said NaN here, since that would ask any clients of
// executionCount to use best judgement - but that seems unnecessary since we know for
// sure what the executionCount should be in this case.
BasicBlock* newRoot = insertionSet.insert(0, 1);
// We'd really like to use an unset origin, but ThreadedCPS won't allow that.
NodeOrigin origin = NodeOrigin(CodeOrigin(0), CodeOrigin(0), false);
Vector<Node*> locals(baseline->m_numCalleeLocals);
for (int local = 0; local < baseline->m_numCalleeLocals; ++local) {
Node* previousHead = target->variablesAtHead.local(local);
if (!previousHead)
continue;
VariableAccessData* variable = previousHead->variableAccessData();
locals[local] = newRoot->appendNode(
m_graph, variable->prediction(), ExtractOSREntryLocal, origin,
OpInfo(variable->local().offset()));
newRoot->appendNode(
m_graph, SpecNone, MovHint, origin, OpInfo(variable->local().offset()),
Edge(locals[local]));
}
// Now use the origin of the target, since it's not OK to exit, and we will probably hoist
// type checks to here.
origin = target->at(0)->origin;
for (int argument = 0; argument < baseline->numParameters(); ++argument) {
Node* oldNode = target->variablesAtHead.argument(argument);
if (!oldNode) {
// Just for sanity, always have a SetArgument even if it's not needed.
oldNode = m_graph.m_arguments[argument];
}
Node* node = newRoot->appendNode(
m_graph, SpecNone, SetArgument, origin,
OpInfo(oldNode->variableAccessData()));
m_graph.m_arguments[argument] = node;
}
for (int local = 0; local < baseline->m_numCalleeLocals; ++local) {
Node* previousHead = target->variablesAtHead.local(local);
if (!previousHead)
continue;
VariableAccessData* variable = previousHead->variableAccessData();
Node* node = locals[local];
newRoot->appendNode(
m_graph, SpecNone, SetLocal, origin, OpInfo(variable), Edge(node));
}
newRoot->appendNode(
m_graph, SpecNone, Jump, origin,
OpInfo(createPreHeader(m_graph, insertionSet, target)));
insertionSet.execute();
m_graph.resetReachability();
m_graph.killUnreachableBlocks();
return true;
}
bool run()
{
for (unsigned i = m_graph.m_variableAccessData.size(); i--;) {
VariableAccessData* variable = &m_graph.m_variableAccessData[i];
if (!variable->isRoot())
continue;
variable->clearVotes();
}
// Identify the set of variables that are always subject to the same structure
// checks. For now, only consider monomorphic structure checks (one structure).
for (BlockIndex blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex) {
BasicBlock* block = m_graph.m_blocks[blockIndex].get();
if (!block)
continue;
for (unsigned indexInBlock = 0; indexInBlock < block->size(); ++indexInBlock) {
NodeIndex nodeIndex = block->at(indexInBlock);
Node& node = m_graph[nodeIndex];
if (!node.shouldGenerate())
continue;
switch (node.op()) {
case CheckStructure: {
Node& child = m_graph[node.child1()];
if (child.op() != GetLocal)
break;
VariableAccessData* variable = child.variableAccessData();
variable->vote(VoteStructureCheck);
if (variable->isCaptured() || variable->structureCheckHoistingFailed())
break;
if (!isCellSpeculation(variable->prediction()))
break;
noticeStructureCheck(variable, node.structureSet());
break;
}
case ForwardCheckStructure:
case ForwardStructureTransitionWatchpoint:
// We currently rely on the fact that we're the only ones who would
// insert this node.
ASSERT_NOT_REACHED();
break;
case GetByOffset:
case PutByOffset:
case PutStructure:
case StructureTransitionWatchpoint:
case AllocatePropertyStorage:
case ReallocatePropertyStorage:
case GetPropertyStorage:
case GetByVal:
case PutByVal:
case PutByValAlias:
case GetArrayLength:
case CheckArray:
case GetIndexedPropertyStorage:
case Phantom:
// Don't count these uses.
break;
default:
m_graph.vote(node, VoteOther);
break;
}
}
}
// Disable structure hoisting on variables that appear to mostly be used in
// contexts where it doesn't make sense.
for (unsigned i = m_graph.m_variableAccessData.size(); i--;) {
VariableAccessData* variable = &m_graph.m_variableAccessData[i];
if (!variable->isRoot())
continue;
if (variable->voteRatio() >= Options::structureCheckVoteRatioForHoisting())
continue;
HashMap<VariableAccessData*, CheckData>::iterator iter = m_map.find(variable);
if (iter == m_map.end())
continue;
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
dataLog("Zeroing the structure to hoist for %s because the ratio is %lf.\n",
m_graph.nameOfVariableAccessData(variable), variable->voteRatio());
#endif
iter->second.m_structure = 0;
}
// Identify the set of variables that are live across a structure clobber.
Operands<VariableAccessData*> live(
m_graph.m_blocks[0]->variablesAtTail.numberOfArguments(),
m_graph.m_blocks[0]->variablesAtTail.numberOfLocals());
for (BlockIndex blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex) {
BasicBlock* block = m_graph.m_blocks[blockIndex].get();
if (!block)
continue;
ASSERT(live.numberOfArguments() == block->variablesAtTail.numberOfArguments());
ASSERT(live.numberOfLocals() == block->variablesAtTail.numberOfLocals());
for (unsigned i = live.size(); i--;) {
NodeIndex indexAtTail = block->variablesAtTail[i];
VariableAccessData* variable;
//.........这里部分代码省略.........
bool run()
{
ASSERT(m_graph.m_form == ThreadedCPS);
for (unsigned i = m_graph.m_variableAccessData.size(); i--;) {
VariableAccessData* variable = &m_graph.m_variableAccessData[i];
if (!variable->isRoot())
continue;
variable->clearVotes();
}
// Identify the set of variables that are always subject to the same structure
// checks. For now, only consider monomorphic structure checks (one structure).
for (BlockIndex blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex) {
BasicBlock* block = m_graph.m_blocks[blockIndex].get();
if (!block)
continue;
for (unsigned indexInBlock = 0; indexInBlock < block->size(); ++indexInBlock) {
Node* node = block->at(indexInBlock);
switch (node->op()) {
case CheckStructure:
case StructureTransitionWatchpoint: {
Node* child = node->child1().node();
if (child->op() != GetLocal)
break;
VariableAccessData* variable = child->variableAccessData();
variable->vote(VoteStructureCheck);
if (!shouldConsiderForHoisting(variable))
break;
noticeStructureCheck(variable, node->structureSet());
break;
}
case ForwardCheckStructure:
case ForwardStructureTransitionWatchpoint:
// We currently rely on the fact that we're the only ones who would
// insert this node.
RELEASE_ASSERT_NOT_REACHED();
break;
case GetByOffset:
case PutByOffset:
case PutStructure:
case AllocatePropertyStorage:
case ReallocatePropertyStorage:
case GetButterfly:
case GetByVal:
case PutByVal:
case PutByValAlias:
case GetArrayLength:
case CheckArray:
case GetIndexedPropertyStorage:
case Phantom:
// Don't count these uses.
break;
case ArrayifyToStructure:
case Arrayify:
if (node->arrayMode().conversion() == Array::RageConvert) {
// Rage conversion changes structures. We should avoid tying to do
// any kind of hoisting when rage conversion is in play.
Node* child = node->child1().node();
if (child->op() != GetLocal)
break;
VariableAccessData* variable = child->variableAccessData();
variable->vote(VoteOther);
if (!shouldConsiderForHoisting(variable))
break;
noticeStructureCheck(variable, 0);
}
break;
case SetLocal: {
// Find all uses of the source of the SetLocal. If any of them are a
// kind of CheckStructure, then we should notice them to ensure that
// we're not hoisting a check that would contravene checks that are
// already being performed.
VariableAccessData* variable = node->variableAccessData();
if (!shouldConsiderForHoisting(variable))
break;
Node* source = node->child1().node();
for (unsigned subIndexInBlock = 0; subIndexInBlock < block->size(); ++subIndexInBlock) {
Node* subNode = block->at(subIndexInBlock);
switch (subNode->op()) {
case CheckStructure: {
if (subNode->child1() != source)
break;
noticeStructureCheck(variable, subNode->structureSet());
break;
}
case StructureTransitionWatchpoint: {
if (subNode->child1() != source)
break;
noticeStructureCheck(variable, subNode->structure());
break;
}
default:
//.........这里部分代码省略.........
bool run()
{
SharedSymbolTable* symbolTable = codeBlock()->symbolTable();
// This enumerates the locals that we actually care about and packs them. So for example
// if we use local 1, 3, 4, 5, 7, then we remap them: 1->0, 3->1, 4->2, 5->3, 7->4. We
// treat a variable as being "used" if there exists an access to it (SetLocal, GetLocal,
// Flush, PhantomLocal).
BitVector usedLocals;
// Collect those variables that are used from IR.
bool hasGetLocalUnlinked = false;
for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) {
BasicBlock* block = m_graph.block(blockIndex);
if (!block)
continue;
for (unsigned nodeIndex = block->size(); nodeIndex--;) {
Node* node = block->at(nodeIndex);
switch (node->op()) {
case GetLocal:
case SetLocal:
case Flush:
case PhantomLocal: {
VariableAccessData* variable = node->variableAccessData();
if (variable->local().isArgument())
break;
usedLocals.set(variable->local().toLocal());
break;
}
case GetLocalUnlinked: {
VirtualRegister operand = node->unlinkedLocal();
if (operand.isArgument())
break;
usedLocals.set(operand.toLocal());
hasGetLocalUnlinked = true;
break;
}
default:
break;
}
}
}
// Ensure that captured variables and captured inline arguments are pinned down.
// They should have been because of flushes, except that the flushes can be optimized
// away.
if (symbolTable) {
for (int i = symbolTable->captureStart(); i > symbolTable->captureEnd(); i--)
usedLocals.set(VirtualRegister(i).toLocal());
}
if (codeBlock()->usesArguments()) {
usedLocals.set(codeBlock()->argumentsRegister().toLocal());
usedLocals.set(unmodifiedArgumentsRegister(codeBlock()->argumentsRegister()).toLocal());
}
if (codeBlock()->uncheckedActivationRegister().isValid())
usedLocals.set(codeBlock()->activationRegister().toLocal());
for (InlineCallFrameSet::iterator iter = m_graph.m_inlineCallFrames->begin(); !!iter; ++iter) {
InlineCallFrame* inlineCallFrame = *iter;
if (!inlineCallFrame->executable->usesArguments())
continue;
VirtualRegister argumentsRegister = m_graph.argumentsRegisterFor(inlineCallFrame);
usedLocals.set(argumentsRegister.toLocal());
usedLocals.set(unmodifiedArgumentsRegister(argumentsRegister).toLocal());
for (unsigned argument = inlineCallFrame->arguments.size(); argument-- > 1;) {
usedLocals.set(VirtualRegister(
virtualRegisterForArgument(argument).offset() +
inlineCallFrame->stackOffset).toLocal());
}
}
Vector<unsigned> allocation(usedLocals.size());
m_graph.m_nextMachineLocal = 0;
for (unsigned i = 0; i < usedLocals.size(); ++i) {
if (!usedLocals.get(i)) {
allocation[i] = UINT_MAX;
continue;
}
allocation[i] = m_graph.m_nextMachineLocal++;
}
for (unsigned i = m_graph.m_variableAccessData.size(); i--;) {
VariableAccessData* variable = &m_graph.m_variableAccessData[i];
if (!variable->isRoot())
continue;
if (variable->local().isArgument()) {
variable->machineLocal() = variable->local();
continue;
}
size_t local = variable->local().toLocal();
if (local >= allocation.size())
continue;
//.........这里部分代码省略.........
请发表评论