Roll out r108309, r108323, and r108326
[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 ENABLE(DFG_JIT)
54 bool CallFrame::isInlineCallFrameSlow()
55 {
56     if (!callee())
57         return false;
58     JSCell* calleeAsFunctionCell = getJSFunction(callee());
59     if (!calleeAsFunctionCell)
60         return false;
61     JSFunction* calleeAsFunction = asFunction(calleeAsFunctionCell);
62     return calleeAsFunction->executable() != codeBlock()->ownerExecutable();
63 }
64
65 CallFrame* CallFrame::trueCallFrame(AbstractPC pc)
66 {
67     // Am I an inline call frame? If so, we're done.
68     if (isInlineCallFrame())
69         return this;
70     
71     // If I don't have a code block, then I'm not DFG code, so I'm the true call frame.
72     CodeBlock* machineCodeBlock = codeBlock();
73     if (!machineCodeBlock)
74         return this;
75     
76     // If the code block does not have any code origins, then there was no inlining, so
77     // I'm done.
78     if (!machineCodeBlock->hasCodeOrigins())
79         return this;
80     
81     // At this point the PC must be due either to the DFG, or it must be unset.
82     ASSERT(pc.hasJITReturnAddress() || !pc);
83     
84     // Try to determine the CodeOrigin. If we don't have a pc set then the only way
85     // that this makes sense is if the CodeOrigin index was set in the call frame.
86     // FIXME: Note that you will see "Not currently in inlined code" comments below.
87     // Currently, we do not record code origins for code that is not inlined, because
88     // the only thing that we use code origins for is determining the inline stack.
89     // But in the future, we'll want to use this same functionality (having a code
90     // origin mapping for any calls out of JIT code) to determine the PC at any point
91     // in the stack even if not in inlined code. When that happens, the code below
92     // will have to change the way it detects the presence of inlining: it will always
93     // get a code origin, but sometimes, that code origin will not have an inline call
94     // frame. In that case, this method should bail and return this.
95     CodeOrigin codeOrigin;
96     if (pc.isSet()) {
97         ReturnAddressPtr currentReturnPC = pc.jitReturnAddress();
98         
99         bool hasCodeOrigin = machineCodeBlock->codeOriginForReturn(currentReturnPC, codeOrigin);
100         ASSERT_UNUSED(hasCodeOrigin, hasCodeOrigin);
101     } else {
102         unsigned index = codeOriginIndexForDFG();
103         codeOrigin = machineCodeBlock->codeOrigin(index);
104     }
105
106     if (!codeOrigin.inlineCallFrame)
107         return this; // Not currently in inlined code.
108     
109     for (InlineCallFrame* inlineCallFrame = codeOrigin.inlineCallFrame; inlineCallFrame;) {
110         InlineCallFrame* nextInlineCallFrame = inlineCallFrame->caller.inlineCallFrame;
111         
112         CallFrame* inlinedCaller = this + inlineCallFrame->stackOffset;
113         
114         JSFunction* calleeAsFunction = inlineCallFrame->callee.get();
115         
116         // Fill in the inlinedCaller
117         inlinedCaller->setCodeBlock(machineCodeBlock);
118         
119         inlinedCaller->setScopeChain(calleeAsFunction->scope());
120         if (nextInlineCallFrame)
121             inlinedCaller->setCallerFrame(this + nextInlineCallFrame->stackOffset);
122         else
123             inlinedCaller->setCallerFrame(this);
124         
125         inlinedCaller->setInlineCallFrame(inlineCallFrame);
126         inlinedCaller->setArgumentCountIncludingThis(inlineCallFrame->arguments.size());
127         inlinedCaller->setCallee(calleeAsFunction);
128         
129         inlineCallFrame = nextInlineCallFrame;
130     }
131     
132     return this + codeOrigin.inlineCallFrame->stackOffset;
133 }
134         
135 CallFrame* CallFrame::trueCallerFrame()
136 {
137     // this -> The callee; this is either an inlined callee in which case it already has
138     //    a pointer to the true caller. Otherwise it contains current PC in the machine
139     //    caller.
140     //
141     // machineCaller -> The caller according to the machine, which may be zero or
142     //    more frames above the true caller due to inlining.
143
144     // Am I an inline call frame? If so, we're done.
145     if (isInlineCallFrame() || !hasReturnPC())
146         return callerFrame()->removeHostCallFrameFlag();
147     
148     // I am a machine call frame, so the question is: is my caller a machine call frame
149     // that has inlines or a machine call frame that doesn't?
150     CallFrame* machineCaller = callerFrame()->removeHostCallFrameFlag();
151     if (!machineCaller)
152         return 0;
153     ASSERT(!machineCaller->isInlineCallFrame());
154     
155     // Figure out how we want to get the current code location.
156     if (hasHostCallFrameFlag() || returnAddressIsInCtiTrampoline(returnPC()))
157         return machineCaller->trueCallFrameFromVMCode()->removeHostCallFrameFlag();
158     
159     return machineCaller->trueCallFrame(returnPC())->removeHostCallFrameFlag();
160 }
161 #endif
162
163 }