File: FTLOSRExit.h

package info (click to toggle)
webkit2gtk 2.6.2%2Bdfsg1-4
  • links: PTS, VCS
  • area: main
  • in suites: jessie, jessie-kfreebsd
  • size: 115,572 kB
  • ctags: 216,388
  • sloc: cpp: 1,164,175; ansic: 18,422; perl: 16,884; python: 11,608; ruby: 9,409; xml: 8,376; asm: 4,765; yacc: 2,292; lex: 891; sh: 650; makefile: 79
file content (179 lines) | stat: -rw-r--r-- 8,650 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
/*
 * Copyright (C) 2013 Apple Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
 */

#ifndef FTLOSRExit_h
#define FTLOSRExit_h

#if ENABLE(FTL_JIT)

#include "CodeOrigin.h"
#include "DFGExitProfile.h"
#include "DFGOSRExitBase.h"
#include "FTLAbbreviations.h"
#include "FTLExitArgumentList.h"
#include "FTLExitValue.h"
#include "FTLFormattedValue.h"
#include "MethodOfGettingAValueProfile.h"
#include "Operands.h"
#include "ValueProfile.h"
#include "VirtualRegister.h"

namespace JSC { namespace FTL {

// Tracks one OSR exit site within the FTL JIT. OSR exit in FTL works by deconstructing
// the crazy that is OSR down to simple SSA CFG primitives that any compiler backend
// (including of course LLVM) can grok and do meaningful things to. Except for
// watchpoint-based exits, which haven't yet been implemented (see webkit.org/b/113647),
// an exit is just a conditional branch in the emitted code where one destination is the
// continuation and the other is a basic block that performs a no-return tail-call to an
// exit thunk. This thunk takes as its arguments the live non-constant
// not-already-accounted-for bytecode state. To appreciate how this works consider the
// following JavaScript program, and its lowering down to LLVM IR including the relevant
// exits:
//
// function foo(o) {
//     var a = o.a; // predicted int
//     var b = o.b;
//     var c = o.c; // NB this is dead
//     a = a | 5; // our example OSR exit: need to check if a is an int
//     return a + b;
// }
//
// Just consider the "a | 5". In the DFG IR, this looks like:
//
// BitOr(Check:Int32:@a, Int32:5)
//
// Where @a is the node for the GetLocal node that gets the value of the 'a' variable.
// Conceptually, this node can be further broken down to the following (note that this
// particular lowering never actually happens - we skip this step and go straight to
// LLVM IR - but it's still useful to see this):
//
// exitIf(@a is not int32);
// continuation;
//
// Where 'exitIf()' is a function that will exit if the argument is true, and
// 'continuation' is the stuff that we will do after the exitIf() check. (Note that
// FTL refers to 'exitIf()' as 'speculate()', which is in line with DFG terminology.)
// This then gets broken down to the following LLVM IR, assuming that %0 is the LLVM
// value corresponding to variable 'a', and %1 is the LLVM value for variable 'b':
//
//   %2 = ... // the predictate corresponding to '@a is not int32'
//   br i1 %2, label %3, label %4
// ; <label>:3
//   call void exitThunk1(%0, %1) // pass 'a' and 'b', since they're both live-in-bytecode
//   unreachable
// ; <label>:4
//   ... // code for the continuation
//
// Where 'exitThunk1' is the IR to get the exit thunk for *this* OSR exit. Each OSR
// exit will appear to LLVM to have a distinct exit thunk.
//
// Note that this didn't have to pass '5', 'o', or 'c' to the exit thunk. 5 is a
// constant and the DFG already knows that, and can already tell the OSR exit machinery
// what that contant is and which bytecode variables (if any) it needs to be dropped
// into. This is conveyed to the exit statically, via the OSRExit data structure below.
// See the code for ExitValue for details. 'o' is an argument, and arguments are always
// "flushed" - if you never assign them then their values are still in the argument
// stack slots, and if you do assign them then we eagerly store them into those slots.
// 'c' is dead in bytecode, and the DFG knows this; we statically tell the exit thunk
// that it's dead and don't have to pass anything. The exit thunk will "initialize" its
// value to Undefined.
//
// This approach to OSR exit has a number of virtues:
//
// - It is an entirely unsurprising representation for a compiler that already groks
//   CFG-like IRs for C-like languages. All existing analyses and transformations just
//   work.
//
// - It lends itself naturally to modern approaches to code motion. For example, you
//   could sink operations from above the exit to below it, if you just duplicate the
//   operation into the OSR exit block. This is both legal and desirable. It works
//   because the backend sees the OSR exit block as being no different than any other,
//   and LLVM already supports sinking if it sees that a value is only partially used.
//   Hence there exists a value that dominates the exit but is only used by the exit
//   thunk and not by the continuation, sinking ought to kick in for that value.
//   Hoisting operations from below it to above it is also possible, for similar
//   reasons.
//
// - The no-return tail-call to the OSR exit thunk can be subjected to specialized
//   code-size reduction optimizations, though this is optional. For example, instead
//   of actually emitting a call along with all that goes with it (like placing the
//   arguments into argument position), the backend could choose to simply inform us
//   where it had placed the arguments and expect the callee (i.e. the exit thunk) to
//   figure it out from there. It could also tell us what we need to do to pop stack,
//   although again, it doesn't have to; it could just emit that code normally. Though
//   we don't support this yet, we could; the only thing that would change on our end
//   is that we'd need feedback from the backend about the location of the arguments
//   and a description of the things that need to be done to pop stack. This would
//   involve switching the m_values array to use something more akin to ValueRecovery
//   rather than the current ExitValue, albeit possibly with some hacks to better
//   understand the kinds of places where the LLVM backend would put values.
//
// - It could be extended to allow the backend to do its own exit hoisting, by using
//   intrinsics (or meta-data, or something) to inform the backend that it's safe to
//   make the predicate passed to 'exitIf()' more truthy.
//
// - It could be extended to support watchpoints (see webkit.org/b/113647) by making
//   the predicate passed to 'exitIf()' be an intrinsic that the backend knows to be
//   true at compile-time. The backend could then turn the conditional branch into a
//   replaceable jump, much like the DFG does.

struct OSRExit : public DFG::OSRExitBase {
    OSRExit(
        ExitKind, ValueFormat profileValueFormat, MethodOfGettingAValueProfile,
        CodeOrigin, CodeOrigin originForProfile,
        unsigned numberOfArguments, unsigned numberOfLocals);
    
    MacroAssemblerCodeRef m_code;
    
    // The first argument to the exit call may be a value we wish to profile.
    // If that's the case, the format will be not Invalid and we'll have a
    // method of getting a value profile. Note that all of the ExitArgument's
    // are already aware of this possible off-by-one, so there is no need to
    // correct them.
    ValueFormat m_profileValueFormat;
    MethodOfGettingAValueProfile m_valueProfile;
    
    // Offset within the exit stubs of the stub for this exit.
    unsigned m_patchableCodeOffset;
    
    Operands<ExitValue> m_values;
    
    uint32_t m_stackmapID;
    
    CodeLocationJump codeLocationForRepatch(CodeBlock* ftlCodeBlock) const;
    
    bool considerAddingAsFrequentExitSite(CodeBlock* profiledCodeBlock)
    {
        return OSRExitBase::considerAddingAsFrequentExitSite(profiledCodeBlock, ExitFromFTL);
    }
};

} } // namespace JSC::FTL

#endif // ENABLE(FTL_JIT)

#endif // FTLOSRExit_h