source: webkit/trunk/Source/JavaScriptCore/dfg/DFGPlan.cpp

Last change on this file was 294873, checked in by [email protected], 3 years ago

[JSC] Introduce unlinked StructureStubInfo into uDFG
https://bugs.webkit.org/show_bug.cgi?id=240557

Reviewed by Saam Barati.

This patch introduces unlinked StructureStubInfo into uDFG. To make it work, we refactor existing StructureStubInfo mechanism
to make unlinked StructureStubInfo first citizen instead of adhoc code.

  1. JITXXXGenerator takes CompileTimeStructureStubInfo as its argument. It is variant of unlinked / linked StructureStubInfo. And we configure registers etc. in one place. JITXXXGenerator sets necessary fields for each type of StructureStubInfo so we have massive less code in Baseline and uDFG.
  2. DFG::JITCompiler::LinkableConstant takes DFG::JITCompiler instead of DFG::Graph to make code simpler.
  3. Introduce DFG::LinkerIR, which is currently just a constant pool. We will eventually extend it to support many uDFG LinkerIR opcodes.
  4. Clean up some of unused registers in some JITXXXGenerator to make code simpler.
  5. Rename useDataICInOptimizingJIT to useDataICInFTL and use it only for FTL. That flag was used to keep maintaining DataIC in DFG / FTL, and in uDFG case, we already have forceUnlinkedDFG flag.
  • Tools/Scripts/run-jsc-stress-tests:
  • JSTests/microbenchmarks/deltablue-varargs.js:
  • JSTests/microbenchmarks/richards-try-catch.js:
  • Source/JavaScriptCore/bytecode/AccessCase.cpp:

(JSC::AccessCase::generateWithGuard):
(JSC::AccessCase::generateImpl):

  • Source/JavaScriptCore/bytecode/CodeBlock.cpp:

(JSC::CodeBlock::setupWithUnlinkedBaselineCode):
(JSC::CodeBlock::~CodeBlock):
(JSC::CodeBlock::propagateTransitions):
(JSC::CodeBlock::finalizeJITInlineCaches):
(JSC::CodeBlock::getICStatusMap):
(JSC::CodeBlock::findStubInfo):
(JSC::CodeBlock::stronglyVisitStrongReferences):
(JSC::CodeBlock::findPC):
(JSC::CodeBlock::useDataIC const):

  • Source/JavaScriptCore/bytecode/CodeBlock.h:

(JSC::CodeBlock::useDataIC const): Deleted.

  • Source/JavaScriptCore/bytecode/InlineAccess.cpp:

(JSC::InlineAccess::generateSelfPropertyAccess):
(JSC::getScratchRegister):
(JSC::InlineAccess::generateSelfPropertyReplace):
(JSC::InlineAccess::generateArrayLength):
(JSC::InlineAccess::generateStringLength):
(JSC::InlineAccess::generateSelfInAccess):

  • Source/JavaScriptCore/bytecode/PolymorphicAccess.cpp:

(JSC::AccessGenerationState::makeDefaultScratchAllocator):
(JSC::PolymorphicAccess::regenerate):

  • Source/JavaScriptCore/bytecode/PolymorphicAccess.h:

(JSC::AccessGenerationState::AccessGenerationState):

  • Source/JavaScriptCore/bytecode/StructureStubInfo.cpp:

(JSC::slowOperationFromUnlinkedStructureStubInfo):
(JSC::StructureStubInfo::initializeFromUnlinkedStructureStubInfo):
(JSC::StructureStubInfo::initializeFromDFGUnlinkedStructureStubInfo):
(JSC::StructureStubInfo::checkConsistency):

  • Source/JavaScriptCore/bytecode/StructureStubInfo.h:

(JSC::StructureStubInfo::StructureStubInfo):
(JSC::StructureStubInfo::valueRegs const):
(JSC::StructureStubInfo::propertyRegs const):
(JSC::StructureStubInfo::baseRegs const):
(JSC::StructureStubInfo::thisValueIsInExtraGPR const):
(JSC::StructureStubInfo::thisGPR const):
(JSC::StructureStubInfo::prototypeGPR const):
(JSC::StructureStubInfo::propertyGPR const):
(JSC::StructureStubInfo::brandGPR const):
(JSC::StructureStubInfo::thisValueIsInThisGPR const): Deleted.

  • Source/JavaScriptCore/dfg/DFGInlineCacheWrapperInlines.h:

(JSC::DFG::InlineCacheWrapper<GeneratorType>::finalize):

  • Source/JavaScriptCore/dfg/DFGJITCode.cpp:

(JSC::DFG::JITData::JITData):

  • Source/JavaScriptCore/dfg/DFGJITCode.h:

(JSC::DFG::LinkerIR::ValueHash::hash):
(JSC::DFG::LinkerIR::ValueHash::equal):
(JSC::DFG::LinkerIR::ValueTraits::emptyValue):
(JSC::DFG::LinkerIR::ValueTraits::constructDeletedValue):
(JSC::DFG::LinkerIR::ValueTraits::isDeletedValue):
(JSC::DFG::LinkerIR::LinkerIR):
(JSC::DFG::LinkerIR::size const):
(JSC::DFG::LinkerIR::at const):
(JSC::DFG::JITData::create):

  • Source/JavaScriptCore/dfg/DFGJITCompiler.cpp:

(JSC::DFG::JITCompiler::link):
(JSC::DFG::JITCompiler::loadConstant):
(JSC::DFG::JITCompiler::LinkableConstant::LinkableConstant):
(JSC::DFG::JITCompiler::addToConstantPool):
(JSC::DFG::JITCompiler::addStructureStubInfo):

  • Source/JavaScriptCore/dfg/DFGJITCompiler.h:
  • Source/JavaScriptCore/dfg/DFGPlan.cpp:

(JSC::DFG::Plan::finalizeJITData):
(JSC::DFG::Plan::addLinkableConstant): Deleted.

  • Source/JavaScriptCore/dfg/DFGPlan.h:
  • Source/JavaScriptCore/dfg/DFGSlowPathGenerator.h:

(JSC::DFG::slowPathICCall):

  • Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp:

(JSC::DFG::SpeculativeJIT::emitGetCallee):
(JSC::DFG::SpeculativeJIT::silentFill):
(JSC::DFG::SpeculativeJIT::compileGetById):
(JSC::DFG::SpeculativeJIT::compileGetByIdFlush):
(JSC::DFG::SpeculativeJIT::compileDeleteById):
(JSC::DFG::SpeculativeJIT::compileDeleteByVal):
(JSC::DFG::SpeculativeJIT::compileInById):
(JSC::DFG::SpeculativeJIT::compileInByVal):
(JSC::DFG::SpeculativeJIT::compileHasPrivate):
(JSC::DFG::SpeculativeJIT::compilePushWithScope):
(JSC::DFG::SpeculativeJIT::compileStringSlice):
(JSC::DFG::SpeculativeJIT::compileToLowerCase):
(JSC::DFG::SpeculativeJIT::compileCheckTraps):
(JSC::DFG::SpeculativeJIT::compileContiguousPutByVal):
(JSC::DFG::SpeculativeJIT::compileDoublePutByVal):
(JSC::DFG::SpeculativeJIT::compilePutByVal):
(JSC::DFG::SpeculativeJIT::compileGetByValOnString):
(JSC::DFG::SpeculativeJIT::compileFromCharCode):
(JSC::DFG::SpeculativeJIT::compilePutByValForIntTypedArray):

  • Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h:
  • Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp:

(JSC::DFG::SpeculativeJIT::cachedGetById):
(JSC::DFG::SpeculativeJIT::cachedGetByIdWithThis):
(JSC::DFG::SpeculativeJIT::nonSpeculativeNonPeepholeCompareNullOrUndefined):
(JSC::DFG::SpeculativeJIT::nonSpeculativePeepholeBranchNullOrUndefined):
(JSC::DFG::SpeculativeJIT::nonSpeculativePeepholeStrictEq):
(JSC::DFG::SpeculativeJIT::genericJSValueNonPeepholeStrictEq):
(JSC::DFG::SpeculativeJIT::emitCall):
(JSC::DFG::SpeculativeJIT::compileToBooleanObjectOrOther):
(JSC::DFG::SpeculativeJIT::emitObjectOrOtherBranch):
(JSC::DFG::SpeculativeJIT::compileGetByVal):
(JSC::DFG::SpeculativeJIT::compile):
(JSC::DFG::SpeculativeJIT::compileArithRandom):

  • Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp:

(JSC::DFG::SpeculativeJIT::cachedGetById):
(JSC::DFG::SpeculativeJIT::cachedGetByIdWithThis):
(JSC::DFG::SpeculativeJIT::nonSpeculativeNonPeepholeCompareNullOrUndefined):
(JSC::DFG::SpeculativeJIT::nonSpeculativePeepholeBranchNullOrUndefined):
(JSC::DFG::SpeculativeJIT::nonSpeculativePeepholeStrictEq):
(JSC::DFG::SpeculativeJIT::genericJSValueNonPeepholeStrictEq):
(JSC::DFG::SpeculativeJIT::emitCall):
(JSC::DFG::SpeculativeJIT::compileCompareEqPtr):
(JSC::DFG::SpeculativeJIT::compileToBooleanObjectOrOther):
(JSC::DFG::SpeculativeJIT::emitObjectOrOtherBranch):
(JSC::DFG::SpeculativeJIT::emitUntypedBranch):
(JSC::DFG::SpeculativeJIT::compileGetByVal):
(JSC::DFG::SpeculativeJIT::compileRegExpTestInline):
(JSC::DFG::SpeculativeJIT::compile):

  • Source/JavaScriptCore/dfg/DFGStrengthReductionPhase.cpp:

(JSC::DFG::StrengthReductionPhase::handleNode):

  • Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp:

(JSC::FTL::DFG::LowerDFGToB3::getPrivateName):
(JSC::FTL::DFG::LowerDFGToB3::compilePrivateBrandAccess):
(JSC::FTL::DFG::LowerDFGToB3::compilePutPrivateName):
(JSC::FTL::DFG::LowerDFGToB3::cachedPutById):
(JSC::FTL::DFG::LowerDFGToB3::compileGetByValImpl):
(JSC::FTL::DFG::LowerDFGToB3::compilePutByVal):
(JSC::FTL::DFG::LowerDFGToB3::compileDelBy):
(JSC::FTL::DFG::LowerDFGToB3::compileCompareStrictEq):

  • Source/JavaScriptCore/ftl/FTLState.cpp:

(JSC::FTL::State::addStructureStubInfo):

  • Source/JavaScriptCore/ftl/FTLState.h:
  • Source/JavaScriptCore/jit/BaselineJITCode.h:
  • Source/JavaScriptCore/jit/BaselineJITRegisters.h:
  • Source/JavaScriptCore/jit/GPRInfo.h:

(JSC::JSValueRegs::gpr const):
(JSC::JSValueRegs::JSValueRegs):
(JSC::JSValueRegs::withTwoAvailableRegs):

  • Source/JavaScriptCore/jit/IntrinsicEmitter.cpp:

(JSC::IntrinsicGetterAccessCase::canEmitIntrinsicGetter):

  • Source/JavaScriptCore/jit/JIT.cpp:

(JSC::JIT::addUnlinkedStructureStubInfo):
(JSC::JIT::link):

  • Source/JavaScriptCore/jit/JIT.h:
  • Source/JavaScriptCore/jit/JITCall.cpp:

(JSC::JIT::emit_op_iterator_open):
(JSC::JIT::emit_op_iterator_next):

  • Source/JavaScriptCore/jit/JITCode.h:

(JSC::JITCode::useDataIC): Deleted.

  • Source/JavaScriptCore/jit/JITInlineCacheGenerator.cpp:

(JSC::JITInlineCacheGenerator::JITInlineCacheGenerator):
(JSC::JITInlineCacheGenerator::finalize):
(JSC::JITInlineCacheGenerator::generateDFGDataICFastPath):
(JSC::JITInlineCacheGenerator::generateBaselineDataICFastPath):
(JSC::JITByIdGenerator::JITByIdGenerator):
(JSC::JITByIdGenerator::finalize):
(JSC::JITByIdGenerator::generateFastCommon):
(JSC::JITGetByIdGenerator::JITGetByIdGenerator):
(JSC::JITGetByIdGenerator::generateFastPath):
(JSC::JITGetByIdGenerator::generateBaselineDataICFastPath):
(JSC::JITGetByIdGenerator::generateDFGDataICFastPath):
(JSC::JITGetByIdWithThisGenerator::JITGetByIdWithThisGenerator):
(JSC::JITGetByIdWithThisGenerator::generateFastPath):
(JSC::JITGetByIdWithThisGenerator::generateBaselineDataICFastPath):
(JSC::JITGetByIdWithThisGenerator::generateDFGDataICFastPath):
(JSC::JITPutByIdGenerator::JITPutByIdGenerator):
(JSC::JITPutByIdGenerator::generateBaselineDataICFastPath):
(JSC::JITPutByIdGenerator::generateDFGDataICFastPath):
(JSC::JITPutByIdGenerator::generateFastPath):
(JSC::JITDelByValGenerator::JITDelByValGenerator):
(JSC::JITDelByValGenerator::generateFastPath):
(JSC::JITDelByValGenerator::finalize):
(JSC::JITDelByIdGenerator::JITDelByIdGenerator):
(JSC::JITDelByIdGenerator::generateFastPath):
(JSC::JITDelByIdGenerator::finalize):
(JSC::JITInByValGenerator::JITInByValGenerator):
(JSC::JITInByValGenerator::generateFastPath):
(JSC::JITInByValGenerator::finalize):
(JSC::JITInByIdGenerator::JITInByIdGenerator):
(JSC::JITInByIdGenerator::generateFastPath):
(JSC::JITInByIdGenerator::generateBaselineDataICFastPath):
(JSC::JITInByIdGenerator::generateDFGDataICFastPath):
(JSC::JITInstanceOfGenerator::JITInstanceOfGenerator):
(JSC::JITInstanceOfGenerator::generateFastPath):
(JSC::JITInstanceOfGenerator::finalize):
(JSC::JITGetByValGenerator::JITGetByValGenerator):
(JSC::JITGetByValGenerator::generateFastPath):
(JSC::JITGetByValGenerator::finalize):
(JSC::JITPutByValGenerator::JITPutByValGenerator):
(JSC::JITPutByValGenerator::generateFastPath):
(JSC::JITPutByValGenerator::finalize):
(JSC::JITPrivateBrandAccessGenerator::JITPrivateBrandAccessGenerator):
(JSC::JITPrivateBrandAccessGenerator::generateFastPath):
(JSC::JITPrivateBrandAccessGenerator::finalize):

  • Source/JavaScriptCore/jit/JITInlineCacheGenerator.h:

(JSC::JITInlineCacheGenerator::setUpStubInfoImpl):
(JSC::JITByIdGenerator::setUpStubInfoImpl):
(JSC::JITInByValGenerator::setUpStubInfo):

  • Source/JavaScriptCore/jit/JITOpcodes.cpp:

(JSC::JIT::emit_op_instanceof):

  • Source/JavaScriptCore/jit/JITPropertyAccess.cpp:

(JSC::JIT::emit_op_get_by_val):
(JSC::JIT::emit_op_get_private_name):
(JSC::JIT::emit_op_set_private_brand):
(JSC::JIT::emit_op_check_private_brand):
(JSC::JIT::emit_op_put_by_val):
(JSC::JIT::emit_op_put_private_name):
(JSC::JIT::emit_op_del_by_id):
(JSC::JIT::emit_op_del_by_val):
(JSC::JIT::emit_op_try_get_by_id):
(JSC::JIT::emit_op_get_by_id_direct):
(JSC::JIT::emit_op_get_by_id):
(JSC::JIT::emit_op_get_by_id_with_this):
(JSC::JIT::emit_op_put_by_id):
(JSC::JIT::emit_op_in_by_id):
(JSC::JIT::emit_op_in_by_val):
(JSC::JIT::emitHasPrivate):
(JSC::JIT::emit_op_enumerator_get_by_val):

  • Source/JavaScriptCore/runtime/OptionsList.h:
  • Source/WTF/wtf/CompactPointerTuple.h:

Canonical link: https://commits.webkit.org/251003@main

  • Property svn:eol-style set to native
File size: 24.7 KB
Line 
1/*
2 * Copyright (C) 2013-2021 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "DFGPlan.h"
28
29#if ENABLE(DFG_JIT)
30
31#include "DFGArgumentsEliminationPhase.h"
32#include "DFGByteCodeParser.h"
33#include "DFGCFAPhase.h"
34#include "DFGCFGSimplificationPhase.h"
35#include "DFGCPSRethreadingPhase.h"
36#include "DFGCSEPhase.h"
37#include "DFGCleanUpPhase.h"
38#include "DFGConstantFoldingPhase.h"
39#include "DFGConstantHoistingPhase.h"
40#include "DFGCriticalEdgeBreakingPhase.h"
41#include "DFGDCEPhase.h"
42#include "DFGFailedFinalizer.h"
43#include "DFGFixupPhase.h"
44#include "DFGGraphSafepoint.h"
45#include "DFGIntegerCheckCombiningPhase.h"
46#include "DFGIntegerRangeOptimizationPhase.h"
47#include "DFGInvalidationPointInjectionPhase.h"
48#include "DFGJITCompiler.h"
49#include "DFGLICMPhase.h"
50#include "DFGLiveCatchVariablePreservationPhase.h"
51#include "DFGLivenessAnalysisPhase.h"
52#include "DFGLoopPreHeaderCreationPhase.h"
53#include "DFGOSRAvailabilityAnalysisPhase.h"
54#include "DFGOSREntrypointCreationPhase.h"
55#include "DFGObjectAllocationSinkingPhase.h"
56#include "DFGPhantomInsertionPhase.h"
57#include "DFGPredictionInjectionPhase.h"
58#include "DFGPredictionPropagationPhase.h"
59#include "DFGPutStackSinkingPhase.h"
60#include "DFGSSAConversionPhase.h"
61#include "DFGSSALoweringPhase.h"
62#include "DFGStackLayoutPhase.h"
63#include "DFGStaticExecutionCountEstimationPhase.h"
64#include "DFGStoreBarrierClusteringPhase.h"
65#include "DFGStoreBarrierInsertionPhase.h"
66#include "DFGStrengthReductionPhase.h"
67#include "DFGThunks.h"
68#include "DFGTierUpCheckInjectionPhase.h"
69#include "DFGTypeCheckHoistingPhase.h"
70#include "DFGUnificationPhase.h"
71#include "DFGValidate.h"
72#include "DFGValueRepReductionPhase.h"
73#include "DFGVarargsForwardingPhase.h"
74#include "DFGVirtualRegisterAllocationPhase.h"
75#include "DFGWatchpointCollectionPhase.h"
76#include "JSCJSValueInlines.h"
77#include "OperandsInlines.h"
78#include "ProfilerDatabase.h"
79#include "TrackedReferences.h"
80#include "VMInlines.h"
81
82#if ENABLE(FTL_JIT)
83#include "FTLCapabilities.h"
84#include "FTLCompile.h"
85#include "FTLFail.h"
86#include "FTLLink.h"
87#include "FTLLowerDFGToB3.h"
88#include "FTLState.h"
89#endif
90
91namespace JSC { namespace DFG {
92
93namespace {
94
95void dumpAndVerifyGraph(Graph& graph, const char* text, bool forceDump = false)
96{
97 GraphDumpMode modeForFinalValidate = DumpGraph;
98 if (verboseCompilationEnabled(graph.m_plan.mode()) || forceDump) {
99 dataLog(text, "\n");
100 graph.dump();
101 modeForFinalValidate = DontDumpGraph;
102 }
103 if (validationEnabled())
104 validate(graph, modeForFinalValidate);
105}
106
107Profiler::CompilationKind profilerCompilationKindForMode(JITCompilationMode mode)
108{
109 switch (mode) {
110 case JITCompilationMode::InvalidCompilation:
111 case JITCompilationMode::Baseline:
112 RELEASE_ASSERT_NOT_REACHED();
113 return Profiler::DFG;
114 case JITCompilationMode::DFG:
115 return Profiler::DFG;
116 case JITCompilationMode::UnlinkedDFG:
117 return Profiler::UnlinkedDFG;
118 case JITCompilationMode::FTL:
119 return Profiler::FTL;
120 case JITCompilationMode::FTLForOSREntry:
121 return Profiler::FTLForOSREntry;
122 }
123 RELEASE_ASSERT_NOT_REACHED();
124 return Profiler::DFG;
125}
126
127} // anonymous namespace
128
129Plan::Plan(CodeBlock* passedCodeBlock, CodeBlock* profiledDFGCodeBlock,
130 JITCompilationMode mode, BytecodeIndex osrEntryBytecodeIndex,
131 const Operands<std::optional<JSValue>>& mustHandleValues)
132 : Base(mode, passedCodeBlock)
133 , m_profiledDFGCodeBlock(profiledDFGCodeBlock)
134 , m_mustHandleValues(mustHandleValues)
135 , m_osrEntryBytecodeIndex(osrEntryBytecodeIndex)
136 , m_compilation(UNLIKELY(m_vm->m_perBytecodeProfiler) ? adoptRef(new Profiler::Compilation(m_vm->m_perBytecodeProfiler->ensureBytecodesFor(m_codeBlock), profilerCompilationKindForMode(mode))) : nullptr)
137 , m_inlineCallFrames(adoptRef(new InlineCallFrameSet()))
138 , m_identifiers(m_codeBlock)
139 , m_weakReferences(m_codeBlock)
140 , m_transitions(m_codeBlock)
141{
142 RELEASE_ASSERT(m_codeBlock->alternative()->jitCode());
143 m_inlineCallFrames->disableThreadingChecks();
144}
145
146Plan::~Plan()
147{
148}
149
150size_t Plan::codeSize() const
151{
152 if (!m_finalizer)
153 return 0;
154 return m_finalizer->codeSize();
155}
156
157void Plan::finalizeInGC()
158{
159 ASSERT(m_vm);
160 m_recordedStatuses.finalizeWithoutDeleting(*m_vm);
161}
162
163void Plan::notifyReady()
164{
165 Base::notifyReady();
166 m_callback->compilationDidBecomeReadyAsynchronously(m_codeBlock, m_profiledDFGCodeBlock);
167}
168
169void Plan::cancel()
170{
171 Base::cancel();
172 m_profiledDFGCodeBlock = nullptr;
173 m_mustHandleValues.clear();
174 m_compilation = nullptr;
175 m_finalizer = nullptr;
176 m_inlineCallFrames = nullptr;
177 m_watchpoints = DesiredWatchpoints();
178 m_identifiers = DesiredIdentifiers();
179 m_weakReferences = DesiredWeakReferences();
180 m_transitions = DesiredTransitions();
181 m_callback = nullptr;
182}
183
184Plan::CompilationPath Plan::compileInThreadImpl()
185{
186 {
187 CompilerTimingScope timingScope("DFG", "clean must handle values");
188 cleanMustHandleValuesIfNecessary();
189 }
190
191 if (verboseCompilationEnabled(m_mode) && m_osrEntryBytecodeIndex) {
192 dataLog("\n");
193 dataLog("Compiler must handle OSR entry from ", m_osrEntryBytecodeIndex, " with values: ", m_mustHandleValues, "\n");
194 dataLog("\n");
195 }
196
197 Graph dfg(*m_vm, *this);
198
199 {
200 CompilerTimingScope timingScope("DFG", "bytecode parser");
201 parse(dfg);
202 }
203
204 bool changed = false;
205
206#define RUN_PHASE(phase) \
207 do { \
208 if (Options::safepointBeforeEachPhase()) { \
209 Safepoint::Result safepointResult; \
210 { \
211 GraphSafepoint safepoint(dfg, safepointResult); \
212 } \
213 if (safepointResult.didGetCancelled()) \
214 return CancelPath; \
215 } \
216 dfg.nextPhase(); \
217 changed |= phase(dfg); \
218 } while (false); \
219
220
221 // By this point the DFG bytecode parser will have potentially mutated various tables
222 // in the CodeBlock. This is a good time to perform an early shrink, which is more
223 // powerful than a late one. It's safe to do so because we haven't generated any code
224 // that references any of the tables directly, yet.
225 {
226 ConcurrentJSLocker locker(m_codeBlock->m_lock);
227 m_codeBlock->shrinkToFit(locker, CodeBlock::ShrinkMode::EarlyShrink);
228 }
229
230 if (validationEnabled())
231 validate(dfg);
232
233 if (Options::dumpGraphAfterParsing()) {
234 dataLog("Graph after parsing:\n");
235 dfg.dump();
236 }
237
238 RUN_PHASE(performLiveCatchVariablePreservationPhase);
239
240 RUN_PHASE(performCPSRethreading);
241 RUN_PHASE(performUnification);
242 RUN_PHASE(performPredictionInjection);
243
244 RUN_PHASE(performStaticExecutionCountEstimation);
245
246 if (m_mode == JITCompilationMode::FTLForOSREntry) {
247 bool result = performOSREntrypointCreation(dfg);
248 if (!result) {
249 m_finalizer = makeUnique<FailedFinalizer>(*this);
250 return FailPath;
251 }
252 RUN_PHASE(performCPSRethreading);
253 }
254
255 if (validationEnabled())
256 validate(dfg);
257
258 RUN_PHASE(performPredictionPropagation);
259 RUN_PHASE(performFixup);
260 RUN_PHASE(performInvalidationPointInjection);
261 RUN_PHASE(performTypeCheckHoisting);
262
263 dfg.m_fixpointState = FixpointNotConverged;
264
265 // For now we're back to avoiding a fixpoint. Note that we've ping-ponged on this decision
266 // many times. For maximum throughput, it's best to fixpoint. But the throughput benefit is
267 // small and not likely to show up in FTL anyway. On the other hand, not fixpointing means
268 // that the compiler compiles more quickly. We want the third tier to compile quickly, which
269 // not fixpointing accomplishes; and the fourth tier shouldn't need a fixpoint.
270 if (validationEnabled())
271 validate(dfg);
272
273 RUN_PHASE(performStrengthReduction);
274 RUN_PHASE(performCPSRethreading);
275 RUN_PHASE(performCFA);
276 RUN_PHASE(performConstantFolding);
277 changed = false;
278 RUN_PHASE(performCFGSimplification);
279 RUN_PHASE(performLocalCSE);
280
281 if (validationEnabled())
282 validate(dfg);
283
284 RUN_PHASE(performCPSRethreading);
285 if (!isFTL()) {
286 // Only run this if we're not FTLing, because currently for a LoadVarargs that is forwardable and
287 // in a non-varargs inlined call frame, this will generate ForwardVarargs while the FTL
288 // ArgumentsEliminationPhase will create a sequence of GetStack+PutStacks. The GetStack+PutStack
289 // sequence then gets sunk, eliminating anything that looks like an escape for subsequent phases,
290 // while the ForwardVarargs doesn't get simplified until later (or not at all) and looks like an
291 // escape for all of the arguments. This then disables object allocation sinking.
292 //
293 // So, for now, we just disable this phase for the FTL.
294 //
295 // If we wanted to enable it, we'd have to do any of the following:
296 // - Enable ForwardVarargs->GetStack+PutStack strength reduction, and have that run before
297 // PutStack sinking and object allocation sinking.
298 // - Make VarargsForwarding emit a GetLocal+SetLocal sequence, that we can later turn into
299 // GetStack+PutStack.
300 //
301 // But, it's not super valuable to enable those optimizations, since the FTL
302 // ArgumentsEliminationPhase does everything that this phase does, and it doesn't introduce this
303 // pathology.
304
305 RUN_PHASE(performVarargsForwarding); // Do this after CFG simplification and CPS rethreading.
306 }
307 if (changed) {
308 RUN_PHASE(performCFA);
309 RUN_PHASE(performConstantFolding);
310 RUN_PHASE(performCFGSimplification);
311 }
312
313 // If we're doing validation, then run some analyses, to give them an opportunity
314 // to self-validate. Now is as good a time as any to do this.
315 if (validationEnabled()) {
316 dfg.ensureCPSDominators();
317 dfg.ensureCPSNaturalLoops();
318 }
319
320 switch (m_mode) {
321 case JITCompilationMode::DFG:
322 case JITCompilationMode::UnlinkedDFG: {
323 dfg.m_fixpointState = FixpointConverged;
324
325 RUN_PHASE(performTierUpCheckInjection);
326
327 RUN_PHASE(performFastStoreBarrierInsertion);
328 RUN_PHASE(performStoreBarrierClustering);
329 RUN_PHASE(performCleanUp);
330 RUN_PHASE(performCPSRethreading);
331 RUN_PHASE(performDCE);
332 RUN_PHASE(performPhantomInsertion);
333 RUN_PHASE(performStackLayout);
334 RUN_PHASE(performVirtualRegisterAllocation);
335 RUN_PHASE(performWatchpointCollection);
336 dumpAndVerifyGraph(dfg, "Graph after optimization:");
337
338 {
339 CompilerTimingScope timingScope("DFG", "machine code generation");
340
341 JITCompiler dataFlowJIT(dfg);
342 if (m_codeBlock->codeType() == FunctionCode)
343 dataFlowJIT.compileFunction();
344 else
345 dataFlowJIT.compile();
346 }
347
348 return DFGPath;
349 }
350
351 case JITCompilationMode::FTL:
352 case JITCompilationMode::FTLForOSREntry: {
353#if ENABLE(FTL_JIT)
354 if (FTL::canCompile(dfg) == FTL::CannotCompile) {
355 m_finalizer = makeUnique<FailedFinalizer>(*this);
356 return FailPath;
357 }
358
359 RUN_PHASE(performCleanUp); // Reduce the graph size a bit.
360 RUN_PHASE(performCriticalEdgeBreaking);
361 if (Options::createPreHeaders())
362 RUN_PHASE(performLoopPreHeaderCreation);
363 RUN_PHASE(performCPSRethreading);
364 RUN_PHASE(performSSAConversion);
365 RUN_PHASE(performSSALowering);
366
367 // Ideally, these would be run to fixpoint with the object allocation sinking phase.
368 RUN_PHASE(performArgumentsElimination);
369 if (Options::usePutStackSinking())
370 RUN_PHASE(performPutStackSinking);
371
372 RUN_PHASE(performConstantHoisting);
373 RUN_PHASE(performGlobalCSE);
374 RUN_PHASE(performLivenessAnalysis);
375 RUN_PHASE(performCFA);
376 RUN_PHASE(performConstantFolding);
377 RUN_PHASE(performCFGSimplification);
378 RUN_PHASE(performCleanUp); // Reduce the graph size a lot.
379 changed = false;
380 RUN_PHASE(performStrengthReduction);
381 if (Options::useObjectAllocationSinking()) {
382 RUN_PHASE(performCriticalEdgeBreaking);
383 RUN_PHASE(performObjectAllocationSinking);
384 }
385 if (Options::useValueRepElimination())
386 RUN_PHASE(performValueRepReduction);
387 if (changed) {
388 // State-at-tail and state-at-head will be invalid if we did strength reduction since
389 // it might increase live ranges.
390 RUN_PHASE(performLivenessAnalysis);
391 RUN_PHASE(performCFA);
392 RUN_PHASE(performConstantFolding);
393 RUN_PHASE(performCFGSimplification);
394 }
395
396 // Currently, this relies on pre-headers still being valid. That precludes running CFG
397 // simplification before it, unless we re-created the pre-headers. There wouldn't be anything
398 // wrong with running LICM earlier, if we wanted to put other CFG transforms above this point.
399 // Alternatively, we could run loop pre-header creation after SSA conversion - but if we did that
400 // then we'd need to do some simple SSA fix-up.
401 RUN_PHASE(performLivenessAnalysis);
402 RUN_PHASE(performCFA);
403 RUN_PHASE(performLICM);
404
405 // FIXME: Currently: IntegerRangeOptimization *must* be run after LICM.
406 //
407 // IntegerRangeOptimization makes changes on nodes based on preceding blocks
408 // and nodes. LICM moves nodes which can invalidates assumptions used
409 // by IntegerRangeOptimization.
410 //
411 // Ideally, the dependencies should be explicit. See https://bugs.webkit.org/show_bug.cgi?id=157534.
412 RUN_PHASE(performLivenessAnalysis);
413 RUN_PHASE(performIntegerRangeOptimization);
414
415 RUN_PHASE(performCleanUp);
416 RUN_PHASE(performIntegerCheckCombining);
417 RUN_PHASE(performGlobalCSE);
418
419 // At this point we're not allowed to do any further code motion because our reasoning
420 // about code motion assumes that it's OK to insert GC points in random places.
421 dfg.m_fixpointState = FixpointConverged;
422
423 RUN_PHASE(performLivenessAnalysis);
424 RUN_PHASE(performCFA);
425 RUN_PHASE(performGlobalStoreBarrierInsertion);
426 RUN_PHASE(performStoreBarrierClustering);
427 RUN_PHASE(performCleanUp);
428 RUN_PHASE(performDCE); // We rely on this to kill dead code that won't be recognized as dead by B3.
429 RUN_PHASE(performStackLayout);
430 RUN_PHASE(performLivenessAnalysis);
431 RUN_PHASE(performOSRAvailabilityAnalysis);
432 RUN_PHASE(performWatchpointCollection);
433
434 if (FTL::canCompile(dfg) == FTL::CannotCompile) {
435 m_finalizer = makeUnique<FailedFinalizer>(*this);
436 return FailPath;
437 }
438
439 dfg.nextPhase();
440 dumpAndVerifyGraph(dfg, "Graph just before FTL lowering:", shouldDumpDisassembly(m_mode));
441
442 // Flash a safepoint in case the GC wants some action.
443 Safepoint::Result safepointResult;
444 {
445 GraphSafepoint safepoint(dfg, safepointResult);
446 }
447 if (safepointResult.didGetCancelled())
448 return CancelPath;
449
450 dfg.nextPhase();
451 FTL::State state(dfg);
452 FTL::lowerDFGToB3(state);
453
454 if (UNLIKELY(computeCompileTimes()))
455 m_timeBeforeFTL = MonotonicTime::now();
456
457 if (UNLIKELY(Options::b3AlwaysFailsBeforeCompile())) {
458 FTL::fail(state);
459 return FTLPath;
460 }
461
462 FTL::compile(state, safepointResult);
463 if (safepointResult.didGetCancelled())
464 return CancelPath;
465
466 if (UNLIKELY(Options::b3AlwaysFailsBeforeLink())) {
467 FTL::fail(state);
468 return FTLPath;
469 }
470
471 if (state.allocationFailed) {
472 FTL::fail(state);
473 return FTLPath;
474 }
475
476 FTL::link(state);
477
478 if (state.allocationFailed) {
479 FTL::fail(state);
480 return FTLPath;
481 }
482
483 return FTLPath;
484#else
485 RELEASE_ASSERT_NOT_REACHED();
486 return FailPath;
487#endif // ENABLE(FTL_JIT)
488 }
489
490 default:
491 RELEASE_ASSERT_NOT_REACHED();
492 return FailPath;
493 }
494
495#undef RUN_PHASE
496}
497
498bool Plan::isStillValid()
499{
500 CodeBlock* replacement = m_codeBlock->replacement();
501 if (!replacement)
502 return false;
503 // FIXME: This is almost certainly not necessary. There's no way for the baseline
504 // code to be replaced during a compilation, except if we delete the plan, in which
505 // case we wouldn't be here.
506 // https://bugs.webkit.org/show_bug.cgi?id=132707
507 if (m_codeBlock->alternative() != replacement->baselineVersion())
508 return false;
509 if (!m_watchpoints.areStillValid())
510 return false;
511 return true;
512}
513
514void Plan::reallyAdd(CommonData* commonData)
515{
516 ASSERT(m_vm->heap.isDeferred());
517 m_identifiers.reallyAdd(*m_vm, commonData);
518 m_weakReferences.reallyAdd(*m_vm, commonData);
519 m_transitions.reallyAdd(*m_vm, commonData);
520 m_watchpoints.reallyAdd(m_codeBlock, m_identifiers, commonData);
521 {
522 ConcurrentJSLocker locker(m_codeBlock->m_lock);
523 commonData->recordedStatuses = WTFMove(m_recordedStatuses);
524 }
525}
526
527bool Plan::isStillValidOnMainThread()
528{
529 return m_watchpoints.areStillValidOnMainThread(*m_vm, m_identifiers);
530}
531
532CompilationResult Plan::finalize()
533{
534 // We perform multiple stores before emitting a write-barrier. To ensure that no GC happens between store and write-barrier, we should ensure that
535 // GC is deferred when this function is called.
536 ASSERT(m_vm->heap.isDeferred());
537
538 CompilationResult result = [&] {
539 if (!isStillValidOnMainThread() || !isStillValid()) {
540 CODEBLOCK_LOG_EVENT(m_codeBlock, "dfgFinalize", ("invalidated"));
541 return CompilationInvalidated;
542 }
543
544 bool result = m_finalizer->finalize();
545 if (!result) {
546 CODEBLOCK_LOG_EVENT(m_codeBlock, "dfgFinalize", ("failed"));
547 return CompilationFailed;
548 }
549
550 reallyAdd(m_codeBlock->jitCode()->dfgCommon());
551 {
552 ConcurrentJSLocker locker(m_codeBlock->m_lock);
553 m_codeBlock->jitCode()->shrinkToFit(locker);
554 m_codeBlock->shrinkToFit(locker, CodeBlock::ShrinkMode::LateShrink);
555 }
556
557 // Since Plan::reallyAdd could fire watchpoints (see ArrayBufferViewWatchpointAdaptor::add),
558 // it is possible that the current CodeBlock is now invalidated & jettisoned.
559 if (m_codeBlock->isJettisoned()) {
560 CODEBLOCK_LOG_EVENT(m_codeBlock, "dfgFinalize", ("invalidated"));
561 return CompilationInvalidated;
562 }
563
564 if (validationEnabled()) {
565 TrackedReferences trackedReferences;
566
567 for (WriteBarrier<JSCell>& reference : m_codeBlock->jitCode()->dfgCommon()->m_weakReferences)
568 trackedReferences.add(reference.get());
569 for (StructureID structureID : m_codeBlock->jitCode()->dfgCommon()->m_weakStructureReferences)
570 trackedReferences.add(structureID.decode());
571 for (WriteBarrier<Unknown>& constant : m_codeBlock->constants())
572 trackedReferences.add(constant.get());
573
574 for (auto* inlineCallFrame : *m_inlineCallFrames) {
575 ASSERT(inlineCallFrame->baselineCodeBlock.get());
576 trackedReferences.add(inlineCallFrame->baselineCodeBlock.get());
577 }
578
579 // Check that any other references that we have anywhere in the JITCode are also
580 // tracked either strongly or weakly.
581 m_codeBlock->jitCode()->validateReferences(trackedReferences);
582 }
583
584 CODEBLOCK_LOG_EVENT(m_codeBlock, "dfgFinalize", ("succeeded"));
585 return CompilationSuccessful;
586 }();
587
588 // We will establish new references from the code block to things. So, we need a barrier.
589 m_vm->writeBarrier(m_codeBlock);
590
591 m_callback->compilationDidComplete(m_codeBlock, m_profiledDFGCodeBlock, result);
592
593 return result;
594}
595
596bool Plan::iterateCodeBlocksForGC(AbstractSlotVisitor& visitor, const Function<void(CodeBlock*)>& func)
597{
598 if (!Base::iterateCodeBlocksForGC(visitor, func))
599 return false;
600
601 // Compilation writes lots of values to a CodeBlock without performing
602 // an explicit barrier. So, we need to be pessimistic and assume that
603 // all our CodeBlocks must be visited during GC.
604 func(m_codeBlock->alternative());
605 if (m_profiledDFGCodeBlock)
606 func(m_profiledDFGCodeBlock);
607 return true;
608}
609
610bool Plan::checkLivenessAndVisitChildren(AbstractSlotVisitor& visitor)
611{
612 if (!Base::checkLivenessAndVisitChildren(visitor))
613 return false;
614
615 cleanMustHandleValuesIfNecessary();
616 for (unsigned i = m_mustHandleValues.size(); i--;) {
617 std::optional<JSValue> value = m_mustHandleValues[i];
618 if (value)
619 visitor.appendUnbarriered(value.value());
620 }
621
622 m_recordedStatuses.visitAggregate(visitor);
623 m_recordedStatuses.markIfCheap(visitor);
624
625 visitor.appendUnbarriered(m_codeBlock->alternative());
626 visitor.appendUnbarriered(m_profiledDFGCodeBlock);
627
628 if (m_inlineCallFrames) {
629 for (auto* inlineCallFrame : *m_inlineCallFrames) {
630 ASSERT(inlineCallFrame->baselineCodeBlock.get());
631 visitor.appendUnbarriered(inlineCallFrame->baselineCodeBlock.get());
632 }
633 }
634
635 m_weakReferences.visitChildren(visitor);
636 m_transitions.visitChildren(visitor);
637 return true;
638}
639
640bool Plan::isKnownToBeLiveDuringGC(AbstractSlotVisitor& visitor)
641{
642 if (!Base::isKnownToBeLiveDuringGC(visitor))
643 return false;
644 if (!visitor.isMarked(m_codeBlock->alternative()))
645 return false;
646 if (!!m_profiledDFGCodeBlock && !visitor.isMarked(m_profiledDFGCodeBlock))
647 return false;
648 return true;
649}
650
651bool Plan::isKnownToBeLiveAfterGC()
652{
653 if (!Base::isKnownToBeLiveAfterGC())
654 return false;
655 if (!m_vm->heap.isMarked(m_codeBlock->alternative()))
656 return false;
657 if (!!m_profiledDFGCodeBlock && !m_vm->heap.isMarked(m_profiledDFGCodeBlock))
658 return false;
659 return true;
660}
661
662void Plan::cleanMustHandleValuesIfNecessary()
663{
664 Locker locker { m_mustHandleValueCleaningLock };
665
666 if (!m_mustHandleValuesMayIncludeGarbage)
667 return;
668
669 m_mustHandleValuesMayIncludeGarbage = false;
670
671 if (!m_codeBlock)
672 return;
673
674 if (!m_mustHandleValues.numberOfLocals())
675 return;
676
677 CodeBlock* alternative = m_codeBlock->alternative();
678 FastBitVector liveness = alternative->livenessAnalysis().getLivenessInfoAtInstruction(alternative, m_osrEntryBytecodeIndex);
679
680 for (unsigned local = m_mustHandleValues.numberOfLocals(); local--;) {
681 if (!liveness[local])
682 m_mustHandleValues.local(local) = std::nullopt;
683 }
684}
685
686std::unique_ptr<JITData> Plan::finalizeJITData(const JITCode& jitCode)
687{
688 auto osrExitThunk = m_vm->getCTIStub(osrExitGenerationThunkGenerator).retagged<OSRExitPtrTag>();
689 auto exits = JITData::ExitVector::createWithSizeAndConstructorArguments(jitCode.m_osrExit.size(), osrExitThunk);
690 auto jitData = JITData::create(jitCode, WTFMove(exits));
691 return jitData;
692}
693
694} } // namespace JSC::DFG
695
696#endif // ENABLE(DFG_JIT)
697
Note: See TracBrowser for help on using the repository browser.