1/*
2 * Copyright (C) 2011-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#pragma once
27
28#if ENABLE(DFG_JIT)
29
30#include "DFGOSRExitBase.h"
31#include "DFGVariableEventStream.h"
32#include "GPRInfo.h"
33#include "MacroAssembler.h"
34#include "MethodOfGettingAValueProfile.h"
35#include "Operands.h"
36#include "ValueRecovery.h"
37#include <wtf/RefPtr.h>
38
39namespace JSC {
40
41class ArrayProfile;
42class CCallHelpers;
43
44namespace Probe {
45class Context;
46} // namespace Probe
47
48namespace Profiler {
49class OSRExit;
50} // namespace Profiler
51
52namespace DFG {
53
54class SpeculativeJIT;
55struct BasicBlock;
56struct Node;
57
58// This enum describes the types of additional recovery that
59// may need be performed should a speculation check fail.
60enum SpeculationRecoveryType : uint8_t {
61 SpeculativeAdd,
62 SpeculativeAddSelf,
63 SpeculativeAddImmediate,
64 BooleanSpeculationCheck
65};
66
67// === SpeculationRecovery ===
68//
69// This class provides additional information that may be associated with a
70// speculation check - for example
71class SpeculationRecovery {
72public:
73 SpeculationRecovery(SpeculationRecoveryType type, GPRReg dest, GPRReg src)
74 : m_src(src)
75 , m_dest(dest)
76 , m_type(type)
77 {
78 ASSERT(m_type == SpeculativeAdd || m_type == SpeculativeAddSelf || m_type == BooleanSpeculationCheck);
79 }
80
81 SpeculationRecovery(SpeculationRecoveryType type, GPRReg dest, int32_t immediate)
82 : m_immediate(immediate)
83 , m_dest(dest)
84 , m_type(type)
85 {
86 ASSERT(m_type == SpeculativeAddImmediate);
87 }
88
89 SpeculationRecoveryType type() { return m_type; }
90 GPRReg dest() { return m_dest; }
91 GPRReg src() { return m_src; }
92 int32_t immediate() { return m_immediate; }
93
94private:
95 // different recovery types may required different additional information here.
96 union {
97 GPRReg m_src;
98 int32_t m_immediate;
99 };
100 GPRReg m_dest;
101
102 // Indicates the type of additional recovery to be performed.
103 SpeculationRecoveryType m_type;
104};
105
106enum class ExtraInitializationLevel;
107
108struct OSRExitState : RefCounted<OSRExitState> {
109 OSRExitState(OSRExitBase& exit, CodeBlock* codeBlock, CodeBlock* baselineCodeBlock, Operands<ValueRecovery>& operands, Vector<UndefinedOperandSpan>&& undefinedOperandSpans, SpeculationRecovery* recovery, ptrdiff_t stackPointerOffset, int32_t activeThreshold, double memoryUsageAdjustedThreshold, void* jumpTarget, ArrayProfile* arrayProfile)
110 : exit(exit)
111 , codeBlock(codeBlock)
112 , baselineCodeBlock(baselineCodeBlock)
113 , operands(operands)
114 , undefinedOperandSpans(undefinedOperandSpans)
115 , recovery(recovery)
116 , stackPointerOffset(stackPointerOffset)
117 , activeThreshold(activeThreshold)
118 , memoryUsageAdjustedThreshold(memoryUsageAdjustedThreshold)
119 , jumpTarget(jumpTarget)
120 , arrayProfile(arrayProfile)
121 { }
122
123 OSRExitBase& exit;
124 CodeBlock* codeBlock;
125 CodeBlock* baselineCodeBlock;
126 Operands<ValueRecovery> operands;
127 Vector<UndefinedOperandSpan> undefinedOperandSpans;
128 SpeculationRecovery* recovery;
129 ptrdiff_t stackPointerOffset;
130 uint32_t activeThreshold;
131 double memoryUsageAdjustedThreshold;
132 void* jumpTarget;
133 ArrayProfile* arrayProfile;
134
135 ExtraInitializationLevel extraInitializationLevel;
136 Profiler::OSRExit* profilerExit { nullptr };
137};
138
139// === OSRExit ===
140//
141// This structure describes how to exit the speculative path by
142// going into baseline code.
143struct OSRExit : public OSRExitBase {
144 OSRExit(ExitKind, JSValueSource, MethodOfGettingAValueProfile, SpeculativeJIT*, unsigned streamIndex, unsigned recoveryIndex = UINT_MAX);
145
146 static void JIT_OPERATION compileOSRExit(ExecState*) WTF_INTERNAL;
147 static void executeOSRExit(Probe::Context&);
148
149 CodeLocationLabel<JSInternalPtrTag> m_patchableJumpLocation;
150 MacroAssemblerCodeRef<OSRExitPtrTag> m_code;
151
152 RefPtr<OSRExitState> exitState;
153
154 JSValueSource m_jsValueSource;
155 MethodOfGettingAValueProfile m_valueProfile;
156
157 unsigned m_recoveryIndex;
158
159 CodeLocationJump<JSInternalPtrTag> codeLocationForRepatch() const;
160
161 unsigned m_streamIndex;
162 void considerAddingAsFrequentExitSite(CodeBlock* profiledCodeBlock)
163 {
164 OSRExitBase::considerAddingAsFrequentExitSite(profiledCodeBlock, ExitFromDFG);
165 }
166
167private:
168 static void compileExit(CCallHelpers&, VM&, const OSRExit&, const Operands<ValueRecovery>&, SpeculationRecovery*);
169 static void emitRestoreArguments(CCallHelpers&, const Operands<ValueRecovery>&);
170 static void JIT_OPERATION debugOperationPrintSpeculationFailure(ExecState*, void*, void*) WTF_INTERNAL;
171};
172
173struct SpeculationFailureDebugInfo {
174 CodeBlock* codeBlock;
175 ExitKind kind;
176 unsigned bytecodeOffset;
177};
178
179} } // namespace JSC::DFG
180
181#endif // ENABLE(DFG_JIT)
182