blob: 32dfe92a941ec9bf8282c964c01f5ba571fc31cc [file] [log] [blame]
oliver@apple.comea771492013-07-25 03:58:38 +00001/*
fpizlo@apple.combcfd8eb2015-02-26 19:51:52 +00002 * Copyright (C) 2013-2015 Apple Inc. All rights reserved.
oliver@apple.comea771492013-07-25 03:58:38 +00003 *
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#ifndef FTLOSRExit_h
27#define FTLOSRExit_h
28
oliver@apple.comea771492013-07-25 03:58:38 +000029#if ENABLE(FTL_JIT)
30
31#include "CodeOrigin.h"
32#include "DFGExitProfile.h"
33#include "DFGOSRExitBase.h"
benjamin@webkit.org0badc6d2015-11-18 01:53:44 +000034#include "FTLAbbreviatedTypes.h"
fpizlo@apple.comfc70ba62014-09-26 03:59:33 +000035#include "FTLExitTimeObjectMaterialization.h"
oliver@apple.comea771492013-07-25 03:58:38 +000036#include "FTLExitValue.h"
37#include "FTLFormattedValue.h"
sbarati@apple.com5bebda72015-11-10 07:48:54 +000038#include "FTLStackMaps.h"
sbarati@apple.comc13003f2015-11-10 20:42:32 +000039#include "FTLStackmapArgumentList.h"
sbarati@apple.com5bebda72015-11-10 07:48:54 +000040#include "HandlerInfo.h"
oliver@apple.comea771492013-07-25 03:58:38 +000041#include "MethodOfGettingAValueProfile.h"
42#include "Operands.h"
sbarati@apple.com5bebda72015-11-10 07:48:54 +000043#include "Reg.h"
oliver@apple.comea771492013-07-25 03:58:38 +000044#include "ValueProfile.h"
msaboff@apple.com62aa8b72013-09-26 22:53:54 +000045#include "VirtualRegister.h"
oliver@apple.comea771492013-07-25 03:58:38 +000046
fpizlo@apple.com93398892015-07-10 21:19:51 +000047namespace JSC {
48
49class TrackedReferences;
50
51namespace FTL {
oliver@apple.comea771492013-07-25 03:58:38 +000052
53// Tracks one OSR exit site within the FTL JIT. OSR exit in FTL works by deconstructing
54// the crazy that is OSR down to simple SSA CFG primitives that any compiler backend
fpizlo@apple.combcfd8eb2015-02-26 19:51:52 +000055// (including of course LLVM) can grok and do meaningful things to. An exit is just a
56// conditional branch in the emitted code where one destination is the continuation and
57// the other is a basic block that performs a no-return tail-call to an exit thunk.
58// This thunk takes as its arguments the live non-constant not-already-accounted-for
59// bytecode state. To appreciate how this works consider the following JavaScript
60// program, and its lowering down to LLVM IR including the relevant exits:
oliver@apple.comea771492013-07-25 03:58:38 +000061//
62// function foo(o) {
63// var a = o.a; // predicted int
64// var b = o.b;
65// var c = o.c; // NB this is dead
66// a = a | 5; // our example OSR exit: need to check if a is an int
67// return a + b;
68// }
69//
70// Just consider the "a | 5". In the DFG IR, this looks like:
71//
72// BitOr(Check:Int32:@a, Int32:5)
73//
fpizlo@apple.combcfd8eb2015-02-26 19:51:52 +000074// Where @a is the node for the value of the 'a' variable. Conceptually, this node can
75// be further broken down to the following (note that this particular lowering never
76// actually happens - we skip this step and go straight to LLVM IR - but it's still
77// useful to see this):
oliver@apple.comea771492013-07-25 03:58:38 +000078//
79// exitIf(@a is not int32);
80// continuation;
81//
82// Where 'exitIf()' is a function that will exit if the argument is true, and
83// 'continuation' is the stuff that we will do after the exitIf() check. (Note that
84// FTL refers to 'exitIf()' as 'speculate()', which is in line with DFG terminology.)
85// This then gets broken down to the following LLVM IR, assuming that %0 is the LLVM
86// value corresponding to variable 'a', and %1 is the LLVM value for variable 'b':
87//
88// %2 = ... // the predictate corresponding to '@a is not int32'
89// br i1 %2, label %3, label %4
90// ; <label>:3
91// call void exitThunk1(%0, %1) // pass 'a' and 'b', since they're both live-in-bytecode
92// unreachable
93// ; <label>:4
94// ... // code for the continuation
95//
96// Where 'exitThunk1' is the IR to get the exit thunk for *this* OSR exit. Each OSR
97// exit will appear to LLVM to have a distinct exit thunk.
98//
99// Note that this didn't have to pass '5', 'o', or 'c' to the exit thunk. 5 is a
100// constant and the DFG already knows that, and can already tell the OSR exit machinery
101// what that contant is and which bytecode variables (if any) it needs to be dropped
102// into. This is conveyed to the exit statically, via the OSRExit data structure below.
103// See the code for ExitValue for details. 'o' is an argument, and arguments are always
104// "flushed" - if you never assign them then their values are still in the argument
105// stack slots, and if you do assign them then we eagerly store them into those slots.
106// 'c' is dead in bytecode, and the DFG knows this; we statically tell the exit thunk
107// that it's dead and don't have to pass anything. The exit thunk will "initialize" its
108// value to Undefined.
109//
110// This approach to OSR exit has a number of virtues:
111//
112// - It is an entirely unsurprising representation for a compiler that already groks
113// CFG-like IRs for C-like languages. All existing analyses and transformations just
114// work.
115//
116// - It lends itself naturally to modern approaches to code motion. For example, you
117// could sink operations from above the exit to below it, if you just duplicate the
118// operation into the OSR exit block. This is both legal and desirable. It works
119// because the backend sees the OSR exit block as being no different than any other,
120// and LLVM already supports sinking if it sees that a value is only partially used.
121// Hence there exists a value that dominates the exit but is only used by the exit
122// thunk and not by the continuation, sinking ought to kick in for that value.
123// Hoisting operations from below it to above it is also possible, for similar
124// reasons.
125//
126// - The no-return tail-call to the OSR exit thunk can be subjected to specialized
127// code-size reduction optimizations, though this is optional. For example, instead
128// of actually emitting a call along with all that goes with it (like placing the
129// arguments into argument position), the backend could choose to simply inform us
130// where it had placed the arguments and expect the callee (i.e. the exit thunk) to
131// figure it out from there. It could also tell us what we need to do to pop stack,
fpizlo@apple.combcfd8eb2015-02-26 19:51:52 +0000132// although again, it doesn't have to; it could just emit that code normally. We do
133// all of these things through the patchpoint/stackmap LLVM intrinsics.
oliver@apple.comea771492013-07-25 03:58:38 +0000134//
135// - It could be extended to allow the backend to do its own exit hoisting, by using
136// intrinsics (or meta-data, or something) to inform the backend that it's safe to
137// make the predicate passed to 'exitIf()' more truthy.
oliver@apple.comea771492013-07-25 03:58:38 +0000138
sbarati@apple.comb887f0d2015-12-01 00:55:32 +0000139enum class ExceptionType : uint8_t {
sbarati@apple.com621078b2015-11-13 21:36:18 +0000140 None,
141 CCallException,
142 JSCall,
143 GetById,
sbarati@apple.comb887f0d2015-12-01 00:55:32 +0000144 GetByIdCallOperation,
sbarati@apple.com621078b2015-11-13 21:36:18 +0000145 PutById,
sbarati@apple.comb887f0d2015-12-01 00:55:32 +0000146 PutByIdCallOperation,
sbarati@apple.com621078b2015-11-13 21:36:18 +0000147 LazySlowPath,
sbarati@apple.comb887f0d2015-12-01 00:55:32 +0000148 SubGenerator,
sbarati@apple.com621078b2015-11-13 21:36:18 +0000149};
150
sbarati@apple.comcda241d2015-10-19 20:29:45 +0000151struct OSRExitDescriptor {
152 OSRExitDescriptor(
sbarati@apple.com621078b2015-11-13 21:36:18 +0000153 ExitKind, ExceptionType, DataFormat profileDataFormat, MethodOfGettingAValueProfile,
fpizlo@apple.com9a5ab802013-11-12 03:28:41 +0000154 CodeOrigin, CodeOrigin originForProfile,
oliver@apple.comcf496162013-07-25 04:05:22 +0000155 unsigned numberOfArguments, unsigned numberOfLocals);
sbarati@apple.comcda241d2015-10-19 20:29:45 +0000156
sbarati@apple.com621078b2015-11-13 21:36:18 +0000157 bool isExceptionHandler() const;
158
sbarati@apple.comcda241d2015-10-19 20:29:45 +0000159 ExitKind m_kind;
sbarati@apple.com621078b2015-11-13 21:36:18 +0000160 ExceptionType m_exceptionType;
sbarati@apple.comcda241d2015-10-19 20:29:45 +0000161 CodeOrigin m_codeOrigin;
162 CodeOrigin m_codeOriginForExitProfile;
sbarati@apple.com5bebda72015-11-10 07:48:54 +0000163 CodeOrigin m_semanticCodeOriginForCallFrameHeader;
oliver@apple.comea771492013-07-25 03:58:38 +0000164
165 // The first argument to the exit call may be a value we wish to profile.
166 // If that's the case, the format will be not Invalid and we'll have a
167 // method of getting a value profile. Note that all of the ExitArgument's
168 // are already aware of this possible off-by-one, so there is no need to
169 // correct them.
basile_clement@apple.com3ed5a3a2015-09-04 18:24:38 +0000170 DataFormat m_profileDataFormat;
oliver@apple.comea771492013-07-25 03:58:38 +0000171 MethodOfGettingAValueProfile m_valueProfile;
172
oliver@apple.comea771492013-07-25 03:58:38 +0000173 Operands<ExitValue> m_values;
fpizlo@apple.comfc70ba62014-09-26 03:59:33 +0000174 Bag<ExitTimeObjectMaterialization> m_materializations;
oliver@apple.comea771492013-07-25 03:58:38 +0000175
fpizlo@apple.comea92c202013-10-10 04:24:57 +0000176 uint32_t m_stackmapID;
sbarati@apple.com5bebda72015-11-10 07:48:54 +0000177 HandlerInfo m_baselineExceptionHandler;
178 bool m_isInvalidationPoint : 1;
fpizlo@apple.comea92c202013-10-10 04:24:57 +0000179
sbarati@apple.comcda241d2015-10-19 20:29:45 +0000180 void validateReferences(const TrackedReferences&);
181};
182
183struct OSRExit : public DFG::OSRExitBase {
184 OSRExit(OSRExitDescriptor&, uint32_t stackmapRecordIndex);
185
186 OSRExitDescriptor& m_descriptor;
187 MacroAssemblerCodeRef m_code;
188 // Offset within the exit stubs of the stub for this exit.
189 unsigned m_patchableCodeOffset;
190 // Offset within Stackmap::records
191 uint32_t m_stackmapRecordIndex;
sbarati@apple.comb887f0d2015-12-01 00:55:32 +0000192 ExceptionType m_exceptionType;
sbarati@apple.comcda241d2015-10-19 20:29:45 +0000193
sbarati@apple.com5bebda72015-11-10 07:48:54 +0000194 RegisterSet registersToPreserveForCallThatMightThrow;
195
oliver@apple.comea771492013-07-25 03:58:38 +0000196 CodeLocationJump codeLocationForRepatch(CodeBlock* ftlCodeBlock) const;
benjamin@webkit.org6f63a8b2015-02-18 07:04:10 +0000197 void considerAddingAsFrequentExitSite(CodeBlock* profiledCodeBlock)
msaboff@apple.com95894332014-01-29 19:18:54 +0000198 {
benjamin@webkit.org6f63a8b2015-02-18 07:04:10 +0000199 OSRExitBase::considerAddingAsFrequentExitSite(profiledCodeBlock, ExitFromFTL);
msaboff@apple.com95894332014-01-29 19:18:54 +0000200 }
sbarati@apple.com5bebda72015-11-10 07:48:54 +0000201
202 void gatherRegistersToSpillForCallIfException(StackMaps&, StackMaps::Record&);
203 void spillRegistersToSpillSlot(CCallHelpers&, int32_t stackSpillSlot);
204 void recoverRegistersFromSpillSlot(CCallHelpers& jit, int32_t stackSpillSlot);
sbarati@apple.comb887f0d2015-12-01 00:55:32 +0000205
206 bool willArriveAtOSRExitFromGenericUnwind() const;
207 bool willArriveAtExitFromIndirectExceptionCheck() const;
208 bool willArriveAtOSRExitFromCallOperation() const;
209 bool needsRegisterRecoveryOnGenericUnwindOSRExitPath() const;
oliver@apple.comea771492013-07-25 03:58:38 +0000210};
211
212} } // namespace JSC::FTL
213
214#endif // ENABLE(FTL_JIT)
215
216#endif // FTLOSRExit_h
217