diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
commit | 1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch) | |
tree | 46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/JavaScriptCore/dfg/DFGOSRAvailabilityAnalysisPhase.cpp | |
parent | 32761a6cee1d0dee366b885b7b9c777e67885688 (diff) | |
download | WebKitGtk-tarball-master.tar.gz |
webkitgtk-2.16.5HEADwebkitgtk-2.16.5master
Diffstat (limited to 'Source/JavaScriptCore/dfg/DFGOSRAvailabilityAnalysisPhase.cpp')
-rw-r--r-- | Source/JavaScriptCore/dfg/DFGOSRAvailabilityAnalysisPhase.cpp | 250 |
1 files changed, 188 insertions, 62 deletions
diff --git a/Source/JavaScriptCore/dfg/DFGOSRAvailabilityAnalysisPhase.cpp b/Source/JavaScriptCore/dfg/DFGOSRAvailabilityAnalysisPhase.cpp index a64963581..e8b45c45a 100644 --- a/Source/JavaScriptCore/dfg/DFGOSRAvailabilityAnalysisPhase.cpp +++ b/Source/JavaScriptCore/dfg/DFGOSRAvailabilityAnalysisPhase.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Apple Inc. All rights reserved. + * Copyright (C) 2013-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -32,7 +32,7 @@ #include "DFGGraph.h" #include "DFGInsertionSet.h" #include "DFGPhase.h" -#include "Operations.h" +#include "JSCInlines.h" namespace JSC { namespace DFG { @@ -51,29 +51,22 @@ public: BasicBlock* block = m_graph.block(blockIndex); if (!block) continue; - block->ssa->availabilityAtHead.fill(Availability()); - block->ssa->availabilityAtTail.fill(Availability()); + block->ssa->availabilityAtHead.clear(); + block->ssa->availabilityAtTail.clear(); } BasicBlock* root = m_graph.block(0); - for (unsigned argument = root->ssa->availabilityAtHead.numberOfArguments(); argument--;) { - root->ssa->availabilityAtHead.argument(argument) = - Availability::unavailable().withFlush( - FlushedAt(FlushedJSValue, virtualRegisterForArgument(argument))); + root->ssa->availabilityAtHead.m_locals.fill(Availability::unavailable()); + for (unsigned argument = m_graph.m_argumentFormats.size(); argument--;) { + FlushedAt flushedAt = FlushedAt( + m_graph.m_argumentFormats[argument], + virtualRegisterForArgument(argument)); + root->ssa->availabilityAtHead.m_locals.argument(argument) = Availability(flushedAt); } - for (unsigned local = root->ssa->availabilityAtHead.numberOfLocals(); local--;) - root->ssa->availabilityAtHead.local(local) = Availability::unavailable(); - - if (m_graph.m_plan.mode == FTLForOSREntryMode) { - for (unsigned local = m_graph.m_profiledBlock->m_numCalleeRegisters; local--;) { - root->ssa->availabilityAtHead.local(local) = - Availability::unavailable().withFlush( - FlushedAt(FlushedJSValue, virtualRegisterForLocal(local))); - } - } - + // This could be made more efficient by processing blocks in reverse postorder. - Operands<Availability> availability; + + LocalOSRAvailabilityCalculator calculator(m_graph); bool changed; do { changed = false; @@ -83,69 +76,202 @@ public: if (!block) continue; - availability = block->ssa->availabilityAtHead; + calculator.beginBlock(block); - for (unsigned nodeIndex = 0; nodeIndex < block->size(); ++nodeIndex) { - Node* node = block->at(nodeIndex); - - switch (node->op()) { - case SetLocal: { - VariableAccessData* variable = node->variableAccessData(); - availability.operand(variable->local()) = - Availability(node->child1().node(), variable->flushedAt()); - break; - } - - case GetArgument: { - VariableAccessData* variable = node->variableAccessData(); - availability.operand(variable->local()) = - Availability(node, variable->flushedAt()); - break; - } - - case MovHint: { - availability.operand(node->unlinkedLocal()) = - Availability(node->child1().node()); - break; - } - - case ZombieHint: { - availability.operand(node->unlinkedLocal()) = - Availability::unavailable(); - break; - } - - default: - break; - } - } + for (unsigned nodeIndex = 0; nodeIndex < block->size(); ++nodeIndex) + calculator.executeNode(block->at(nodeIndex)); - if (availability == block->ssa->availabilityAtTail) + if (calculator.m_availability == block->ssa->availabilityAtTail) continue; - block->ssa->availabilityAtTail = availability; + block->ssa->availabilityAtTail = calculator.m_availability; changed = true; for (unsigned successorIndex = block->numSuccessors(); successorIndex--;) { BasicBlock* successor = block->successor(successorIndex); - for (unsigned i = availability.size(); i--;) { - successor->ssa->availabilityAtHead[i] = availability[i].merge( - successor->ssa->availabilityAtHead[i]); - } + successor->ssa->availabilityAtHead.merge(calculator.m_availability); + successor->ssa->availabilityAtHead.pruneByLiveness( + m_graph, successor->at(0)->origin.forExit); } } } while (changed); + + if (validationEnabled()) { + + for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) { + BasicBlock* block = m_graph.block(blockIndex); + if (!block) + continue; + + calculator.beginBlock(block); + + for (unsigned nodeIndex = 0; nodeIndex < block->size(); ++nodeIndex) { + if (block->at(nodeIndex)->origin.exitOK) { + // If we're allowed to exit here, the heap must be in a state + // where exiting wouldn't crash. These particular fields are + // required for correctness because we use them during OSR exit + // to do meaningful things. It would be wrong for any of them + // to be dead. + + AvailabilityMap availabilityMap = calculator.m_availability; + availabilityMap.pruneByLiveness(m_graph, block->at(nodeIndex)->origin.forExit); + + for (auto heapPair : availabilityMap.m_heap) { + switch (heapPair.key.kind()) { + case ActivationScopePLoc: + case ActivationSymbolTablePLoc: + case FunctionActivationPLoc: + case FunctionExecutablePLoc: + case StructurePLoc: + if (heapPair.value.isDead()) { + dataLogLn("PromotedHeapLocation is dead, but should not be: ", heapPair.key); + availabilityMap.dump(WTF::dataFile()); + CRASH(); + } + break; + + default: + break; + } + } + } + + calculator.executeNode(block->at(nodeIndex)); + } + } + } return true; } + }; bool performOSRAvailabilityAnalysis(Graph& graph) { - SamplingRegion samplingRegion("DFG OSR Availability Analysis Phase"); return runPhase<OSRAvailabilityAnalysisPhase>(graph); } +LocalOSRAvailabilityCalculator::LocalOSRAvailabilityCalculator(Graph& graph) + : m_graph(graph) +{ +} + +LocalOSRAvailabilityCalculator::~LocalOSRAvailabilityCalculator() +{ +} + +void LocalOSRAvailabilityCalculator::beginBlock(BasicBlock* block) +{ + m_availability = block->ssa->availabilityAtHead; +} + +void LocalOSRAvailabilityCalculator::endBlock(BasicBlock* block) +{ + m_availability = block->ssa->availabilityAtTail; +} + +void LocalOSRAvailabilityCalculator::executeNode(Node* node) +{ + switch (node->op()) { + case PutStack: { + StackAccessData* data = node->stackAccessData(); + m_availability.m_locals.operand(data->local).setFlush(data->flushedAt()); + break; + } + + case KillStack: { + m_availability.m_locals.operand(node->unlinkedLocal()).setFlush(FlushedAt(ConflictingFlush)); + break; + } + + case GetStack: { + StackAccessData* data = node->stackAccessData(); + m_availability.m_locals.operand(data->local) = Availability(node, data->flushedAt()); + break; + } + + case MovHint: { + m_availability.m_locals.operand(node->unlinkedLocal()).setNode(node->child1().node()); + break; + } + + case ZombieHint: { + m_availability.m_locals.operand(node->unlinkedLocal()).setNodeUnavailable(); + break; + } + + case LoadVarargs: + case ForwardVarargs: { + LoadVarargsData* data = node->loadVarargsData(); + m_availability.m_locals.operand(data->count) = + Availability(FlushedAt(FlushedInt32, data->machineCount)); + for (unsigned i = data->limit; i--;) { + m_availability.m_locals.operand(VirtualRegister(data->start.offset() + i)) = + Availability(FlushedAt(FlushedJSValue, VirtualRegister(data->machineStart.offset() + i))); + } + break; + } + + case PhantomCreateRest: + case PhantomDirectArguments: + case PhantomClonedArguments: { + InlineCallFrame* inlineCallFrame = node->origin.semantic.inlineCallFrame; + if (!inlineCallFrame) { + // We don't need to record anything about how the arguments are to be recovered. It's just a + // given that we can read them from the stack. + break; + } + + unsigned numberOfArgumentsToSkip = 0; + if (node->op() == PhantomCreateRest) + numberOfArgumentsToSkip = node->numberOfArgumentsToSkip(); + + if (inlineCallFrame->isVarargs()) { + // Record how to read each argument and the argument count. + Availability argumentCount = + m_availability.m_locals.operand(inlineCallFrame->stackOffset + CallFrameSlot::argumentCount); + + m_availability.m_heap.set(PromotedHeapLocation(ArgumentCountPLoc, node), argumentCount); + } + + if (inlineCallFrame->isClosureCall) { + Availability callee = m_availability.m_locals.operand( + inlineCallFrame->stackOffset + CallFrameSlot::callee); + m_availability.m_heap.set(PromotedHeapLocation(ArgumentsCalleePLoc, node), callee); + } + + for (unsigned i = numberOfArgumentsToSkip; i < inlineCallFrame->arguments.size() - 1; ++i) { + Availability argument = m_availability.m_locals.operand( + inlineCallFrame->stackOffset + CallFrame::argumentOffset(i)); + + m_availability.m_heap.set(PromotedHeapLocation(ArgumentPLoc, node, i), argument); + } + break; + } + + case PutHint: { + m_availability.m_heap.set( + PromotedHeapLocation(node->child1().node(), node->promotedLocationDescriptor()), + Availability(node->child2().node())); + break; + } + + case PhantomSpread: + m_availability.m_heap.set(PromotedHeapLocation(SpreadPLoc, node), Availability(node->child1().node())); + break; + + case PhantomNewArrayWithSpread: + for (unsigned i = 0; i < node->numChildren(); i++) { + Node* child = m_graph.varArgChild(node, i).node(); + m_availability.m_heap.set(PromotedHeapLocation(NewArrayWithSpreadArgumentPLoc, node, i), Availability(child)); + } + break; + + default: + break; + } +} + } } // namespace JSC::DFG #endif // ENABLE(DFG_JIT) |