]> git.saurik.com Git - apple/javascriptcore.git/blob - interpreter/Interpreter.h
c77019e5a1c987379f028c39cfe26fa2b526fcde
[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 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 #include "SourceProvider.h"
42
43 #include <wtf/HashMap.h>
44 #include <wtf/text/StringBuilder.h>
45
46 namespace JSC {
47
48 class CodeBlock;
49 class EvalExecutable;
50 class ExecutableBase;
51 class FunctionExecutable;
52 class VM;
53 class JSGlobalObject;
54 class LLIntOffsetsExtractor;
55 class ProgramExecutable;
56 class Register;
57 class JSScope;
58 class SamplingTool;
59 struct CallFrameClosure;
60 struct HandlerInfo;
61 struct Instruction;
62 struct ProtoCallFrame;
63
64 enum DebugHookID {
65 WillExecuteProgram,
66 DidExecuteProgram,
67 DidEnterCallFrame,
68 DidReachBreakpoint,
69 WillLeaveCallFrame,
70 WillExecuteStatement
71 };
72
73 enum StackFrameCodeType {
74 StackFrameGlobalCode,
75 StackFrameEvalCode,
76 StackFrameFunctionCode,
77 StackFrameNativeCode
78 };
79
80 struct StackFrame {
81 Strong<JSObject> callee;
82 StackFrameCodeType codeType;
83 Strong<ExecutableBase> executable;
84 Strong<UnlinkedCodeBlock> codeBlock;
85 RefPtr<SourceProvider> code;
86 int lineOffset;
87 unsigned firstLineColumnOffset;
88 unsigned characterOffset;
89 unsigned bytecodeOffset;
90 String sourceURL;
91 JS_EXPORT_PRIVATE String toString(CallFrame*);
92 String friendlySourceURL() const
93 {
94 String traceLine;
95
96 switch (codeType) {
97 case StackFrameEvalCode:
98 case StackFrameFunctionCode:
99 case StackFrameGlobalCode:
100 if (!sourceURL.isEmpty())
101 traceLine = sourceURL.impl();
102 break;
103 case StackFrameNativeCode:
104 traceLine = "[native code]";
105 break;
106 }
107 return traceLine.isNull() ? emptyString() : traceLine;
108 }
109 String friendlyFunctionName(CallFrame* callFrame) const
110 {
111 String traceLine;
112 JSObject* stackFrameCallee = callee.get();
113
114 switch (codeType) {
115 case StackFrameEvalCode:
116 traceLine = "eval code";
117 break;
118 case StackFrameNativeCode:
119 if (callee)
120 traceLine = getCalculatedDisplayName(callFrame, stackFrameCallee).impl();
121 break;
122 case StackFrameFunctionCode:
123 traceLine = getCalculatedDisplayName(callFrame, stackFrameCallee).impl();
124 break;
125 case StackFrameGlobalCode:
126 traceLine = "global code";
127 break;
128 }
129 return traceLine.isNull() ? emptyString() : traceLine;
130 }
131 JS_EXPORT_PRIVATE void computeLineAndColumn(unsigned& line, unsigned& column);
132
133 private:
134 void expressionInfo(int& divot, int& startOffset, int& endOffset, unsigned& line, unsigned& column);
135 };
136
137 class ClearExceptionScope {
138 public:
139 ClearExceptionScope(VM* vm): m_vm(vm)
140 {
141 vm->getExceptionInfo(oldException, oldExceptionStack);
142 vm->clearException();
143 }
144 ~ClearExceptionScope()
145 {
146 m_vm->setExceptionInfo(oldException, oldExceptionStack);
147 }
148 private:
149 JSC::JSValue oldException;
150 RefCountedArray<JSC::StackFrame> oldExceptionStack;
151 VM* m_vm;
152 };
153
154 class TopCallFrameSetter {
155 public:
156 TopCallFrameSetter(VM& currentVM, CallFrame* callFrame)
157 : vm(currentVM)
158 , oldCallFrame(currentVM.topCallFrame)
159 {
160 ASSERT(!callFrame->isVMEntrySentinel());
161 currentVM.topCallFrame = callFrame;
162 }
163
164 ~TopCallFrameSetter()
165 {
166 ASSERT(!oldCallFrame->isVMEntrySentinel());
167 vm.topCallFrame = oldCallFrame;
168 }
169 private:
170 VM& vm;
171 CallFrame* oldCallFrame;
172 };
173
174 class NativeCallFrameTracer {
175 public:
176 ALWAYS_INLINE NativeCallFrameTracer(VM* vm, CallFrame* callFrame)
177 {
178 ASSERT(vm);
179 ASSERT(callFrame);
180 ASSERT(!callFrame->isVMEntrySentinel());
181 vm->topCallFrame = callFrame;
182 }
183
184 enum VMEntrySentinelOKTag { VMEntrySentinelOK };
185 ALWAYS_INLINE NativeCallFrameTracer(VM* vm, CallFrame* callFrame, VMEntrySentinelOKTag)
186 {
187 ASSERT(vm);
188 ASSERT(callFrame);
189 if (!callFrame->isVMEntrySentinel())
190 vm->topCallFrame = callFrame;
191 }
192 };
193
194 class Interpreter {
195 WTF_MAKE_FAST_ALLOCATED;
196 friend class CachedCall;
197 friend class LLIntOffsetsExtractor;
198 friend class JIT;
199 friend class VM;
200
201 public:
202 Interpreter(VM &);
203 ~Interpreter();
204
205 void initialize(bool canUseJIT);
206
207 JSStack& stack() { return m_stack; }
208
209 Opcode getOpcode(OpcodeID id)
210 {
211 ASSERT(m_initialized);
212 #if ENABLE(COMPUTED_GOTO_OPCODES)
213 return m_opcodeTable[id];
214 #else
215 return id;
216 #endif
217 }
218
219 OpcodeID getOpcodeID(Opcode opcode)
220 {
221 ASSERT(m_initialized);
222 #if ENABLE(COMPUTED_GOTO_OPCODES)
223 ASSERT(isOpcode(opcode));
224 return m_opcodeIDTable.get(opcode);
225 #else
226 return opcode;
227 #endif
228 }
229
230 bool isOpcode(Opcode);
231
232 JSValue execute(ProgramExecutable*, CallFrame*, JSObject* thisObj);
233 JSValue executeCall(CallFrame*, JSObject* function, CallType, const CallData&, JSValue thisValue, const ArgList&);
234 JSObject* executeConstruct(CallFrame*, JSObject* function, ConstructType, const ConstructData&, const ArgList&);
235 JSValue execute(EvalExecutable*, CallFrame*, JSValue thisValue, JSScope*);
236
237 void getArgumentsData(CallFrame*, JSFunction*&, ptrdiff_t& firstParameterIndex, Register*& argv, int& argc);
238
239 SamplingTool* sampler() { return m_sampler.get(); }
240
241 NEVER_INLINE HandlerInfo* unwind(CallFrame*&, JSValue&);
242 NEVER_INLINE void debug(CallFrame*, DebugHookID);
243 JSString* stackTraceAsString(ExecState*, Vector<StackFrame>);
244
245 static EncodedJSValue JSC_HOST_CALL constructWithErrorConstructor(ExecState*);
246 static EncodedJSValue JSC_HOST_CALL callErrorConstructor(ExecState*);
247 static EncodedJSValue JSC_HOST_CALL constructWithNativeErrorConstructor(ExecState*);
248 static EncodedJSValue JSC_HOST_CALL callNativeErrorConstructor(ExecState*);
249
250 void dumpSampleData(ExecState* exec);
251 void startSampling();
252 void stopSampling();
253
254 JS_EXPORT_PRIVATE void dumpCallFrame(CallFrame*);
255
256 private:
257 enum ExecutionFlag { Normal, InitializeAndReturn };
258
259 CallFrameClosure prepareForRepeatCall(FunctionExecutable*, CallFrame*, ProtoCallFrame*, JSFunction*, int argumentCountIncludingThis, JSScope*, JSValue*);
260
261 JSValue execute(CallFrameClosure&);
262
263 void getStackTrace(Vector<StackFrame>& results, size_t maxStackSize = std::numeric_limits<size_t>::max());
264
265 void dumpRegisters(CallFrame*);
266
267 bool isCallBytecode(Opcode opcode) { return opcode == getOpcode(op_call) || opcode == getOpcode(op_construct) || opcode == getOpcode(op_call_eval); }
268
269 void enableSampler();
270 int m_sampleEntryDepth;
271 OwnPtr<SamplingTool> m_sampler;
272
273 VM& m_vm;
274 JSStack m_stack;
275 int m_errorHandlingModeReentry;
276
277 #if ENABLE(COMPUTED_GOTO_OPCODES)
278 Opcode* m_opcodeTable; // Maps OpcodeID => Opcode for compiling
279 HashMap<Opcode, OpcodeID> m_opcodeIDTable; // Maps Opcode => OpcodeID for decompiling
280 #endif
281
282 #if !ASSERT_DISABLED
283 bool m_initialized;
284 #endif
285 };
286
287 JSValue eval(CallFrame*);
288 CallFrame* sizeFrameForVarargs(CallFrame*, JSStack*, JSValue, int, uint32_t firstVarArgOffset);
289 void loadVarargs(CallFrame*, CallFrame*, JSValue, JSValue, uint32_t firstVarArgOffset);
290 } // namespace JSC
291
292 #endif // Interpreter_h