1/*
2 * Copyright (C) 2013-2018 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 "DFGBackwardsPropagationPhase.h"
33#include "DFGByteCodeParser.h"
34#include "DFGCFAPhase.h"
35#include "DFGCFGSimplificationPhase.h"
36#include "DFGCPSRethreadingPhase.h"
37#include "DFGCSEPhase.h"
38#include "DFGCleanUpPhase.h"
39#include "DFGConstantFoldingPhase.h"
40#include "DFGConstantHoistingPhase.h"
41#include "DFGCriticalEdgeBreakingPhase.h"
42#include "DFGDCEPhase.h"
43#include "DFGFailedFinalizer.h"
44#include "DFGFixupPhase.h"
45#include "DFGGraphSafepoint.h"
46#include "DFGIntegerCheckCombiningPhase.h"
47#include "DFGIntegerRangeOptimizationPhase.h"
48#include "DFGInvalidationPointInjectionPhase.h"
49#include "DFGJITCompiler.h"
50#include "DFGLICMPhase.h"
51#include "DFGLiveCatchVariablePreservationPhase.h"
52#include "DFGLivenessAnalysisPhase.h"
53#include "DFGLoopPreHeaderCreationPhase.h"
54#include "DFGMaximalFlushInsertionPhase.h"
55#include "DFGMovHintRemovalPhase.h"
56#include "DFGOSRAvailabilityAnalysisPhase.h"
57#include "DFGOSREntrypointCreationPhase.h"
58#include "DFGObjectAllocationSinkingPhase.h"
59#include "DFGPhantomInsertionPhase.h"
60#include "DFGPredictionInjectionPhase.h"
61#include "DFGPredictionPropagationPhase.h"
62#include "DFGPutStackSinkingPhase.h"
63#include "DFGSSAConversionPhase.h"
64#include "DFGSSALoweringPhase.h"
65#include "DFGStackLayoutPhase.h"
66#include "DFGStaticExecutionCountEstimationPhase.h"
67#include "DFGStoreBarrierClusteringPhase.h"
68#include "DFGStoreBarrierInsertionPhase.h"
69#include "DFGStrengthReductionPhase.h"
70#include "DFGTierUpCheckInjectionPhase.h"
71#include "DFGTypeCheckHoistingPhase.h"
72#include "DFGUnificationPhase.h"
73#include "DFGValidate.h"
74#include "DFGValueRepReductionPhase.h"
75#include "DFGVarargsForwardingPhase.h"
76#include "DFGVirtualRegisterAllocationPhase.h"
77#include "DFGWatchpointCollectionPhase.h"
78#include "JSCInlines.h"
79#include "OperandsInlines.h"
80#include "ProfilerDatabase.h"
81#include "TrackedReferences.h"
82#include "VMInlines.h"
83
84#if ENABLE(FTL_JIT)
85#include "FTLCapabilities.h"
86#include "FTLCompile.h"
87#include "FTLFail.h"
88#include "FTLLink.h"
89#include "FTLLowerDFGToB3.h"
90#include "FTLState.h"
91#endif
92
93namespace JSC {
94
95extern Seconds totalDFGCompileTime;
96extern Seconds totalFTLCompileTime;
97extern Seconds totalFTLDFGCompileTime;
98extern Seconds totalFTLB3CompileTime;
99
100}
101
102namespace JSC { namespace DFG {
103
104namespace {
105
106void dumpAndVerifyGraph(Graph& graph, const char* text, bool forceDump = false)
107{
108 GraphDumpMode modeForFinalValidate = DumpGraph;
109 if (verboseCompilationEnabled(graph.m_plan.mode()) || forceDump) {
110 dataLog(text, "\n");
111 graph.dump();
112 modeForFinalValidate = DontDumpGraph;
113 }
114 if (validationEnabled())
115 validate(graph, modeForFinalValidate);
116}
117
118Profiler::CompilationKind profilerCompilationKindForMode(CompilationMode mode)
119{
120 switch (mode) {
121 case InvalidCompilationMode:
122 RELEASE_ASSERT_NOT_REACHED();
123 return Profiler::DFG;
124 case DFGMode:
125 return Profiler::DFG;
126 case FTLMode:
127 return Profiler::FTL;
128 case FTLForOSREntryMode:
129 return Profiler::FTLForOSREntry;
130 }
131 RELEASE_ASSERT_NOT_REACHED();
132 return Profiler::DFG;
133}
134
135} // anonymous namespace
136
137Plan::Plan(CodeBlock* passedCodeBlock, CodeBlock* profiledDFGCodeBlock,
138 CompilationMode mode, unsigned osrEntryBytecodeIndex,
139 const Operands<Optional<JSValue>>& mustHandleValues)
140 : m_mode(mode)
141 , m_vm(passedCodeBlock->vm())
142 , m_codeBlock(passedCodeBlock)
143 , m_profiledDFGCodeBlock(profiledDFGCodeBlock)
144 , m_mustHandleValues(mustHandleValues)
145 , m_osrEntryBytecodeIndex(osrEntryBytecodeIndex)
146 , m_compilation(UNLIKELY(m_vm->m_perBytecodeProfiler) ? adoptRef(new Profiler::Compilation(m_vm->m_perBytecodeProfiler->ensureBytecodesFor(m_codeBlock), profilerCompilationKindForMode(mode))) : nullptr)
147 , m_inlineCallFrames(adoptRef(new InlineCallFrameSet()))
148 , m_identifiers(m_codeBlock)
149 , m_weakReferences(m_codeBlock)
150 , m_stage(Preparing)
151{
152 RELEASE_ASSERT(m_codeBlock->alternative()->jitCode());
153}
154
155Plan::~Plan()
156{
157}
158
159bool Plan::computeCompileTimes() const
160{
161 return reportCompileTimes()
162 || Options::reportTotalCompileTimes()
163 || (m_vm && m_vm->m_perBytecodeProfiler);
164}
165
166bool Plan::reportCompileTimes() const
167{
168 return Options::reportCompileTimes()
169 || Options::reportDFGCompileTimes()
170 || (Options::reportFTLCompileTimes() && isFTL());
171}
172
173void Plan::compileInThread(ThreadData* threadData)
174{
175 m_threadData = threadData;
176
177 MonotonicTime before { };
178 CString codeBlockName;
179 if (UNLIKELY(computeCompileTimes()))
180 before = MonotonicTime::now();
181 if (UNLIKELY(reportCompileTimes()))
182 codeBlockName = toCString(*m_codeBlock);
183
184 CompilationScope compilationScope;
185
186 if (logCompilationChanges(m_mode) || Options::logPhaseTimes())
187 dataLog("DFG(Plan) compiling ", *m_codeBlock, " with ", m_mode, ", instructions size = ", m_codeBlock->instructionsSize(), "\n");
188
189 CompilationPath path = compileInThreadImpl();
190
191 RELEASE_ASSERT(path == CancelPath || m_finalizer);
192 RELEASE_ASSERT((path == CancelPath) == (m_stage == Cancelled));
193
194 MonotonicTime after { };
195 if (UNLIKELY(computeCompileTimes())) {
196 after = MonotonicTime::now();
197
198 if (Options::reportTotalCompileTimes()) {
199 if (isFTL()) {
200 totalFTLCompileTime += after - before;
201 totalFTLDFGCompileTime += m_timeBeforeFTL - before;
202 totalFTLB3CompileTime += after - m_timeBeforeFTL;
203 } else
204 totalDFGCompileTime += after - before;
205 }
206 }
207 const char* pathName = nullptr;
208 switch (path) {
209 case FailPath:
210 pathName = "N/A (fail)";
211 break;
212 case DFGPath:
213 pathName = "DFG";
214 break;
215 case FTLPath:
216 pathName = "FTL";
217 break;
218 case CancelPath:
219 pathName = "Cancelled";
220 break;
221 default:
222 RELEASE_ASSERT_NOT_REACHED();
223 break;
224 }
225 if (m_codeBlock) { // m_codeBlock will be null if the compilation was cancelled.
226 if (path == FTLPath)
227 CODEBLOCK_LOG_EVENT(m_codeBlock, "ftlCompile", ("took ", (after - before).milliseconds(), " ms (DFG: ", (m_timeBeforeFTL - before).milliseconds(), ", B3: ", (after - m_timeBeforeFTL).milliseconds(), ") with ", pathName));
228 else
229 CODEBLOCK_LOG_EVENT(m_codeBlock, "dfgCompile", ("took ", (after - before).milliseconds(), " ms with ", pathName));
230 }
231 if (UNLIKELY(reportCompileTimes())) {
232 dataLog("Optimized ", codeBlockName, " using ", m_mode, " with ", pathName, " into ", m_finalizer ? m_finalizer->codeSize() : 0, " bytes in ", (after - before).milliseconds(), " ms");
233 if (path == FTLPath)
234 dataLog(" (DFG: ", (m_timeBeforeFTL - before).milliseconds(), ", B3: ", (after - m_timeBeforeFTL).milliseconds(), ")");
235 dataLog(".\n");
236 }
237}
238
239Plan::CompilationPath Plan::compileInThreadImpl()
240{
241 cleanMustHandleValuesIfNecessary();
242
243 if (verboseCompilationEnabled(m_mode) && m_osrEntryBytecodeIndex != UINT_MAX) {
244 dataLog("\n");
245 dataLog("Compiler must handle OSR entry from bc#", m_osrEntryBytecodeIndex, " with values: ", m_mustHandleValues, "\n");
246 dataLog("\n");
247 }
248
249 Graph dfg(*m_vm, *this);
250 parse(dfg);
251
252 m_codeBlock->setCalleeSaveRegisters(RegisterSet::dfgCalleeSaveRegisters());
253
254 bool changed = false;
255
256#define RUN_PHASE(phase) \
257 do { \
258 if (Options::safepointBeforeEachPhase()) { \
259 Safepoint::Result safepointResult; \
260 { \
261 GraphSafepoint safepoint(dfg, safepointResult); \
262 } \
263 if (safepointResult.didGetCancelled()) \
264 return CancelPath; \
265 } \
266 changed |= phase(dfg); \
267 } while (false); \
268
269
270 // By this point the DFG bytecode parser will have potentially mutated various tables
271 // in the CodeBlock. This is a good time to perform an early shrink, which is more
272 // powerful than a late one. It's safe to do so because we haven't generated any code
273 // that references any of the tables directly, yet.
274 m_codeBlock->shrinkToFit(CodeBlock::EarlyShrink);
275
276 if (validationEnabled())
277 validate(dfg);
278
279 if (Options::dumpGraphAfterParsing()) {
280 dataLog("Graph after parsing:\n");
281 dfg.dump();
282 }
283
284 RUN_PHASE(performLiveCatchVariablePreservationPhase);
285
286 if (Options::useMaximalFlushInsertionPhase())
287 RUN_PHASE(performMaximalFlushInsertion);
288
289 RUN_PHASE(performCPSRethreading);
290 RUN_PHASE(performUnification);
291 RUN_PHASE(performPredictionInjection);
292
293 RUN_PHASE(performStaticExecutionCountEstimation);
294
295 if (m_mode == FTLForOSREntryMode) {
296 bool result = performOSREntrypointCreation(dfg);
297 if (!result) {
298 m_finalizer = std::make_unique<FailedFinalizer>(*this);
299 return FailPath;
300 }
301 RUN_PHASE(performCPSRethreading);
302 }
303
304 if (validationEnabled())
305 validate(dfg);
306
307 RUN_PHASE(performBackwardsPropagation);
308 RUN_PHASE(performPredictionPropagation);
309 RUN_PHASE(performFixup);
310 RUN_PHASE(performInvalidationPointInjection);
311 RUN_PHASE(performTypeCheckHoisting);
312
313 dfg.m_fixpointState = FixpointNotConverged;
314
315 // For now we're back to avoiding a fixpoint. Note that we've ping-ponged on this decision
316 // many times. For maximum throughput, it's best to fixpoint. But the throughput benefit is
317 // small and not likely to show up in FTL anyway. On the other hand, not fixpointing means
318 // that the compiler compiles more quickly. We want the third tier to compile quickly, which
319 // not fixpointing accomplishes; and the fourth tier shouldn't need a fixpoint.
320 if (validationEnabled())
321 validate(dfg);
322
323 RUN_PHASE(performStrengthReduction);
324 RUN_PHASE(performCPSRethreading);
325 RUN_PHASE(performCFA);
326 RUN_PHASE(performConstantFolding);
327 changed = false;
328 RUN_PHASE(performCFGSimplification);
329 RUN_PHASE(performLocalCSE);
330
331 if (validationEnabled())
332 validate(dfg);
333
334 RUN_PHASE(performCPSRethreading);
335 if (!isFTL()) {
336 // Only run this if we're not FTLing, because currently for a LoadVarargs that is forwardable and
337 // in a non-varargs inlined call frame, this will generate ForwardVarargs while the FTL
338 // ArgumentsEliminationPhase will create a sequence of GetStack+PutStacks. The GetStack+PutStack
339 // sequence then gets sunk, eliminating anything that looks like an escape for subsequent phases,
340 // while the ForwardVarargs doesn't get simplified until later (or not at all) and looks like an
341 // escape for all of the arguments. This then disables object allocation sinking.
342 //
343 // So, for now, we just disable this phase for the FTL.
344 //
345 // If we wanted to enable it, we'd have to do any of the following:
346 // - Enable ForwardVarargs->GetStack+PutStack strength reduction, and have that run before
347 // PutStack sinking and object allocation sinking.
348 // - Make VarargsForwarding emit a GetLocal+SetLocal sequence, that we can later turn into
349 // GetStack+PutStack.
350 //
351 // But, it's not super valuable to enable those optimizations, since the FTL
352 // ArgumentsEliminationPhase does everything that this phase does, and it doesn't introduce this
353 // pathology.
354
355 RUN_PHASE(performVarargsForwarding); // Do this after CFG simplification and CPS rethreading.
356 }
357 if (changed) {
358 RUN_PHASE(performCFA);
359 RUN_PHASE(performConstantFolding);
360 }
361
362 // If we're doing validation, then run some analyses, to give them an opportunity
363 // to self-validate. Now is as good a time as any to do this.
364 if (validationEnabled()) {
365 dfg.ensureCPSDominators();
366 dfg.ensureCPSNaturalLoops();
367 }
368
369 switch (m_mode) {
370 case DFGMode: {
371 dfg.m_fixpointState = FixpointConverged;
372
373 RUN_PHASE(performTierUpCheckInjection);
374
375 RUN_PHASE(performFastStoreBarrierInsertion);
376 RUN_PHASE(performStoreBarrierClustering);
377 RUN_PHASE(performCleanUp);
378 RUN_PHASE(performCPSRethreading);
379 RUN_PHASE(performDCE);
380 RUN_PHASE(performPhantomInsertion);
381 RUN_PHASE(performStackLayout);
382 RUN_PHASE(performVirtualRegisterAllocation);
383 RUN_PHASE(performWatchpointCollection);
384 dumpAndVerifyGraph(dfg, "Graph after optimization:");
385
386 JITCompiler dataFlowJIT(dfg);
387 if (m_codeBlock->codeType() == FunctionCode)
388 dataFlowJIT.compileFunction();
389 else
390 dataFlowJIT.compile();
391
392 return DFGPath;
393 }
394
395 case FTLMode:
396 case FTLForOSREntryMode: {
397#if ENABLE(FTL_JIT)
398 if (FTL::canCompile(dfg) == FTL::CannotCompile) {
399 m_finalizer = std::make_unique<FailedFinalizer>(*this);
400 return FailPath;
401 }
402
403 RUN_PHASE(performCleanUp); // Reduce the graph size a bit.
404 RUN_PHASE(performCriticalEdgeBreaking);
405 if (Options::createPreHeaders())
406 RUN_PHASE(performLoopPreHeaderCreation);
407 RUN_PHASE(performCPSRethreading);
408 RUN_PHASE(performSSAConversion);
409 RUN_PHASE(performSSALowering);
410
411 // Ideally, these would be run to fixpoint with the object allocation sinking phase.
412 RUN_PHASE(performArgumentsElimination);
413 if (Options::usePutStackSinking())
414 RUN_PHASE(performPutStackSinking);
415
416 RUN_PHASE(performConstantHoisting);
417 RUN_PHASE(performGlobalCSE);
418 RUN_PHASE(performLivenessAnalysis);
419 RUN_PHASE(performCFA);
420 RUN_PHASE(performConstantFolding);
421 RUN_PHASE(performCleanUp); // Reduce the graph size a lot.
422 changed = false;
423 RUN_PHASE(performStrengthReduction);
424 if (Options::useObjectAllocationSinking()) {
425 RUN_PHASE(performCriticalEdgeBreaking);
426 RUN_PHASE(performObjectAllocationSinking);
427 }
428 if (Options::useValueRepElimination())
429 RUN_PHASE(performValueRepReduction);
430 if (changed) {
431 // State-at-tail and state-at-head will be invalid if we did strength reduction since
432 // it might increase live ranges.
433 RUN_PHASE(performLivenessAnalysis);
434 RUN_PHASE(performCFA);
435 RUN_PHASE(performConstantFolding);
436 }
437
438 // Currently, this relies on pre-headers still being valid. That precludes running CFG
439 // simplification before it, unless we re-created the pre-headers. There wouldn't be anything
440 // wrong with running LICM earlier, if we wanted to put other CFG transforms above this point.
441 // Alternatively, we could run loop pre-header creation after SSA conversion - but if we did that
442 // then we'd need to do some simple SSA fix-up.
443 RUN_PHASE(performLivenessAnalysis);
444 RUN_PHASE(performCFA);
445 RUN_PHASE(performLICM);
446
447 // FIXME: Currently: IntegerRangeOptimization *must* be run after LICM.
448 //
449 // IntegerRangeOptimization makes changes on nodes based on preceding blocks
450 // and nodes. LICM moves nodes which can invalidates assumptions used
451 // by IntegerRangeOptimization.
452 //
453 // Ideally, the dependencies should be explicit. See https://bugs.webkit.org/show_bug.cgi?id=157534.
454 RUN_PHASE(performLivenessAnalysis);
455 RUN_PHASE(performIntegerRangeOptimization);
456
457 RUN_PHASE(performCleanUp);
458 RUN_PHASE(performIntegerCheckCombining);
459 RUN_PHASE(performGlobalCSE);
460
461 // At this point we're not allowed to do any further code motion because our reasoning
462 // about code motion assumes that it's OK to insert GC points in random places.
463 dfg.m_fixpointState = FixpointConverged;
464
465 RUN_PHASE(performLivenessAnalysis);
466 RUN_PHASE(performCFA);
467 RUN_PHASE(performGlobalStoreBarrierInsertion);
468 RUN_PHASE(performStoreBarrierClustering);
469 if (Options::useMovHintRemoval())
470 RUN_PHASE(performMovHintRemoval);
471 RUN_PHASE(performCleanUp);
472 RUN_PHASE(performDCE); // We rely on this to kill dead code that won't be recognized as dead by B3.
473 RUN_PHASE(performStackLayout);
474 RUN_PHASE(performLivenessAnalysis);
475 RUN_PHASE(performOSRAvailabilityAnalysis);
476 RUN_PHASE(performWatchpointCollection);
477
478 if (FTL::canCompile(dfg) == FTL::CannotCompile) {
479 m_finalizer = std::make_unique<FailedFinalizer>(*this);
480 return FailPath;
481 }
482
483 dumpAndVerifyGraph(dfg, "Graph just before FTL lowering:", shouldDumpDisassembly(m_mode));
484
485 // Flash a safepoint in case the GC wants some action.
486 Safepoint::Result safepointResult;
487 {
488 GraphSafepoint safepoint(dfg, safepointResult);
489 }
490 if (safepointResult.didGetCancelled())
491 return CancelPath;
492
493 FTL::State state(dfg);
494 FTL::lowerDFGToB3(state);
495
496 if (UNLIKELY(computeCompileTimes()))
497 m_timeBeforeFTL = MonotonicTime::now();
498
499 if (Options::b3AlwaysFailsBeforeCompile()) {
500 FTL::fail(state);
501 return FTLPath;
502 }
503
504 FTL::compile(state, safepointResult);
505 if (safepointResult.didGetCancelled())
506 return CancelPath;
507
508 if (Options::b3AlwaysFailsBeforeLink()) {
509 FTL::fail(state);
510 return FTLPath;
511 }
512
513 if (state.allocationFailed) {
514 FTL::fail(state);
515 return FTLPath;
516 }
517
518 FTL::link(state);
519
520 if (state.allocationFailed) {
521 FTL::fail(state);
522 return FTLPath;
523 }
524
525 return FTLPath;
526#else
527 RELEASE_ASSERT_NOT_REACHED();
528 return FailPath;
529#endif // ENABLE(FTL_JIT)
530 }
531
532 default:
533 RELEASE_ASSERT_NOT_REACHED();
534 return FailPath;
535 }
536
537#undef RUN_PHASE
538}
539
540bool Plan::isStillValid()
541{
542 CodeBlock* replacement = m_codeBlock->replacement();
543 if (!replacement)
544 return false;
545 // FIXME: This is almost certainly not necessary. There's no way for the baseline
546 // code to be replaced during a compilation, except if we delete the plan, in which
547 // case we wouldn't be here.
548 // https://bugs.webkit.org/show_bug.cgi?id=132707
549 if (m_codeBlock->alternative() != replacement->baselineVersion())
550 return false;
551 if (!m_watchpoints.areStillValid())
552 return false;
553 return true;
554}
555
556void Plan::reallyAdd(CommonData* commonData)
557{
558 m_watchpoints.reallyAdd(m_codeBlock, *commonData);
559 m_identifiers.reallyAdd(*m_vm, commonData);
560 m_weakReferences.reallyAdd(*m_vm, commonData);
561 m_transitions.reallyAdd(*m_vm, commonData);
562 m_globalProperties.reallyAdd(m_codeBlock, m_identifiers, *commonData);
563 commonData->recordedStatuses = WTFMove(m_recordedStatuses);
564}
565
566void Plan::notifyCompiling()
567{
568 m_stage = Compiling;
569}
570
571void Plan::notifyReady()
572{
573 m_callback->compilationDidBecomeReadyAsynchronously(m_codeBlock, m_profiledDFGCodeBlock);
574 m_stage = Ready;
575}
576
577bool Plan::isStillValidOnMainThread()
578{
579 return m_globalProperties.isStillValidOnMainThread(*m_vm, m_identifiers);
580}
581
582CompilationResult Plan::finalizeWithoutNotifyingCallback()
583{
584 // We will establish new references from the code block to things. So, we need a barrier.
585 m_vm->heap.writeBarrier(m_codeBlock);
586
587 if (!isStillValidOnMainThread() || !isStillValid()) {
588 CODEBLOCK_LOG_EVENT(m_codeBlock, "dfgFinalize", ("invalidated"));
589 return CompilationInvalidated;
590 }
591
592 bool result;
593 if (m_codeBlock->codeType() == FunctionCode)
594 result = m_finalizer->finalizeFunction();
595 else
596 result = m_finalizer->finalize();
597
598 if (!result) {
599 CODEBLOCK_LOG_EVENT(m_codeBlock, "dfgFinalize", ("failed"));
600 return CompilationFailed;
601 }
602
603 reallyAdd(m_codeBlock->jitCode()->dfgCommon());
604
605 if (validationEnabled()) {
606 TrackedReferences trackedReferences;
607
608 for (WriteBarrier<JSCell>& reference : m_codeBlock->jitCode()->dfgCommon()->weakReferences)
609 trackedReferences.add(reference.get());
610 for (WriteBarrier<Structure>& reference : m_codeBlock->jitCode()->dfgCommon()->weakStructureReferences)
611 trackedReferences.add(reference.get());
612 for (WriteBarrier<Unknown>& constant : m_codeBlock->constants())
613 trackedReferences.add(constant.get());
614
615 for (auto* inlineCallFrame : *m_inlineCallFrames) {
616 ASSERT(inlineCallFrame->baselineCodeBlock.get());
617 trackedReferences.add(inlineCallFrame->baselineCodeBlock.get());
618 }
619
620 // Check that any other references that we have anywhere in the JITCode are also
621 // tracked either strongly or weakly.
622 m_codeBlock->jitCode()->validateReferences(trackedReferences);
623 }
624
625 CODEBLOCK_LOG_EVENT(m_codeBlock, "dfgFinalize", ("succeeded"));
626 return CompilationSuccessful;
627}
628
629void Plan::finalizeAndNotifyCallback()
630{
631 m_callback->compilationDidComplete(m_codeBlock, m_profiledDFGCodeBlock, finalizeWithoutNotifyingCallback());
632}
633
634CompilationKey Plan::key()
635{
636 return CompilationKey(m_codeBlock->alternative(), m_mode);
637}
638
639void Plan::checkLivenessAndVisitChildren(SlotVisitor& visitor)
640{
641 if (!isKnownToBeLiveDuringGC())
642 return;
643
644 cleanMustHandleValuesIfNecessary();
645 for (unsigned i = m_mustHandleValues.size(); i--;) {
646 Optional<JSValue> value = m_mustHandleValues[i];
647 if (value)
648 visitor.appendUnbarriered(value.value());
649 }
650
651 m_recordedStatuses.markIfCheap(visitor);
652
653 visitor.appendUnbarriered(m_codeBlock);
654 visitor.appendUnbarriered(m_codeBlock->alternative());
655 visitor.appendUnbarriered(m_profiledDFGCodeBlock);
656
657 if (m_inlineCallFrames) {
658 for (auto* inlineCallFrame : *m_inlineCallFrames) {
659 ASSERT(inlineCallFrame->baselineCodeBlock.get());
660 visitor.appendUnbarriered(inlineCallFrame->baselineCodeBlock.get());
661 }
662 }
663
664 m_weakReferences.visitChildren(visitor);
665 m_transitions.visitChildren(visitor);
666}
667
668void Plan::finalizeInGC()
669{
670 ASSERT(m_vm);
671 m_recordedStatuses.finalizeWithoutDeleting(*m_vm);
672}
673
674bool Plan::isKnownToBeLiveDuringGC()
675{
676 if (m_stage == Cancelled)
677 return false;
678 if (!m_vm->heap.isMarked(m_codeBlock->ownerExecutable()))
679 return false;
680 if (!m_vm->heap.isMarked(m_codeBlock->alternative()))
681 return false;
682 if (!!m_profiledDFGCodeBlock && !m_vm->heap.isMarked(m_profiledDFGCodeBlock))
683 return false;
684 return true;
685}
686
687void Plan::cancel()
688{
689 m_vm = nullptr;
690 m_codeBlock = nullptr;
691 m_profiledDFGCodeBlock = nullptr;
692 m_mustHandleValues.clear();
693 m_compilation = nullptr;
694 m_finalizer = nullptr;
695 m_inlineCallFrames = nullptr;
696 m_watchpoints = DesiredWatchpoints();
697 m_identifiers = DesiredIdentifiers();
698 m_globalProperties = DesiredGlobalProperties();
699 m_weakReferences = DesiredWeakReferences();
700 m_transitions = DesiredTransitions();
701 m_callback = nullptr;
702 m_stage = Cancelled;
703}
704
705void Plan::cleanMustHandleValuesIfNecessary()
706{
707 LockHolder locker(m_mustHandleValueCleaningLock);
708
709 if (!m_mustHandleValuesMayIncludeGarbage)
710 return;
711
712 m_mustHandleValuesMayIncludeGarbage = false;
713
714 if (!m_codeBlock)
715 return;
716
717 if (!m_mustHandleValues.numberOfLocals())
718 return;
719
720 CodeBlock* alternative = m_codeBlock->alternative();
721 FastBitVector liveness = alternative->livenessAnalysis().getLivenessInfoAtBytecodeOffset(alternative, m_osrEntryBytecodeIndex);
722
723 for (unsigned local = m_mustHandleValues.numberOfLocals(); local--;) {
724 if (!liveness[local])
725 m_mustHandleValues.local(local) = WTF::nullopt;
726 }
727}
728
729} } // namespace JSC::DFG
730
731#endif // ENABLE(DFG_JIT)
732
733