b0e5ea0f64388b174bb04c3c724c239827a62911
[WebKit-https.git] / Source / JavaScriptCore / 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 = asFunction(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 }