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