summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/dfg/DFGPlan.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/DFGPlan.cpp
parent32761a6cee1d0dee366b885b7b9c777e67885688 (diff)
downloadWebKitGtk-tarball-master.tar.gz
Diffstat (limited to 'Source/JavaScriptCore/dfg/DFGPlan.cpp')
-rw-r--r--Source/JavaScriptCore/dfg/DFGPlan.cpp619
1 files changed, 474 insertions, 145 deletions
diff --git a/Source/JavaScriptCore/dfg/DFGPlan.cpp b/Source/JavaScriptCore/dfg/DFGPlan.cpp
index 735f5ffa2..0307dc63c 100644
--- a/Source/JavaScriptCore/dfg/DFGPlan.cpp
+++ b/Source/JavaScriptCore/dfg/DFGPlan.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2013-2017 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -28,43 +28,57 @@
#if ENABLE(DFG_JIT)
-#include "DFGArgumentsSimplificationPhase.h"
+#include "DFGArgumentsEliminationPhase.h"
#include "DFGBackwardsPropagationPhase.h"
#include "DFGByteCodeParser.h"
#include "DFGCFAPhase.h"
#include "DFGCFGSimplificationPhase.h"
#include "DFGCPSRethreadingPhase.h"
#include "DFGCSEPhase.h"
+#include "DFGCleanUpPhase.h"
#include "DFGConstantFoldingPhase.h"
+#include "DFGConstantHoistingPhase.h"
#include "DFGCriticalEdgeBreakingPhase.h"
#include "DFGDCEPhase.h"
#include "DFGFailedFinalizer.h"
-#include "DFGFlushLivenessAnalysisPhase.h"
#include "DFGFixupPhase.h"
+#include "DFGGraphSafepoint.h"
+#include "DFGIntegerCheckCombiningPhase.h"
+#include "DFGIntegerRangeOptimizationPhase.h"
#include "DFGInvalidationPointInjectionPhase.h"
#include "DFGJITCompiler.h"
#include "DFGLICMPhase.h"
+#include "DFGLiveCatchVariablePreservationPhase.h"
#include "DFGLivenessAnalysisPhase.h"
#include "DFGLoopPreHeaderCreationPhase.h"
+#include "DFGMaximalFlushInsertionPhase.h"
+#include "DFGMovHintRemovalPhase.h"
#include "DFGOSRAvailabilityAnalysisPhase.h"
#include "DFGOSREntrypointCreationPhase.h"
+#include "DFGObjectAllocationSinkingPhase.h"
+#include "DFGPhantomInsertionPhase.h"
#include "DFGPredictionInjectionPhase.h"
#include "DFGPredictionPropagationPhase.h"
-#include "DFGResurrectionForValidationPhase.h"
+#include "DFGPutStackSinkingPhase.h"
#include "DFGSSAConversionPhase.h"
#include "DFGSSALoweringPhase.h"
#include "DFGStackLayoutPhase.h"
-#include "DFGStoreBarrierElisionPhase.h"
+#include "DFGStaticExecutionCountEstimationPhase.h"
+#include "DFGStoreBarrierClusteringPhase.h"
+#include "DFGStoreBarrierInsertionPhase.h"
#include "DFGStrengthReductionPhase.h"
#include "DFGTierUpCheckInjectionPhase.h"
#include "DFGTypeCheckHoistingPhase.h"
#include "DFGUnificationPhase.h"
#include "DFGValidate.h"
+#include "DFGVarargsForwardingPhase.h"
#include "DFGVirtualRegisterAllocationPhase.h"
#include "DFGWatchpointCollectionPhase.h"
-#include "Debugger.h"
+#include "JSCInlines.h"
#include "OperandsInlines.h"
-#include "Operations.h"
+#include "ProfilerDatabase.h"
+#include "TrackedReferences.h"
+#include "VMInlines.h"
#include <wtf/CurrentTime.h>
#if ENABLE(FTL_JIT)
@@ -72,17 +86,27 @@
#include "FTLCompile.h"
#include "FTLFail.h"
#include "FTLLink.h"
-#include "FTLLowerDFGToLLVM.h"
+#include "FTLLowerDFGToB3.h"
#include "FTLState.h"
-#include "InitializeLLVM.h"
#endif
+namespace JSC {
+
+extern double totalDFGCompileTime;
+extern double totalFTLCompileTime;
+extern double totalFTLDFGCompileTime;
+extern double totalFTLB3CompileTime;
+
+}
+
namespace JSC { namespace DFG {
-static void dumpAndVerifyGraph(Graph& graph, const char* text)
+namespace {
+
+void dumpAndVerifyGraph(Graph& graph, const char* text, bool forceDump = false)
{
GraphDumpMode modeForFinalValidate = DumpGraph;
- if (verboseCompilationEnabled()) {
+ if (verboseCompilationEnabled(graph.m_plan.mode) || forceDump) {
dataLog(text, "\n");
graph.dump();
modeForFinalValidate = DontDumpGraph;
@@ -91,18 +115,39 @@ static void dumpAndVerifyGraph(Graph& graph, const char* text)
validate(graph, modeForFinalValidate);
}
-Plan::Plan(
- PassRefPtr<CodeBlock> passedCodeBlock, CompilationMode mode,
- unsigned osrEntryBytecodeIndex, const Operands<JSValue>& mustHandleValues)
- : vm(*passedCodeBlock->vm())
+Profiler::CompilationKind profilerCompilationKindForMode(CompilationMode mode)
+{
+ switch (mode) {
+ case InvalidCompilationMode:
+ RELEASE_ASSERT_NOT_REACHED();
+ return Profiler::DFG;
+ case DFGMode:
+ return Profiler::DFG;
+ case FTLMode:
+ return Profiler::FTL;
+ case FTLForOSREntryMode:
+ return Profiler::FTLForOSREntry;
+ }
+ RELEASE_ASSERT_NOT_REACHED();
+ return Profiler::DFG;
+}
+
+} // anonymous namespace
+
+Plan::Plan(CodeBlock* passedCodeBlock, CodeBlock* profiledDFGCodeBlock,
+ CompilationMode mode, unsigned osrEntryBytecodeIndex,
+ const Operands<JSValue>& mustHandleValues)
+ : vm(passedCodeBlock->vm())
, codeBlock(passedCodeBlock)
+ , profiledDFGCodeBlock(profiledDFGCodeBlock)
, mode(mode)
, osrEntryBytecodeIndex(osrEntryBytecodeIndex)
, mustHandleValues(mustHandleValues)
- , compilation(codeBlock->vm()->m_perBytecodeProfiler ? adoptRef(new Profiler::Compilation(codeBlock->vm()->m_perBytecodeProfiler->ensureBytecodesFor(codeBlock.get()), Profiler::DFG)) : 0)
- , identifiers(codeBlock.get())
- , weakReferences(codeBlock.get())
- , isCompiled(false)
+ , compilation(vm->m_perBytecodeProfiler ? adoptRef(new Profiler::Compilation(vm->m_perBytecodeProfiler->ensureBytecodesFor(codeBlock), profilerCompilationKindForMode(mode))) : 0)
+ , inlineCallFrames(adoptRef(new InlineCallFrameSet()))
+ , identifiers(codeBlock)
+ , weakReferences(codeBlock)
+ , stage(Preparing)
{
}
@@ -110,61 +155,120 @@ Plan::~Plan()
{
}
-void Plan::compileInThread(LongLivedState& longLivedState)
+bool Plan::computeCompileTimes() const
+{
+ return reportCompileTimes()
+ || Options::reportTotalCompileTimes()
+ || (vm && vm->m_perBytecodeProfiler);
+}
+
+bool Plan::reportCompileTimes() const
{
+ return Options::reportCompileTimes()
+ || Options::reportDFGCompileTimes()
+ || (Options::reportFTLCompileTimes() && isFTL(mode));
+}
+
+void Plan::compileInThread(LongLivedState& longLivedState, ThreadData* threadData)
+{
+ this->threadData = threadData;
+
double before = 0;
- if (Options::reportCompileTimes())
- before = currentTimeMS();
+ CString codeBlockName;
+ if (UNLIKELY(computeCompileTimes()))
+ before = monotonicallyIncreasingTimeMS();
+ if (UNLIKELY(reportCompileTimes()))
+ codeBlockName = toCString(*codeBlock);
- SamplingRegion samplingRegion("DFG Compilation (Plan)");
CompilationScope compilationScope;
- if (logCompilationChanges())
+ if (logCompilationChanges(mode) || Options::reportDFGPhaseTimes())
dataLog("DFG(Plan) compiling ", *codeBlock, " with ", mode, ", number of instructions = ", codeBlock->instructionCount(), "\n");
CompilationPath path = compileInThreadImpl(longLivedState);
- RELEASE_ASSERT(finalizer);
-
- if (Options::reportCompileTimes()) {
- const char* pathName;
- switch (path) {
- case FailPath:
- pathName = "N/A (fail)";
- break;
- case DFGPath:
- pathName = "DFG";
- break;
- case FTLPath:
- pathName = "FTL";
- break;
- default:
- RELEASE_ASSERT_NOT_REACHED();
- pathName = "";
- break;
+ RELEASE_ASSERT(path == CancelPath || finalizer);
+ RELEASE_ASSERT((path == CancelPath) == (stage == Cancelled));
+
+ double after = 0;
+ if (UNLIKELY(computeCompileTimes())) {
+ after = monotonicallyIncreasingTimeMS();
+
+ if (Options::reportTotalCompileTimes()) {
+ if (isFTL(mode)) {
+ totalFTLCompileTime += after - before;
+ totalFTLDFGCompileTime += m_timeBeforeFTL - before;
+ totalFTLB3CompileTime += after - m_timeBeforeFTL;
+ } else
+ totalDFGCompileTime += after - before;
}
- double now = currentTimeMS();
- dataLog("Optimized ", *codeBlock->alternative(), " using ", mode, " with ", pathName, " in ", now - before, " ms");
+ }
+ const char* pathName = nullptr;
+ switch (path) {
+ case FailPath:
+ pathName = "N/A (fail)";
+ break;
+ case DFGPath:
+ pathName = "DFG";
+ break;
+ case FTLPath:
+ pathName = "FTL";
+ break;
+ case CancelPath:
+ pathName = "Cancelled";
+ break;
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ break;
+ }
+ if (codeBlock) { // codeBlock will be null if the compilation was cancelled.
+ if (path == FTLPath)
+ CODEBLOCK_LOG_EVENT(codeBlock, "ftlCompile", ("took ", after - before, " ms (DFG: ", m_timeBeforeFTL - before, ", B3: ", after - m_timeBeforeFTL, ") with ", pathName));
+ else
+ CODEBLOCK_LOG_EVENT(codeBlock, "dfgCompile", ("took ", after - before, " ms with ", pathName));
+ }
+ if (UNLIKELY(reportCompileTimes())) {
+ dataLog("Optimized ", codeBlockName, " using ", mode, " with ", pathName, " into ", finalizer ? finalizer->codeSize() : 0, " bytes in ", after - before, " ms");
if (path == FTLPath)
- dataLog(" (DFG: ", beforeFTL - before, ", LLVM: ", now - beforeFTL, ")");
+ dataLog(" (DFG: ", m_timeBeforeFTL - before, ", B3: ", after - m_timeBeforeFTL, ")");
dataLog(".\n");
}
}
Plan::CompilationPath Plan::compileInThreadImpl(LongLivedState& longLivedState)
{
- if (verboseCompilationEnabled() && osrEntryBytecodeIndex != UINT_MAX) {
+ cleanMustHandleValuesIfNecessary();
+
+ if (verboseCompilationEnabled(mode) && osrEntryBytecodeIndex != UINT_MAX) {
dataLog("\n");
dataLog("Compiler must handle OSR entry from bc#", osrEntryBytecodeIndex, " with values: ", mustHandleValues, "\n");
dataLog("\n");
}
- Graph dfg(vm, *this, longLivedState);
+ Graph dfg(*vm, *this, longLivedState);
if (!parse(dfg)) {
- finalizer = adoptPtr(new FailedFinalizer(*this));
+ finalizer = std::make_unique<FailedFinalizer>(*this);
return FailPath;
}
+
+ codeBlock->setCalleeSaveRegisters(RegisterSet::dfgCalleeSaveRegisters());
+
+ bool changed = false;
+
+#define RUN_PHASE(phase) \
+ do { \
+ if (Options::safepointBeforeEachPhase()) { \
+ Safepoint::Result safepointResult; \
+ { \
+ GraphSafepoint safepoint(dfg, safepointResult); \
+ } \
+ if (safepointResult.didGetCancelled()) \
+ return CancelPath; \
+ } \
+ changed |= phase(dfg); \
+ } while (false); \
+
// By this point the DFG bytecode parser will have potentially mutated various tables
// in the CodeBlock. This is a good time to perform an early shrink, which is more
@@ -175,85 +279,119 @@ Plan::CompilationPath Plan::compileInThreadImpl(LongLivedState& longLivedState)
if (validationEnabled())
validate(dfg);
- performCPSRethreading(dfg);
- performUnification(dfg);
- performPredictionInjection(dfg);
+ if (Options::dumpGraphAfterParsing()) {
+ dataLog("Graph after parsing:\n");
+ dfg.dump();
+ }
+
+ RUN_PHASE(performLiveCatchVariablePreservationPhase);
+
+ if (Options::useMaximalFlushInsertionPhase())
+ RUN_PHASE(performMaximalFlushInsertion);
+
+ RUN_PHASE(performCPSRethreading);
+ RUN_PHASE(performUnification);
+ RUN_PHASE(performPredictionInjection);
+
+ RUN_PHASE(performStaticExecutionCountEstimation);
if (mode == FTLForOSREntryMode) {
bool result = performOSREntrypointCreation(dfg);
if (!result) {
- finalizer = adoptPtr(new FailedFinalizer(*this));
+ finalizer = std::make_unique<FailedFinalizer>(*this);
return FailPath;
}
- performCPSRethreading(dfg);
+ RUN_PHASE(performCPSRethreading);
}
if (validationEnabled())
validate(dfg);
- performBackwardsPropagation(dfg);
- performPredictionPropagation(dfg);
- performFixup(dfg);
- performInvalidationPointInjection(dfg);
- performTypeCheckHoisting(dfg);
+ RUN_PHASE(performBackwardsPropagation);
+ RUN_PHASE(performPredictionPropagation);
+ RUN_PHASE(performFixup);
+ RUN_PHASE(performInvalidationPointInjection);
+ RUN_PHASE(performTypeCheckHoisting);
- unsigned count = 1;
dfg.m_fixpointState = FixpointNotConverged;
- for (;; ++count) {
- if (logCompilationChanges())
- dataLogF("DFG beginning optimization fixpoint iteration #%u.\n", count);
- bool changed = false;
-
- if (validationEnabled())
- validate(dfg);
-
- changed |= performStrengthReduction(dfg);
- performCFA(dfg);
- changed |= performConstantFolding(dfg);
- changed |= performArgumentsSimplification(dfg);
- changed |= performCFGSimplification(dfg);
- changed |= performCSE(dfg);
+
+ // For now we're back to avoiding a fixpoint. Note that we've ping-ponged on this decision
+ // many times. For maximum throughput, it's best to fixpoint. But the throughput benefit is
+ // small and not likely to show up in FTL anyway. On the other hand, not fixpointing means
+ // that the compiler compiles more quickly. We want the third tier to compile quickly, which
+ // not fixpointing accomplishes; and the fourth tier shouldn't need a fixpoint.
+ if (validationEnabled())
+ validate(dfg);
- if (!changed)
- break;
+ RUN_PHASE(performStrengthReduction);
+ RUN_PHASE(performCPSRethreading);
+ RUN_PHASE(performCFA);
+ RUN_PHASE(performConstantFolding);
+ changed = false;
+ RUN_PHASE(performCFGSimplification);
+ RUN_PHASE(performLocalCSE);
+
+ if (validationEnabled())
+ validate(dfg);
+
+ RUN_PHASE(performCPSRethreading);
+ if (!isFTL(mode)) {
+ // Only run this if we're not FTLing, because currently for a LoadVarargs that is forwardable and
+ // in a non-varargs inlined call frame, this will generate ForwardVarargs while the FTL
+ // ArgumentsEliminationPhase will create a sequence of GetStack+PutStacks. The GetStack+PutStack
+ // sequence then gets sunk, eliminating anything that looks like an escape for subsequent phases,
+ // while the ForwardVarargs doesn't get simplified until later (or not at all) and looks like an
+ // escape for all of the arguments. This then disables object allocation sinking.
+ //
+ // So, for now, we just disable this phase for the FTL.
+ //
+ // If we wanted to enable it, we'd have to do any of the following:
+ // - Enable ForwardVarargs->GetStack+PutStack strength reduction, and have that run before
+ // PutStack sinking and object allocation sinking.
+ // - Make VarargsForwarding emit a GetLocal+SetLocal sequence, that we can later turn into
+ // GetStack+PutStack.
+ //
+ // But, it's not super valuable to enable those optimizations, since the FTL
+ // ArgumentsEliminationPhase does everything that this phase does, and it doesn't introduce this
+ // pathology.
- performCPSRethreading(dfg);
+ RUN_PHASE(performVarargsForwarding); // Do this after CFG simplification and CPS rethreading.
+ }
+ if (changed) {
+ RUN_PHASE(performCFA);
+ RUN_PHASE(performConstantFolding);
}
-
- if (logCompilationChanges())
- dataLogF("DFG optimization fixpoint converged in %u iterations.\n", count);
-
- dfg.m_fixpointState = FixpointConverged;
-
- performStoreBarrierElision(dfg);
- performStoreElimination(dfg);
// If we're doing validation, then run some analyses, to give them an opportunity
// to self-validate. Now is as good a time as any to do this.
if (validationEnabled()) {
- dfg.m_dominators.computeIfNecessary(dfg);
- dfg.m_naturalLoops.computeIfNecessary(dfg);
+ dfg.ensureDominators();
+ dfg.ensureNaturalLoops();
+ dfg.ensurePrePostNumbering();
}
switch (mode) {
case DFGMode: {
- performTierUpCheckInjection(dfg);
+ dfg.m_fixpointState = FixpointConverged;
+
+ RUN_PHASE(performTierUpCheckInjection);
- performCPSRethreading(dfg);
- performDCE(dfg);
- performStackLayout(dfg);
- performVirtualRegisterAllocation(dfg);
- performWatchpointCollection(dfg);
+ RUN_PHASE(performFastStoreBarrierInsertion);
+ RUN_PHASE(performStoreBarrierClustering);
+ RUN_PHASE(performCleanUp);
+ RUN_PHASE(performCPSRethreading);
+ RUN_PHASE(performDCE);
+ RUN_PHASE(performPhantomInsertion);
+ RUN_PHASE(performStackLayout);
+ RUN_PHASE(performVirtualRegisterAllocation);
+ RUN_PHASE(performWatchpointCollection);
dumpAndVerifyGraph(dfg, "Graph after optimization:");
JITCompiler dataFlowJIT(dfg);
- if (codeBlock->codeType() == FunctionCode) {
+ if (codeBlock->codeType() == FunctionCode)
dataFlowJIT.compileFunction();
- dataFlowJIT.linkFunction();
- } else {
+ else
dataFlowJIT.compile();
- dataFlowJIT.link();
- }
return DFGPath;
}
@@ -262,53 +400,130 @@ Plan::CompilationPath Plan::compileInThreadImpl(LongLivedState& longLivedState)
case FTLForOSREntryMode: {
#if ENABLE(FTL_JIT)
if (FTL::canCompile(dfg) == FTL::CannotCompile) {
- finalizer = adoptPtr(new FailedFinalizer(*this));
+ finalizer = std::make_unique<FailedFinalizer>(*this);
return FailPath;
}
- performCriticalEdgeBreaking(dfg);
- performLoopPreHeaderCreation(dfg);
- performCPSRethreading(dfg);
- performSSAConversion(dfg);
- performSSALowering(dfg);
- performLivenessAnalysis(dfg);
- performCFA(dfg);
- performLICM(dfg);
- performCSE(dfg);
- performLivenessAnalysis(dfg);
- performCFA(dfg);
- if (Options::validateFTLOSRExitLiveness())
- performResurrectionForValidation(dfg);
- performDCE(dfg); // We rely on this to convert dead SetLocals into the appropriate hint, and to kill dead code that won't be recognized as dead by LLVM.
- performStackLayout(dfg);
- performLivenessAnalysis(dfg);
- performFlushLivenessAnalysis(dfg);
- performOSRAvailabilityAnalysis(dfg);
- performWatchpointCollection(dfg);
+ RUN_PHASE(performCleanUp); // Reduce the graph size a bit.
+ RUN_PHASE(performCriticalEdgeBreaking);
+ if (Options::createPreHeaders())
+ RUN_PHASE(performLoopPreHeaderCreation);
+ RUN_PHASE(performCPSRethreading);
+ RUN_PHASE(performSSAConversion);
+ RUN_PHASE(performSSALowering);
- dumpAndVerifyGraph(dfg, "Graph just before FTL lowering:");
+ // Ideally, these would be run to fixpoint with the object allocation sinking phase.
+ RUN_PHASE(performArgumentsElimination);
+ if (Options::usePutStackSinking())
+ RUN_PHASE(performPutStackSinking);
- initializeLLVM();
+ RUN_PHASE(performConstantHoisting);
+ RUN_PHASE(performGlobalCSE);
+ RUN_PHASE(performLivenessAnalysis);
+ RUN_PHASE(performCFA);
+ RUN_PHASE(performConstantFolding);
+ RUN_PHASE(performCleanUp); // Reduce the graph size a lot.
+ changed = false;
+ RUN_PHASE(performStrengthReduction);
+ if (Options::useObjectAllocationSinking()) {
+ RUN_PHASE(performCriticalEdgeBreaking);
+ RUN_PHASE(performObjectAllocationSinking);
+ }
+ if (changed) {
+ // State-at-tail and state-at-head will be invalid if we did strength reduction since
+ // it might increase live ranges.
+ RUN_PHASE(performLivenessAnalysis);
+ RUN_PHASE(performCFA);
+ RUN_PHASE(performConstantFolding);
+ }
+
+ // Currently, this relies on pre-headers still being valid. That precludes running CFG
+ // simplification before it, unless we re-created the pre-headers. There wouldn't be anything
+ // wrong with running LICM earlier, if we wanted to put other CFG transforms above this point.
+ // Alternatively, we could run loop pre-header creation after SSA conversion - but if we did that
+ // then we'd need to do some simple SSA fix-up.
+ RUN_PHASE(performLivenessAnalysis);
+ RUN_PHASE(performCFA);
+ RUN_PHASE(performLICM);
+
+ // FIXME: Currently: IntegerRangeOptimization *must* be run after LICM.
+ //
+ // IntegerRangeOptimization makes changes on nodes based on preceding blocks
+ // and nodes. LICM moves nodes which can invalidates assumptions used
+ // by IntegerRangeOptimization.
+ //
+ // Ideally, the dependencies should be explicit. See https://bugs.webkit.org/show_bug.cgi?id=157534.
+ RUN_PHASE(performLivenessAnalysis);
+ RUN_PHASE(performIntegerRangeOptimization);
+
+ RUN_PHASE(performCleanUp);
+ RUN_PHASE(performIntegerCheckCombining);
+ RUN_PHASE(performGlobalCSE);
+ // At this point we're not allowed to do any further code motion because our reasoning
+ // about code motion assumes that it's OK to insert GC points in random places.
+ dfg.m_fixpointState = FixpointConverged;
+
+ RUN_PHASE(performLivenessAnalysis);
+ RUN_PHASE(performCFA);
+ RUN_PHASE(performGlobalStoreBarrierInsertion);
+ RUN_PHASE(performStoreBarrierClustering);
+ if (Options::useMovHintRemoval())
+ RUN_PHASE(performMovHintRemoval);
+ RUN_PHASE(performCleanUp);
+ RUN_PHASE(performDCE); // We rely on this to kill dead code that won't be recognized as dead by B3.
+ RUN_PHASE(performStackLayout);
+ RUN_PHASE(performLivenessAnalysis);
+ RUN_PHASE(performOSRAvailabilityAnalysis);
+ RUN_PHASE(performWatchpointCollection);
+
+ if (FTL::canCompile(dfg) == FTL::CannotCompile) {
+ finalizer = std::make_unique<FailedFinalizer>(*this);
+ return FailPath;
+ }
+
+ dumpAndVerifyGraph(dfg, "Graph just before FTL lowering:", shouldDumpDisassembly(mode));
+
+ // Flash a safepoint in case the GC wants some action.
+ Safepoint::Result safepointResult;
+ {
+ GraphSafepoint safepoint(dfg, safepointResult);
+ }
+ if (safepointResult.didGetCancelled())
+ return CancelPath;
+
FTL::State state(dfg);
- FTL::lowerDFGToLLVM(state);
+ FTL::lowerDFGToB3(state);
- if (Options::reportCompileTimes())
- beforeFTL = currentTimeMS();
+ if (UNLIKELY(computeCompileTimes()))
+ m_timeBeforeFTL = monotonicallyIncreasingTimeMS();
- if (Options::llvmAlwaysFailsBeforeCompile()) {
+ if (Options::b3AlwaysFailsBeforeCompile()) {
FTL::fail(state);
return FTLPath;
}
- FTL::compile(state);
-
- if (Options::llvmAlwaysFailsBeforeLink()) {
+ FTL::compile(state, safepointResult);
+ if (safepointResult.didGetCancelled())
+ return CancelPath;
+
+ if (Options::b3AlwaysFailsBeforeLink()) {
FTL::fail(state);
return FTLPath;
}
+ if (state.allocationFailed) {
+ FTL::fail(state);
+ return FTLPath;
+ }
+
FTL::link(state);
+
+ if (state.allocationFailed) {
+ FTL::fail(state);
+ return FTLPath;
+ }
+
return FTLPath;
#else
RELEASE_ASSERT_NOT_REACHED();
@@ -320,40 +535,54 @@ Plan::CompilationPath Plan::compileInThreadImpl(LongLivedState& longLivedState)
RELEASE_ASSERT_NOT_REACHED();
return FailPath;
}
+
+#undef RUN_PHASE
}
bool Plan::isStillValid()
{
- return watchpoints.areStillValid()
- && chains.areStillValid();
+ CodeBlock* replacement = codeBlock->replacement();
+ if (!replacement)
+ return false;
+ // FIXME: This is almost certainly not necessary. There's no way for the baseline
+ // code to be replaced during a compilation, except if we delete the plan, in which
+ // case we wouldn't be here.
+ // https://bugs.webkit.org/show_bug.cgi?id=132707
+ if (codeBlock->alternative() != replacement->baselineVersion())
+ return false;
+ if (!watchpoints.areStillValid())
+ return false;
+ return true;
}
void Plan::reallyAdd(CommonData* commonData)
{
- watchpoints.reallyAdd(codeBlock.get(), *commonData);
- identifiers.reallyAdd(vm, commonData);
- weakReferences.reallyAdd(vm, commonData);
- transitions.reallyAdd(vm, commonData);
- writeBarriers.trigger(vm);
+ watchpoints.reallyAdd(codeBlock, *commonData);
+ identifiers.reallyAdd(*vm, commonData);
+ weakReferences.reallyAdd(*vm, commonData);
+ transitions.reallyAdd(*vm, commonData);
+}
+
+void Plan::notifyCompiling()
+{
+ stage = Compiling;
}
void Plan::notifyReady()
{
- callback->compilationDidBecomeReadyAsynchronously(codeBlock.get());
- isCompiled = true;
+ callback->compilationDidBecomeReadyAsynchronously(codeBlock, profiledDFGCodeBlock);
+ stage = Ready;
}
CompilationResult Plan::finalizeWithoutNotifyingCallback()
{
- if (!isStillValid())
- return CompilationInvalidated;
-
- if (vm.enabledProfiler())
- return CompilationInvalidated;
-
- Debugger* debugger = codeBlock->globalObject()->debugger();
- if (debugger && (debugger->isStepping() || codeBlock->baselineAlternative()->hasDebuggerRequests()))
+ // We will establish new references from the code block to things. So, we need a barrier.
+ vm->heap.writeBarrier(codeBlock);
+
+ if (!isStillValid()) {
+ CODEBLOCK_LOG_EVENT(codeBlock, "dfgFinalize", ("invalidated"));
return CompilationInvalidated;
+ }
bool result;
if (codeBlock->codeType() == FunctionCode)
@@ -361,17 +590,40 @@ CompilationResult Plan::finalizeWithoutNotifyingCallback()
else
result = finalizer->finalize();
- if (!result)
+ if (!result) {
+ CODEBLOCK_LOG_EVENT(codeBlock, "dfgFinalize", ("failed"));
return CompilationFailed;
+ }
reallyAdd(codeBlock->jitCode()->dfgCommon());
+ if (validationEnabled()) {
+ TrackedReferences trackedReferences;
+
+ for (WriteBarrier<JSCell>& reference : codeBlock->jitCode()->dfgCommon()->weakReferences)
+ trackedReferences.add(reference.get());
+ for (WriteBarrier<Structure>& reference : codeBlock->jitCode()->dfgCommon()->weakStructureReferences)
+ trackedReferences.add(reference.get());
+ for (WriteBarrier<Unknown>& constant : codeBlock->constants())
+ trackedReferences.add(constant.get());
+
+ for (auto* inlineCallFrame : *inlineCallFrames) {
+ ASSERT(inlineCallFrame->baselineCodeBlock.get());
+ trackedReferences.add(inlineCallFrame->baselineCodeBlock.get());
+ }
+
+ // Check that any other references that we have anywhere in the JITCode are also
+ // tracked either strongly or weakly.
+ codeBlock->jitCode()->validateReferences(trackedReferences);
+ }
+
+ CODEBLOCK_LOG_EVENT(codeBlock, "dfgFinalize", ("succeeded"));
return CompilationSuccessful;
}
void Plan::finalizeAndNotifyCallback()
{
- callback->compilationDidComplete(codeBlock.get(), finalizeWithoutNotifyingCallback());
+ callback->compilationDidComplete(codeBlock, profiledDFGCodeBlock, finalizeWithoutNotifyingCallback());
}
CompilationKey Plan::key()
@@ -379,6 +631,83 @@ CompilationKey Plan::key()
return CompilationKey(codeBlock->alternative(), mode);
}
+void Plan::checkLivenessAndVisitChildren(SlotVisitor& visitor)
+{
+ if (!isKnownToBeLiveDuringGC())
+ return;
+
+ cleanMustHandleValuesIfNecessary();
+ for (unsigned i = mustHandleValues.size(); i--;)
+ visitor.appendUnbarriered(mustHandleValues[i]);
+
+ visitor.appendUnbarriered(codeBlock);
+ visitor.appendUnbarriered(codeBlock->alternative());
+ visitor.appendUnbarriered(profiledDFGCodeBlock);
+
+ if (inlineCallFrames) {
+ for (auto* inlineCallFrame : *inlineCallFrames) {
+ ASSERT(inlineCallFrame->baselineCodeBlock.get());
+ visitor.appendUnbarriered(inlineCallFrame->baselineCodeBlock.get());
+ }
+ }
+
+ weakReferences.visitChildren(visitor);
+ transitions.visitChildren(visitor);
+}
+
+bool Plan::isKnownToBeLiveDuringGC()
+{
+ if (stage == Cancelled)
+ return false;
+ if (!Heap::isMarked(codeBlock->ownerExecutable()))
+ return false;
+ if (!Heap::isMarked(codeBlock->alternative()))
+ return false;
+ if (!!profiledDFGCodeBlock && !Heap::isMarked(profiledDFGCodeBlock))
+ return false;
+ return true;
+}
+
+void Plan::cancel()
+{
+ vm = nullptr;
+ codeBlock = nullptr;
+ profiledDFGCodeBlock = nullptr;
+ mustHandleValues.clear();
+ compilation = nullptr;
+ finalizer = nullptr;
+ inlineCallFrames = nullptr;
+ watchpoints = DesiredWatchpoints();
+ identifiers = DesiredIdentifiers();
+ weakReferences = DesiredWeakReferences();
+ transitions = DesiredTransitions();
+ callback = nullptr;
+ stage = Cancelled;
+}
+
+void Plan::cleanMustHandleValuesIfNecessary()
+{
+ LockHolder locker(mustHandleValueCleaningLock);
+
+ if (!mustHandleValuesMayIncludeGarbage)
+ return;
+
+ mustHandleValuesMayIncludeGarbage = false;
+
+ if (!codeBlock)
+ return;
+
+ if (!mustHandleValues.numberOfLocals())
+ return;
+
+ FastBitVector liveness = codeBlock->alternative()->livenessAnalysis().getLivenessInfoAtBytecodeOffset(osrEntryBytecodeIndex);
+
+ for (unsigned local = mustHandleValues.numberOfLocals(); local--;) {
+ if (!liveness[local])
+ mustHandleValues.local(local) = jsUndefined();
+ }
+}
+
} } // namespace JSC::DFG
#endif // ENABLE(DFG_JIT)