1/* 2 * Copyright (C) 2013 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#ifndef FTLOSRExit_h 27#define FTLOSRExit_h 28 29#if ENABLE(FTL_JIT) 30 31#include "CodeOrigin.h" 32#include "DFGExitProfile.h" 33#include "DFGOSRExitBase.h" 34#include "FTLAbbreviations.h" 35#include "FTLExitArgumentList.h" 36#include "FTLExitValue.h" 37#include "FTLFormattedValue.h" 38#include "MethodOfGettingAValueProfile.h" 39#include "Operands.h" 40#include "ValueProfile.h" 41#include "VirtualRegister.h" 42 43namespace JSC { namespace FTL { 44 45// Tracks one OSR exit site within the FTL JIT. OSR exit in FTL works by deconstructing 46// the crazy that is OSR down to simple SSA CFG primitives that any compiler backend 47// (including of course LLVM) can grok and do meaningful things to. Except for 48// watchpoint-based exits, which haven't yet been implemented (see webkit.org/b/113647), 49// an exit is just a conditional branch in the emitted code where one destination is the 50// continuation and the other is a basic block that performs a no-return tail-call to an 51// exit thunk. This thunk takes as its arguments the live non-constant 52// not-already-accounted-for bytecode state. To appreciate how this works consider the 53// following JavaScript program, and its lowering down to LLVM IR including the relevant 54// exits: 55// 56// function foo(o) { 57// var a = o.a; // predicted int 58// var b = o.b; 59// var c = o.c; // NB this is dead 60// a = a | 5; // our example OSR exit: need to check if a is an int 61// return a + b; 62// } 63// 64// Just consider the "a | 5". In the DFG IR, this looks like: 65// 66// BitOr(Check:Int32:@a, Int32:5) 67// 68// Where @a is the node for the GetLocal node that gets the value of the 'a' variable. 69// Conceptually, this node can be further broken down to the following (note that this 70// particular lowering never actually happens - we skip this step and go straight to 71// LLVM IR - but it's still useful to see this): 72// 73// exitIf(@a is not int32); 74// continuation; 75// 76// Where 'exitIf()' is a function that will exit if the argument is true, and 77// 'continuation' is the stuff that we will do after the exitIf() check. (Note that 78// FTL refers to 'exitIf()' as 'speculate()', which is in line with DFG terminology.) 79// This then gets broken down to the following LLVM IR, assuming that %0 is the LLVM 80// value corresponding to variable 'a', and %1 is the LLVM value for variable 'b': 81// 82// %2 = ... // the predictate corresponding to '@a is not int32' 83// br i1 %2, label %3, label %4 84// ; <label>:3 85// call void exitThunk1(%0, %1) // pass 'a' and 'b', since they're both live-in-bytecode 86// unreachable 87// ; <label>:4 88// ... // code for the continuation 89// 90// Where 'exitThunk1' is the IR to get the exit thunk for *this* OSR exit. Each OSR 91// exit will appear to LLVM to have a distinct exit thunk. 92// 93// Note that this didn't have to pass '5', 'o', or 'c' to the exit thunk. 5 is a 94// constant and the DFG already knows that, and can already tell the OSR exit machinery 95// what that contant is and which bytecode variables (if any) it needs to be dropped 96// into. This is conveyed to the exit statically, via the OSRExit data structure below. 97// See the code for ExitValue for details. 'o' is an argument, and arguments are always 98// "flushed" - if you never assign them then their values are still in the argument 99// stack slots, and if you do assign them then we eagerly store them into those slots. 100// 'c' is dead in bytecode, and the DFG knows this; we statically tell the exit thunk 101// that it's dead and don't have to pass anything. The exit thunk will "initialize" its 102// value to Undefined. 103// 104// This approach to OSR exit has a number of virtues: 105// 106// - It is an entirely unsurprising representation for a compiler that already groks 107// CFG-like IRs for C-like languages. All existing analyses and transformations just 108// work. 109// 110// - It lends itself naturally to modern approaches to code motion. For example, you 111// could sink operations from above the exit to below it, if you just duplicate the 112// operation into the OSR exit block. This is both legal and desirable. It works 113// because the backend sees the OSR exit block as being no different than any other, 114// and LLVM already supports sinking if it sees that a value is only partially used. 115// Hence there exists a value that dominates the exit but is only used by the exit 116// thunk and not by the continuation, sinking ought to kick in for that value. 117// Hoisting operations from below it to above it is also possible, for similar 118// reasons. 119// 120// - The no-return tail-call to the OSR exit thunk can be subjected to specialized 121// code-size reduction optimizations, though this is optional. For example, instead 122// of actually emitting a call along with all that goes with it (like placing the 123// arguments into argument position), the backend could choose to simply inform us 124// where it had placed the arguments and expect the callee (i.e. the exit thunk) to 125// figure it out from there. It could also tell us what we need to do to pop stack, 126// although again, it doesn't have to; it could just emit that code normally. Though 127// we don't support this yet, we could; the only thing that would change on our end 128// is that we'd need feedback from the backend about the location of the arguments 129// and a description of the things that need to be done to pop stack. This would 130// involve switching the m_values array to use something more akin to ValueRecovery 131// rather than the current ExitValue, albeit possibly with some hacks to better 132// understand the kinds of places where the LLVM backend would put values. 133// 134// - It could be extended to allow the backend to do its own exit hoisting, by using 135// intrinsics (or meta-data, or something) to inform the backend that it's safe to 136// make the predicate passed to 'exitIf()' more truthy. 137// 138// - It could be extended to support watchpoints (see webkit.org/b/113647) by making 139// the predicate passed to 'exitIf()' be an intrinsic that the backend knows to be 140// true at compile-time. The backend could then turn the conditional branch into a 141// replaceable jump, much like the DFG does. 142 143struct OSRExit : public DFG::OSRExitBase { 144 OSRExit( 145 ExitKind, ValueFormat profileValueFormat, MethodOfGettingAValueProfile, 146 CodeOrigin, CodeOrigin originForProfile, 147 unsigned numberOfArguments, unsigned numberOfLocals); 148 149 MacroAssemblerCodeRef m_code; 150 151 // The first argument to the exit call may be a value we wish to profile. 152 // If that's the case, the format will be not Invalid and we'll have a 153 // method of getting a value profile. Note that all of the ExitArgument's 154 // are already aware of this possible off-by-one, so there is no need to 155 // correct them. 156 ValueFormat m_profileValueFormat; 157 MethodOfGettingAValueProfile m_valueProfile; 158 159 // Offset within the exit stubs of the stub for this exit. 160 unsigned m_patchableCodeOffset; 161 162 Operands<ExitValue> m_values; 163 164 uint32_t m_stackmapID; 165 166 CodeLocationJump codeLocationForRepatch(CodeBlock* ftlCodeBlock) const; 167 168 bool considerAddingAsFrequentExitSite(CodeBlock* profiledCodeBlock) 169 { 170 return OSRExitBase::considerAddingAsFrequentExitSite(profiledCodeBlock, ExitFromFTL); 171 } 172}; 173 174} } // namespace JSC::FTL 175 176#endif // ENABLE(FTL_JIT) 177 178#endif // FTLOSRExit_h 179 180