]> git.saurik.com Git - apple/javascriptcore.git/blob - interpreter/Interpreter.h
JavaScriptCore-1218.35.tar.gz
[apple/javascriptcore.git] / interpreter / Interpreter.h
1 /*
2 * Copyright (C) 2008, 2013 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 "JSCJSValue.h"
35 #include "JSCell.h"
36 #include "JSFunction.h"
37 #include "JSObject.h"
38 #include "JSStack.h"
39 #include "LLIntData.h"
40 #include "Opcode.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 VM;
52 class JSGlobalObject;
53 class LLIntOffsetsExtractor;
54 class ProgramExecutable;
55 class Register;
56 class JSScope;
57 class SamplingTool;
58 struct CallFrameClosure;
59 struct HandlerInfo;
60 struct Instruction;
61
62 enum DebugHookID {
63 WillExecuteProgram,
64 DidExecuteProgram,
65 DidEnterCallFrame,
66 DidReachBreakpoint,
67 WillLeaveCallFrame,
68 WillExecuteStatement
69 };
70
71 enum StackFrameCodeType {
72 StackFrameGlobalCode,
73 StackFrameEvalCode,
74 StackFrameFunctionCode,
75 StackFrameNativeCode
76 };
77
78 struct StackFrame {
79 Strong<JSObject> callee;
80 StackFrameCodeType codeType;
81 Strong<ExecutableBase> executable;
82 Strong<UnlinkedCodeBlock> codeBlock;
83 RefPtr<SourceProvider> code;
84 int lineOffset;
85 unsigned firstLineColumnOffset;
86 unsigned characterOffset;
87 unsigned bytecodeOffset;
88 String sourceURL;
89 JS_EXPORT_PRIVATE String toString(CallFrame*);
90 String friendlySourceURL() const
91 {
92 String traceLine;
93
94 switch (codeType) {
95 case StackFrameEvalCode:
96 case StackFrameFunctionCode:
97 case StackFrameGlobalCode:
98 if (!sourceURL.isEmpty())
99 traceLine = sourceURL.impl();
100 break;
101 case StackFrameNativeCode:
102 traceLine = "[native code]";
103 break;
104 }
105 return traceLine.isNull() ? emptyString() : traceLine;
106 }
107 String friendlyFunctionName(CallFrame* callFrame) const
108 {
109 String traceLine;
110 JSObject* stackFrameCallee = callee.get();
111
112 switch (codeType) {
113 case StackFrameEvalCode:
114 traceLine = "eval code";
115 break;
116 case StackFrameNativeCode:
117 if (callee)
118 traceLine = getCalculatedDisplayName(callFrame, stackFrameCallee).impl();
119 break;
120 case StackFrameFunctionCode:
121 traceLine = getCalculatedDisplayName(callFrame, stackFrameCallee).impl();
122 break;
123 case StackFrameGlobalCode:
124 traceLine = "global code";
125 break;
126 }
127 return traceLine.isNull() ? emptyString() : traceLine;
128 }
129 JS_EXPORT_PRIVATE void computeLineAndColumn(unsigned& line, unsigned& column);
130
131 private:
132 void expressionInfo(int& divot, int& startOffset, int& endOffset, unsigned& line, unsigned& column);
133 };
134
135 class TopCallFrameSetter {
136 public:
137 TopCallFrameSetter(VM& global, CallFrame* callFrame)
138 : vm(global)
139 , oldCallFrame(global.topCallFrame)
140 {
141 global.topCallFrame = callFrame;
142 }
143
144 ~TopCallFrameSetter()
145 {
146 vm.topCallFrame = oldCallFrame;
147 }
148 private:
149 VM& vm;
150 CallFrame* oldCallFrame;
151 };
152
153 class NativeCallFrameTracer {
154 public:
155 ALWAYS_INLINE NativeCallFrameTracer(VM* global, CallFrame* callFrame)
156 {
157 ASSERT(global);
158 ASSERT(callFrame);
159 global->topCallFrame = callFrame;
160 }
161 };
162
163 class Interpreter {
164 WTF_MAKE_FAST_ALLOCATED;
165 friend class CachedCall;
166 friend class LLIntOffsetsExtractor;
167 friend class JIT;
168
169 public:
170 class ErrorHandlingMode {
171 public:
172 JS_EXPORT_PRIVATE ErrorHandlingMode(ExecState*);
173 JS_EXPORT_PRIVATE ~ErrorHandlingMode();
174 private:
175 Interpreter& m_interpreter;
176 };
177
178 Interpreter(VM &);
179 ~Interpreter();
180
181 void initialize(bool canUseJIT);
182
183 JSStack& stack() { return m_stack; }
184
185 Opcode getOpcode(OpcodeID id)
186 {
187 ASSERT(m_initialized);
188 #if ENABLE(COMPUTED_GOTO_OPCODES)
189 return m_opcodeTable[id];
190 #else
191 return id;
192 #endif
193 }
194
195 OpcodeID getOpcodeID(Opcode opcode)
196 {
197 ASSERT(m_initialized);
198 #if ENABLE(COMPUTED_GOTO_OPCODES) && ENABLE(LLINT)
199 ASSERT(isOpcode(opcode));
200 return m_opcodeIDTable.get(opcode);
201 #else
202 return opcode;
203 #endif
204 }
205
206 bool isOpcode(Opcode);
207
208 JSValue execute(ProgramExecutable*, CallFrame*, 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, JSScope*);
212
213 JSValue retrieveArgumentsFromVMCode(CallFrame*, JSFunction*) const;
214 JSValue retrieveCallerFromVMCode(CallFrame*, JSFunction*) const;
215 JS_EXPORT_PRIVATE void retrieveLastCaller(CallFrame*, int& lineNumber, intptr_t& sourceID, String& sourceURL, JSValue& function) const;
216
217 void getArgumentsData(CallFrame*, JSFunction*&, ptrdiff_t& firstParameterIndex, Register*& argv, int& argc);
218
219 SamplingTool* sampler() { return m_sampler.get(); }
220
221 NEVER_INLINE HandlerInfo* throwException(CallFrame*&, JSValue&, unsigned bytecodeOffset);
222 NEVER_INLINE void debug(CallFrame*, DebugHookID, int firstLine, int lastLine, int column);
223 static const String getTraceLine(CallFrame*, StackFrameCodeType, const String&, int);
224 JS_EXPORT_PRIVATE static void getStackTrace(VM*, Vector<StackFrame>& results, size_t maxStackSize = std::numeric_limits<size_t>::max());
225 static void addStackTraceIfNecessary(CallFrame*, JSValue error);
226
227 void dumpSampleData(ExecState* exec);
228 void startSampling();
229 void stopSampling();
230
231 JS_EXPORT_PRIVATE void dumpCallFrame(CallFrame*);
232
233 private:
234 class StackPolicy {
235 public:
236 StackPolicy(Interpreter&, const StackBounds&);
237 inline size_t requiredCapacity() { return m_requiredCapacity; }
238
239 private:
240 Interpreter& m_interpreter;
241 size_t m_requiredCapacity;
242 };
243
244 enum ExecutionFlag { Normal, InitializeAndReturn };
245
246 CallFrameClosure prepareForRepeatCall(FunctionExecutable*, CallFrame*, JSFunction*, int argumentCountIncludingThis, JSScope*);
247 void endRepeatCall(CallFrameClosure&);
248 JSValue execute(CallFrameClosure&);
249
250 NEVER_INLINE bool unwindCallFrame(CallFrame*&, JSValue, unsigned& bytecodeOffset, CodeBlock*&);
251
252 static CallFrame* findFunctionCallFrameFromVMCode(CallFrame*, JSFunction*);
253
254 void dumpRegisters(CallFrame*);
255
256 bool isCallBytecode(Opcode opcode) { return opcode == getOpcode(op_call) || opcode == getOpcode(op_construct) || opcode == getOpcode(op_call_eval); }
257
258 void enableSampler();
259 int m_sampleEntryDepth;
260 OwnPtr<SamplingTool> m_sampler;
261
262 JSStack m_stack;
263 int m_errorHandlingModeReentry;
264
265 #if ENABLE(COMPUTED_GOTO_OPCODES) && ENABLE(LLINT)
266 Opcode* m_opcodeTable; // Maps OpcodeID => Opcode for compiling
267 HashMap<Opcode, OpcodeID> m_opcodeIDTable; // Maps Opcode => OpcodeID for decompiling
268 #endif
269
270 #if !ASSERT_DISABLED
271 bool m_initialized;
272 #endif
273 };
274
275 // This value must not be an object that would require this conversion (WebCore's global object).
276 inline bool isValidThisObject(JSValue thisValue, ExecState* exec)
277 {
278 return !thisValue.isObject() || thisValue.toThisObject(exec) == thisValue;
279 }
280
281 JSValue eval(CallFrame*);
282 CallFrame* loadVarargs(CallFrame*, JSStack*, JSValue thisValue, JSValue arguments, int firstFreeRegister);
283
284 } // namespace JSC
285
286 #endif // Interpreter_h