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