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
46namespace 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
293