1/*
2 * Copyright (C) 2008, 2013, 2015 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 "JSObject.h"
37#include "JSStack.h"
38#include "LLIntData.h"
39#include "Opcode.h"
40#include "SourceProvider.h"
41#include "StackAlignment.h"
42
43#include <wtf/HashMap.h>
44#include <wtf/text/StringBuilder.h>
45
46namespace JSC {
47
48 class CodeBlock;
49 class EvalExecutable;
50 class ExecutableBase;
51 class FunctionExecutable;
52 class VM;
53 class JSFunction;
54 class JSGlobalObject;
55 class JSModuleEnvironment;
56 class JSModuleRecord;
57 class LLIntOffsetsExtractor;
58 class ProgramExecutable;
59 class ModuleProgramExecutable;
60 class Register;
61 class JSScope;
62 class SamplingTool;
63 struct CallFrameClosure;
64 struct HandlerInfo;
65 struct Instruction;
66 struct ProtoCallFrame;
67
68 enum UnwindStart { UnwindFromCurrentFrame, UnwindFromCallerFrame };
69
70 enum DebugHookID {
71 WillExecuteProgram,
72 DidExecuteProgram,
73 DidEnterCallFrame,
74 DidReachBreakpoint,
75 WillLeaveCallFrame,
76 WillExecuteStatement
77 };
78
79 enum StackFrameCodeType {
80 StackFrameGlobalCode,
81 StackFrameEvalCode,
82 StackFrameModuleCode,
83 StackFrameFunctionCode,
84 StackFrameNativeCode
85 };
86
87 struct StackFrame {
88 Strong<JSObject> callee;
89 StackFrameCodeType codeType;
90 Strong<ScriptExecutable> executable;
91 Strong<UnlinkedCodeBlock> codeBlock;
92 RefPtr<SourceProvider> code;
93 int lineOffset;
94 unsigned firstLineColumnOffset;
95 unsigned characterOffset;
96 unsigned bytecodeOffset;
97 String sourceURL;
98 JS_EXPORT_PRIVATE String toString(CallFrame*);
99 String friendlySourceURL() const;
100 String friendlyFunctionName(CallFrame*) const;
101 JS_EXPORT_PRIVATE void computeLineAndColumn(unsigned& line, unsigned& column);
102
103 private:
104 void expressionInfo(int& divot, int& startOffset, int& endOffset, unsigned& line, unsigned& column);
105 };
106
107 class SuspendExceptionScope {
108 public:
109 SuspendExceptionScope(VM* vm)
110 : m_vm(vm)
111 {
112 oldException = vm->exception();
113 vm->clearException();
114 }
115 ~SuspendExceptionScope()
116 {
117 m_vm->restorePreviousException(oldException);
118 }
119 private:
120 Exception* oldException;
121 VM* m_vm;
122 };
123
124 class TopCallFrameSetter {
125 public:
126 TopCallFrameSetter(VM& currentVM, CallFrame* callFrame)
127 : vm(currentVM)
128 , oldCallFrame(currentVM.topCallFrame)
129 {
130 currentVM.topCallFrame = callFrame;
131 }
132
133 ~TopCallFrameSetter()
134 {
135 vm.topCallFrame = oldCallFrame;
136 }
137 private:
138 VM& vm;
139 CallFrame* oldCallFrame;
140 };
141
142 class NativeCallFrameTracer {
143 public:
144 ALWAYS_INLINE NativeCallFrameTracer(VM* vm, CallFrame* callFrame)
145 {
146 ASSERT(vm);
147 ASSERT(callFrame);
148 ASSERT(callFrame < vm->topVMEntryFrame);
149 vm->topCallFrame = callFrame;
150 }
151 };
152
153 class NativeCallFrameTracerWithRestore {
154 public:
155 ALWAYS_INLINE NativeCallFrameTracerWithRestore(VM* vm, VMEntryFrame* vmEntryFrame, CallFrame* callFrame)
156 : m_vm(vm)
157 {
158 ASSERT(vm);
159 ASSERT(callFrame);
160 m_savedTopVMEntryFrame = vm->topVMEntryFrame;
161 m_savedTopCallFrame = vm->topCallFrame;
162 vm->topVMEntryFrame = vmEntryFrame;
163 vm->topCallFrame = callFrame;
164 }
165
166 ALWAYS_INLINE ~NativeCallFrameTracerWithRestore()
167 {
168 m_vm->topVMEntryFrame = m_savedTopVMEntryFrame;
169 m_vm->topCallFrame = m_savedTopCallFrame;
170 }
171
172 private:
173 VM* m_vm;
174 VMEntryFrame* m_savedTopVMEntryFrame;
175 CallFrame* m_savedTopCallFrame;
176 };
177
178 class Interpreter {
179 WTF_MAKE_FAST_ALLOCATED;
180 friend class CachedCall;
181 friend class LLIntOffsetsExtractor;
182 friend class JIT;
183 friend class VM;
184
185 public:
186 Interpreter(VM &);
187 ~Interpreter();
188
189 void initialize();
190
191 JSStack& stack() { return m_stack; }
192
193 Opcode getOpcode(OpcodeID id)
194 {
195 ASSERT(m_initialized);
196#if ENABLE(COMPUTED_GOTO_OPCODES)
197 return m_opcodeTable[id];
198#else
199 return id;
200#endif
201 }
202
203 OpcodeID getOpcodeID(Opcode opcode)
204 {
205 ASSERT(m_initialized);
206#if ENABLE(COMPUTED_GOTO_OPCODES)
207 ASSERT(isOpcode(opcode));
208 return m_opcodeIDTable.get(opcode);
209#else
210 return opcode;
211#endif
212 }
213
214 bool isOpcode(Opcode);
215
216 JSValue execute(ProgramExecutable*, CallFrame*, JSObject* thisObj);
217 JSValue executeCall(CallFrame*, JSObject* function, CallType, const CallData&, JSValue thisValue, const ArgList&);
218 JSObject* executeConstruct(CallFrame*, JSObject* function, ConstructType, const ConstructData&, const ArgList&, JSValue newTarget);
219 JSValue execute(EvalExecutable*, CallFrame*, JSValue thisValue, JSScope*);
220 JSValue execute(ModuleProgramExecutable*, CallFrame*, JSModuleEnvironment*);
221
222 void getArgumentsData(CallFrame*, JSFunction*&, ptrdiff_t& firstParameterIndex, Register*& argv, int& argc);
223
224 SamplingTool* sampler() { return m_sampler.get(); }
225
226 NEVER_INLINE HandlerInfo* unwind(VM&, CallFrame*&, Exception*, UnwindStart);
227 void notifyDebuggerOfExceptionToBeThrown(CallFrame*, Exception*);
228 NEVER_INLINE void debug(CallFrame*, DebugHookID);
229 JSString* stackTraceAsString(ExecState*, Vector<StackFrame>);
230
231 static EncodedJSValue JSC_HOST_CALL constructWithErrorConstructor(ExecState*);
232 static EncodedJSValue JSC_HOST_CALL callErrorConstructor(ExecState*);
233 static EncodedJSValue JSC_HOST_CALL constructWithNativeErrorConstructor(ExecState*);
234 static EncodedJSValue JSC_HOST_CALL callNativeErrorConstructor(ExecState*);
235
236 void dumpSampleData(ExecState* exec);
237 void startSampling();
238 void stopSampling();
239
240 JS_EXPORT_PRIVATE void dumpCallFrame(CallFrame*);
241
242 void getStackTrace(Vector<StackFrame>& results, size_t maxStackSize = std::numeric_limits<size_t>::max());
243
244 private:
245 enum ExecutionFlag { Normal, InitializeAndReturn };
246
247 CallFrameClosure prepareForRepeatCall(FunctionExecutable*, CallFrame*, ProtoCallFrame*, JSFunction*, int argumentCountIncludingThis, JSScope*, JSValue*);
248
249 JSValue execute(CallFrameClosure&);
250
251
252
253 void dumpRegisters(CallFrame*);
254
255 bool isCallBytecode(Opcode opcode) { return opcode == getOpcode(op_call) || opcode == getOpcode(op_construct) || opcode == getOpcode(op_call_eval) || opcode == getOpcode(op_tail_call); }
256
257 void enableSampler();
258 int m_sampleEntryDepth;
259 std::unique_ptr<SamplingTool> m_sampler;
260
261 VM& m_vm;
262 JSStack m_stack;
263 int m_errorHandlingModeReentry;
264
265#if ENABLE(COMPUTED_GOTO_OPCODES)
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 JSValue eval(CallFrame*);
276
277 inline CallFrame* calleeFrameForVarargs(CallFrame* callFrame, unsigned numUsedStackSlots, unsigned argumentCountIncludingThis)
278 {
279 // We want the new frame to be allocated on a stack aligned offset with a stack
280 // aligned size. Align the size here.
281 argumentCountIncludingThis = WTF::roundUpToMultipleOf(
282 stackAlignmentRegisters(),
283 argumentCountIncludingThis + JSStack::CallFrameHeaderSize) - JSStack::CallFrameHeaderSize;
284
285 // Align the frame offset here.
286 unsigned paddedCalleeFrameOffset = WTF::roundUpToMultipleOf(
287 stackAlignmentRegisters(),
288 numUsedStackSlots + argumentCountIncludingThis + JSStack::CallFrameHeaderSize);
289 return CallFrame::create(callFrame->registers() - paddedCalleeFrameOffset);
290 }
291
292 unsigned sizeOfVarargs(CallFrame* exec, JSValue arguments, uint32_t firstVarArgOffset);
293 static const unsigned maxArguments = 0x10000;
294 unsigned sizeFrameForVarargs(CallFrame* exec, JSStack*, JSValue arguments, unsigned numUsedStackSlots, uint32_t firstVarArgOffset);
295 void loadVarargs(CallFrame* execCaller, VirtualRegister firstElementDest, JSValue source, uint32_t offset, uint32_t length);
296 void setupVarargsFrame(CallFrame* execCaller, CallFrame* execCallee, JSValue arguments, uint32_t firstVarArgOffset, uint32_t length);
297 void setupVarargsFrameAndSetThis(CallFrame* execCaller, CallFrame* execCallee, JSValue thisValue, JSValue arguments, uint32_t firstVarArgOffset, uint32_t length);
298
299} // namespace JSC
300
301#endif // Interpreter_h
302