diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2016-04-10 09:28:39 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2016-04-10 09:28:39 +0000 |
commit | 32761a6cee1d0dee366b885b7b9c777e67885688 (patch) | |
tree | d6bec92bebfb216f4126356e55518842c2f476a1 /Source/JavaScriptCore/interpreter/Interpreter.cpp | |
parent | a4e969f4965059196ca948db781e52f7cfebf19e (diff) | |
download | WebKitGtk-tarball-32761a6cee1d0dee366b885b7b9c777e67885688.tar.gz |
webkitgtk-2.4.11webkitgtk-2.4.11
Diffstat (limited to 'Source/JavaScriptCore/interpreter/Interpreter.cpp')
-rw-r--r-- | Source/JavaScriptCore/interpreter/Interpreter.cpp | 746 |
1 files changed, 306 insertions, 440 deletions
diff --git a/Source/JavaScriptCore/interpreter/Interpreter.cpp b/Source/JavaScriptCore/interpreter/Interpreter.cpp index 18a90760d..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 "ClonedArguments.h" +#include "CallFrameInlines.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 "JSModuleEnvironment.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,53 +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 StackFrameModuleCode: - 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 StackFrameModuleCode: - traceLine = "module 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) @@ -143,27 +113,21 @@ JSValue eval(CallFrame* callFrame) JSValue program = callFrame->argument(0); if (!program.isString()) return program; - + TopCallFrameSetter topCallFrame(callFrame->vm(), callFrame); - JSGlobalObject* globalObject = callFrame->lexicalGlobalObject(); - if (!globalObject->evalEnabled()) { - callFrame->vm().throwException(callFrame, createEvalError(callFrame, globalObject->evalDisabledErrorMessage())); - return jsUndefined(); - } String programSource = asString(program)->value(callFrame); if (callFrame->hadException()) return JSValue(); CallFrame* callerFrame = callFrame->callerFrame(); CodeBlock* callerCodeBlock = callerFrame->codeBlock(); - JSScope* callerScopeChain = callerFrame->uncheckedR(callerCodeBlock->scopeRegister().offset()).Register::scope(); - UnlinkedCodeBlock* callerUnlinkedCodeBlock = callerCodeBlock->unlinkedCodeBlock(); - - bool isArrowFunctionContext = callerUnlinkedCodeBlock->isArrowFunction() || callerUnlinkedCodeBlock->isArrowFunctionContext(); - EvalExecutable* eval = callerCodeBlock->evalCodeCache().tryGet(callerCodeBlock->isStrictMode(), programSource, isArrowFunctionContext, callerScopeChain); + 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()) @@ -178,11 +142,7 @@ JSValue eval(CallFrame* callFrame) // If the literal parser bailed, it should not have thrown exceptions. ASSERT(!callFrame->vm().exception()); - ThisTDZMode thisTDZMode = ThisTDZMode::CheckIfNeeded; - if (callerUnlinkedCodeBlock->constructorKind() == ConstructorKind::Derived) - thisTDZMode = ThisTDZMode::AlwaysCheck; - - eval = callerCodeBlock->evalCodeCache().getSlow(callFrame, callerCodeBlock, callerCodeBlock->isStrictMode(), thisTDZMode, callerCodeBlock->unlinkedCodeBlock()->derivedContextType(), callerCodeBlock->unlinkedCodeBlock()->isArrowFunction(), programSource, callerScopeChain); + eval = callerCodeBlock->evalCodeCache().getSlow(callFrame, callerCodeBlock->ownerExecutable(), callerCodeBlock->isStrictMode(), programSource, callerScopeChain); if (!eval) return jsUndefined(); } @@ -192,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()) || !length) + 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); - return; - case ScopedArgumentsType: - jsCast<ScopedArguments*>(cell)->copyToArguments(callFrame, firstElementDest, offset, length); + if (arguments.isUndefinedOrNull()) { + newCallFrame->setArgumentCountIncludingThis(1); + newCallFrame->setThisValue(thisValue); 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) @@ -306,9 +272,11 @@ Interpreter::~Interpreter() { } -void Interpreter::initialize() +void Interpreter::initialize(bool canUseJIT) { -#if ENABLE(COMPUTED_GOTO_OPCODES) + UNUSED_PARAM(canUseJIT); + +#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)); @@ -393,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()); @@ -420,7 +388,7 @@ void Interpreter::dumpRegisters(CallFrame* callFrame) } dataLogF("-----------------------------------------------------------------------------\n"); - end = it - codeBlock->m_numCalleeLocals + codeBlock->m_numVars; + end = it - codeBlock->m_numCalleeRegisters + codeBlock->m_numVars; if (it != end) { do { JSValue v = (*it).jsValue(); @@ -437,21 +405,68 @@ 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 } +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()) { + if (callFrame->callee()) + debugger->returnEvent(callFrame); + else + debugger->didExecuteProgram(callFrame); + } + + 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) { switch (visitor->codeType()) { case StackVisitor::Frame::Eval: return StackFrameEvalCode; - case StackVisitor::Frame::Module: - return StackFrameModuleCode; case StackVisitor::Frame::Function: return StackFrameFunctionCode; case StackVisitor::Frame::Global: @@ -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) @@ -516,16 +528,6 @@ String StackFrame::toString(CallFrame* callFrame) return traceBuild.toString().impl(); } -static inline bool isWebAssemblyExecutable(ExecutableBase* executable) -{ -#if !ENABLE(WEBASSEMBLY) - UNUSED_PARAM(executable); - return false; -#else - return executable->isWebAssemblyExecutable(); -#endif -} - class GetStackTraceFunctor { public: GetStackTraceFunctor(VM& vm, Vector<StackFrame>& results, size_t remainingCapacity) @@ -539,17 +541,15 @@ public: { VM& vm = m_vm; if (m_remainingCapacityForFrameCapture) { - if (visitor->isJSFrame() - && !isWebAssemblyExecutable(visitor->codeBlock()->ownerExecutable()) - && !visitor->codeBlock()->unlinkedCodeBlock()->isBuiltinFunction()) { + if (visitor->isJSFrame()) { CodeBlock* codeBlock = visitor->codeBlock(); StackFrame s = { Strong<JSObject>(vm, visitor->callee()), getStackFrameCodeType(visitor), - Strong<ScriptExecutable>(vm, codeBlock->ownerScriptExecutable()), + Strong<ExecutableBase>(vm, codeBlock->ownerExecutable()), Strong<UnlinkedCodeBlock>(vm, codeBlock->unlinkedCodeBlock()), codeBlock->source(), - codeBlock->ownerScriptExecutable()->firstLine(), + codeBlock->ownerExecutable()->lineNo(), codeBlock->firstLineColumnOffset(), codeBlock->sourceOffset(), visitor->bytecodeOffset(), @@ -557,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); } @@ -576,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; @@ -596,26 +597,9 @@ JSString* Interpreter::stackTraceAsString(ExecState* exec, Vector<StackFrame> st return jsString(&exec->vm(), builder.toString()); } -ALWAYS_INLINE static HandlerInfo* findExceptionHandler(StackVisitor& visitor, CodeBlock* codeBlock, CodeBlock::RequiredHandler requiredHandler) -{ - ASSERT(codeBlock); -#if ENABLE(DFG_JIT) - ASSERT(!visitor->isInlinedFrame()); -#endif - - CallFrame* callFrame = visitor->callFrame(); - unsigned exceptionHandlerIndex; - if (JITCode::isOptimizingJIT(codeBlock->jitType())) - exceptionHandlerIndex = callFrame->callSiteIndex().bits(); - else - exceptionHandlerIndex = callFrame->bytecodeOffset(); - - return codeBlock->handlerForIndex(exceptionHandlerIndex, requiredHandler); -} - -class GetCatchHandlerFunctor { +class GetExceptionHandlerFunctor { public: - GetCatchHandlerFunctor() + GetExceptionHandlerFunctor() : m_handler(0) { } @@ -624,13 +608,12 @@ public: StackVisitor::Status operator()(StackVisitor& visitor) { - visitor.unwindToMachineCodeBlockFrame(); - CodeBlock* codeBlock = visitor->codeBlock(); if (!codeBlock) return StackVisitor::Continue; - m_handler = findExceptionHandler(visitor, codeBlock, CodeBlock::RequiredHandler::CatchHandler); + unsigned bytecodeOffset = visitor->bytecodeOffset(); + m_handler = codeBlock->handlerForBytecodeOffset(bytecodeOffset); if (m_handler) return StackVisitor::Done; @@ -641,18 +624,6 @@ private: HandlerInfo* m_handler; }; -ALWAYS_INLINE static void notifyDebuggerOfUnwinding(CallFrame* callFrame) -{ - if (Debugger* debugger = callFrame->vmEntryGlobalObject()->debugger()) { - SuspendExceptionScope scope(&callFrame->vm()); - if (jsDynamicCast<JSFunction*>(callFrame->callee())) - debugger->returnEvent(callFrame); - else - debugger->didExecuteProgram(callFrame); - ASSERT(!callFrame->hadException()); - } -} - class UnwindFunctor { public: UnwindFunctor(CallFrame*& callFrame, bool isTermination, CodeBlock*& codeBlock, HandlerInfo*& handler) @@ -665,92 +636,35 @@ public: StackVisitor::Status operator()(StackVisitor& visitor) { - visitor.unwindToMachineCodeBlockFrame(); VM& vm = m_callFrame->vm(); m_callFrame = visitor->callFrame(); m_codeBlock = visitor->codeBlock(); + unsigned bytecodeOffset = visitor->bytecodeOffset(); - m_handler = nullptr; - if (!m_isTermination) { - if (m_codeBlock && !isWebAssemblyExecutable(m_codeBlock->ownerExecutable())) - m_handler = findExceptionHandler(visitor, m_codeBlock, CodeBlock::RequiredHandler::AnyHandler); - } - - if (m_handler) - return StackVisitor::Done; - - notifyDebuggerOfUnwinding(m_callFrame); - - bool shouldStopUnwinding = visitor->callerIsVMEntryFrame(); - if (shouldStopUnwinding) { - if (LegacyProfiler* profiler = vm.enabledProfiler()) - profiler->exceptionUnwind(m_callFrame); - - copyCalleeSavesToVMCalleeSavesBuffer(visitor); - + if (m_isTermination || !(m_handler = m_codeBlock->handlerForBytecodeOffset(bytecodeOffset))) { + if (!unwindCallFrame(visitor)) { + if (LegacyProfiler* profiler = vm.enabledProfiler()) + profiler->exceptionUnwind(m_callFrame); + return StackVisitor::Done; + } + } else return StackVisitor::Done; - } - - copyCalleeSavesToVMCalleeSavesBuffer(visitor); return StackVisitor::Continue; } private: - void copyCalleeSavesToVMCalleeSavesBuffer(StackVisitor& visitor) - { -#if ENABLE(JIT) && NUMBER_OF_CALLEE_SAVES_REGISTERS > 0 - - if (!visitor->isJSFrame()) - return; - -#if ENABLE(DFG_JIT) - if (visitor->inlineCallFrame()) - return; -#endif - RegisterAtOffsetList* currentCalleeSaves = m_codeBlock ? m_codeBlock->calleeSaveRegisters() : nullptr; - - if (!currentCalleeSaves) - return; - - VM& vm = m_callFrame->vm(); - RegisterAtOffsetList* allCalleeSaves = vm.getAllCalleeSaveRegisterOffsets(); - RegisterSet dontCopyRegisters = RegisterSet::stackRegisters(); - intptr_t* frame = reinterpret_cast<intptr_t*>(m_callFrame->registers()); - - unsigned registerCount = currentCalleeSaves->size(); - for (unsigned i = 0; i < registerCount; i++) { - RegisterAtOffset currentEntry = currentCalleeSaves->at(i); - if (dontCopyRegisters.get(currentEntry.reg())) - continue; - RegisterAtOffset* vmCalleeSavesEntry = allCalleeSaves->find(currentEntry.reg()); - - vm.calleeSaveRegistersBuffer[vmCalleeSavesEntry->offsetAsIndex()] = *(frame + currentEntry.offsetAsIndex()); - } -#else - UNUSED_PARAM(visitor); -#endif - } - CallFrame*& m_callFrame; bool m_isTermination; CodeBlock*& m_codeBlock; HandlerInfo*& m_handler; }; -NEVER_INLINE HandlerInfo* Interpreter::unwind(VM& vm, CallFrame*& callFrame, Exception* exception, UnwindStart unwindStart) +NEVER_INLINE HandlerInfo* Interpreter::unwind(CallFrame*& callFrame, JSValue& exceptionValue) { - if (unwindStart == UnwindFromCallerFrame) { - if (callFrame->callerFrameOrVMEntryFrame() == vm.topVMEntryFrame) - return nullptr; - - callFrame = callFrame->callerFrame(); - vm.topCallFrame = callFrame; - } - 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 @@ -758,42 +672,60 @@ NEVER_INLINE HandlerInfo* Interpreter::unwind(VM& vm, CallFrame*& callFrame, Exc if (exceptionValue.isEmpty() || (exceptionValue.isCell() && !exceptionValue.asCell())) exceptionValue = jsNull(); - ASSERT(vm.exception() && vm.exception()->stack().size()); - - // Calculate an exception handler vPC, unwinding call frames as necessary. - HandlerInfo* handler = nullptr; - UnwindFunctor functor(callFrame, isTerminatedExecutionException(exception), codeBlock, handler); - callFrame->iterate(functor); - if (!handler) - return nullptr; + if (exceptionValue.isObject()) { + isTermination = isTerminatedExecutionException(asObject(exceptionValue)); + } - return handler; -} + ASSERT(callFrame->vm().exceptionStack().size()); -void Interpreter::notifyDebuggerOfExceptionToBeThrown(CallFrame* callFrame, Exception* exception) -{ Debugger* debugger = callFrame->vmEntryGlobalObject()->debugger(); - if (debugger && debugger->needsExceptionCallbacks() && !exception->didNotifyInspectorOfThrow()) { + 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. + 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 isTermination = isTerminatedExecutionException(exception); + 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, exception->value(), hasCatchHandler); + 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(callFrame, isTermination, codeBlock, handler); + callFrame->iterate(functor); + if (!handler) + return 0; + + 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; } static inline JSValue checkedReturn(JSValue returnValue) @@ -826,16 +758,16 @@ private: JSValue Interpreter::execute(ProgramExecutable* program, CallFrame* callFrame, JSObject* thisObj) { SamplingScope samplingScope(this); - - JSScope* scope = thisObj->globalObject()->globalScope(); + + 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)); @@ -845,7 +777,7 @@ JSValue Interpreter::execute(ProgramExecutable* program, CallFrame* callFrame, J Vector<JSONPData> JSONPData; bool parseResult; - StringView programSource = program->source().view(); + const String programSource = program->source().toString(); if (programSource.isNull()) return jsUndefined(); if (programSource.is8Bit()) { @@ -876,10 +808,10 @@ JSValue Interpreter::execute(ProgramExecutable* program, CallFrame* callFrame, J switch (JSONPPath[i].m_type) { case JSONPPathEntryTypeDot: { if (i == 0) { - PropertySlot slot(globalObject, PropertySlot::InternalMethodType::Get); + 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); @@ -942,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); } @@ -986,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)); } @@ -1016,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); @@ -1028,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()) @@ -1045,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()); @@ -1056,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)); } @@ -1086,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); @@ -1098,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()); @@ -1128,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(); @@ -1138,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; @@ -1150,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()) @@ -1183,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(); @@ -1196,55 +1136,27 @@ 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; - } } } } - 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(); - // We can't declare a "var"/"function" that overwrites a global "let"/"const"/"class" in a sloppy-mode eval. - if (variableObject->isGlobalObject() && !eval->isStrictMode() && (numVariables || numFunctions)) { - JSGlobalLexicalEnvironment* globalLexicalEnvironment = jsCast<JSGlobalObject*>(variableObject)->globalLexicalEnvironment(); - for (unsigned i = 0; i < numVariables; ++i) { - const Identifier& ident = codeBlock->variable(i); - PropertySlot slot(globalLexicalEnvironment, PropertySlot::InternalMethodType::VMInquiry); - if (JSGlobalLexicalEnvironment::getOwnPropertySlot(globalLexicalEnvironment, callFrame, ident, slot)) { - return checkedReturn(callFrame->vm().throwException(callFrame, - createTypeError(callFrame, makeString("Can't create duplicate global variable in eval: '", String(ident.impl()), "'")))); - } - } - - for (int i = 0; i < numFunctions; ++i) { - FunctionExecutable* function = codeBlock->functionDecl(i); - PropertySlot slot(globalLexicalEnvironment, PropertySlot::InternalMethodType::VMInquiry); - if (JSGlobalLexicalEnvironment::getOwnPropertySlot(globalLexicalEnvironment, callFrame, function->name(), slot)) { - return checkedReturn(callFrame->vm().throwException(callFrame, - createTypeError(callFrame, makeString("Can't create duplicate global variable in eval: '", String(function->name().impl()), "'")))); - } - } - } - 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); @@ -1261,74 +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'. - ProtoCallFrame protoCallFrame; - protoCallFrame.init(codeBlock, JSCallee::create(vm, scope->globalObject(), scope), thisValue, 1); - - if (LegacyProfiler* profiler = vm.enabledProfiler()) - profiler->willExecute(callFrame, eval->sourceURL(), eval->firstLine(), eval->startColumn()); - - // Execute the code: - JSValue result; - { - SamplingTool::CallRecord callRecord(m_sampler.get()); - result = eval->generatedJITCode()->execute(&vm, &protoCallFrame); - } - - if (LegacyProfiler* profiler = vm.enabledProfiler()) - profiler->didExecute(callFrame, eval->sourceURL(), eval->firstLine(), eval->startColumn()); - - return checkedReturn(result); -} - -JSValue Interpreter::execute(ModuleProgramExecutable* executable, CallFrame* callFrame, JSModuleEnvironment* scope) -{ - VM& vm = *scope->vm(); - SamplingScope samplingScope(this); - - ASSERT(scope->vm() == &callFrame->vm()); - ASSERT(!vm.exception()); - ASSERT(!vm.isCollectorBusy()); - RELEASE_ASSERT(vm.currentThreadIsHoldingAPILock()); - if (vm.isCollectorBusy()) - return jsNull(); - - VMEntryScope entryScope(vm, scope->globalObject()); - if (!vm.isSafeToRecurse()) + if (UNLIKELY(!m_stack.entryCheck(codeBlock, 1))) return checkedReturn(throwStackOverflowError(callFrame)); - JSObject* compileError = executable->prepareForExecution(callFrame, nullptr, scope, CodeForCall); - if (UNLIKELY(!!compileError)) - return checkedReturn(callFrame->vm().throwException(callFrame, compileError)); - ModuleProgramCodeBlock* codeBlock = executable->codeBlock(); - - if (UNLIKELY(vm.shouldTriggerTermination(callFrame))) - return throwTerminatedExecutionException(callFrame); - - ASSERT(codeBlock->numParameters() == 1); // 1 parameter for 'this'. - - // The |this| of the module is always `undefined`. - // http://www.ecma-international.org/ecma-262/6.0/#sec-module-environment-records-hasthisbinding - // http://www.ecma-international.org/ecma-262/6.0/#sec-module-environment-records-getthisbinding ProtoCallFrame protoCallFrame; - protoCallFrame.init(codeBlock, JSCallee::create(vm, scope->globalObject(), scope), jsUndefined(), 1); + protoCallFrame.init(codeBlock, scope, 0, thisValue, 1); if (LegacyProfiler* profiler = vm.enabledProfiler()) - profiler->willExecute(callFrame, executable->sourceURL(), executable->firstLine(), executable->startColumn()); + profiler->willExecute(callFrame, eval->sourceURL(), eval->lineNo()); // Execute the code: JSValue result; { SamplingTool::CallRecord callRecord(m_sampler.get()); - result = executable->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, executable->sourceURL(), executable->firstLine(), executable->startColumn()); + profiler->didExecute(callFrame, eval->sourceURL(), eval->lineNo()); return checkedReturn(result); } @@ -1338,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 |