1/*
2 * Copyright (C) 2008-2018 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#pragma once
31
32#include "ArgList.h"
33#include "JSCJSValue.h"
34#include "JSObject.h"
35#include "Opcode.h"
36#include "StackAlignment.h"
37#include <wtf/HashMap.h>
38
39#if ENABLE(C_LOOP)
40#include "CLoopStack.h"
41#endif
42
43
44namespace JSC {
45
46 class CodeBlock;
47 class EvalExecutable;
48 class FunctionExecutable;
49 class VM;
50 class JSFunction;
51 class JSGlobalObject;
52 class JSModuleEnvironment;
53 class JSModuleRecord;
54 class LLIntOffsetsExtractor;
55 class ProgramExecutable;
56 class ModuleProgramExecutable;
57 class Register;
58 class JSScope;
59 class SourceCode;
60 class StackFrame;
61 struct CallFrameClosure;
62 struct HandlerInfo;
63 struct Instruction;
64 struct ProtoCallFrame;
65
66 enum DebugHookType {
67 WillExecuteProgram,
68 DidExecuteProgram,
69 DidEnterCallFrame,
70 DidReachBreakpoint,
71 WillLeaveCallFrame,
72 WillExecuteStatement,
73 WillExecuteExpression,
74 };
75
76 enum StackFrameCodeType {
77 StackFrameGlobalCode,
78 StackFrameEvalCode,
79 StackFrameModuleCode,
80 StackFrameFunctionCode,
81 StackFrameNativeCode
82 };
83
84 class Interpreter {
85 WTF_MAKE_FAST_ALLOCATED;
86 friend class CachedCall;
87 friend class LLIntOffsetsExtractor;
88 friend class JIT;
89 friend class VM;
90
91 public:
92 Interpreter(VM &);
93 ~Interpreter();
94
95#if ENABLE(C_LOOP)
96 CLoopStack& cloopStack() { return m_cloopStack; }
97#endif
98
99 static inline Opcode getOpcode(OpcodeID);
100
101 static inline OpcodeID getOpcodeID(Opcode);
102
103#if !ASSERT_DISABLED
104 static bool isOpcode(Opcode);
105#endif
106
107 JSValue executeProgram(const SourceCode&, JSGlobalObject*, JSObject* thisObj);
108 JSValue executeModuleProgram(ModuleProgramExecutable*, JSGlobalObject*, JSModuleEnvironment*);
109 JSValue executeCall(JSGlobalObject*, JSObject* function, CallType, const CallData&, JSValue thisValue, const ArgList&);
110 JSObject* executeConstruct(JSGlobalObject*, JSObject* function, ConstructType, const ConstructData&, const ArgList&, JSValue newTarget);
111 JSValue execute(EvalExecutable*, JSGlobalObject*, JSValue thisValue, JSScope*);
112
113 void getArgumentsData(CallFrame*, JSFunction*&, ptrdiff_t& firstParameterIndex, Register*& argv, int& argc);
114
115 NEVER_INLINE HandlerInfo* unwind(VM&, CallFrame*&, Exception*);
116 void notifyDebuggerOfExceptionToBeThrown(VM&, JSGlobalObject*, CallFrame*, Exception*);
117 NEVER_INLINE void debug(CallFrame*, DebugHookType);
118 static String stackTraceAsString(VM&, const Vector<StackFrame>&);
119
120 void getStackTrace(JSCell* owner, Vector<StackFrame>& results, size_t framesToSkip = 0, size_t maxStackSize = std::numeric_limits<size_t>::max());
121
122 private:
123 enum ExecutionFlag { Normal, InitializeAndReturn };
124
125 static JSValue checkedReturn(JSValue returnValue)
126 {
127 ASSERT(returnValue);
128 return returnValue;
129 }
130
131 static JSObject* checkedReturn(JSObject* returnValue)
132 {
133 ASSERT(returnValue);
134 return returnValue;
135 }
136
137 CallFrameClosure prepareForRepeatCall(FunctionExecutable*, CallFrame*, ProtoCallFrame*, JSFunction*, int argumentCountIncludingThis, JSScope*, const ArgList&);
138
139 JSValue execute(CallFrameClosure&);
140
141 VM& m_vm;
142#if ENABLE(C_LOOP)
143 CLoopStack m_cloopStack;
144#endif
145
146#if ENABLE(COMPUTED_GOTO_OPCODES)
147#if !USE(LLINT_EMBEDDED_OPCODE_ID) || !ASSERT_DISABLED
148 static HashMap<Opcode, OpcodeID>& opcodeIDTable(); // Maps Opcode => OpcodeID.
149#endif // !USE(LLINT_EMBEDDED_OPCODE_ID) || !ASSERT_DISABLED
150#endif // ENABLE(COMPUTED_GOTO_OPCODES)
151 };
152
153 JSValue eval(JSGlobalObject*, CallFrame*);
154
155 inline CallFrame* calleeFrameForVarargs(CallFrame* callFrame, unsigned numUsedStackSlots, unsigned argumentCountIncludingThis)
156 {
157 // We want the new frame to be allocated on a stack aligned offset with a stack
158 // aligned size. Align the size here.
159 argumentCountIncludingThis = WTF::roundUpToMultipleOf(
160 stackAlignmentRegisters(),
161 argumentCountIncludingThis + CallFrame::headerSizeInRegisters) - CallFrame::headerSizeInRegisters;
162
163 // Align the frame offset here.
164 unsigned paddedCalleeFrameOffset = WTF::roundUpToMultipleOf(
165 stackAlignmentRegisters(),
166 numUsedStackSlots + argumentCountIncludingThis + CallFrame::headerSizeInRegisters);
167 return CallFrame::create(callFrame->registers() - paddedCalleeFrameOffset);
168 }
169
170 unsigned sizeOfVarargs(JSGlobalObject*, JSValue arguments, uint32_t firstVarArgOffset);
171 static constexpr unsigned maxArguments = 0x10000;
172 unsigned sizeFrameForVarargs(JSGlobalObject*, CallFrame*, VM&, JSValue arguments, unsigned numUsedStackSlots, uint32_t firstVarArgOffset);
173 unsigned sizeFrameForForwardArguments(JSGlobalObject*, CallFrame*, VM&, unsigned numUsedStackSlots);
174 void loadVarargs(JSGlobalObject*, CallFrame* execCaller, VirtualRegister firstElementDest, JSValue source, uint32_t offset, uint32_t length);
175 void setupVarargsFrame(JSGlobalObject*, CallFrame* execCaller, CallFrame* execCallee, JSValue arguments, uint32_t firstVarArgOffset, uint32_t length);
176 void setupVarargsFrameAndSetThis(JSGlobalObject*, CallFrame* execCaller, CallFrame* execCallee, JSValue thisValue, JSValue arguments, uint32_t firstVarArgOffset, uint32_t length);
177 void setupForwardArgumentsFrame(JSGlobalObject*, CallFrame* execCaller, CallFrame* execCallee, uint32_t length);
178 void setupForwardArgumentsFrameAndSetThis(JSGlobalObject*, CallFrame* execCaller, CallFrame* execCallee, JSValue thisValue, uint32_t length);
179
180} // namespace JSC
181
182namespace WTF {
183
184class PrintStream;
185
186void printInternal(PrintStream&, JSC::DebugHookType);
187
188} // namespace WTF
189