dumpCallFrame is broken in ToT
[WebKit-https.git] / Source / JavaScriptCore / interpreter / Interpreter.h
1 /*
2  * Copyright (C) 2008 Apple Inc. All rights reserved.
3  * Copyright (C) 2012 Research In Motion Limited. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1.  Redistributions of source code must retain the above copyright
10  *     notice, this list of conditions and the following disclaimer.
11  * 2.  Redistributions in binary form must reproduce the above copyright
12  *     notice, this list of conditions and the following disclaimer in the
13  *     documentation and/or other materials provided with the distribution.
14  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
15  *     its contributors may be used to endorse or promote products derived
16  *     from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
19  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
22  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 #ifndef Interpreter_h
31 #define Interpreter_h
32
33 #include "ArgList.h"
34 #include "JSCell.h"
35 #include "JSFunction.h"
36 #include "JSValue.h"
37 #include "JSObject.h"
38 #include "LLIntData.h"
39 #include "Opcode.h"
40 #include "RegisterFile.h"
41
42 #include <wtf/HashMap.h>
43 #include <wtf/text/StringBuilder.h>
44
45 namespace JSC {
46
47     class CodeBlock;
48     class EvalExecutable;
49     class ExecutableBase;
50     class FunctionExecutable;
51     class JSGlobalObject;
52     class LLIntOffsetsExtractor;
53     class ProgramExecutable;
54     class Register;
55     class ScopeChainNode;
56     class SamplingTool;
57     struct CallFrameClosure;
58     struct HandlerInfo;
59     struct Instruction;
60     
61     enum DebugHookID {
62         WillExecuteProgram,
63         DidExecuteProgram,
64         DidEnterCallFrame,
65         DidReachBreakpoint,
66         WillLeaveCallFrame,
67         WillExecuteStatement
68     };
69
70     enum StackFrameCodeType {
71         StackFrameGlobalCode,
72         StackFrameEvalCode,
73         StackFrameFunctionCode,
74         StackFrameNativeCode
75     };
76
77     struct StackFrame {
78         Strong<JSObject> callee;
79         StackFrameCodeType codeType;
80         Strong<ExecutableBase> executable;
81         int line;
82         UString sourceURL;
83         UString toString(CallFrame* callFrame) const
84         {
85             StringBuilder traceBuild;
86             String functionName = friendlyFunctionName(callFrame);
87             String sourceURL = friendlySourceURL();
88             traceBuild.append(functionName);
89             if (!sourceURL.isEmpty()) {
90                 if (!functionName.isEmpty())
91                     traceBuild.append('@');
92                 traceBuild.append(sourceURL);
93                 if (line > -1) {
94                     traceBuild.append(':');
95                     traceBuild.append(String::number(line));
96                 }
97             }
98             return traceBuild.toString().impl();
99         }
100         String friendlySourceURL() const
101         {
102             String traceLine;
103
104             switch (codeType) {
105             case StackFrameEvalCode:
106             case StackFrameFunctionCode:
107             case StackFrameGlobalCode:
108                 if (!sourceURL.isEmpty())
109                     traceLine = sourceURL.impl();
110                 break;
111             case StackFrameNativeCode:
112                 traceLine = "[native code]";
113                 break;
114             }
115             return traceLine.isNull() ? emptyString() : traceLine;
116         }
117         String friendlyFunctionName(CallFrame* callFrame) const
118         {
119             String traceLine;
120             JSObject* stackFrameCallee = callee.get();
121
122             switch (codeType) {
123             case StackFrameEvalCode:
124                 traceLine = "eval code";
125                 break;
126             case StackFrameNativeCode:
127                 if (callee)
128                     traceLine = getCalculatedDisplayName(callFrame, stackFrameCallee).impl();
129                 break;
130             case StackFrameFunctionCode:
131                 traceLine = getCalculatedDisplayName(callFrame, stackFrameCallee).impl();
132                 break;
133             case StackFrameGlobalCode:
134                 traceLine = "global code";
135                 break;
136             }
137             return traceLine.isNull() ? emptyString() : traceLine;
138         }
139         unsigned friendlyLineNumber() const
140         {
141             return line > -1 ? line : 0;
142         }
143     };
144
145     class TopCallFrameSetter {
146     public:
147         TopCallFrameSetter(JSGlobalData& global, CallFrame* callFrame)
148             : globalData(global)
149             , oldCallFrame(global.topCallFrame) 
150         {
151             global.topCallFrame = callFrame;
152         }
153         
154         ~TopCallFrameSetter() 
155         {
156             globalData.topCallFrame = oldCallFrame;
157         }
158     private:
159         JSGlobalData& globalData;
160         CallFrame* oldCallFrame;
161     };
162     
163     class NativeCallFrameTracer {
164     public:
165         ALWAYS_INLINE NativeCallFrameTracer(JSGlobalData* global, CallFrame* callFrame)
166         {
167             ASSERT(global);
168             ASSERT(callFrame);
169             global->topCallFrame = callFrame;
170         }
171     };
172
173     // We use a smaller reentrancy limit on iPhone because of the high amount of
174     // stack space required on the web thread.
175 #if PLATFORM(IOS)
176     enum { MaxLargeThreadReentryDepth = 64, MaxSmallThreadReentryDepth = 16 };
177 #else
178     enum { MaxLargeThreadReentryDepth = 256, MaxSmallThreadReentryDepth = 16 };
179 #endif // PLATFORM(IOS)
180
181     class Interpreter {
182         WTF_MAKE_FAST_ALLOCATED;
183         friend class CachedCall;
184         friend class LLIntOffsetsExtractor;
185         friend class JIT;
186     public:
187         Interpreter();
188         ~Interpreter();
189         
190         void initialize(LLInt::Data*, bool canUseJIT);
191
192         RegisterFile& registerFile() { return m_registerFile; }
193         
194         Opcode getOpcode(OpcodeID id)
195         {
196             ASSERT(m_initialized);
197 #if ENABLE(COMPUTED_GOTO_CLASSIC_INTERPRETER) || ENABLE(LLINT)
198             return m_opcodeTable[id];
199 #else
200             return id;
201 #endif
202         }
203
204         OpcodeID getOpcodeID(Opcode opcode)
205         {
206             ASSERT(m_initialized);
207 #if ENABLE(LLINT)
208             ASSERT(isOpcode(opcode));
209             return m_opcodeIDTable.get(opcode);
210 #elif ENABLE(COMPUTED_GOTO_CLASSIC_INTERPRETER)
211             ASSERT(isOpcode(opcode));
212             if (!m_classicEnabled)
213                 return static_cast<OpcodeID>(bitwise_cast<uintptr_t>(opcode));
214
215             return m_opcodeIDTable.get(opcode);
216 #else
217             return opcode;
218 #endif
219         }
220         
221         bool classicEnabled()
222         {
223             return m_classicEnabled;
224         }
225
226         bool isOpcode(Opcode);
227
228         JSValue execute(ProgramExecutable*, CallFrame*, ScopeChainNode*, JSObject* thisObj);
229         JSValue executeCall(CallFrame*, JSObject* function, CallType, const CallData&, JSValue thisValue, const ArgList&);
230         JSObject* executeConstruct(CallFrame*, JSObject* function, ConstructType, const ConstructData&, const ArgList&);
231         JSValue execute(EvalExecutable*, CallFrame*, JSValue thisValue, ScopeChainNode*);
232         JSValue execute(EvalExecutable*, CallFrame*, JSValue thisValue, ScopeChainNode*, int globalRegisterOffset);
233
234         JSValue retrieveArgumentsFromVMCode(CallFrame*, JSFunction*) const;
235         JSValue retrieveCallerFromVMCode(CallFrame*, JSFunction*) const;
236         JS_EXPORT_PRIVATE void retrieveLastCaller(CallFrame*, int& lineNumber, intptr_t& sourceID, UString& sourceURL, JSValue& function) const;
237         
238         void getArgumentsData(CallFrame*, JSFunction*&, ptrdiff_t& firstParameterIndex, Register*& argv, int& argc);
239         
240         SamplingTool* sampler() { return m_sampler.get(); }
241
242         NEVER_INLINE HandlerInfo* throwException(CallFrame*&, JSValue&, unsigned bytecodeOffset);
243         NEVER_INLINE void debug(CallFrame*, DebugHookID, int firstLine, int lastLine);
244         static const UString getTraceLine(CallFrame*, StackFrameCodeType, const UString&, int);
245         JS_EXPORT_PRIVATE static void getStackTrace(JSGlobalData*, Vector<StackFrame>& results);
246         static void addStackTraceIfNecessary(CallFrame*, JSObject* error);
247
248         void dumpSampleData(ExecState* exec);
249         void startSampling();
250         void stopSampling();
251
252         JS_EXPORT_PRIVATE void dumpCallFrame(CallFrame*);
253
254     private:
255         enum ExecutionFlag { Normal, InitializeAndReturn };
256
257         CallFrameClosure prepareForRepeatCall(FunctionExecutable*, CallFrame*, JSFunction*, int argumentCountIncludingThis, ScopeChainNode*);
258         void endRepeatCall(CallFrameClosure&);
259         JSValue execute(CallFrameClosure&);
260
261 #if ENABLE(CLASSIC_INTERPRETER)
262         NEVER_INLINE bool resolve(CallFrame*, Instruction*, JSValue& exceptionValue);
263         NEVER_INLINE bool resolveSkip(CallFrame*, Instruction*, JSValue& exceptionValue);
264         NEVER_INLINE bool resolveGlobal(CallFrame*, Instruction*, JSValue& exceptionValue);
265         NEVER_INLINE bool resolveGlobalDynamic(CallFrame*, Instruction*, JSValue& exceptionValue);
266         NEVER_INLINE void resolveBase(CallFrame*, Instruction* vPC);
267         NEVER_INLINE bool resolveBaseAndProperty(CallFrame*, Instruction*, JSValue& exceptionValue);
268         NEVER_INLINE bool resolveThisAndProperty(CallFrame*, Instruction*, JSValue& exceptionValue);
269         NEVER_INLINE ScopeChainNode* createExceptionScope(CallFrame*, const Instruction* vPC);
270
271         void tryCacheGetByID(CallFrame*, CodeBlock*, Instruction*, JSValue baseValue, const Identifier& propertyName, const PropertySlot&);
272         void uncacheGetByID(CodeBlock*, Instruction* vPC);
273         void tryCachePutByID(CallFrame*, CodeBlock*, Instruction*, JSValue baseValue, const PutPropertySlot&);
274         void uncachePutByID(CodeBlock*, Instruction* vPC);        
275 #endif // ENABLE(CLASSIC_INTERPRETER)
276
277         NEVER_INLINE bool unwindCallFrame(CallFrame*&, JSValue, unsigned& bytecodeOffset, CodeBlock*&);
278
279         static ALWAYS_INLINE CallFrame* slideRegisterWindowForCall(CodeBlock*, RegisterFile*, CallFrame*, size_t registerOffset, int argc);
280
281         static CallFrame* findFunctionCallFrameFromVMCode(CallFrame*, JSFunction*);
282
283         JSValue privateExecute(ExecutionFlag, RegisterFile*, CallFrame*);
284
285         void dumpRegisters(CallFrame*);
286         
287         bool isCallBytecode(Opcode opcode) { return opcode == getOpcode(op_call) || opcode == getOpcode(op_construct) || opcode == getOpcode(op_call_eval); }
288
289         void enableSampler();
290         int m_sampleEntryDepth;
291         OwnPtr<SamplingTool> m_sampler;
292
293         int m_reentryDepth;
294
295         RegisterFile m_registerFile;
296         
297 #if ENABLE(LLINT)
298         Opcode* m_opcodeTable; // Maps OpcodeID => Opcode for compiling
299         HashMap<Opcode, OpcodeID> m_opcodeIDTable; // Maps Opcode => OpcodeID for decompiling
300 #elif ENABLE(COMPUTED_GOTO_CLASSIC_INTERPRETER)
301         Opcode m_opcodeTable[numOpcodeIDs]; // Maps OpcodeID => Opcode for compiling
302         HashMap<Opcode, OpcodeID> m_opcodeIDTable; // Maps Opcode => OpcodeID for decompiling
303 #endif
304
305 #if !ASSERT_DISABLED
306         bool m_initialized;
307 #endif
308         bool m_classicEnabled;
309     };
310
311     // This value must not be an object that would require this conversion (WebCore's global object).
312     inline bool isValidThisObject(JSValue thisValue, ExecState* exec)
313     {
314         return !thisValue.isObject() || thisValue.toThisObject(exec) == thisValue;
315     }
316
317     inline JSValue Interpreter::execute(EvalExecutable* eval, CallFrame* callFrame, JSValue thisValue, ScopeChainNode* scopeChain)
318     {
319         return execute(eval, callFrame, thisValue, scopeChain, m_registerFile.size() + 1 + RegisterFile::CallFrameHeaderSize);
320     }
321
322     JSValue eval(CallFrame*);
323     CallFrame* loadVarargs(CallFrame*, RegisterFile*, JSValue thisValue, JSValue arguments, int firstFreeRegister);
324
325 } // namespace JSC
326
327 #endif // Interpreter_h