X-Git-Url: https://git.saurik.com/apple/javascriptcore.git/blobdiff_plain/6fe7ccc865dc7d7541b93c5bcaf6368d2c98a174..refs/heads/master:/interpreter/Interpreter.h diff --git a/interpreter/Interpreter.h b/interpreter/Interpreter.h index 7e34bba..ef4ec0d 100644 --- a/interpreter/Interpreter.h +++ b/interpreter/Interpreter.h @@ -1,5 +1,6 @@ /* - * Copyright (C) 2008 Apple Inc. All rights reserved. + * Copyright (C) 2008, 2013, 2015 Apple Inc. All rights reserved. + * Copyright (C) 2012 Research In Motion Limited. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -10,7 +11,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * 3. Neither the name of Apple Inc. ("Apple") nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * @@ -30,15 +31,17 @@ #define Interpreter_h #include "ArgList.h" +#include "JSCJSValue.h" #include "JSCell.h" -#include "JSFunction.h" -#include "JSValue.h" #include "JSObject.h" +#include "JSStack.h" #include "LLIntData.h" #include "Opcode.h" -#include "RegisterFile.h" +#include "SourceProvider.h" +#include "StackAlignment.h" #include +#include namespace JSC { @@ -46,16 +49,19 @@ namespace JSC { class EvalExecutable; class ExecutableBase; class FunctionExecutable; + class VM; + class JSFunction; class JSGlobalObject; class LLIntOffsetsExtractor; class ProgramExecutable; class Register; - class ScopeChainNode; + class JSScope; class SamplingTool; struct CallFrameClosure; struct HandlerInfo; struct Instruction; - + struct ProtoCallFrame; + enum DebugHookID { WillExecuteProgram, DidExecuteProgram, @@ -75,102 +81,112 @@ namespace JSC { struct StackFrame { Strong callee; StackFrameCodeType codeType; - Strong executable; - int line; - UString sourceURL; - UString toString(CallFrame* callFrame) const + Strong executable; + Strong codeBlock; + RefPtr code; + int lineOffset; + unsigned firstLineColumnOffset; + unsigned characterOffset; + unsigned bytecodeOffset; + String sourceURL; + JS_EXPORT_PRIVATE String toString(CallFrame*); + String friendlySourceURL() const; + String friendlyFunctionName(CallFrame*) const; + JS_EXPORT_PRIVATE void computeLineAndColumn(unsigned& line, unsigned& column); + + private: + void expressionInfo(int& divot, int& startOffset, int& endOffset, unsigned& line, unsigned& column); + }; + + class SuspendExceptionScope { + public: + SuspendExceptionScope(VM* vm) + : m_vm(vm) + { + oldException = vm->exception(); + vm->clearException(); + } + ~SuspendExceptionScope() { - bool hasSourceURLInfo = !sourceURL.isNull() && !sourceURL.isEmpty(); - bool hasLineInfo = line > -1; - String traceLine; - JSObject* stackFrameCallee = callee.get(); - - switch (codeType) { - case StackFrameEvalCode: - if (hasSourceURLInfo) { - traceLine = hasLineInfo ? String::format("eval code@%s:%d", sourceURL.ascii().data(), line) - : String::format("eval code@%s", sourceURL.ascii().data()); - } else - traceLine = String::format("eval code"); - break; - case StackFrameNativeCode: { - if (callee) { - UString functionName = getCalculatedDisplayName(callFrame, stackFrameCallee); - traceLine = String::format("%s@[native code]", functionName.ascii().data()); - } else - traceLine = "[native code]"; - break; - } - case StackFrameFunctionCode: { - UString functionName = getCalculatedDisplayName(callFrame, stackFrameCallee); - if (hasSourceURLInfo) { - traceLine = hasLineInfo ? String::format("%s@%s:%d", functionName.ascii().data(), sourceURL.ascii().data(), line) - : String::format("%s@%s", functionName.ascii().data(), sourceURL.ascii().data()); - } else - traceLine = String::format("%s\n", functionName.ascii().data()); - break; - } - case StackFrameGlobalCode: - if (hasSourceURLInfo) { - traceLine = hasLineInfo ? String::format("global code@%s:%d", sourceURL.ascii().data(), line) - : String::format("global code@%s", sourceURL.ascii().data()); - } else - traceLine = String::format("global code"); - - } - return traceLine.impl(); + m_vm->setException(oldException); } + private: + Exception* oldException; + VM* m_vm; }; - + class TopCallFrameSetter { public: - TopCallFrameSetter(JSGlobalData& global, CallFrame* callFrame) - : globalData(global) - , oldCallFrame(global.topCallFrame) + TopCallFrameSetter(VM& currentVM, CallFrame* callFrame) + : vm(currentVM) + , oldCallFrame(currentVM.topCallFrame) { - global.topCallFrame = callFrame; + currentVM.topCallFrame = callFrame; } ~TopCallFrameSetter() { - globalData.topCallFrame = oldCallFrame; + vm.topCallFrame = oldCallFrame; } private: - JSGlobalData& globalData; + VM& vm; CallFrame* oldCallFrame; }; class NativeCallFrameTracer { public: - ALWAYS_INLINE NativeCallFrameTracer(JSGlobalData* global, CallFrame* callFrame) + ALWAYS_INLINE NativeCallFrameTracer(VM* vm, CallFrame* callFrame) { - ASSERT(global); + ASSERT(vm); ASSERT(callFrame); - global->topCallFrame = callFrame; + vm->topCallFrame = callFrame; } }; - // We use a smaller reentrancy limit on iPhone because of the high amount of - // stack space required on the web thread. - enum { MaxLargeThreadReentryDepth = 64, MaxSmallThreadReentryDepth = 16 }; + class NativeCallFrameTracerWithRestore { + public: + ALWAYS_INLINE NativeCallFrameTracerWithRestore(VM* vm, VMEntryFrame* vmEntryFrame, CallFrame* callFrame) + : m_vm(vm) + { + ASSERT(vm); + ASSERT(callFrame); + m_savedTopVMEntryFrame = vm->topVMEntryFrame; + m_savedTopCallFrame = vm->topCallFrame; + vm->topVMEntryFrame = vmEntryFrame; + vm->topCallFrame = callFrame; + } + + ALWAYS_INLINE ~NativeCallFrameTracerWithRestore() + { + m_vm->topVMEntryFrame = m_savedTopVMEntryFrame; + m_vm->topCallFrame = m_savedTopCallFrame; + } + + private: + VM* m_vm; + VMEntryFrame* m_savedTopVMEntryFrame; + CallFrame* m_savedTopCallFrame; + }; class Interpreter { WTF_MAKE_FAST_ALLOCATED; friend class CachedCall; friend class LLIntOffsetsExtractor; friend class JIT; + friend class VM; + public: - Interpreter(); + Interpreter(VM &); ~Interpreter(); - void initialize(LLInt::Data*, bool canUseJIT); + void initialize(bool canUseJIT); - RegisterFile& registerFile() { return m_registerFile; } + JSStack& stack() { return m_stack; } Opcode getOpcode(OpcodeID id) { ASSERT(m_initialized); -#if ENABLE(COMPUTED_GOTO_CLASSIC_INTERPRETER) || ENABLE(LLINT) +#if ENABLE(COMPUTED_GOTO_OPCODES) return m_opcodeTable[id]; #else return id; @@ -180,122 +196,90 @@ namespace JSC { OpcodeID getOpcodeID(Opcode opcode) { ASSERT(m_initialized); -#if ENABLE(LLINT) +#if ENABLE(COMPUTED_GOTO_OPCODES) ASSERT(isOpcode(opcode)); - return m_opcodeIDTable.get(opcode); -#elif ENABLE(COMPUTED_GOTO_CLASSIC_INTERPRETER) - ASSERT(isOpcode(opcode)); - if (!m_classicEnabled) - return static_cast(bitwise_cast(opcode)); - return m_opcodeIDTable.get(opcode); #else return opcode; #endif } - bool classicEnabled() - { - return m_classicEnabled; - } - bool isOpcode(Opcode); - JSValue execute(ProgramExecutable*, CallFrame*, ScopeChainNode*, JSObject* thisObj); + JSValue execute(ProgramExecutable*, CallFrame*, JSObject* thisObj); JSValue executeCall(CallFrame*, JSObject* function, CallType, const CallData&, JSValue thisValue, const ArgList&); JSObject* executeConstruct(CallFrame*, JSObject* function, ConstructType, const ConstructData&, const ArgList&); - JSValue execute(EvalExecutable*, CallFrame*, JSValue thisValue, ScopeChainNode*); - JSValue execute(EvalExecutable*, CallFrame*, JSValue thisValue, ScopeChainNode*, int globalRegisterOffset); + JSValue execute(EvalExecutable*, CallFrame*, JSValue thisValue, JSScope*); - JSValue retrieveArgumentsFromVMCode(CallFrame*, JSFunction*) const; - JSValue retrieveCallerFromVMCode(CallFrame*, JSFunction*) const; - JS_EXPORT_PRIVATE void retrieveLastCaller(CallFrame*, int& lineNumber, intptr_t& sourceID, UString& sourceURL, JSValue& function) const; - void getArgumentsData(CallFrame*, JSFunction*&, ptrdiff_t& firstParameterIndex, Register*& argv, int& argc); SamplingTool* sampler() { return m_sampler.get(); } - NEVER_INLINE HandlerInfo* throwException(CallFrame*&, JSValue&, unsigned bytecodeOffset); - NEVER_INLINE void debug(CallFrame*, DebugHookID, int firstLine, int lastLine); - static const UString getTraceLine(CallFrame*, StackFrameCodeType, const UString&, int); - JS_EXPORT_PRIVATE static void getStackTrace(JSGlobalData*, Vector& results); - static void addStackTraceIfNecessary(CallFrame*, JSObject* error); + NEVER_INLINE HandlerInfo* unwind(VMEntryFrame*&, CallFrame*&, Exception*); + NEVER_INLINE void debug(CallFrame*, DebugHookID); + JSString* stackTraceAsString(ExecState*, Vector); + + static EncodedJSValue JSC_HOST_CALL constructWithErrorConstructor(ExecState*); + static EncodedJSValue JSC_HOST_CALL callErrorConstructor(ExecState*); + static EncodedJSValue JSC_HOST_CALL constructWithNativeErrorConstructor(ExecState*); + static EncodedJSValue JSC_HOST_CALL callNativeErrorConstructor(ExecState*); void dumpSampleData(ExecState* exec); void startSampling(); void stopSampling(); - private: - enum ExecutionFlag { Normal, InitializeAndReturn }; - CallFrameClosure prepareForRepeatCall(FunctionExecutable*, CallFrame*, JSFunction*, int argumentCountIncludingThis, ScopeChainNode*); - void endRepeatCall(CallFrameClosure&); - JSValue execute(CallFrameClosure&); + JS_EXPORT_PRIVATE void dumpCallFrame(CallFrame*); -#if ENABLE(CLASSIC_INTERPRETER) - NEVER_INLINE bool resolve(CallFrame*, Instruction*, JSValue& exceptionValue); - NEVER_INLINE bool resolveSkip(CallFrame*, Instruction*, JSValue& exceptionValue); - NEVER_INLINE bool resolveGlobal(CallFrame*, Instruction*, JSValue& exceptionValue); - NEVER_INLINE bool resolveGlobalDynamic(CallFrame*, Instruction*, JSValue& exceptionValue); - NEVER_INLINE void resolveBase(CallFrame*, Instruction* vPC); - NEVER_INLINE bool resolveBaseAndProperty(CallFrame*, Instruction*, JSValue& exceptionValue); - NEVER_INLINE bool resolveThisAndProperty(CallFrame*, Instruction*, JSValue& exceptionValue); - NEVER_INLINE ScopeChainNode* createExceptionScope(CallFrame*, const Instruction* vPC); + void getStackTrace(Vector& results, size_t maxStackSize = std::numeric_limits::max()); - void tryCacheGetByID(CallFrame*, CodeBlock*, Instruction*, JSValue baseValue, const Identifier& propertyName, const PropertySlot&); - void uncacheGetByID(CodeBlock*, Instruction* vPC); - void tryCachePutByID(CallFrame*, CodeBlock*, Instruction*, JSValue baseValue, const PutPropertySlot&); - void uncachePutByID(CodeBlock*, Instruction* vPC); -#endif // ENABLE(CLASSIC_INTERPRETER) + private: + enum ExecutionFlag { Normal, InitializeAndReturn }; - NEVER_INLINE bool unwindCallFrame(CallFrame*&, JSValue, unsigned& bytecodeOffset, CodeBlock*&); + CallFrameClosure prepareForRepeatCall(FunctionExecutable*, CallFrame*, ProtoCallFrame*, JSFunction*, int argumentCountIncludingThis, JSScope*, JSValue*); - static ALWAYS_INLINE CallFrame* slideRegisterWindowForCall(CodeBlock*, RegisterFile*, CallFrame*, size_t registerOffset, int argc); + JSValue execute(CallFrameClosure&); - static CallFrame* findFunctionCallFrameFromVMCode(CallFrame*, JSFunction*); - JSValue privateExecute(ExecutionFlag, RegisterFile*, CallFrame*); - void dumpCallFrame(CallFrame*); void dumpRegisters(CallFrame*); bool isCallBytecode(Opcode opcode) { return opcode == getOpcode(op_call) || opcode == getOpcode(op_construct) || opcode == getOpcode(op_call_eval); } void enableSampler(); int m_sampleEntryDepth; - OwnPtr m_sampler; + std::unique_ptr m_sampler; - int m_reentryDepth; - - RegisterFile m_registerFile; + VM& m_vm; + JSStack m_stack; + int m_errorHandlingModeReentry; -#if ENABLE(LLINT) +#if ENABLE(COMPUTED_GOTO_OPCODES) Opcode* m_opcodeTable; // Maps OpcodeID => Opcode for compiling HashMap m_opcodeIDTable; // Maps Opcode => OpcodeID for decompiling -#elif ENABLE(COMPUTED_GOTO_CLASSIC_INTERPRETER) - Opcode m_opcodeTable[numOpcodeIDs]; // Maps OpcodeID => Opcode for compiling - HashMap m_opcodeIDTable; // Maps Opcode => OpcodeID for decompiling #endif #if !ASSERT_DISABLED bool m_initialized; #endif - bool m_classicEnabled; }; - // This value must not be an object that would require this conversion (WebCore's global object). - inline bool isValidThisObject(JSValue thisValue, ExecState* exec) - { - return !thisValue.isObject() || thisValue.toThisObject(exec) == thisValue; - } + JSValue eval(CallFrame*); - inline JSValue Interpreter::execute(EvalExecutable* eval, CallFrame* callFrame, JSValue thisValue, ScopeChainNode* scopeChain) + inline CallFrame* calleeFrameForVarargs(CallFrame* callFrame, unsigned numUsedStackSlots, unsigned argumentCountIncludingThis) { - return execute(eval, callFrame, thisValue, scopeChain, m_registerFile.size() + 1 + RegisterFile::CallFrameHeaderSize); + unsigned paddedCalleeFrameOffset = WTF::roundUpToMultipleOf( + stackAlignmentRegisters(), + numUsedStackSlots + argumentCountIncludingThis + JSStack::CallFrameHeaderSize); + return CallFrame::create(callFrame->registers() - paddedCalleeFrameOffset); } - JSValue eval(CallFrame*); - CallFrame* loadVarargs(CallFrame*, RegisterFile*, JSValue thisValue, JSValue arguments, int firstFreeRegister); - + unsigned sizeOfVarargs(CallFrame* exec, JSValue arguments, uint32_t firstVarArgOffset); + static const unsigned maxArguments = 0x10000; + unsigned sizeFrameForVarargs(CallFrame* exec, JSStack*, JSValue arguments, unsigned numUsedStackSlots, uint32_t firstVarArgOffset); + void loadVarargs(CallFrame* execCaller, VirtualRegister firstElementDest, JSValue source, uint32_t offset, uint32_t length); + void setupVarargsFrame(CallFrame* execCaller, CallFrame* execCallee, JSValue arguments, uint32_t firstVarArgOffset, uint32_t length); + void setupVarargsFrameAndSetThis(CallFrame* execCaller, CallFrame* execCallee, JSValue thisValue, JSValue arguments, uint32_t firstVarArgOffset, uint32_t length); + } // namespace JSC #endif // Interpreter_h