summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/dfg/DFGOSRAvailabilityAnalysisPhase.cpp
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
commit1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch)
tree46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/JavaScriptCore/dfg/DFGOSRAvailabilityAnalysisPhase.cpp
parent32761a6cee1d0dee366b885b7b9c777e67885688 (diff)
downloadWebKitGtk-tarball-master.tar.gz
Diffstat (limited to 'Source/JavaScriptCore/dfg/DFGOSRAvailabilityAnalysisPhase.cpp')
-rw-r--r--Source/JavaScriptCore/dfg/DFGOSRAvailabilityAnalysisPhase.cpp250
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)