X-Git-Url: https://git.saurik.com/apple/javascriptcore.git/blobdiff_plain/40a37d088818fc2fbeba2ef850dbcaaf294befbf..refs/heads/master:/interpreter/Interpreter.cpp diff --git a/interpreter/Interpreter.cpp b/interpreter/Interpreter.cpp index fb07429..c997d2c 100644 --- a/interpreter/Interpreter.cpp +++ b/interpreter/Interpreter.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008, 2009, 2010, 2012, 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2008, 2009, 2010, 2012-2015 Apple Inc. All rights reserved. * Copyright (C) 2008 Cameron Zwarich * * Redistribution and use in source and binary forms, with or without @@ -30,24 +30,26 @@ #include "config.h" #include "Interpreter.h" -#include "Arguments.h" #include "BatchedTransitionOptimizer.h" #include "CallFrameClosure.h" #include "CallFrameInlines.h" +#include "ClonedArguments.h" #include "CodeBlock.h" +#include "DirectArguments.h" #include "Heap.h" #include "Debugger.h" #include "DebuggerCallFrame.h" #include "ErrorInstance.h" #include "EvalCodeCache.h" +#include "Exception.h" #include "ExceptionHelpers.h" #include "GetterSetter.h" -#include "JSActivation.h" #include "JSArray.h" #include "JSBoundFunction.h" +#include "JSCInlines.h" +#include "JSLexicalEnvironment.h" #include "JSNameScope.h" #include "JSNotAnObject.h" -#include "JSPropertyNameIterator.h" #include "JSStackInlines.h" #include "JSString.h" #include "JSWithScope.h" @@ -55,19 +57,19 @@ #include "LLIntThunks.h" #include "LegacyProfiler.h" #include "LiteralParser.h" -#include "NameInstance.h" #include "ObjectPrototype.h" -#include "JSCInlines.h" #include "Parser.h" #include "ProtoCallFrame.h" #include "RegExpObject.h" #include "RegExpPrototype.h" #include "Register.h" #include "SamplingTool.h" +#include "ScopedArguments.h" #include "StackAlignment.h" #include "StackVisitor.h" #include "StrictEvalActivation.h" #include "StrongInlines.h" +#include "Symbol.h" #include "VMEntryScope.h" #include "VirtualRegister.h" @@ -84,12 +86,51 @@ #include "JIT.h" #endif -#define WTF_USE_GCC_COMPUTED_GOTO_WORKAROUND (!defined(__llvm__)) - using namespace std; namespace JSC { +String StackFrame::friendlySourceURL() const +{ + String traceLine; + + switch (codeType) { + case StackFrameEvalCode: + case StackFrameFunctionCode: + case StackFrameGlobalCode: + if (!sourceURL.isEmpty()) + traceLine = sourceURL.impl(); + break; + case StackFrameNativeCode: + traceLine = "[native code]"; + break; + } + return traceLine.isNull() ? emptyString() : traceLine; +} + +String StackFrame::friendlyFunctionName(CallFrame* callFrame) const +{ + String traceLine; + JSObject* stackFrameCallee = callee.get(); + + switch (codeType) { + case StackFrameEvalCode: + traceLine = "eval code"; + break; + case StackFrameNativeCode: + if (callee) + traceLine = getCalculatedDisplayName(callFrame, stackFrameCallee).impl(); + break; + case StackFrameFunctionCode: + traceLine = getCalculatedDisplayName(callFrame, stackFrameCallee).impl(); + break; + case StackFrameGlobalCode: + traceLine = "global code"; + break; + } + return traceLine.isNull() ? emptyString() : traceLine; +} + JSValue eval(CallFrame* callFrame) { if (!callFrame->argumentCount()) @@ -106,13 +147,11 @@ JSValue eval(CallFrame* callFrame) CallFrame* callerFrame = callFrame->callerFrame(); CodeBlock* callerCodeBlock = callerFrame->codeBlock(); - JSScope* callerScopeChain = callerFrame->scope(); + JSScope* callerScopeChain = callerFrame->uncheckedR(callerCodeBlock->scopeRegister().offset()).Register::scope(); EvalExecutable* eval = callerCodeBlock->evalCodeCache().tryGet(callerCodeBlock->isStrictMode(), programSource, callerScopeChain); if (!eval) { if (!callerCodeBlock->isStrictMode()) { - // FIXME: We can use the preparser in strict mode, we just need additional logic - // to prevent duplicates. if (programSource.is8Bit()) { LiteralParser preparser(callFrame, programSource.characters8(), programSource.length(), NonStrictJSON); if (JSValue parsedObject = preparser.tryLiteralParse()) @@ -127,7 +166,8 @@ JSValue eval(CallFrame* callFrame) // If the literal parser bailed, it should not have thrown exceptions. ASSERT(!callFrame->vm().exception()); - eval = callerCodeBlock->evalCodeCache().getSlow(callFrame, callerCodeBlock->ownerExecutable(), callerCodeBlock->isStrictMode(), programSource, callerScopeChain); + ThisTDZMode thisTDZMode = callerCodeBlock->unlinkedCodeBlock()->constructorKind() == ConstructorKind::Derived ? ThisTDZMode::AlwaysCheck : ThisTDZMode::CheckIfNeeded; + eval = callerCodeBlock->evalCodeCache().getSlow(callFrame, callerCodeBlock->ownerExecutable(), callerCodeBlock->isStrictMode(), thisTDZMode, programSource, callerScopeChain); if (!eval) return jsUndefined(); } @@ -137,149 +177,103 @@ JSValue eval(CallFrame* callFrame) return interpreter->execute(eval, callFrame, thisValue, callerScopeChain); } -CallFrame* sizeFrameForVarargs(CallFrame* callFrame, JSStack* stack, JSValue arguments, int firstFreeRegister, uint32_t firstVarArgOffset) +unsigned sizeOfVarargs(CallFrame* callFrame, JSValue arguments, uint32_t firstVarArgOffset) { - if (!arguments) { // f.apply(x, arguments), with arguments unmodified. - unsigned argumentCountIncludingThis = callFrame->argumentCountIncludingThis(); - if (argumentCountIncludingThis > firstVarArgOffset) - argumentCountIncludingThis -= firstVarArgOffset; - else - argumentCountIncludingThis = 1; - unsigned paddedCalleeFrameOffset = WTF::roundUpToMultipleOf(stackAlignmentRegisters(), -firstFreeRegister + argumentCountIncludingThis + JSStack::CallFrameHeaderSize + 1); - CallFrame* newCallFrame = CallFrame::create(callFrame->registers() - paddedCalleeFrameOffset); - if (argumentCountIncludingThis > Arguments::MaxArguments + 1 || !stack->ensureCapacityFor(newCallFrame->registers())) { - throwStackOverflowError(callFrame); - return 0; - } - return newCallFrame; - } - - if (arguments.isUndefinedOrNull()) { - unsigned argumentCountIncludingThis = 1; - unsigned paddedCalleeFrameOffset = WTF::roundUpToMultipleOf(stackAlignmentRegisters(), -firstFreeRegister + argumentCountIncludingThis + JSStack::CallFrameHeaderSize + 1); - CallFrame* newCallFrame = CallFrame::create(callFrame->registers() - paddedCalleeFrameOffset); - if (!stack->ensureCapacityFor(newCallFrame->registers())) { - throwStackOverflowError(callFrame); + if (UNLIKELY(!arguments.isCell())) { + if (arguments.isUndefinedOrNull()) return 0; - } - return newCallFrame; - } - - if (!arguments.isObject()) { - callFrame->vm().throwException(callFrame, createInvalidParameterError(callFrame, "Function.prototype.apply", arguments)); + + callFrame->vm().throwException(callFrame, createInvalidFunctionApplyParameterError(callFrame, arguments)); return 0; } - - if (asObject(arguments)->classInfo() == Arguments::info()) { - Arguments* argsObject = asArguments(arguments); - unsigned argCount = argsObject->length(callFrame); - callFrame->vm().varargsLength = argCount; - if (argCount >= firstVarArgOffset) - argCount -= firstVarArgOffset; - else - argCount = 0; - unsigned paddedCalleeFrameOffset = WTF::roundUpToMultipleOf(stackAlignmentRegisters(), -firstFreeRegister + CallFrame::offsetFor(argCount + 1)); - CallFrame* newCallFrame = CallFrame::create(callFrame->registers() - paddedCalleeFrameOffset); - if (argCount > Arguments::MaxArguments || !stack->ensureCapacityFor(newCallFrame->registers())) { - throwStackOverflowError(callFrame); - return 0; - } - return newCallFrame; - } - - if (isJSArray(arguments)) { - JSArray* array = asArray(arguments); - unsigned argCount = array->length(); - if (argCount >= firstVarArgOffset) - argCount -= firstVarArgOffset; + + JSCell* cell = arguments.asCell(); + unsigned length; + switch (cell->type()) { + case DirectArgumentsType: + length = jsCast(cell)->length(callFrame); + break; + case ScopedArgumentsType: + length =jsCast(cell)->length(callFrame); + break; + case StringType: + callFrame->vm().throwException(callFrame, createInvalidFunctionApplyParameterError(callFrame, arguments)); + return 0; + default: + ASSERT(arguments.isObject()); + if (isJSArray(cell)) + length = jsCast(cell)->length(); else - argCount = 0; - unsigned paddedCalleeFrameOffset = WTF::roundUpToMultipleOf(stackAlignmentRegisters(), -firstFreeRegister + CallFrame::offsetFor(argCount + 1)); - CallFrame* newCallFrame = CallFrame::create(callFrame->registers() - paddedCalleeFrameOffset); - if (argCount > Arguments::MaxArguments || !stack->ensureCapacityFor(newCallFrame->registers())) { - throwStackOverflowError(callFrame); - return 0; - } - return newCallFrame; + length = jsCast(cell)->get(callFrame, callFrame->propertyNames().length).toUInt32(callFrame); + break; } - - JSObject* argObject = asObject(arguments); - unsigned argCount = argObject->get(callFrame, callFrame->propertyNames().length).toUInt32(callFrame); - callFrame->vm().varargsLength = argCount; - if (argCount >= firstVarArgOffset) - argCount -= firstVarArgOffset; + + if (length >= firstVarArgOffset) + length -= firstVarArgOffset; else - argCount = 0; - unsigned paddedCalleeFrameOffset = WTF::roundUpToMultipleOf(stackAlignmentRegisters(), -firstFreeRegister + CallFrame::offsetFor(argCount + 1)); - CallFrame* newCallFrame = CallFrame::create(callFrame->registers() - paddedCalleeFrameOffset); - if (argCount > Arguments::MaxArguments || !stack->ensureCapacityFor(newCallFrame->registers())) { + length = 0; + + return length; +} + +unsigned sizeFrameForVarargs(CallFrame* callFrame, JSStack* stack, JSValue arguments, unsigned numUsedStackSlots, uint32_t firstVarArgOffset) +{ + unsigned length = sizeOfVarargs(callFrame, arguments, firstVarArgOffset); + + CallFrame* calleeFrame = calleeFrameForVarargs(callFrame, numUsedStackSlots, length + 1); + if (length > maxArguments || !stack->ensureCapacityFor(calleeFrame->registers())) { throwStackOverflowError(callFrame); return 0; } - return newCallFrame; + + return length; } -void loadVarargs(CallFrame* callFrame, CallFrame* newCallFrame, JSValue thisValue, JSValue arguments, uint32_t firstVarArgOffset) +void loadVarargs(CallFrame* callFrame, VirtualRegister firstElementDest, JSValue arguments, uint32_t offset, uint32_t length) { - if (!arguments) { // f.apply(x, arguments), with arguments unmodified. - unsigned argumentCountIncludingThis = callFrame->argumentCountIncludingThis(); - if (argumentCountIncludingThis > firstVarArgOffset) - argumentCountIncludingThis -= firstVarArgOffset; - else - argumentCountIncludingThis = 1; - newCallFrame->setArgumentCountIncludingThis(argumentCountIncludingThis); - newCallFrame->setThisValue(thisValue); - for (size_t i = firstVarArgOffset; i < callFrame->argumentCount(); ++i) - newCallFrame->setArgument(i - firstVarArgOffset, callFrame->argumentAfterCapture(i)); + if (UNLIKELY(!arguments.isCell())) return; - } - if (arguments.isUndefinedOrNull()) { - newCallFrame->setArgumentCountIncludingThis(1); - newCallFrame->setThisValue(thisValue); + JSCell* cell = arguments.asCell(); + switch (cell->type()) { + case DirectArgumentsType: + jsCast(cell)->copyToArguments(callFrame, firstElementDest, offset, length); return; - } - - if (asObject(arguments)->classInfo() == Arguments::info()) { - Arguments* argsObject = asArguments(arguments); - unsigned argCount = callFrame->vm().varargsLength; - callFrame->vm().varargsLength = 0; - if (argCount >= firstVarArgOffset) { - argCount -= firstVarArgOffset; - newCallFrame->setArgumentCountIncludingThis(argCount + 1); - argsObject->copyToArguments(callFrame, newCallFrame, argCount, firstVarArgOffset); - } else - newCallFrame->setArgumentCountIncludingThis(1); - newCallFrame->setThisValue(thisValue); + case ScopedArgumentsType: + jsCast(cell)->copyToArguments(callFrame, firstElementDest, offset, length); return; - } - - if (isJSArray(arguments)) { - JSArray* array = asArray(arguments); - unsigned argCount = array->length(); - if (argCount >= firstVarArgOffset) { - argCount -= firstVarArgOffset; - newCallFrame->setArgumentCountIncludingThis(argCount + 1); - array->copyToArguments(callFrame, newCallFrame, argCount, firstVarArgOffset); - } else - newCallFrame->setArgumentCountIncludingThis(1); - newCallFrame->setThisValue(thisValue); + default: { + ASSERT(arguments.isObject()); + JSObject* object = jsCast(cell); + if (isJSArray(object)) { + jsCast(object)->copyToArguments(callFrame, firstElementDest, offset, length); + return; + } + unsigned i; + for (i = 0; i < length && object->canGetIndexQuickly(i + offset); ++i) + callFrame->r(firstElementDest + i) = object->getIndexQuickly(i + offset); + for (; i < length; ++i) + callFrame->r(firstElementDest + i) = object->get(callFrame, i + offset); return; - } + } } +} + +void setupVarargsFrame(CallFrame* callFrame, CallFrame* newCallFrame, JSValue arguments, uint32_t offset, uint32_t length) +{ + VirtualRegister calleeFrameOffset(newCallFrame - callFrame); - unsigned argCount = callFrame->vm().varargsLength; - if (argCount >= firstVarArgOffset) { - argCount -= firstVarArgOffset; - newCallFrame->setArgumentCountIncludingThis(argCount + 1); - } else - newCallFrame->setArgumentCountIncludingThis(1); + loadVarargs( + callFrame, + calleeFrameOffset + CallFrame::argumentOffset(0), + arguments, offset, length); + + newCallFrame->setArgumentCountIncludingThis(length + 1); +} +void setupVarargsFrameAndSetThis(CallFrame* callFrame, CallFrame* newCallFrame, JSValue thisValue, JSValue arguments, uint32_t firstVarArgOffset, uint32_t length) +{ + setupVarargsFrame(callFrame, newCallFrame, arguments, firstVarArgOffset, length); newCallFrame->setThisValue(thisValue); - for (size_t i = 0; i < argCount; ++i) { - newCallFrame->setArgument(i, asObject(arguments)->get(callFrame, i + firstVarArgOffset)); - if (UNLIKELY(callFrame->vm().exception())) - return; - } } Interpreter::Interpreter(VM& vm) @@ -386,7 +380,7 @@ void Interpreter::dumpRegisters(CallFrame* callFrame) --it; dataLogF("[Callee] | %10p | %p \n", it, callFrame->callee()); --it; - dataLogF("[ScopeChain] | %10p | %p \n", it, callFrame->scope()); + // FIXME: Remove the next decrement when the ScopeChain slot is removed from the call header --it; #if ENABLE(JIT) AbstractPC pc = callFrame->abstractReturnPC(callFrame->vm()); @@ -441,49 +435,16 @@ bool Interpreter::isOpcode(Opcode opcode) static bool unwindCallFrame(StackVisitor& visitor) { CallFrame* callFrame = visitor->callFrame(); - CodeBlock* codeBlock = visitor->codeBlock(); - JSScope* scope = callFrame->scope(); - if (Debugger* debugger = callFrame->vmEntryGlobalObject()->debugger()) { - ClearExceptionScope scope(&callFrame->vm()); - if (callFrame->callee()) + SuspendExceptionScope scope(&callFrame->vm()); + if (jsDynamicCast(callFrame->callee())) debugger->returnEvent(callFrame); else debugger->didExecuteProgram(callFrame); ASSERT(!callFrame->hadException()); } - JSValue activation; - if (codeBlock->codeType() == FunctionCode && codeBlock->needsActivation()) { -#if ENABLE(DFG_JIT) - RELEASE_ASSERT(!visitor->isInlinedFrame()); -#endif - activation = callFrame->uncheckedActivation(); - // Protect against the activation not being created, or the variable still being - // initialized to Undefined inside op_enter. - if (activation && activation.isCell()) { - JSActivation* activationObject = jsCast(activation); - // Protect against throwing exceptions after tear-off. - if (!activationObject->isTornOff()) - activationObject->tearOff(*scope->vm()); - } - } - - if (codeBlock->codeType() == FunctionCode && codeBlock->usesArguments()) { - if (Arguments* arguments = visitor->existingArguments()) { - if (activation && activation.isCell()) - arguments->didTearOffActivation(callFrame, jsCast(activation)); -#if ENABLE(DFG_JIT) - else if (visitor->isInlinedFrame()) - arguments->tearOff(callFrame, visitor->inlineCallFrame()); -#endif - else - arguments->tearOff(callFrame); - } - } - - CallFrame* callerFrame = callFrame->callerFrame(); - return !callerFrame->isVMEntrySentinel(); + return !visitor->callerIsVMEntryFrame(); } static StackFrameCodeType getStackFrameCodeType(StackVisitor& visitor) @@ -520,6 +481,9 @@ void StackFrame::computeLineAndColumn(unsigned& line, unsigned& column) line = divotLine + lineOffset; column = divotColumn + (divotLine ? 1 : firstLineColumnOffset); + + if (executable->hasOverrideLineNumber()) + line = executable->overrideLineNumber(); } void StackFrame::expressionInfo(int& divot, int& startOffset, int& endOffset, unsigned& line, unsigned& column) @@ -570,10 +534,10 @@ public: StackFrame s = { Strong(vm, visitor->callee()), getStackFrameCodeType(visitor), - Strong(vm, codeBlock->ownerExecutable()), + Strong(vm, codeBlock->ownerExecutable()), Strong(vm, codeBlock->unlinkedCodeBlock()), codeBlock->source(), - codeBlock->ownerExecutable()->lineNo(), + codeBlock->ownerExecutable()->firstLine(), codeBlock->firstLineColumnOffset(), codeBlock->sourceOffset(), visitor->bytecodeOffset(), @@ -581,7 +545,7 @@ public: }; m_results.append(s); } else { - StackFrame s = { Strong(vm, visitor->callee()), StackFrameNativeCode, Strong(), Strong(), 0, 0, 0, 0, 0, String()}; + StackFrame s = { Strong(vm, visitor->callee()), StackFrameNativeCode, Strong(), Strong(), 0, 0, 0, 0, 0, String()}; m_results.append(s); } @@ -600,7 +564,6 @@ private: void Interpreter::getStackTrace(Vector& results, size_t maxStackSize) { VM& vm = m_vm; - ASSERT(!vm.topCallFrame->isVMEntrySentinel()); CallFrame* callFrame = vm.topCallFrame; if (!callFrame) return; @@ -621,9 +584,9 @@ JSString* Interpreter::stackTraceAsString(ExecState* exec, Vector st return jsString(&exec->vm(), builder.toString()); } -class GetExceptionHandlerFunctor { +class GetCatchHandlerFunctor { public: - GetExceptionHandlerFunctor() + GetCatchHandlerFunctor() : m_handler(0) { } @@ -637,7 +600,7 @@ public: return StackVisitor::Continue; unsigned bytecodeOffset = visitor->bytecodeOffset(); - m_handler = codeBlock->handlerForBytecodeOffset(bytecodeOffset); + m_handler = codeBlock->handlerForBytecodeOffset(bytecodeOffset, CodeBlock::RequiredHandler::CatchHandler); if (m_handler) return StackVisitor::Done; @@ -650,8 +613,9 @@ private: class UnwindFunctor { public: - UnwindFunctor(CallFrame*& callFrame, bool isTermination, CodeBlock*& codeBlock, HandlerInfo*& handler) - : m_callFrame(callFrame) + UnwindFunctor(VMEntryFrame*& vmEntryFrame, CallFrame*& callFrame, bool isTermination, CodeBlock*& codeBlock, HandlerInfo*& handler) + : m_vmEntryFrame(vmEntryFrame) + , m_callFrame(callFrame) , m_isTermination(isTermination) , m_codeBlock(codeBlock) , m_handler(handler) @@ -661,11 +625,12 @@ public: StackVisitor::Status operator()(StackVisitor& visitor) { VM& vm = m_callFrame->vm(); + m_vmEntryFrame = visitor->vmEntryFrame(); m_callFrame = visitor->callFrame(); m_codeBlock = visitor->codeBlock(); unsigned bytecodeOffset = visitor->bytecodeOffset(); - if (m_isTermination || !(m_handler = m_codeBlock->handlerForBytecodeOffset(bytecodeOffset))) { + if (m_isTermination || !(m_handler = m_codeBlock ? m_codeBlock->handlerForBytecodeOffset(bytecodeOffset) : nullptr)) { if (!unwindCallFrame(visitor)) { if (LegacyProfiler* profiler = vm.enabledProfiler()) profiler->exceptionUnwind(m_callFrame); @@ -678,27 +643,19 @@ public: } private: + VMEntryFrame*& m_vmEntryFrame; CallFrame*& m_callFrame; bool m_isTermination; CodeBlock*& m_codeBlock; HandlerInfo*& m_handler; }; -NEVER_INLINE HandlerInfo* Interpreter::unwind(CallFrame*& callFrame, JSValue& exceptionValue) +NEVER_INLINE HandlerInfo* Interpreter::unwind(VMEntryFrame*& vmEntryFrame, CallFrame*& callFrame, Exception* exception) { - if (callFrame->isVMEntrySentinel()) { - // This happens when we throw stack overflow in a function that is called - // directly from callToJavaScript. Stack overflow throws the exception in the - // context of the caller. In that case the caller is the sentinel frame. The - // right thing to do is to pretend that the exception is uncaught so that we - // go to the uncaught exception handler, which returns through callToJavaScript. - return 0; - } - CodeBlock* codeBlock = callFrame->codeBlock(); - ASSERT(codeBlock); bool isTermination = false; + JSValue exceptionValue = exception->value(); ASSERT(!exceptionValue.isEmpty()); ASSERT(!exceptionValue.isCell() || exceptionValue.asCell()); // This shouldn't be possible (hence the assertions), but we're already in the slowest of @@ -707,38 +664,41 @@ NEVER_INLINE HandlerInfo* Interpreter::unwind(CallFrame*& callFrame, JSValue& ex exceptionValue = jsNull(); if (exceptionValue.isObject()) - isTermination = isTerminatedExecutionException(asObject(exceptionValue)); + isTermination = isTerminatedExecutionException(exception); - ASSERT(callFrame->vm().exceptionStack().size()); + ASSERT(callFrame->vm().exception() && callFrame->vm().exception()->stack().size()); Debugger* debugger = callFrame->vmEntryGlobalObject()->debugger(); - if (debugger && debugger->needsExceptionCallbacks()) { - // We need to clear the exception and the exception stack here in order to see if a new exception happens. + if (debugger && debugger->needsExceptionCallbacks() && !exception->didNotifyInspectorOfThrow()) { + // We need to clear the exception here in order to see if a new exception happens. // Afterwards, the values are put back to continue processing this error. - ClearExceptionScope scope(&callFrame->vm()); + SuspendExceptionScope scope(&callFrame->vm()); // This code assumes that if the debugger is enabled then there is no inlining. // If that assumption turns out to be false then we'll ignore the inlined call // frames. // https://bugs.webkit.org/show_bug.cgi?id=121754 - bool hasHandler; + bool hasCatchHandler; if (isTermination) - hasHandler = false; + hasCatchHandler = false; else { - GetExceptionHandlerFunctor functor; + GetCatchHandlerFunctor functor; callFrame->iterate(functor); - hasHandler = !!functor.handler(); + HandlerInfo* handler = functor.handler(); + ASSERT(!handler || handler->isCatchHandler()); + hasCatchHandler = !!handler; } - debugger->exception(callFrame, exceptionValue, hasHandler); + debugger->exception(callFrame, exceptionValue, hasCatchHandler); ASSERT(!callFrame->hadException()); } + exception->setDidNotifyInspectorOfThrow(); // Calculate an exception handler vPC, unwinding call frames as necessary. HandlerInfo* handler = 0; VM& vm = callFrame->vm(); ASSERT(callFrame == vm.topCallFrame); - UnwindFunctor functor(callFrame, isTermination, codeBlock, handler); + UnwindFunctor functor(vmEntryFrame, callFrame, isTermination, codeBlock, handler); callFrame->iterate(functor); if (!handler) return 0; @@ -751,13 +711,15 @@ NEVER_INLINE HandlerInfo* Interpreter::unwind(CallFrame*& callFrame, JSValue& ex if (codeBlock->needsActivation() && callFrame->hasActivation()) ++targetScopeDepth; - JSScope* scope = callFrame->scope(); + int scopeRegisterOffset = codeBlock->scopeRegister().offset(); + JSScope* scope = callFrame->scope(scopeRegisterOffset); int scopeDelta = scope->depth() - targetScopeDepth; RELEASE_ASSERT(scopeDelta >= 0); while (scopeDelta--) scope = scope->next(); - callFrame->setScope(scope); + + callFrame->setScope(scopeRegisterOffset, scope); return handler; } @@ -792,8 +754,8 @@ private: JSValue Interpreter::execute(ProgramExecutable* program, CallFrame* callFrame, JSObject* thisObj) { SamplingScope samplingScope(this); - - JSScope* scope = callFrame->scope(); + + JSScope* scope = thisObj->globalObject(); VM& vm = *scope->vm(); ASSERT(!vm.exception()); @@ -845,7 +807,7 @@ JSValue Interpreter::execute(ProgramExecutable* program, CallFrame* callFrame, J PropertySlot slot(globalObject); if (!globalObject->getPropertySlot(callFrame, JSONPPath[i].m_pathEntryName, slot)) { if (entry) - return callFrame->vm().throwException(callFrame, createUndefinedVariableError(globalObject->globalExec(), JSONPPath[i].m_pathEntryName)); + return callFrame->vm().throwException(callFrame, createUndefinedVariableError(callFrame, JSONPPath[i].m_pathEntryName)); goto failedJSONP; } baseObject = slot.getValue(callFrame, JSONPPath[i].m_pathEntryName); @@ -914,7 +876,7 @@ failedJSONP: if (JSObject* error = program->initializeGlobalProperties(vm, callFrame, scope)) return checkedReturn(callFrame->vm().throwException(callFrame, error)); - if (JSObject* error = program->prepareForExecution(callFrame, nullptr, &scope, CodeForCall)) + if (JSObject* error = program->prepareForExecution(callFrame, nullptr, scope, CodeForCall)) return checkedReturn(callFrame->vm().throwException(callFrame, error)); ProgramCodeBlock* codeBlock = program->codeBlock(); @@ -925,10 +887,10 @@ failedJSONP: ASSERT(codeBlock->numParameters() == 1); // 1 parameter for 'this'. ProtoCallFrame protoCallFrame; - protoCallFrame.init(codeBlock, scope, 0, thisObj, 1); + protoCallFrame.init(codeBlock, JSCallee::create(vm, scope->globalObject(), scope), thisObj, 1); if (LegacyProfiler* profiler = vm.enabledProfiler()) - profiler->willExecute(callFrame, program->sourceURL(), program->lineNo(), program->startColumn()); + profiler->willExecute(callFrame, program->sourceURL(), program->firstLine(), program->startColumn()); // Execute the code: JSValue result; @@ -940,7 +902,7 @@ failedJSONP: } if (LegacyProfiler* profiler = vm.enabledProfiler()) - profiler->didExecute(callFrame, program->sourceURL(), program->lineNo(), program->startColumn()); + profiler->didExecute(callFrame, program->sourceURL(), program->firstLine(), program->startColumn()); return checkedReturn(result); } @@ -954,24 +916,27 @@ JSValue Interpreter::executeCall(CallFrame* callFrame, JSObject* function, CallT return jsNull(); bool isJSCall = (callType == CallTypeJS); - JSScope* scope; + JSScope* scope = nullptr; CodeBlock* newCodeBlock; size_t argsCount = 1 + args.size(); // implicit "this" parameter - if (isJSCall) + JSGlobalObject* globalObject; + + if (isJSCall) { scope = callData.js.scope; - else { + globalObject = scope->globalObject(); + } else { ASSERT(callType == CallTypeHost); - scope = callFrame->scope(); + globalObject = function->globalObject(); } - VMEntryScope entryScope(vm, scope->globalObject()); + VMEntryScope entryScope(vm, globalObject); if (!vm.isSafeToRecurse()) return checkedReturn(throwStackOverflowError(callFrame)); if (isJSCall) { // Compile the callee: - JSObject* compileError = callData.js.functionExecutable->prepareForExecution(callFrame, jsCast(function), &scope, CodeForCall); + JSObject* compileError = callData.js.functionExecutable->prepareForExecution(callFrame, jsCast(function), scope, CodeForCall); if (UNLIKELY(!!compileError)) { return checkedReturn(callFrame->vm().throwException(callFrame, compileError)); } @@ -985,7 +950,7 @@ JSValue Interpreter::executeCall(CallFrame* callFrame, JSObject* function, CallT return throwTerminatedExecutionException(callFrame); ProtoCallFrame protoCallFrame; - protoCallFrame.init(newCodeBlock, scope, function, thisValue, argsCount, args.data()); + protoCallFrame.init(newCodeBlock, function, thisValue, argsCount, args.data()); if (LegacyProfiler* profiler = vm.enabledProfiler()) profiler->willExecute(callFrame, function); @@ -999,7 +964,7 @@ JSValue Interpreter::executeCall(CallFrame* callFrame, JSObject* function, CallT if (isJSCall) result = callData.js.functionExecutable->generatedJITCodeForCall()->execute(&vm, &protoCallFrame); else { - result = JSValue::decode(callToNativeFunction(reinterpret_cast(callData.native.function), &vm, &protoCallFrame)); + result = JSValue::decode(vmEntryToNative(reinterpret_cast(callData.native.function), &vm, &protoCallFrame)); if (callFrame->hadException()) result = jsNull(); } @@ -1022,24 +987,27 @@ JSObject* Interpreter::executeConstruct(CallFrame* callFrame, JSObject* construc return checkedReturn(throwStackOverflowError(callFrame)); bool isJSConstruct = (constructType == ConstructTypeJS); - JSScope* scope; + JSScope* scope = nullptr; CodeBlock* newCodeBlock; size_t argsCount = 1 + args.size(); // implicit "this" parameter - if (isJSConstruct) + JSGlobalObject* globalObject; + + if (isJSConstruct) { scope = constructData.js.scope; - else { + globalObject = scope->globalObject(); + } else { ASSERT(constructType == ConstructTypeHost); - scope = callFrame->scope(); + globalObject = constructor->globalObject(); } - VMEntryScope entryScope(vm, scope->globalObject()); + VMEntryScope entryScope(vm, globalObject); if (!vm.isSafeToRecurse()) return checkedReturn(throwStackOverflowError(callFrame)); if (isJSConstruct) { // Compile the callee: - JSObject* compileError = constructData.js.functionExecutable->prepareForExecution(callFrame, jsCast(constructor), &scope, CodeForConstruct); + JSObject* compileError = constructData.js.functionExecutable->prepareForExecution(callFrame, jsCast(constructor), scope, CodeForConstruct); if (UNLIKELY(!!compileError)) { return checkedReturn(callFrame->vm().throwException(callFrame, compileError)); } @@ -1053,7 +1021,7 @@ JSObject* Interpreter::executeConstruct(CallFrame* callFrame, JSObject* construc return throwTerminatedExecutionException(callFrame); ProtoCallFrame protoCallFrame; - protoCallFrame.init(newCodeBlock, scope, constructor, jsUndefined(), argsCount, args.data()); + protoCallFrame.init(newCodeBlock, constructor, constructor, argsCount, args.data()); if (LegacyProfiler* profiler = vm.enabledProfiler()) profiler->willExecute(callFrame, constructor); @@ -1067,7 +1035,7 @@ JSObject* Interpreter::executeConstruct(CallFrame* callFrame, JSObject* construc if (isJSConstruct) result = constructData.js.functionExecutable->generatedJITCodeForConstruct()->execute(&vm, &protoCallFrame); else { - result = JSValue::decode(callToNativeFunction(reinterpret_cast(constructData.native.function), &vm, &protoCallFrame)); + result = JSValue::decode(vmEntryToNative(reinterpret_cast(constructData.native.function), &vm, &protoCallFrame)); if (!callFrame->hadException()) RELEASE_ASSERT(result.isObject()); @@ -1092,7 +1060,7 @@ CallFrameClosure Interpreter::prepareForRepeatCall(FunctionExecutable* functionE return CallFrameClosure(); // Compile the callee: - JSObject* error = functionExecutable->prepareForExecution(callFrame, function, &scope, CodeForCall); + JSObject* error = functionExecutable->prepareForExecution(callFrame, function, scope, CodeForCall); if (error) { callFrame->vm().throwException(callFrame, error); return CallFrameClosure(); @@ -1102,7 +1070,7 @@ CallFrameClosure Interpreter::prepareForRepeatCall(FunctionExecutable* functionE size_t argsCount = argumentCountIncludingThis; - protoCallFrame->init(newCodeBlock, scope, function, jsUndefined(), argsCount, args); + protoCallFrame->init(newCodeBlock, function, jsUndefined(), argsCount, args); // Return the successful closure: CallFrameClosure result = { callFrame, protoCallFrame, function, functionExecutable, &vm, scope, newCodeBlock->numParameters(), argumentCountIncludingThis }; return result; @@ -1119,7 +1087,6 @@ JSValue Interpreter::execute(CallFrameClosure& closure) return jsNull(); StackStats::CheckPoint stackCheckPoint; - closure.resetCallFrame(); if (LegacyProfiler* profiler = vm.enabledProfiler()) profiler->willExecute(closure.oldCallFrame, closure.function); @@ -1163,19 +1130,20 @@ JSValue Interpreter::execute(EvalExecutable* eval, CallFrame* callFrame, JSValue JSScope* variableObject; if ((numVariables || numFunctions) && eval->isStrictMode()) { - scope = StrictEvalActivation::create(callFrame); + scope = StrictEvalActivation::create(callFrame, scope); variableObject = scope; } else { for (JSScope* node = scope; ; node = node->next()) { RELEASE_ASSERT(node); - if (node->isVariableObject() && !node->isNameScopeObject()) { + if (node->isVariableObject()) { + ASSERT(!node->isNameScopeObject()); variableObject = node; break; } } } - JSObject* compileError = eval->prepareForExecution(callFrame, nullptr, &scope, CodeForCall); + JSObject* compileError = eval->prepareForExecution(callFrame, nullptr, scope, CodeForCall); if (UNLIKELY(!!compileError)) return checkedReturn(callFrame->vm().throwException(callFrame, compileError)); EvalCodeBlock* codeBlock = eval->codeBlock(); @@ -1183,7 +1151,7 @@ JSValue Interpreter::execute(EvalExecutable* eval, CallFrame* callFrame, JSValue if (numVariables || numFunctions) { BatchedTransitionOptimizer optimizer(vm, variableObject); if (variableObject->next()) - variableObject->globalObject()->varInjectionWatchpoint()->fireAll(); + variableObject->globalObject()->varInjectionWatchpoint()->fireAll("Executed eval, fired VarInjection watchpoint"); for (unsigned i = 0; i < numVariables; ++i) { const Identifier& ident = codeBlock->variable(i); @@ -1206,10 +1174,10 @@ JSValue Interpreter::execute(EvalExecutable* eval, CallFrame* callFrame, JSValue ASSERT(codeBlock->numParameters() == 1); // 1 parameter for 'this'. ProtoCallFrame protoCallFrame; - protoCallFrame.init(codeBlock, scope, 0, thisValue, 1); + protoCallFrame.init(codeBlock, JSCallee::create(vm, scope->globalObject(), scope), thisValue, 1); if (LegacyProfiler* profiler = vm.enabledProfiler()) - profiler->willExecute(callFrame, eval->sourceURL(), eval->lineNo(), eval->startColumn()); + profiler->willExecute(callFrame, eval->sourceURL(), eval->firstLine(), eval->startColumn()); // Execute the code: JSValue result; @@ -1221,7 +1189,7 @@ JSValue Interpreter::execute(EvalExecutable* eval, CallFrame* callFrame, JSValue } if (LegacyProfiler* profiler = vm.enabledProfiler()) - profiler->didExecute(callFrame, eval->sourceURL(), eval->lineNo(), eval->startColumn()); + profiler->didExecute(callFrame, eval->sourceURL(), eval->firstLine(), eval->startColumn()); return checkedReturn(result); } @@ -1262,7 +1230,7 @@ void Interpreter::enableSampler() { #if ENABLE(OPCODE_SAMPLING) if (!m_sampler) { - m_sampler = adoptPtr(new SamplingTool(this)); + m_sampler = std::make_unique(this); m_sampler->setup(); } #endif