Implement a faster Interpreter::getOpcodeID().
[WebKit-https.git] / Source / JavaScriptCore / interpreter / Interpreter.h
1 /*
2  * Copyright (C) 2008-2017 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 "CatchScope.h"
34 #include "FrameTracers.h"
35 #include "JSCJSValue.h"
36 #include "JSCell.h"
37 #include "JSObject.h"
38 #include "Opcode.h"
39 #include "StackAlignment.h"
40 #include <wtf/HashMap.h>
41
42 #if !ENABLE(JIT)
43 #include "CLoopStack.h"
44 #endif
45
46
47 namespace JSC {
48
49     class CodeBlock;
50     class EvalExecutable;
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 StackFrame;
63     struct CallFrameClosure;
64     struct HandlerInfo;
65     struct Instruction;
66     struct ProtoCallFrame;
67     struct UnlinkedInstruction;
68
69     enum UnwindStart : uint8_t { UnwindFromCurrentFrame, UnwindFromCallerFrame };
70
71     enum DebugHookType {
72         WillExecuteProgram,
73         DidExecuteProgram,
74         DidEnterCallFrame,
75         DidReachBreakpoint,
76         WillLeaveCallFrame,
77         WillExecuteStatement,
78         WillExecuteExpression,
79     };
80
81     enum StackFrameCodeType {
82         StackFrameGlobalCode,
83         StackFrameEvalCode,
84         StackFrameModuleCode,
85         StackFrameFunctionCode,
86         StackFrameNativeCode
87     };
88
89     class Interpreter {
90         WTF_MAKE_FAST_ALLOCATED;
91         friend class CachedCall;
92         friend class LLIntOffsetsExtractor;
93         friend class JIT;
94         friend class VM;
95
96     public:
97         Interpreter(VM &);
98         ~Interpreter();
99         
100 #if !ENABLE(JIT)
101         CLoopStack& cloopStack() { return m_cloopStack; }
102 #endif
103         
104         Opcode getOpcode(OpcodeID id)
105         {
106 #if ENABLE(COMPUTED_GOTO_OPCODES)
107             return m_opcodeTable[id];
108 #else
109             return id;
110 #endif
111         }
112
113         OpcodeID getOpcodeID(Opcode opcode)
114         {
115 #if ENABLE(COMPUTED_GOTO_OPCODES)
116             ASSERT(isOpcode(opcode));
117 #if USE(LLINT_EMBEDDED_OPCODE_ID)
118             // The OpcodeID is embedded in the int32_t word preceding the location of
119             // the LLInt code for the opcode (see the EMBED_OPCODE_ID_IF_NEEDED macro
120             // in LowLevelInterpreter.cpp).
121             MacroAssemblerCodePtr codePtr(reinterpret_cast<void*>(opcode));
122             int32_t* opcodeIDAddress = reinterpret_cast<int32_t*>(codePtr.dataLocation()) - 1;
123             OpcodeID opcodeID = static_cast<OpcodeID>(*opcodeIDAddress);
124             ASSERT(opcodeID < NUMBER_OF_BYTECODE_IDS);
125             return opcodeID;
126 #else
127             return m_opcodeIDTable.get(opcode);
128 #endif // USE(LLINT_EMBEDDED_OPCODE_ID)
129
130 #else // not ENABLE(COMPUTED_GOTO_OPCODES)
131             return opcode;
132 #endif
133         }
134
135         OpcodeID getOpcodeID(const Instruction&);
136         OpcodeID getOpcodeID(const UnlinkedInstruction&);
137
138 #if !ASSERT_DISABLED
139         bool isOpcode(Opcode);
140 #endif
141
142         JSValue executeProgram(const SourceCode&, CallFrame*, JSObject* thisObj);
143         JSValue executeModuleProgram(ModuleProgramExecutable*, CallFrame*, JSModuleEnvironment*);
144         JSValue executeCall(CallFrame*, JSObject* function, CallType, const CallData&, JSValue thisValue, const ArgList&);
145         JSObject* executeConstruct(CallFrame*, JSObject* function, ConstructType, const ConstructData&, const ArgList&, JSValue newTarget);
146         JSValue execute(EvalExecutable*, CallFrame*, JSValue thisValue, JSScope*);
147
148         void getArgumentsData(CallFrame*, JSFunction*&, ptrdiff_t& firstParameterIndex, Register*& argv, int& argc);
149         
150         NEVER_INLINE HandlerInfo* unwind(VM&, CallFrame*&, Exception*, UnwindStart);
151         void notifyDebuggerOfExceptionToBeThrown(VM&, CallFrame*, Exception*);
152         NEVER_INLINE void debug(CallFrame*, DebugHookType);
153         static JSString* stackTraceAsString(VM&, const Vector<StackFrame>&);
154
155         static EncodedJSValue JSC_HOST_CALL constructWithErrorConstructor(ExecState*);
156         static EncodedJSValue JSC_HOST_CALL callErrorConstructor(ExecState*);
157         static EncodedJSValue JSC_HOST_CALL constructWithNativeErrorConstructor(ExecState*);
158         static EncodedJSValue JSC_HOST_CALL callNativeErrorConstructor(ExecState*);
159
160         JS_EXPORT_PRIVATE void dumpCallFrame(CallFrame*);
161
162         void getStackTrace(Vector<StackFrame>& results, size_t framesToSkip = 0, size_t maxStackSize = std::numeric_limits<size_t>::max());
163
164     private:
165         enum ExecutionFlag { Normal, InitializeAndReturn };
166
167         CallFrameClosure prepareForRepeatCall(FunctionExecutable*, CallFrame*, ProtoCallFrame*, JSFunction*, int argumentCountIncludingThis, JSScope*, const ArgList&);
168
169         JSValue execute(CallFrameClosure&);
170
171
172
173         void dumpRegisters(CallFrame*);
174         
175         bool isCallBytecode(Opcode opcode) { return opcode == getOpcode(op_call) || opcode == getOpcode(op_construct) || opcode == getOpcode(op_call_eval) || opcode == getOpcode(op_tail_call); }
176
177         VM& m_vm;
178 #if !ENABLE(JIT)
179         CLoopStack m_cloopStack;
180 #endif
181         
182 #if ENABLE(COMPUTED_GOTO_OPCODES)
183         const Opcode* m_opcodeTable; // Maps OpcodeID => Opcode for compiling
184
185 #if !USE(LLINT_EMBEDDED_OPCODE_ID) || !ASSERT_DISABLED
186         HashMap<Opcode, OpcodeID>& m_opcodeIDTable; // Maps Opcode => OpcodeID for decompiling
187
188         static HashMap<Opcode, OpcodeID>& opcodeIDTable();
189 #endif // !USE(LLINT_EMBEDDED_OPCODE_ID) || !ASSERT_DISABLED
190 #endif // ENABLE(COMPUTED_GOTO_OPCODES)
191     };
192
193     JSValue eval(CallFrame*);
194
195     inline CallFrame* calleeFrameForVarargs(CallFrame* callFrame, unsigned numUsedStackSlots, unsigned argumentCountIncludingThis)
196     {
197         // We want the new frame to be allocated on a stack aligned offset with a stack
198         // aligned size. Align the size here.
199         argumentCountIncludingThis = WTF::roundUpToMultipleOf(
200             stackAlignmentRegisters(),
201             argumentCountIncludingThis + CallFrame::headerSizeInRegisters) - CallFrame::headerSizeInRegisters;
202
203         // Align the frame offset here.
204         unsigned paddedCalleeFrameOffset = WTF::roundUpToMultipleOf(
205             stackAlignmentRegisters(),
206             numUsedStackSlots + argumentCountIncludingThis + CallFrame::headerSizeInRegisters);
207         return CallFrame::create(callFrame->registers() - paddedCalleeFrameOffset);
208     }
209
210     unsigned sizeOfVarargs(CallFrame* exec, JSValue arguments, uint32_t firstVarArgOffset);
211     static const unsigned maxArguments = 0x10000;
212     unsigned sizeFrameForVarargs(CallFrame* exec, VM&, JSValue arguments, unsigned numUsedStackSlots, uint32_t firstVarArgOffset);
213     unsigned sizeFrameForForwardArguments(CallFrame* exec, VM&, unsigned numUsedStackSlots);
214     void loadVarargs(CallFrame* execCaller, VirtualRegister firstElementDest, JSValue source, uint32_t offset, uint32_t length);
215     void setupVarargsFrame(CallFrame* execCaller, CallFrame* execCallee, JSValue arguments, uint32_t firstVarArgOffset, uint32_t length);
216     void setupVarargsFrameAndSetThis(CallFrame* execCaller, CallFrame* execCallee, JSValue thisValue, JSValue arguments, uint32_t firstVarArgOffset, uint32_t length);
217     void setupForwardArgumentsFrame(CallFrame* execCaller, CallFrame* execCallee, uint32_t length);
218     void setupForwardArgumentsFrameAndSetThis(CallFrame* execCaller, CallFrame* execCallee, JSValue thisValue, uint32_t length);
219     
220 } // namespace JSC