]> git.saurik.com Git - apple/javascriptcore.git/blob - interpreter/CallFrame.cpp
a5ffaee8d61499f4d696575623ac8d3d3093a48c
[apple/javascriptcore.git] / interpreter / CallFrame.cpp
1 /*
2 * Copyright (C) 2008 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 "CallFrame.h"
28
29 #include "CodeBlock.h"
30 #include "Interpreter.h"
31
32 namespace JSC {
33
34 #ifndef NDEBUG
35 void CallFrame::dumpCaller()
36 {
37 int signedLineNumber;
38 intptr_t sourceID;
39 UString urlString;
40 JSValue function;
41
42 interpreter()->retrieveLastCaller(this, signedLineNumber, sourceID, urlString, function);
43 dataLog("Callpoint => %s:%d\n", urlString.utf8().data(), signedLineNumber);
44 }
45
46 RegisterFile* CallFrame::registerFile()
47 {
48 return &interpreter()->registerFile();
49 }
50
51 #endif
52
53 #if USE(JSVALUE32_64)
54 unsigned CallFrame::bytecodeOffsetForNonDFGCode() const
55 {
56 ASSERT(codeBlock());
57 return currentVPC() - codeBlock()->instructions().begin();
58 }
59
60 void CallFrame::setBytecodeOffsetForNonDFGCode(unsigned offset)
61 {
62 ASSERT(codeBlock());
63 setCurrentVPC(codeBlock()->instructions().begin() + offset);
64 }
65 #else
66 Instruction* CallFrame::currentVPC() const
67 {
68 return codeBlock()->instructions().begin() + bytecodeOffsetForNonDFGCode();
69 }
70 void CallFrame::setCurrentVPC(Instruction* vpc)
71 {
72 setBytecodeOffsetForNonDFGCode(vpc - codeBlock()->instructions().begin());
73 }
74 #endif
75
76 #if ENABLE(DFG_JIT)
77 bool CallFrame::isInlineCallFrameSlow()
78 {
79 if (!callee())
80 return false;
81 JSCell* calleeAsFunctionCell = getJSFunction(callee());
82 if (!calleeAsFunctionCell)
83 return false;
84 JSFunction* calleeAsFunction = jsCast<JSFunction*>(calleeAsFunctionCell);
85 return calleeAsFunction->executable() != codeBlock()->ownerExecutable();
86 }
87
88 CallFrame* CallFrame::trueCallFrame(AbstractPC pc)
89 {
90 // Am I an inline call frame? If so, we're done.
91 if (isInlineCallFrame())
92 return this;
93
94 // If I don't have a code block, then I'm not DFG code, so I'm the true call frame.
95 CodeBlock* machineCodeBlock = codeBlock();
96 if (!machineCodeBlock)
97 return this;
98
99 // If the code block does not have any code origins, then there was no inlining, so
100 // I'm done.
101 if (!machineCodeBlock->hasCodeOrigins())
102 return this;
103
104 // At this point the PC must be due either to the DFG, or it must be unset.
105 ASSERT(pc.hasJITReturnAddress() || !pc);
106
107 // Try to determine the CodeOrigin. If we don't have a pc set then the only way
108 // that this makes sense is if the CodeOrigin index was set in the call frame.
109 // FIXME: Note that you will see "Not currently in inlined code" comments below.
110 // Currently, we do not record code origins for code that is not inlined, because
111 // the only thing that we use code origins for is determining the inline stack.
112 // But in the future, we'll want to use this same functionality (having a code
113 // origin mapping for any calls out of JIT code) to determine the PC at any point
114 // in the stack even if not in inlined code. When that happens, the code below
115 // will have to change the way it detects the presence of inlining: it will always
116 // get a code origin, but sometimes, that code origin will not have an inline call
117 // frame. In that case, this method should bail and return this.
118 CodeOrigin codeOrigin;
119 if (pc.isSet()) {
120 ReturnAddressPtr currentReturnPC = pc.jitReturnAddress();
121
122 bool hasCodeOrigin = machineCodeBlock->codeOriginForReturn(currentReturnPC, codeOrigin);
123 ASSERT_UNUSED(hasCodeOrigin, hasCodeOrigin);
124 } else {
125 unsigned index = codeOriginIndexForDFG();
126 codeOrigin = machineCodeBlock->codeOrigin(index);
127 }
128
129 if (!codeOrigin.inlineCallFrame)
130 return this; // Not currently in inlined code.
131
132 for (InlineCallFrame* inlineCallFrame = codeOrigin.inlineCallFrame; inlineCallFrame;) {
133 InlineCallFrame* nextInlineCallFrame = inlineCallFrame->caller.inlineCallFrame;
134
135 CallFrame* inlinedCaller = this + inlineCallFrame->stackOffset;
136
137 JSFunction* calleeAsFunction = inlineCallFrame->callee.get();
138
139 // Fill in the inlinedCaller
140 inlinedCaller->setCodeBlock(machineCodeBlock);
141
142 inlinedCaller->setScopeChain(calleeAsFunction->scope());
143 if (nextInlineCallFrame)
144 inlinedCaller->setCallerFrame(this + nextInlineCallFrame->stackOffset);
145 else
146 inlinedCaller->setCallerFrame(this);
147
148 inlinedCaller->setInlineCallFrame(inlineCallFrame);
149 inlinedCaller->setArgumentCountIncludingThis(inlineCallFrame->arguments.size());
150 inlinedCaller->setCallee(calleeAsFunction);
151
152 inlineCallFrame = nextInlineCallFrame;
153 }
154
155 return this + codeOrigin.inlineCallFrame->stackOffset;
156 }
157
158 CallFrame* CallFrame::trueCallerFrame()
159 {
160 // this -> The callee; this is either an inlined callee in which case it already has
161 // a pointer to the true caller. Otherwise it contains current PC in the machine
162 // caller.
163 //
164 // machineCaller -> The caller according to the machine, which may be zero or
165 // more frames above the true caller due to inlining.
166
167 // Am I an inline call frame? If so, we're done.
168 if (isInlineCallFrame())
169 return callerFrame()->removeHostCallFrameFlag();
170
171 // I am a machine call frame, so the question is: is my caller a machine call frame
172 // that has inlines or a machine call frame that doesn't?
173 CallFrame* machineCaller = callerFrame()->removeHostCallFrameFlag();
174 if (!machineCaller)
175 return 0;
176 ASSERT(!machineCaller->isInlineCallFrame());
177
178 // Figure out how we want to get the current code location.
179 if (!hasReturnPC() || returnAddressIsInCtiTrampoline(returnPC()))
180 return machineCaller->trueCallFrameFromVMCode()->removeHostCallFrameFlag();
181
182 return machineCaller->trueCallFrame(returnPC())->removeHostCallFrameFlag();
183 }
184 #endif
185
186 Register* CallFrame::frameExtentInternal()
187 {
188 CodeBlock* codeBlock = this->codeBlock();
189 ASSERT(codeBlock);
190 return registers() + codeBlock->m_numCalleeRegisters;
191 }
192
193 }