2 * Copyright (C) 2008, 2013 Apple Inc. All Rights Reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
27 #include "CallFrame.h"
29 #include "CodeBlock.h"
30 #include "Interpreter.h"
31 #include "Operations.h"
36 void CallFrame::dumpCaller()
43 interpreter()->retrieveLastCaller(this, signedLineNumber
, sourceID
, urlString
, function
);
44 dataLogF("Callpoint => %s:%d\n", urlString
.utf8().data(), signedLineNumber
);
47 JSStack
* CallFrame::stack()
49 return &interpreter()->stack();
55 unsigned CallFrame::bytecodeOffsetForNonDFGCode() const
58 return currentVPC() - codeBlock()->instructions().begin();
61 void CallFrame::setBytecodeOffsetForNonDFGCode(unsigned offset
)
64 setCurrentVPC(codeBlock()->instructions().begin() + offset
);
67 Instruction
* CallFrame::currentVPC() const
69 return codeBlock()->instructions().begin() + bytecodeOffsetForNonDFGCode();
71 void CallFrame::setCurrentVPC(Instruction
* vpc
)
73 setBytecodeOffsetForNonDFGCode(vpc
- codeBlock()->instructions().begin());
78 bool CallFrame::isInlineCallFrameSlow()
82 JSCell
* calleeAsFunctionCell
= getJSFunction(callee());
83 if (!calleeAsFunctionCell
)
85 JSFunction
* calleeAsFunction
= jsCast
<JSFunction
*>(calleeAsFunctionCell
);
86 return calleeAsFunction
->executable() != codeBlock()->ownerExecutable();
89 CallFrame
* CallFrame::trueCallFrame(AbstractPC pc
)
91 // Am I an inline call frame? If so, we're done.
92 if (isInlineCallFrame())
95 // If I don't have a code block, then I'm not DFG code, so I'm the true call frame.
96 CodeBlock
* machineCodeBlock
= codeBlock();
97 if (!machineCodeBlock
)
100 // If the code block does not have any code origins, then there was no inlining, so
102 if (!machineCodeBlock
->hasCodeOrigins())
105 // At this point the PC must be due either to the DFG, or it must be unset.
106 ASSERT(pc
.hasJITReturnAddress() || !pc
);
108 // Try to determine the CodeOrigin. If we don't have a pc set then the only way
109 // that this makes sense is if the CodeOrigin index was set in the call frame.
110 // FIXME: Note that you will see "Not currently in inlined code" comments below.
111 // Currently, we do not record code origins for code that is not inlined, because
112 // the only thing that we use code origins for is determining the inline stack.
113 // But in the future, we'll want to use this same functionality (having a code
114 // origin mapping for any calls out of JIT code) to determine the PC at any point
115 // in the stack even if not in inlined code. When that happens, the code below
116 // will have to change the way it detects the presence of inlining: it will always
117 // get a code origin, but sometimes, that code origin will not have an inline call
118 // frame. In that case, this method should bail and return this.
119 CodeOrigin codeOrigin
;
121 ReturnAddressPtr currentReturnPC
= pc
.jitReturnAddress();
123 bool hasCodeOrigin
= machineCodeBlock
->codeOriginForReturn(currentReturnPC
, codeOrigin
);
124 ASSERT(hasCodeOrigin
);
125 if (!hasCodeOrigin
) {
126 // In release builds, if we find ourselves in a situation where the return PC doesn't
127 // correspond to a valid CodeOrigin, we return zero instead of continuing. Some of
128 // the callers of trueCallFrame() will be able to recover and do conservative things,
129 // while others will crash.
133 unsigned index
= codeOriginIndexForDFG();
134 ASSERT(machineCodeBlock
->canGetCodeOrigin(index
));
135 if (!machineCodeBlock
->canGetCodeOrigin(index
)) {
136 // See above. In release builds, we try to protect ourselves from crashing even
137 // though stack walking will be goofed up.
140 codeOrigin
= machineCodeBlock
->codeOrigin(index
);
143 if (!codeOrigin
.inlineCallFrame
)
144 return this; // Not currently in inlined code.
146 for (InlineCallFrame
* inlineCallFrame
= codeOrigin
.inlineCallFrame
; inlineCallFrame
;) {
147 InlineCallFrame
* nextInlineCallFrame
= inlineCallFrame
->caller
.inlineCallFrame
;
149 CallFrame
* inlinedCaller
= this + inlineCallFrame
->stackOffset
;
151 JSFunction
* calleeAsFunction
= inlineCallFrame
->callee
.get();
153 // Fill in the inlinedCaller
154 inlinedCaller
->setCodeBlock(machineCodeBlock
);
155 if (calleeAsFunction
)
156 inlinedCaller
->setScope(calleeAsFunction
->scope());
157 if (nextInlineCallFrame
)
158 inlinedCaller
->setCallerFrame(this + nextInlineCallFrame
->stackOffset
);
160 inlinedCaller
->setCallerFrame(this);
162 inlinedCaller
->setInlineCallFrame(inlineCallFrame
);
163 inlinedCaller
->setArgumentCountIncludingThis(inlineCallFrame
->arguments
.size());
164 if (calleeAsFunction
)
165 inlinedCaller
->setCallee(calleeAsFunction
);
167 inlineCallFrame
= nextInlineCallFrame
;
170 return this + codeOrigin
.inlineCallFrame
->stackOffset
;
173 CallFrame
* CallFrame::trueCallerFrame()
176 return callerFrame()->removeHostCallFrameFlag();
178 // this -> The callee; this is either an inlined callee in which case it already has
179 // a pointer to the true caller. Otherwise it contains current PC in the machine
182 // machineCaller -> The caller according to the machine, which may be zero or
183 // more frames above the true caller due to inlining.
185 // Am I an inline call frame? If so, we're done.
186 if (isInlineCallFrame())
187 return callerFrame()->removeHostCallFrameFlag();
189 // I am a machine call frame, so the question is: is my caller a machine call frame
190 // that has inlines or a machine call frame that doesn't?
191 CallFrame
* machineCaller
= callerFrame()->removeHostCallFrameFlag();
194 ASSERT(!machineCaller
->isInlineCallFrame());
196 // Figure out how we want to get the current code location.
197 if (!hasReturnPC() || returnAddressIsInCtiTrampoline(returnPC()))
198 return machineCaller
->trueCallFrameFromVMCode()->removeHostCallFrameFlag();
200 return machineCaller
->trueCallFrame(returnPC())->removeHostCallFrameFlag();
203 CodeBlock
* CallFrame::someCodeBlockForPossiblyInlinedCode()
205 if (!isInlineCallFrame())
208 return jsCast
<FunctionExecutable
*>(inlineCallFrame()->executable
.get())->baselineCodeBlockFor(
209 inlineCallFrame()->isCall
? CodeForCall
: CodeForConstruct
);
214 Register
* CallFrame::frameExtentInternal()
216 CodeBlock
* codeBlock
= this->codeBlock();
218 return registers() + codeBlock
->m_numCalleeRegisters
;