/* * Copyright (C) 2008 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. */ #include "config.h" #include "CallFrame.h" #include "CodeBlock.h" #include "Interpreter.h" namespace JSC { #ifndef NDEBUG void CallFrame::dumpCaller() { int signedLineNumber; intptr_t sourceID; String urlString; JSValue function; interpreter()->retrieveLastCaller(this, signedLineNumber, sourceID, urlString, function); dataLog("Callpoint => %s:%d\n", urlString.utf8().data(), signedLineNumber); } JSStack* CallFrame::stack() { return &interpreter()->stack(); } #endif #if USE(JSVALUE32_64) unsigned CallFrame::bytecodeOffsetForNonDFGCode() const { ASSERT(codeBlock()); return currentVPC() - codeBlock()->instructions().begin(); } void CallFrame::setBytecodeOffsetForNonDFGCode(unsigned offset) { ASSERT(codeBlock()); setCurrentVPC(codeBlock()->instructions().begin() + offset); } #else Instruction* CallFrame::currentVPC() const { return codeBlock()->instructions().begin() + bytecodeOffsetForNonDFGCode(); } void CallFrame::setCurrentVPC(Instruction* vpc) { setBytecodeOffsetForNonDFGCode(vpc - codeBlock()->instructions().begin()); } #endif #if ENABLE(DFG_JIT) bool CallFrame::isInlineCallFrameSlow() { if (!callee()) return false; JSCell* calleeAsFunctionCell = getJSFunction(callee()); if (!calleeAsFunctionCell) return false; JSFunction* calleeAsFunction = jsCast(calleeAsFunctionCell); return calleeAsFunction->executable() != codeBlock()->ownerExecutable(); } CallFrame* CallFrame::trueCallFrame(AbstractPC pc) { // Am I an inline call frame? If so, we're done. if (isInlineCallFrame()) return this; // If I don't have a code block, then I'm not DFG code, so I'm the true call frame. CodeBlock* machineCodeBlock = codeBlock(); if (!machineCodeBlock) return this; // If the code block does not have any code origins, then there was no inlining, so // I'm done. if (!machineCodeBlock->hasCodeOrigins()) return this; // At this point the PC must be due either to the DFG, or it must be unset. ASSERT(pc.hasJITReturnAddress() || !pc); // Try to determine the CodeOrigin. If we don't have a pc set then the only way // that this makes sense is if the CodeOrigin index was set in the call frame. // FIXME: Note that you will see "Not currently in inlined code" comments below. // Currently, we do not record code origins for code that is not inlined, because // the only thing that we use code origins for is determining the inline stack. // But in the future, we'll want to use this same functionality (having a code // origin mapping for any calls out of JIT code) to determine the PC at any point // in the stack even if not in inlined code. When that happens, the code below // will have to change the way it detects the presence of inlining: it will always // get a code origin, but sometimes, that code origin will not have an inline call // frame. In that case, this method should bail and return this. CodeOrigin codeOrigin; if (pc.isSet()) { ReturnAddressPtr currentReturnPC = pc.jitReturnAddress(); bool hasCodeOrigin = machineCodeBlock->codeOriginForReturn(currentReturnPC, codeOrigin); ASSERT_UNUSED(hasCodeOrigin, hasCodeOrigin); } else { unsigned index = codeOriginIndexForDFG(); codeOrigin = machineCodeBlock->codeOrigin(index); } if (!codeOrigin.inlineCallFrame) return this; // Not currently in inlined code. for (InlineCallFrame* inlineCallFrame = codeOrigin.inlineCallFrame; inlineCallFrame;) { InlineCallFrame* nextInlineCallFrame = inlineCallFrame->caller.inlineCallFrame; CallFrame* inlinedCaller = this + inlineCallFrame->stackOffset; JSFunction* calleeAsFunction = inlineCallFrame->callee.get(); // Fill in the inlinedCaller inlinedCaller->setCodeBlock(machineCodeBlock); inlinedCaller->setScope(calleeAsFunction->scope()); if (nextInlineCallFrame) inlinedCaller->setCallerFrame(this + nextInlineCallFrame->stackOffset); else inlinedCaller->setCallerFrame(this); inlinedCaller->setInlineCallFrame(inlineCallFrame); inlinedCaller->setArgumentCountIncludingThis(inlineCallFrame->arguments.size()); inlinedCaller->setCallee(calleeAsFunction); inlineCallFrame = nextInlineCallFrame; } return this + codeOrigin.inlineCallFrame->stackOffset; } CallFrame* CallFrame::trueCallerFrame() { // this -> The callee; this is either an inlined callee in which case it already has // a pointer to the true caller. Otherwise it contains current PC in the machine // caller. // // machineCaller -> The caller according to the machine, which may be zero or // more frames above the true caller due to inlining. // Am I an inline call frame? If so, we're done. if (isInlineCallFrame()) return callerFrame()->removeHostCallFrameFlag(); // I am a machine call frame, so the question is: is my caller a machine call frame // that has inlines or a machine call frame that doesn't? CallFrame* machineCaller = callerFrame()->removeHostCallFrameFlag(); if (!machineCaller) return 0; ASSERT(!machineCaller->isInlineCallFrame()); // Figure out how we want to get the current code location. if (!hasReturnPC() || returnAddressIsInCtiTrampoline(returnPC())) return machineCaller->trueCallFrameFromVMCode()->removeHostCallFrameFlag(); return machineCaller->trueCallFrame(returnPC())->removeHostCallFrameFlag(); } CodeBlock* CallFrame::someCodeBlockForPossiblyInlinedCode() { if (!isInlineCallFrame()) return codeBlock(); return jsCast(inlineCallFrame()->executable.get())->baselineCodeBlockFor( inlineCallFrame()->isCall ? CodeForCall : CodeForConstruct); } #endif Register* CallFrame::frameExtentInternal() { CodeBlock* codeBlock = this->codeBlock(); ASSERT(codeBlock); return registers() + codeBlock->m_numCalleeRegisters; } }