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#include "Operations.h" 36 37namespace JSC { namespace DFG { 38 39void* 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()); 46 47#if ENABLE(JIT_VERBOSE_OSR) 48 dataLog("OSR in ", *codeBlock->alternative(), " -> ", *codeBlock, " from bc#", bytecodeIndex, "\n"); 49#endif 50 51 VM* vm = &exec->vm(); 52 OSREntryData* entry = codeBlock->dfgOSREntryDataForBytecodeIndex(bytecodeIndex); 53 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 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) 90 dataLogF(" OSR failed because argument %zu was not passed, expected ", argument); 91 entry->m_expectedValues.argument(argument).dump(WTF::dataFile()); 92 dataLogF(".\n"); 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) 105 dataLog(" OSR failed because argument ", argument, " is ", value, ", expected ", entry->m_expectedValues.argument(argument), ".\n"); 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) 115 dataLog(" OSR failed because variable ", local, " is ", exec->registers()[local].jsValue(), ", expected number.\n"); 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) 123 dataLog(" OSR failed because variable ", local, " is ", exec->registers()[local].jsValue(), ", expected ", entry->m_expectedValues.local(local), ".\n"); 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 136 if (!vm->interpreter->stack().grow(&exec->registers()[codeBlock->m_numCalleeRegisters])) { 137#if ENABLE(JIT_VERBOSE_OSR) 138 dataLogF(" OSR failed because stack growth failed.\n"); 139#endif 140 return 0; 141 } 142 143#if ENABLE(JIT_VERBOSE_OSR) 144 dataLogF(" OSR should succeed.\n"); 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) 162 dataLogF(" OSR returning machine code address %p.\n", result); 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) 177