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