diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2015-05-20 09:56:07 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2015-05-20 09:56:07 +0000 |
commit | 41386e9cb918eed93b3f13648cbef387e371e451 (patch) | |
tree | a97f9d7bd1d9d091833286085f72da9d83fd0606 /Source/JavaScriptCore/interpreter/Interpreter.cpp | |
parent | e15dd966d523731101f70ccf768bba12435a0208 (diff) | |
download | WebKitGtk-tarball-41386e9cb918eed93b3f13648cbef387e371e451.tar.gz |
webkitgtk-2.4.9webkitgtk-2.4.9
Diffstat (limited to 'Source/JavaScriptCore/interpreter/Interpreter.cpp')
-rw-r--r-- | Source/JavaScriptCore/interpreter/Interpreter.cpp | 512 |
1 files changed, 267 insertions, 245 deletions
diff --git a/Source/JavaScriptCore/interpreter/Interpreter.cpp b/Source/JavaScriptCore/interpreter/Interpreter.cpp index 518fc0b76..4fbc8229a 100644 --- a/Source/JavaScriptCore/interpreter/Interpreter.cpp +++ b/Source/JavaScriptCore/interpreter/Interpreter.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008, 2009, 2010, 2012-2015 Apple Inc. All rights reserved. + * Copyright (C) 2008, 2009, 2010, 2012, 2013 Apple Inc. All rights reserved. * Copyright (C) 2008 Cameron Zwarich <cwzwarich@uwaterloo.ca> * * Redistribution and use in source and binary forms, with or without @@ -11,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 Inc. ("Apple") nor the names of + * 3. Neither the name of Apple Computer, 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,25 +30,25 @@ #include "config.h" #include "Interpreter.h" +#include "Arguments.h" #include "BatchedTransitionOptimizer.h" +#include "CallFrame.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" @@ -56,27 +56,24 @@ #include "LLIntThunks.h" #include "LegacyProfiler.h" #include "LiteralParser.h" +#include "NameInstance.h" #include "ObjectPrototype.h" +#include "Operations.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 "VMInlines.h" #include "VirtualRegister.h" #include <limits.h> #include <stdio.h> #include <wtf/StackStats.h> -#include <wtf/StdLibExtras.h> #include <wtf/StringPrintStream.h> #include <wtf/Threading.h> #include <wtf/WTFThreadData.h> @@ -86,49 +83,26 @@ #include "JIT.h" #endif +#define WTF_USE_GCC_COMPUTED_GOTO_WORKAROUND (ENABLE(LLINT) && !defined(__llvm__)) + using namespace std; namespace JSC { -String StackFrame::friendlySourceURL() const +Interpreter::ErrorHandlingMode::ErrorHandlingMode(ExecState *exec) + : m_interpreter(*exec->interpreter()) { - 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; + if (!m_interpreter.m_errorHandlingModeReentry) + m_interpreter.stack().enableErrorStackReserve(); + m_interpreter.m_errorHandlingModeReentry++; } -String StackFrame::friendlyFunctionName(CallFrame* callFrame) const +Interpreter::ErrorHandlingMode::~ErrorHandlingMode() { - 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; + m_interpreter.m_errorHandlingModeReentry--; + ASSERT(m_interpreter.m_errorHandlingModeReentry >= 0); + if (!m_interpreter.m_errorHandlingModeReentry) + m_interpreter.stack().disableErrorStackReserve(); } JSValue eval(CallFrame* callFrame) @@ -147,11 +121,13 @@ JSValue eval(CallFrame* callFrame) CallFrame* callerFrame = callFrame->callerFrame(); CodeBlock* callerCodeBlock = callerFrame->codeBlock(); - JSScope* callerScopeChain = callerFrame->uncheckedR(callerCodeBlock->scopeRegister().offset()).Register::scope(); + JSScope* callerScopeChain = callerFrame->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<LChar> preparser(callFrame, programSource.characters8(), programSource.length(), NonStrictJSON); if (JSValue parsedObject = preparser.tryLiteralParse()) @@ -166,8 +142,7 @@ JSValue eval(CallFrame* callFrame) // If the literal parser bailed, it should not have thrown exceptions. ASSERT(!callFrame->vm().exception()); - ThisTDZMode thisTDZMode = callerCodeBlock->unlinkedCodeBlock()->constructorKind() == ConstructorKind::Derived ? ThisTDZMode::AlwaysCheck : ThisTDZMode::CheckIfNeeded; - eval = callerCodeBlock->evalCodeCache().getSlow(callFrame, callerCodeBlock->ownerExecutable(), callerCodeBlock->isStrictMode(), thisTDZMode, programSource, callerScopeChain); + eval = callerCodeBlock->evalCodeCache().getSlow(callFrame, callerCodeBlock->ownerExecutable(), callerCodeBlock->isStrictMode(), programSource, callerScopeChain); if (!eval) return jsUndefined(); } @@ -177,103 +152,109 @@ JSValue eval(CallFrame* callFrame) return interpreter->execute(eval, callFrame, thisValue, callerScopeChain); } -unsigned sizeOfVarargs(CallFrame* callFrame, JSValue arguments, uint32_t firstVarArgOffset) +CallFrame* sizeAndAllocFrameForVarargs(CallFrame* callFrame, JSStack* stack, JSValue arguments, int firstFreeRegister) { - if (UNLIKELY(!arguments.isCell())) { - if (arguments.isUndefinedOrNull()) + if (!arguments) { // f.apply(x, arguments), with arguments unmodified. + unsigned argumentCountIncludingThis = callFrame->argumentCountIncludingThis(); + CallFrame* newCallFrame = CallFrame::create(callFrame->registers() + firstFreeRegister - argumentCountIncludingThis - JSStack::CallFrameHeaderSize - 1); + if (argumentCountIncludingThis > Arguments::MaxArguments + 1 || !stack->grow(newCallFrame->registers())) { + callFrame->vm().throwException(callFrame, createStackOverflowError(callFrame)); return 0; - - callFrame->vm().throwException(callFrame, createInvalidFunctionApplyParameterError(callFrame, arguments)); - return 0; + } + return newCallFrame; } - - JSCell* cell = arguments.asCell(); - unsigned length; - switch (cell->type()) { - case DirectArgumentsType: - length = jsCast<DirectArguments*>(cell)->length(callFrame); - break; - case ScopedArgumentsType: - length =jsCast<ScopedArguments*>(cell)->length(callFrame); - break; - case StringType: - callFrame->vm().throwException(callFrame, createInvalidFunctionApplyParameterError(callFrame, arguments)); + + if (arguments.isUndefinedOrNull()) { + CallFrame* newCallFrame = CallFrame::create(callFrame->registers() + firstFreeRegister - 1 - JSStack::CallFrameHeaderSize - 1); + if (!stack->grow(newCallFrame->registers())) { + callFrame->vm().throwException(callFrame, createStackOverflowError(callFrame)); + return 0; + } + return newCallFrame; + } + + if (!arguments.isObject()) { + callFrame->vm().throwException(callFrame, createInvalidParameterError(callFrame, "Function.prototype.apply", arguments)); return 0; - default: - ASSERT(arguments.isObject()); - if (isJSArray(cell)) - length = jsCast<JSArray*>(cell)->length(); - else - length = jsCast<JSObject*>(cell)->get(callFrame, callFrame->propertyNames().length).toUInt32(callFrame); - break; } - - if (length >= firstVarArgOffset) - length -= firstVarArgOffset; - else - 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); + if (asObject(arguments)->classInfo() == Arguments::info()) { + Arguments* argsObject = asArguments(arguments); + unsigned argCount = argsObject->length(callFrame); + CallFrame* newCallFrame = CallFrame::create(callFrame->registers() + firstFreeRegister - CallFrame::offsetFor(argCount + 1)); + if (argCount > Arguments::MaxArguments || !stack->grow(newCallFrame->registers())) { + callFrame->vm().throwException(callFrame, createStackOverflowError(callFrame)); + return 0; + } + return newCallFrame; + } + + if (isJSArray(arguments)) { + JSArray* array = asArray(arguments); + unsigned argCount = array->length(); + CallFrame* newCallFrame = CallFrame::create(callFrame->registers() + firstFreeRegister - CallFrame::offsetFor(argCount + 1)); + if (argCount > Arguments::MaxArguments || !stack->grow(newCallFrame->registers())) { + callFrame->vm().throwException(callFrame, createStackOverflowError(callFrame)); + return 0; + } + return newCallFrame; + } + + JSObject* argObject = asObject(arguments); + unsigned argCount = argObject->get(callFrame, callFrame->propertyNames().length).toUInt32(callFrame); + CallFrame* newCallFrame = CallFrame::create(callFrame->registers() + firstFreeRegister - CallFrame::offsetFor(argCount + 1)); + if (argCount > Arguments::MaxArguments || !stack->grow(newCallFrame->registers())) { + callFrame->vm().throwException(callFrame, createStackOverflowError(callFrame)); return 0; } - - return length; + return newCallFrame; } -void loadVarargs(CallFrame* callFrame, VirtualRegister firstElementDest, JSValue arguments, uint32_t offset, uint32_t length) +void loadVarargs(CallFrame* callFrame, CallFrame* newCallFrame, JSValue thisValue, JSValue arguments) { - if (UNLIKELY(!arguments.isCell())) + if (!arguments) { // f.apply(x, arguments), with arguments unmodified. + unsigned argumentCountIncludingThis = callFrame->argumentCountIncludingThis(); + + newCallFrame->setArgumentCountIncludingThis(argumentCountIncludingThis); + newCallFrame->setThisValue(thisValue); + for (size_t i = 0; i < callFrame->argumentCount(); ++i) + newCallFrame->setArgument(i, callFrame->argumentAfterCapture(i)); return; + } - JSCell* cell = arguments.asCell(); - switch (cell->type()) { - case DirectArgumentsType: - jsCast<DirectArguments*>(cell)->copyToArguments(callFrame, firstElementDest, offset, length); + if (arguments.isUndefinedOrNull()) { + newCallFrame->setArgumentCountIncludingThis(1); + newCallFrame->setThisValue(thisValue); return; - case ScopedArgumentsType: - jsCast<ScopedArguments*>(cell)->copyToArguments(callFrame, firstElementDest, offset, length); - return; - default: { - ASSERT(arguments.isObject()); - JSObject* object = jsCast<JSObject*>(cell); - if (isJSArray(object)) { - jsCast<JSArray*>(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); + } + + if (asObject(arguments)->classInfo() == Arguments::info()) { + Arguments* argsObject = asArguments(arguments); + unsigned argCount = argsObject->length(callFrame); + newCallFrame->setArgumentCountIncludingThis(argCount + 1); + newCallFrame->setThisValue(thisValue); + argsObject->copyToArguments(callFrame, newCallFrame, argCount); return; - } } -} - -void setupVarargsFrame(CallFrame* callFrame, CallFrame* newCallFrame, JSValue arguments, uint32_t offset, uint32_t length) -{ - VirtualRegister calleeFrameOffset(newCallFrame - callFrame); + } - loadVarargs( - callFrame, - calleeFrameOffset + CallFrame::argumentOffset(0), - arguments, offset, length); + if (isJSArray(arguments)) { + JSArray* array = asArray(arguments); + unsigned argCount = array->length(); + newCallFrame->setArgumentCountIncludingThis(argCount + 1); + newCallFrame->setThisValue(thisValue); + array->copyToArguments(callFrame, newCallFrame, argCount); + return; + } - 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); + JSObject* argObject = asObject(arguments); + unsigned argCount = argObject->get(callFrame, callFrame->propertyNames().length).toUInt32(callFrame); + newCallFrame->setArgumentCountIncludingThis(argCount + 1); newCallFrame->setThisValue(thisValue); + for (size_t i = 0; i < argCount; ++i) { + newCallFrame->setArgument(i, asObject(arguments)->get(callFrame, i)); + if (UNLIKELY(callFrame->vm().exception())) + return; + } } Interpreter::Interpreter(VM& vm) @@ -295,7 +276,7 @@ void Interpreter::initialize(bool canUseJIT) { UNUSED_PARAM(canUseJIT); -#if ENABLE(COMPUTED_GOTO_OPCODES) +#if ENABLE(COMPUTED_GOTO_OPCODES) && ENABLE(LLINT) m_opcodeTable = LLInt::opcodeMap(); for (int i = 0; i < numOpcodeIDs; ++i) m_opcodeIDTable.add(m_opcodeTable[i], static_cast<OpcodeID>(i)); @@ -380,7 +361,7 @@ void Interpreter::dumpRegisters(CallFrame* callFrame) --it; dataLogF("[Callee] | %10p | %p \n", it, callFrame->callee()); --it; - // FIXME: Remove the next decrement when the ScopeChain slot is removed from the call header + dataLogF("[ScopeChain] | %10p | %p \n", it, callFrame->scope()); --it; #if ENABLE(JIT) AbstractPC pc = callFrame->abstractReturnPC(callFrame->vm()); @@ -424,9 +405,13 @@ void Interpreter::dumpRegisters(CallFrame* callFrame) bool Interpreter::isOpcode(Opcode opcode) { #if ENABLE(COMPUTED_GOTO_OPCODES) +#if !ENABLE(LLINT) + return static_cast<OpcodeID>(bitwise_cast<uintptr_t>(opcode)) <= op_end; +#else return opcode != HashTraits<Opcode>::emptyValue() && !HashTraits<Opcode>::isDeletedValue(opcode) && m_opcodeIDTable.contains(opcode); +#endif #else return opcode >= 0 && opcode <= op_end; #endif @@ -435,16 +420,46 @@ bool Interpreter::isOpcode(Opcode opcode) static bool unwindCallFrame(StackVisitor& visitor) { CallFrame* callFrame = visitor->callFrame(); + CodeBlock* codeBlock = visitor->codeBlock(); + CodeBlock* oldCodeBlock = codeBlock; + JSScope* scope = callFrame->scope(); + if (Debugger* debugger = callFrame->vmEntryGlobalObject()->debugger()) { - SuspendExceptionScope scope(&callFrame->vm()); - if (jsDynamicCast<JSFunction*>(callFrame->callee())) + if (callFrame->callee()) debugger->returnEvent(callFrame); else debugger->didExecuteProgram(callFrame); - ASSERT(!callFrame->hadException()); } - return !visitor->callerIsVMEntryFrame(); + JSValue activation; + if (oldCodeBlock->codeType() == FunctionCode && oldCodeBlock->needsActivation()) { +#if ENABLE(DFG_JIT) + RELEASE_ASSERT(!visitor->isInlinedFrame()); +#endif + activation = callFrame->uncheckedR(oldCodeBlock->activationRegister().offset()).jsValue(); + if (activation) + jsCast<JSActivation*>(activation)->tearOff(*scope->vm()); + } + + if (oldCodeBlock->codeType() == FunctionCode && oldCodeBlock->usesArguments()) { + if (Arguments* arguments = visitor->existingArguments()) { + if (activation) + arguments->didTearOffActivation(callFrame, jsCast<JSActivation*>(activation)); +#if ENABLE(DFG_JIT) + else if (visitor->isInlinedFrame()) + arguments->tearOff(callFrame, visitor->inlineCallFrame()); +#endif + else + arguments->tearOff(callFrame); + } + } + + CallFrame* callerFrame = callFrame->callerFrame(); + if (callerFrame->isVMEntrySentinel()) { + callFrame->vm().topCallFrame = callerFrame->vmEntrySentinelCallerFrame(); + return false; + } + return true; } static StackFrameCodeType getStackFrameCodeType(StackVisitor& visitor) @@ -481,9 +496,6 @@ 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) @@ -529,15 +541,15 @@ public: { VM& vm = m_vm; if (m_remainingCapacityForFrameCapture) { - if (visitor->isJSFrame() && !visitor->codeBlock()->unlinkedCodeBlock()->isBuiltinFunction()) { + if (visitor->isJSFrame()) { CodeBlock* codeBlock = visitor->codeBlock(); StackFrame s = { Strong<JSObject>(vm, visitor->callee()), getStackFrameCodeType(visitor), - Strong<ScriptExecutable>(vm, codeBlock->ownerExecutable()), + Strong<ExecutableBase>(vm, codeBlock->ownerExecutable()), Strong<UnlinkedCodeBlock>(vm, codeBlock->unlinkedCodeBlock()), codeBlock->source(), - codeBlock->ownerExecutable()->firstLine(), + codeBlock->ownerExecutable()->lineNo(), codeBlock->firstLineColumnOffset(), codeBlock->sourceOffset(), visitor->bytecodeOffset(), @@ -545,7 +557,7 @@ public: }; m_results.append(s); } else { - StackFrame s = { Strong<JSObject>(vm, visitor->callee()), StackFrameNativeCode, Strong<ScriptExecutable>(), Strong<UnlinkedCodeBlock>(), 0, 0, 0, 0, 0, String()}; + StackFrame s = { Strong<JSObject>(vm, visitor->callee()), StackFrameNativeCode, Strong<ExecutableBase>(), Strong<UnlinkedCodeBlock>(), 0, 0, 0, 0, 0, String()}; m_results.append(s); } @@ -564,6 +576,7 @@ private: void Interpreter::getStackTrace(Vector<StackFrame>& results, size_t maxStackSize) { VM& vm = m_vm; + ASSERT(!vm.topCallFrame->isVMEntrySentinel()); CallFrame* callFrame = vm.topCallFrame; if (!callFrame) return; @@ -584,9 +597,9 @@ JSString* Interpreter::stackTraceAsString(ExecState* exec, Vector<StackFrame> st return jsString(&exec->vm(), builder.toString()); } -class GetCatchHandlerFunctor { +class GetExceptionHandlerFunctor { public: - GetCatchHandlerFunctor() + GetExceptionHandlerFunctor() : m_handler(0) { } @@ -600,7 +613,7 @@ public: return StackVisitor::Continue; unsigned bytecodeOffset = visitor->bytecodeOffset(); - m_handler = codeBlock->handlerForBytecodeOffset(bytecodeOffset, CodeBlock::RequiredHandler::CatchHandler); + m_handler = codeBlock->handlerForBytecodeOffset(bytecodeOffset); if (m_handler) return StackVisitor::Done; @@ -613,9 +626,8 @@ private: class UnwindFunctor { public: - UnwindFunctor(VMEntryFrame*& vmEntryFrame, CallFrame*& callFrame, bool isTermination, CodeBlock*& codeBlock, HandlerInfo*& handler) - : m_vmEntryFrame(vmEntryFrame) - , m_callFrame(callFrame) + UnwindFunctor(CallFrame*& callFrame, bool isTermination, CodeBlock*& codeBlock, HandlerInfo*& handler) + : m_callFrame(callFrame) , m_isTermination(isTermination) , m_codeBlock(codeBlock) , m_handler(handler) @@ -625,12 +637,11 @@ 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 ? m_codeBlock->handlerForBytecodeOffset(bytecodeOffset) : nullptr)) { + if (m_isTermination || !(m_handler = m_codeBlock->handlerForBytecodeOffset(bytecodeOffset))) { if (!unwindCallFrame(visitor)) { if (LegacyProfiler* profiler = vm.enabledProfiler()) profiler->exceptionUnwind(m_callFrame); @@ -643,19 +654,17 @@ public: } private: - VMEntryFrame*& m_vmEntryFrame; CallFrame*& m_callFrame; bool m_isTermination; CodeBlock*& m_codeBlock; HandlerInfo*& m_handler; }; -NEVER_INLINE HandlerInfo* Interpreter::unwind(VMEntryFrame*& vmEntryFrame, CallFrame*& callFrame, Exception* exception) +NEVER_INLINE HandlerInfo* Interpreter::unwind(CallFrame*& callFrame, JSValue& exceptionValue) { CodeBlock* codeBlock = callFrame->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 @@ -663,42 +672,39 @@ NEVER_INLINE HandlerInfo* Interpreter::unwind(VMEntryFrame*& vmEntryFrame, CallF if (exceptionValue.isEmpty() || (exceptionValue.isCell() && !exceptionValue.asCell())) exceptionValue = jsNull(); - if (exceptionValue.isObject()) - isTermination = isTerminatedExecutionException(exception); + if (exceptionValue.isObject()) { + isTermination = isTerminatedExecutionException(asObject(exceptionValue)); + } - ASSERT(callFrame->vm().exception() && callFrame->vm().exception()->stack().size()); + ASSERT(callFrame->vm().exceptionStack().size()); Debugger* debugger = callFrame->vmEntryGlobalObject()->debugger(); - if (debugger && debugger->needsExceptionCallbacks() && !exception->didNotifyInspectorOfThrow()) { - // We need to clear the exception here in order to see if a new exception happens. + if (debugger && debugger->needsExceptionCallbacks()) { + // We need to clear the exception and the exception stack here in order to see if a new exception happens. // Afterwards, the values are put back to continue processing this error. - SuspendExceptionScope scope(&callFrame->vm()); + ClearExceptionScope 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 hasCatchHandler; + bool hasHandler; if (isTermination) - hasCatchHandler = false; + hasHandler = false; else { - GetCatchHandlerFunctor functor; + GetExceptionHandlerFunctor functor; callFrame->iterate(functor); - HandlerInfo* handler = functor.handler(); - ASSERT(!handler || handler->isCatchHandler()); - hasCatchHandler = !!handler; + hasHandler = !!functor.handler(); } - debugger->exception(callFrame, exceptionValue, hasCatchHandler); - ASSERT(!callFrame->hadException()); + debugger->exception(callFrame, exceptionValue, hasHandler); } - 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(vmEntryFrame, callFrame, isTermination, codeBlock, handler); + UnwindFunctor functor(callFrame, isTermination, codeBlock, handler); callFrame->iterate(functor); if (!handler) return 0; @@ -706,6 +712,19 @@ NEVER_INLINE HandlerInfo* Interpreter::unwind(VMEntryFrame*& vmEntryFrame, CallF if (LegacyProfiler* profiler = vm.enabledProfiler()) profiler->exceptionUnwind(callFrame); + // Unwind the scope chain within the exception handler's call frame. + int targetScopeDepth = handler->scopeDepth; + if (codeBlock->needsActivation() && callFrame->uncheckedR(codeBlock->activationRegister().offset()).jsValue()) + ++targetScopeDepth; + + JSScope* scope = callFrame->scope(); + int scopeDelta = scope->depth() - targetScopeDepth; + RELEASE_ASSERT(scopeDelta >= 0); + + while (scopeDelta--) + scope = scope->next(); + callFrame->setScope(scope); + return handler; } @@ -739,16 +758,16 @@ private: JSValue Interpreter::execute(ProgramExecutable* program, CallFrame* callFrame, JSObject* thisObj) { SamplingScope samplingScope(this); - - JSScope* scope = thisObj->globalObject(); + + JSScope* scope = callFrame->scope(); VM& vm = *scope->vm(); ASSERT(!vm.exception()); ASSERT(!vm.isCollectorBusy()); - RELEASE_ASSERT(vm.currentThreadIsHoldingAPILock()); if (vm.isCollectorBusy()) return jsNull(); + VMEntryScope entryScope(vm, scope->globalObject()); if (!vm.isSafeToRecurse()) return checkedReturn(throwStackOverflowError(callFrame)); @@ -792,7 +811,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(callFrame, JSONPPath[i].m_pathEntryName)); + return callFrame->vm().throwException(callFrame, createUndefinedVariableError(globalObject->globalExec(), JSONPPath[i].m_pathEntryName)); goto failedJSONP; } baseObject = slot.getValue(callFrame, JSONPPath[i].m_pathEntryName); @@ -855,37 +874,40 @@ failedJSONP: // If we get here, then we have already proven that the script is not a JSON // object. - VMEntryScope entryScope(vm, scope->globalObject()); - // Compile source to bytecode if necessary: 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, scope, CodeForCall)) return checkedReturn(callFrame->vm().throwException(callFrame, error)); ProgramCodeBlock* codeBlock = program->codeBlock(); - if (UNLIKELY(vm.shouldTriggerTermination(callFrame))) + if (UNLIKELY(vm.watchdog.didFire(callFrame))) return throwTerminatedExecutionException(callFrame); ASSERT(codeBlock->numParameters() == 1); // 1 parameter for 'this'. + if (UNLIKELY(!m_stack.entryCheck(codeBlock, 1))) + return checkedReturn(throwStackOverflowError(callFrame)); + ProtoCallFrame protoCallFrame; - protoCallFrame.init(codeBlock, JSCallee::create(vm, scope->globalObject(), scope), thisObj, 1); + protoCallFrame.init(codeBlock, scope, 0, thisObj, 1); if (LegacyProfiler* profiler = vm.enabledProfiler()) - profiler->willExecute(callFrame, program->sourceURL(), program->firstLine(), program->startColumn()); + profiler->willExecute(callFrame, program->sourceURL(), program->lineNo()); // Execute the code: JSValue result; { SamplingTool::CallRecord callRecord(m_sampler.get()); - result = program->generatedJITCode()->execute(&vm, &protoCallFrame); + Watchdog::Scope watchdogScope(vm.watchdog); + + result = program->generatedJITCode()->execute(&vm, &protoCallFrame, m_stack.getTopOfStack()); } if (LegacyProfiler* profiler = vm.enabledProfiler()) - profiler->didExecute(callFrame, program->sourceURL(), program->firstLine(), program->startColumn()); + profiler->didExecute(callFrame, program->sourceURL(), program->lineNo()); return checkedReturn(result); } @@ -899,27 +921,24 @@ JSValue Interpreter::executeCall(CallFrame* callFrame, JSObject* function, CallT return jsNull(); bool isJSCall = (callType == CallTypeJS); - JSScope* scope = nullptr; + JSScope* scope; CodeBlock* newCodeBlock; size_t argsCount = 1 + args.size(); // implicit "this" parameter - JSGlobalObject* globalObject; - - if (isJSCall) { + if (isJSCall) scope = callData.js.scope; - globalObject = scope->globalObject(); - } else { + else { ASSERT(callType == CallTypeHost); - globalObject = function->globalObject(); + scope = callFrame->scope(); } - VMEntryScope entryScope(vm, globalObject); + VMEntryScope entryScope(vm, scope->globalObject()); if (!vm.isSafeToRecurse()) return checkedReturn(throwStackOverflowError(callFrame)); if (isJSCall) { // Compile the callee: - JSObject* compileError = callData.js.functionExecutable->prepareForExecution(callFrame, jsCast<JSFunction*>(function), scope, CodeForCall); + JSObject* compileError = callData.js.functionExecutable->prepareForExecution(callFrame, scope, CodeForCall); if (UNLIKELY(!!compileError)) { return checkedReturn(callFrame->vm().throwException(callFrame, compileError)); } @@ -929,11 +948,14 @@ JSValue Interpreter::executeCall(CallFrame* callFrame, JSObject* function, CallT } else newCodeBlock = 0; - if (UNLIKELY(vm.shouldTriggerTermination(callFrame))) + if (UNLIKELY(vm.watchdog.didFire(callFrame))) return throwTerminatedExecutionException(callFrame); + if (UNLIKELY(!m_stack.entryCheck(newCodeBlock, argsCount))) + return checkedReturn(throwStackOverflowError(callFrame)); + ProtoCallFrame protoCallFrame; - protoCallFrame.init(newCodeBlock, function, thisValue, argsCount, args.data()); + protoCallFrame.init(newCodeBlock, scope, function, thisValue, argsCount, args.data()); if (LegacyProfiler* profiler = vm.enabledProfiler()) profiler->willExecute(callFrame, function); @@ -941,15 +963,13 @@ JSValue Interpreter::executeCall(CallFrame* callFrame, JSObject* function, CallT JSValue result; { SamplingTool::CallRecord callRecord(m_sampler.get(), !isJSCall); + Watchdog::Scope watchdogScope(vm.watchdog); // Execute the code: if (isJSCall) - result = callData.js.functionExecutable->generatedJITCodeForCall()->execute(&vm, &protoCallFrame); - else { - result = JSValue::decode(vmEntryToNative(reinterpret_cast<void*>(callData.native.function), &vm, &protoCallFrame)); - if (callFrame->hadException()) - result = jsNull(); - } + result = callData.js.functionExecutable->generatedJITCodeForCall()->execute(&vm, &protoCallFrame, m_stack.getTopOfStack()); + else + result = JSValue::decode(callToNativeFunction(reinterpret_cast<void*>(callData.native.function), &vm.topCallFrame, &protoCallFrame, m_stack.getTopOfStack())); } if (LegacyProfiler* profiler = vm.enabledProfiler()) @@ -958,7 +978,7 @@ JSValue Interpreter::executeCall(CallFrame* callFrame, JSObject* function, CallT return checkedReturn(result); } -JSObject* Interpreter::executeConstruct(CallFrame* callFrame, JSObject* constructor, ConstructType constructType, const ConstructData& constructData, const ArgList& args, JSValue newTarget) +JSObject* Interpreter::executeConstruct(CallFrame* callFrame, JSObject* constructor, ConstructType constructType, const ConstructData& constructData, const ArgList& args) { VM& vm = callFrame->vm(); ASSERT(!callFrame->hadException()); @@ -969,27 +989,24 @@ JSObject* Interpreter::executeConstruct(CallFrame* callFrame, JSObject* construc return checkedReturn(throwStackOverflowError(callFrame)); bool isJSConstruct = (constructType == ConstructTypeJS); - JSScope* scope = nullptr; + JSScope* scope; CodeBlock* newCodeBlock; size_t argsCount = 1 + args.size(); // implicit "this" parameter - JSGlobalObject* globalObject; - - if (isJSConstruct) { + if (isJSConstruct) scope = constructData.js.scope; - globalObject = scope->globalObject(); - } else { + else { ASSERT(constructType == ConstructTypeHost); - globalObject = constructor->globalObject(); + scope = callFrame->scope(); } - VMEntryScope entryScope(vm, globalObject); + VMEntryScope entryScope(vm, scope->globalObject()); if (!vm.isSafeToRecurse()) return checkedReturn(throwStackOverflowError(callFrame)); if (isJSConstruct) { // Compile the callee: - JSObject* compileError = constructData.js.functionExecutable->prepareForExecution(callFrame, jsCast<JSFunction*>(constructor), scope, CodeForConstruct); + JSObject* compileError = constructData.js.functionExecutable->prepareForExecution(callFrame, scope, CodeForConstruct); if (UNLIKELY(!!compileError)) { return checkedReturn(callFrame->vm().throwException(callFrame, compileError)); } @@ -999,11 +1016,14 @@ JSObject* Interpreter::executeConstruct(CallFrame* callFrame, JSObject* construc } else newCodeBlock = 0; - if (UNLIKELY(vm.shouldTriggerTermination(callFrame))) + if (UNLIKELY(vm.watchdog.didFire(callFrame))) return throwTerminatedExecutionException(callFrame); + if (UNLIKELY(!m_stack.entryCheck(newCodeBlock, argsCount))) + return checkedReturn(throwStackOverflowError(callFrame)); + ProtoCallFrame protoCallFrame; - protoCallFrame.init(newCodeBlock, constructor, newTarget, argsCount, args.data()); + protoCallFrame.init(newCodeBlock, scope, constructor, jsUndefined(), argsCount, args.data()); if (LegacyProfiler* profiler = vm.enabledProfiler()) profiler->willExecute(callFrame, constructor); @@ -1011,12 +1031,13 @@ JSObject* Interpreter::executeConstruct(CallFrame* callFrame, JSObject* construc JSValue result; { SamplingTool::CallRecord callRecord(m_sampler.get(), !isJSConstruct); + Watchdog::Scope watchdogScope(vm.watchdog); // Execute the code. if (isJSConstruct) - result = constructData.js.functionExecutable->generatedJITCodeForConstruct()->execute(&vm, &protoCallFrame); + result = constructData.js.functionExecutable->generatedJITCodeForConstruct()->execute(&vm, &protoCallFrame, m_stack.getTopOfStack()); else { - result = JSValue::decode(vmEntryToNative(reinterpret_cast<void*>(constructData.native.function), &vm, &protoCallFrame)); + result = JSValue::decode(callToNativeFunction(reinterpret_cast<void*>(constructData.native.function), &vm.topCallFrame, &protoCallFrame, m_stack.getTopOfStack())); if (!callFrame->hadException()) RELEASE_ASSERT(result.isObject()); @@ -1041,7 +1062,7 @@ CallFrameClosure Interpreter::prepareForRepeatCall(FunctionExecutable* functionE return CallFrameClosure(); // Compile the callee: - JSObject* error = functionExecutable->prepareForExecution(callFrame, function, scope, CodeForCall); + JSObject* error = functionExecutable->prepareForExecution(callFrame, scope, CodeForCall); if (error) { callFrame->vm().throwException(callFrame, error); return CallFrameClosure(); @@ -1051,7 +1072,12 @@ CallFrameClosure Interpreter::prepareForRepeatCall(FunctionExecutable* functionE size_t argsCount = argumentCountIncludingThis; - protoCallFrame->init(newCodeBlock, function, jsUndefined(), argsCount, args); + if (UNLIKELY(!m_stack.entryCheck(newCodeBlock, argsCount))) { + throwStackOverflowError(callFrame); + return CallFrameClosure(); + } + + protoCallFrame->init(newCodeBlock, scope, function, jsUndefined(), argsCount, args); // Return the successful closure: CallFrameClosure result = { callFrame, protoCallFrame, function, functionExecutable, &vm, scope, newCodeBlock->numParameters(), argumentCountIncludingThis }; return result; @@ -1063,23 +1089,25 @@ JSValue Interpreter::execute(CallFrameClosure& closure) SamplingScope samplingScope(this); ASSERT(!vm.isCollectorBusy()); - RELEASE_ASSERT(vm.currentThreadIsHoldingAPILock()); if (vm.isCollectorBusy()) return jsNull(); StackStats::CheckPoint stackCheckPoint; + closure.resetCallFrame(); if (LegacyProfiler* profiler = vm.enabledProfiler()) profiler->willExecute(closure.oldCallFrame, closure.function); - if (UNLIKELY(vm.shouldTriggerTermination(closure.oldCallFrame))) + if (UNLIKELY(vm.watchdog.didFire(closure.oldCallFrame))) return throwTerminatedExecutionException(closure.oldCallFrame); // Execute the code: JSValue result; { SamplingTool::CallRecord callRecord(m_sampler.get()); - result = closure.functionExecutable->generatedJITCodeForCall()->execute(&vm, closure.protoCallFrame); + Watchdog::Scope watchdogScope(vm.watchdog); + + result = closure.functionExecutable->generatedJITCodeForCall()->execute(&vm, closure.protoCallFrame, m_stack.getTopOfStack()); } if (LegacyProfiler* profiler = vm.enabledProfiler()) @@ -1096,7 +1124,6 @@ JSValue Interpreter::execute(EvalExecutable* eval, CallFrame* callFrame, JSValue ASSERT(scope->vm() == &callFrame->vm()); ASSERT(!vm.exception()); ASSERT(!vm.isCollectorBusy()); - RELEASE_ASSERT(vm.currentThreadIsHoldingAPILock()); if (vm.isCollectorBusy()) return jsNull(); @@ -1109,26 +1136,19 @@ JSValue Interpreter::execute(EvalExecutable* eval, CallFrame* callFrame, JSValue JSScope* variableObject; if ((numVariables || numFunctions) && eval->isStrictMode()) { - scope = StrictEvalActivation::create(callFrame, scope); + scope = StrictEvalActivation::create(callFrame); variableObject = scope; } else { for (JSScope* node = scope; ; node = node->next()) { RELEASE_ASSERT(node); - if (node->isGlobalObject()) { + if (node->isVariableObject() && !node->isNameScopeObject()) { variableObject = node; break; - } - if (JSLexicalEnvironment* lexicalEnvironment = jsDynamicCast<JSLexicalEnvironment*>(node)) { - if (lexicalEnvironment->symbolTable()->scopeType() == SymbolTable::ScopeType::VarScope) { - variableObject = node; - break; - } } } - ASSERT(!variableObject->isNameScopeObject()); } - JSObject* compileError = eval->prepareForExecution(callFrame, nullptr, scope, CodeForCall); + JSObject* compileError = eval->prepareForExecution(callFrame, scope, CodeForCall); if (UNLIKELY(!!compileError)) return checkedReturn(callFrame->vm().throwException(callFrame, compileError)); EvalCodeBlock* codeBlock = eval->codeBlock(); @@ -1136,7 +1156,7 @@ JSValue Interpreter::execute(EvalExecutable* eval, CallFrame* callFrame, JSValue if (numVariables || numFunctions) { BatchedTransitionOptimizer optimizer(vm, variableObject); if (variableObject->next()) - variableObject->globalObject()->varInjectionWatchpoint()->fireAll("Executed eval, fired VarInjection watchpoint"); + variableObject->globalObject()->varInjectionWatchpoint()->fireAll(); for (unsigned i = 0; i < numVariables; ++i) { const Identifier& ident = codeBlock->variable(i); @@ -1153,26 +1173,31 @@ JSValue Interpreter::execute(EvalExecutable* eval, CallFrame* callFrame, JSValue } } - if (UNLIKELY(vm.shouldTriggerTermination(callFrame))) + if (UNLIKELY(vm.watchdog.didFire(callFrame))) return throwTerminatedExecutionException(callFrame); ASSERT(codeBlock->numParameters() == 1); // 1 parameter for 'this'. + if (UNLIKELY(!m_stack.entryCheck(codeBlock, 1))) + return checkedReturn(throwStackOverflowError(callFrame)); + ProtoCallFrame protoCallFrame; - protoCallFrame.init(codeBlock, JSCallee::create(vm, scope->globalObject(), scope), thisValue, 1); + protoCallFrame.init(codeBlock, scope, 0, thisValue, 1); if (LegacyProfiler* profiler = vm.enabledProfiler()) - profiler->willExecute(callFrame, eval->sourceURL(), eval->firstLine(), eval->startColumn()); + profiler->willExecute(callFrame, eval->sourceURL(), eval->lineNo()); // Execute the code: JSValue result; { SamplingTool::CallRecord callRecord(m_sampler.get()); - result = eval->generatedJITCode()->execute(&vm, &protoCallFrame); + Watchdog::Scope watchdogScope(vm.watchdog); + + result = eval->generatedJITCode()->execute(&vm, &protoCallFrame, m_stack.getTopOfStack()); } if (LegacyProfiler* profiler = vm.enabledProfiler()) - profiler->didExecute(callFrame, eval->sourceURL(), eval->firstLine(), eval->startColumn()); + profiler->didExecute(callFrame, eval->sourceURL(), eval->lineNo()); return checkedReturn(result); } @@ -1182,38 +1207,35 @@ NEVER_INLINE void Interpreter::debug(CallFrame* callFrame, DebugHookID debugHook Debugger* debugger = callFrame->vmEntryGlobalObject()->debugger(); if (!debugger) return; - - ASSERT(callFrame->codeBlock()->hasDebuggerRequests()); - ASSERT(!callFrame->hadException()); + ASSERT(callFrame->codeBlock()->hasDebuggerRequests() || callFrame->hadException()); switch (debugHookID) { case DidEnterCallFrame: debugger->callEvent(callFrame); - break; + return; case WillLeaveCallFrame: debugger->returnEvent(callFrame); - break; + return; case WillExecuteStatement: debugger->atStatement(callFrame); - break; + return; case WillExecuteProgram: debugger->willExecuteProgram(callFrame); - break; + return; case DidExecuteProgram: debugger->didExecuteProgram(callFrame); - break; + return; case DidReachBreakpoint: debugger->didReachBreakpoint(callFrame); - break; + return; } - ASSERT(!callFrame->hadException()); } void Interpreter::enableSampler() { #if ENABLE(OPCODE_SAMPLING) if (!m_sampler) { - m_sampler = std::make_unique<SamplingTool>(this); + m_sampler = adoptPtr(new SamplingTool(this)); m_sampler->setup(); } #endif |