]>
Commit | Line | Data |
---|---|---|
6fe7ccc8 A |
1 | /* |
2 | * Copyright (C) 2011 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 | #include "config.h" | |
27 | #include "DFGOSREntry.h" | |
28 | ||
29 | #if ENABLE(DFG_JIT) | |
30 | ||
31 | #include "CallFrame.h" | |
32 | #include "CodeBlock.h" | |
33 | #include "DFGNode.h" | |
34 | #include "JIT.h" | |
35 | ||
36 | namespace JSC { namespace DFG { | |
37 | ||
38 | void* prepareOSREntry(ExecState* exec, CodeBlock* codeBlock, unsigned bytecodeIndex) | |
39 | { | |
40 | #if DFG_ENABLE(OSR_ENTRY) | |
41 | ASSERT(codeBlock->getJITType() == JITCode::DFGJIT); | |
42 | ASSERT(codeBlock->alternative()); | |
43 | ASSERT(codeBlock->alternative()->getJITType() == JITCode::BaselineJIT); | |
44 | ASSERT(!codeBlock->jitCodeMap()); | |
45 | ASSERT(codeBlock->numberOfDFGOSREntries()); | |
46 | ||
47 | #if ENABLE(JIT_VERBOSE_OSR) | |
48 | dataLog("OSR in %p(%p) from bc#%u\n", codeBlock, codeBlock->alternative(), bytecodeIndex); | |
49 | #endif | |
50 | ||
51 | JSGlobalData* globalData = &exec->globalData(); | |
52 | OSREntryData* entry = codeBlock->dfgOSREntryDataForBytecodeIndex(bytecodeIndex); | |
53 | ||
54 | ASSERT(entry->m_bytecodeIndex == bytecodeIndex); | |
55 | ||
56 | // The code below checks if it is safe to perform OSR entry. It may find | |
57 | // that it is unsafe to do so, for any number of reasons, which are documented | |
58 | // below. If the code decides not to OSR then it returns 0, and it's the caller's | |
59 | // responsibility to patch up the state in such a way as to ensure that it's | |
60 | // both safe and efficient to continue executing baseline code for now. This | |
61 | // should almost certainly include calling either codeBlock->optimizeAfterWarmUp() | |
62 | // or codeBlock->dontOptimizeAnytimeSoon(). | |
63 | ||
64 | // 1) Verify predictions. If the predictions are inconsistent with the actual | |
65 | // values, then OSR entry is not possible at this time. It's tempting to | |
66 | // assume that we could somehow avoid this case. We can certainly avoid it | |
67 | // for first-time loop OSR - that is, OSR into a CodeBlock that we have just | |
68 | // compiled. Then we are almost guaranteed that all of the predictions will | |
69 | // check out. It would be pretty easy to make that a hard guarantee. But | |
70 | // then there would still be the case where two call frames with the same | |
71 | // baseline CodeBlock are on the stack at the same time. The top one | |
72 | // triggers compilation and OSR. In that case, we may no longer have | |
73 | // accurate value profiles for the one deeper in the stack. Hence, when we | |
74 | // pop into the CodeBlock that is deeper on the stack, we might OSR and | |
75 | // realize that the predictions are wrong. Probably, in most cases, this is | |
76 | // just an anomaly in the sense that the older CodeBlock simply went off | |
77 | // into a less-likely path. So, the wisest course of action is to simply not | |
78 | // OSR at this time. | |
79 | ||
80 | for (size_t argument = 0; argument < entry->m_expectedValues.numberOfArguments(); ++argument) { | |
81 | if (argument >= exec->argumentCountIncludingThis()) { | |
82 | #if ENABLE(JIT_VERBOSE_OSR) | |
83 | dataLog(" OSR failed because argument %zu was not passed, expected ", argument); | |
84 | entry->m_expectedValues.argument(argument).dump(WTF::dataFile()); | |
85 | dataLog(".\n"); | |
86 | #endif | |
87 | return 0; | |
88 | } | |
89 | ||
90 | JSValue value; | |
91 | if (!argument) | |
92 | value = exec->hostThisValue(); | |
93 | else | |
94 | value = exec->argument(argument - 1); | |
95 | ||
96 | if (!entry->m_expectedValues.argument(argument).validate(value)) { | |
97 | #if ENABLE(JIT_VERBOSE_OSR) | |
98 | dataLog(" OSR failed because argument %zu is %s, expected ", argument, value.description()); | |
99 | entry->m_expectedValues.argument(argument).dump(WTF::dataFile()); | |
100 | dataLog(".\n"); | |
101 | #endif | |
102 | return 0; | |
103 | } | |
104 | } | |
105 | ||
106 | for (size_t local = 0; local < entry->m_expectedValues.numberOfLocals(); ++local) { | |
107 | if (entry->m_localsForcedDouble.get(local)) { | |
108 | if (!exec->registers()[local].jsValue().isNumber()) { | |
109 | #if ENABLE(JIT_VERBOSE_OSR) | |
110 | dataLog(" OSR failed because variable %zu is %s, expected number.\n", local, exec->registers()[local].jsValue().description()); | |
111 | #endif | |
112 | return 0; | |
113 | } | |
114 | continue; | |
115 | } | |
116 | if (!entry->m_expectedValues.local(local).validate(exec->registers()[local].jsValue())) { | |
117 | #if ENABLE(JIT_VERBOSE_OSR) | |
118 | dataLog(" OSR failed because variable %zu is %s, expected ", local, exec->registers()[local].jsValue().description()); | |
119 | entry->m_expectedValues.local(local).dump(WTF::dataFile()); | |
120 | dataLog(".\n"); | |
121 | #endif | |
122 | return 0; | |
123 | } | |
124 | } | |
125 | ||
126 | // 2) Check the stack height. The DFG JIT may require a taller stack than the | |
127 | // baseline JIT, in some cases. If we can't grow the stack, then don't do | |
128 | // OSR right now. That's the only option we have unless we want basic block | |
129 | // boundaries to start throwing RangeErrors. Although that would be possible, | |
130 | // it seems silly: you'd be diverting the program to error handling when it | |
131 | // would have otherwise just kept running albeit less quickly. | |
132 | ||
133 | if (!globalData->interpreter->registerFile().grow(&exec->registers()[codeBlock->m_numCalleeRegisters])) { | |
134 | #if ENABLE(JIT_VERBOSE_OSR) | |
135 | dataLog(" OSR failed because stack growth failed.\n"); | |
136 | #endif | |
137 | return 0; | |
138 | } | |
139 | ||
140 | #if ENABLE(JIT_VERBOSE_OSR) | |
141 | dataLog(" OSR should succeed.\n"); | |
142 | #endif | |
143 | ||
144 | // 3) Perform data format conversions. | |
145 | for (size_t local = 0; local < entry->m_expectedValues.numberOfLocals(); ++local) { | |
146 | if (entry->m_localsForcedDouble.get(local)) | |
147 | *bitwise_cast<double*>(exec->registers() + local) = exec->registers()[local].jsValue().asNumber(); | |
148 | } | |
149 | ||
150 | // 4) Fix the call frame. | |
151 | ||
152 | exec->setCodeBlock(codeBlock); | |
153 | ||
154 | // 5) Find and return the destination machine code address. | |
155 | ||
156 | void* result = codeBlock->getJITCode().executableAddressAtOffset(entry->m_machineCodeOffset); | |
157 | ||
158 | #if ENABLE(JIT_VERBOSE_OSR) | |
159 | dataLog(" OSR returning machine code address %p.\n", result); | |
160 | #endif | |
161 | ||
162 | return result; | |
163 | #else // DFG_ENABLE(OSR_ENTRY) | |
164 | UNUSED_PARAM(exec); | |
165 | UNUSED_PARAM(codeBlock); | |
166 | UNUSED_PARAM(bytecodeIndex); | |
167 | return 0; | |
168 | #endif | |
169 | } | |
170 | ||
171 | } } // namespace JSC::DFG | |
172 | ||
173 | #endif // ENABLE(DFG_JIT) |