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, bool isJumpToLLInt)
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 , isJumpToLLInt(isJumpToLLInt)
122 { }
123
124 OSRExitBase& exit;
125 CodeBlock* codeBlock;
126 CodeBlock* baselineCodeBlock;
127 Operands<ValueRecovery> operands;
128 Vector<UndefinedOperandSpan> undefinedOperandSpans;
129 SpeculationRecovery* recovery;
130 ptrdiff_t stackPointerOffset;
131 uint32_t activeThreshold;
132 double memoryUsageAdjustedThreshold;
133 void* jumpTarget;
134 ArrayProfile* arrayProfile;
135 bool isJumpToLLInt;
136
137 ExtraInitializationLevel extraInitializationLevel;
138 Profiler::OSRExit* profilerExit { nullptr };
139};
140
141void JIT_OPERATION operationCompileOSRExit(CallFrame*) WTF_INTERNAL;
142void JIT_OPERATION operationDebugPrintSpeculationFailure(CallFrame*, void*, void*) WTF_INTERNAL;
143
144// === OSRExit ===
145//
146// This structure describes how to exit the speculative path by
147// going into baseline code.
148struct OSRExit : public OSRExitBase {
149 OSRExit(ExitKind, JSValueSource, MethodOfGettingAValueProfile, SpeculativeJIT*, unsigned streamIndex, unsigned recoveryIndex = UINT_MAX);
150
151 friend void JIT_OPERATION operationCompileOSRExit(CallFrame*);
152
153 static void executeOSRExit(Probe::Context&);
154
155 CodeLocationLabel<JSInternalPtrTag> m_patchableJumpLocation;
156 MacroAssemblerCodeRef<OSRExitPtrTag> m_code;
157
158 RefPtr<OSRExitState> exitState;
159
160 JSValueSource m_jsValueSource;
161 MethodOfGettingAValueProfile m_valueProfile;
162
163 unsigned m_recoveryIndex;
164
165 CodeLocationJump<JSInternalPtrTag> codeLocationForRepatch() const;
166
167 unsigned m_streamIndex;
168 void considerAddingAsFrequentExitSite(CodeBlock* profiledCodeBlock)
169 {
170 OSRExitBase::considerAddingAsFrequentExitSite(profiledCodeBlock, ExitFromDFG);
171 }
172
173private:
174 static void compileExit(CCallHelpers&, VM&, const OSRExit&, const Operands<ValueRecovery>&, SpeculationRecovery*);
175 static void emitRestoreArguments(CCallHelpers&, VM&, const Operands<ValueRecovery>&);
176 friend void JIT_OPERATION operationDebugPrintSpeculationFailure(CallFrame*, void*, void*);
177};
178
179struct SpeculationFailureDebugInfo {
180 WTF_MAKE_STRUCT_FAST_ALLOCATED;
181 CodeBlock* codeBlock;
182 ExitKind kind;
183 BytecodeIndex bytecodeIndex;
184};
185
186} } // namespace JSC::DFG
187
188#endif // ENABLE(DFG_JIT)
189