diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2016-05-24 08:28:08 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2016-05-24 08:28:08 +0000 |
commit | a4e969f4965059196ca948db781e52f7cfebf19e (patch) | |
tree | 6ca352808c8fdc52006a0f33f6ae3c593b23867d /Source/JavaScriptCore/interpreter/Interpreter.cpp | |
parent | 41386e9cb918eed93b3f13648cbef387e371e451 (diff) | |
download | WebKitGtk-tarball-a4e969f4965059196ca948db781e52f7cfebf19e.tar.gz |
webkitgtk-2.12.3webkitgtk-2.12.3
Diffstat (limited to 'Source/JavaScriptCore/interpreter/Interpreter.cpp')
-rw-r--r-- | Source/JavaScriptCore/interpreter/Interpreter.cpp | 746 |
1 files changed, 440 insertions, 306 deletions
diff --git a/Source/JavaScriptCore/interpreter/Interpreter.cpp b/Source/JavaScriptCore/interpreter/Interpreter.cpp index 4fbc8229a..18a90760d 100644 --- a/Source/JavaScriptCore/interpreter/Interpreter.cpp +++ b/Source/JavaScriptCore/interpreter/Interpreter.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008, 2009, 2010, 2012, 2013 Apple Inc. All rights reserved. + * Copyright (C) 2008, 2009, 2010, 2012-2015 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 Computer, Inc. ("Apple") nor the names of + * 3. Neither the name of Apple Inc. ("Apple") nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * @@ -30,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 "JSNameScope.h" +#include "JSCInlines.h" +#include "JSLexicalEnvironment.h" +#include "JSModuleEnvironment.h" #include "JSNotAnObject.h" -#include "JSPropertyNameIterator.h" #include "JSStackInlines.h" #include "JSString.h" #include "JSWithScope.h" @@ -56,24 +56,27 @@ #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> @@ -83,26 +86,53 @@ #include "JIT.h" #endif -#define WTF_USE_GCC_COMPUTED_GOTO_WORKAROUND (ENABLE(LLINT) && !defined(__llvm__)) - using namespace std; namespace JSC { -Interpreter::ErrorHandlingMode::ErrorHandlingMode(ExecState *exec) - : m_interpreter(*exec->interpreter()) +String StackFrame::friendlySourceURL() const { - if (!m_interpreter.m_errorHandlingModeReentry) - m_interpreter.stack().enableErrorStackReserve(); - m_interpreter.m_errorHandlingModeReentry++; + 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; } -Interpreter::ErrorHandlingMode::~ErrorHandlingMode() +String StackFrame::friendlyFunctionName(CallFrame* callFrame) const { - m_interpreter.m_errorHandlingModeReentry--; - ASSERT(m_interpreter.m_errorHandlingModeReentry >= 0); - if (!m_interpreter.m_errorHandlingModeReentry) - m_interpreter.stack().disableErrorStackReserve(); + 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; } JSValue eval(CallFrame* callFrame) @@ -113,21 +143,27 @@ 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->scope(); - EvalExecutable* eval = callerCodeBlock->evalCodeCache().tryGet(callerCodeBlock->isStrictMode(), programSource, callerScopeChain); + 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); 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()) @@ -142,7 +178,11 @@ 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 = 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); if (!eval) return jsUndefined(); } @@ -152,109 +192,103 @@ JSValue eval(CallFrame* callFrame) return interpreter->execute(eval, callFrame, thisValue, callerScopeChain); } -CallFrame* sizeAndAllocFrameForVarargs(CallFrame* callFrame, JSStack* stack, JSValue arguments, int firstFreeRegister) +unsigned sizeOfVarargs(CallFrame* callFrame, JSValue arguments, uint32_t firstVarArgOffset) { - 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)); + if (UNLIKELY(!arguments.isCell())) { + if (arguments.isUndefinedOrNull()) return 0; - } - return newCallFrame; - } - - 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)); + + 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* 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; + + 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)); + 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; +} - 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)); +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) +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(); - - newCallFrame->setArgumentCountIncludingThis(argumentCountIncludingThis); - newCallFrame->setThisValue(thisValue); - for (size_t i = 0; i < callFrame->argumentCount(); ++i) - newCallFrame->setArgument(i, callFrame->argumentAfterCapture(i)); + if (UNLIKELY(!arguments.isCell()) || !length) return; - } - if (arguments.isUndefinedOrNull()) { - newCallFrame->setArgumentCountIncludingThis(1); - newCallFrame->setThisValue(thisValue); + JSCell* cell = arguments.asCell(); + switch (cell->type()) { + case DirectArgumentsType: + jsCast<DirectArguments*>(cell)->copyToArguments(callFrame, firstElementDest, offset, length); return; - } - - 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); + case ScopedArgumentsType: + jsCast<ScopedArguments*>(cell)->copyToArguments(callFrame, firstElementDest, offset, length); return; - } - - if (isJSArray(arguments)) { - JSArray* array = asArray(arguments); - unsigned argCount = array->length(); - newCallFrame->setArgumentCountIncludingThis(argCount + 1); - newCallFrame->setThisValue(thisValue); - array->copyToArguments(callFrame, newCallFrame, argCount); + 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); return; - } + } } +} + +void setupVarargsFrame(CallFrame* callFrame, CallFrame* newCallFrame, JSValue arguments, uint32_t offset, uint32_t length) +{ + VirtualRegister calleeFrameOffset(newCallFrame - callFrame); - JSObject* argObject = asObject(arguments); - unsigned argCount = argObject->get(callFrame, callFrame->propertyNames().length).toUInt32(callFrame); - newCallFrame->setArgumentCountIncludingThis(argCount + 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)); - if (UNLIKELY(callFrame->vm().exception())) - return; - } } Interpreter::Interpreter(VM& vm) @@ -272,11 +306,9 @@ Interpreter::~Interpreter() { } -void Interpreter::initialize(bool canUseJIT) +void Interpreter::initialize() { - UNUSED_PARAM(canUseJIT); - -#if ENABLE(COMPUTED_GOTO_OPCODES) && ENABLE(LLINT) +#if ENABLE(COMPUTED_GOTO_OPCODES) m_opcodeTable = LLInt::opcodeMap(); for (int i = 0; i < numOpcodeIDs; ++i) m_opcodeIDTable.add(m_opcodeTable[i], static_cast<OpcodeID>(i)); @@ -361,7 +393,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()); @@ -388,7 +420,7 @@ void Interpreter::dumpRegisters(CallFrame* callFrame) } dataLogF("-----------------------------------------------------------------------------\n"); - end = it - codeBlock->m_numCalleeRegisters + codeBlock->m_numVars; + end = it - codeBlock->m_numCalleeLocals + codeBlock->m_numVars; if (it != end) { do { JSValue v = (*it).jsValue(); @@ -405,68 +437,21 @@ 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: @@ -496,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) @@ -528,6 +516,16 @@ 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) @@ -541,15 +539,17 @@ public: { VM& vm = m_vm; if (m_remainingCapacityForFrameCapture) { - if (visitor->isJSFrame()) { + if (visitor->isJSFrame() + && !isWebAssemblyExecutable(visitor->codeBlock()->ownerExecutable()) + && !visitor->codeBlock()->unlinkedCodeBlock()->isBuiltinFunction()) { CodeBlock* codeBlock = visitor->codeBlock(); StackFrame s = { Strong<JSObject>(vm, visitor->callee()), getStackFrameCodeType(visitor), - Strong<ExecutableBase>(vm, codeBlock->ownerExecutable()), + Strong<ScriptExecutable>(vm, codeBlock->ownerScriptExecutable()), Strong<UnlinkedCodeBlock>(vm, codeBlock->unlinkedCodeBlock()), codeBlock->source(), - codeBlock->ownerExecutable()->lineNo(), + codeBlock->ownerScriptExecutable()->firstLine(), 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<ExecutableBase>(), Strong<UnlinkedCodeBlock>(), 0, 0, 0, 0, 0, String()}; + StackFrame s = { Strong<JSObject>(vm, visitor->callee()), StackFrameNativeCode, Strong<ScriptExecutable>(), Strong<UnlinkedCodeBlock>(), 0, 0, 0, 0, 0, String()}; m_results.append(s); } @@ -576,7 +576,6 @@ 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; @@ -597,9 +596,26 @@ JSString* Interpreter::stackTraceAsString(ExecState* exec, Vector<StackFrame> st return jsString(&exec->vm(), builder.toString()); } -class GetExceptionHandlerFunctor { +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 { public: - GetExceptionHandlerFunctor() + GetCatchHandlerFunctor() : m_handler(0) { } @@ -608,12 +624,13 @@ public: StackVisitor::Status operator()(StackVisitor& visitor) { + visitor.unwindToMachineCodeBlockFrame(); + CodeBlock* codeBlock = visitor->codeBlock(); if (!codeBlock) return StackVisitor::Continue; - unsigned bytecodeOffset = visitor->bytecodeOffset(); - m_handler = codeBlock->handlerForBytecodeOffset(bytecodeOffset); + m_handler = findExceptionHandler(visitor, codeBlock, CodeBlock::RequiredHandler::CatchHandler); if (m_handler) return StackVisitor::Done; @@ -624,6 +641,18 @@ 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) @@ -636,35 +665,92 @@ 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(); - 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 + 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); + + 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(CallFrame*& callFrame, JSValue& exceptionValue) +NEVER_INLINE HandlerInfo* Interpreter::unwind(VM& vm, CallFrame*& callFrame, Exception* exception, UnwindStart unwindStart) { + 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 @@ -672,60 +758,42 @@ NEVER_INLINE HandlerInfo* Interpreter::unwind(CallFrame*& callFrame, JSValue& ex if (exceptionValue.isEmpty() || (exceptionValue.isCell() && !exceptionValue.asCell())) exceptionValue = jsNull(); - if (exceptionValue.isObject()) { - isTermination = isTerminatedExecutionException(asObject(exceptionValue)); - } + ASSERT(vm.exception() && vm.exception()->stack().size()); - ASSERT(callFrame->vm().exceptionStack().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; + + return handler; +} +void Interpreter::notifyDebuggerOfExceptionToBeThrown(CallFrame* callFrame, Exception* exception) +{ 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. - // Afterwards, the values are put back to continue processing this error. - ClearExceptionScope scope(&callFrame->vm()); + if (debugger && debugger->needsExceptionCallbacks() && !exception->didNotifyInspectorOfThrow()) { // 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; + bool isTermination = isTerminatedExecutionException(exception); 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, exception->value(), hasCatchHandler); } - - // 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; + exception->setDidNotifyInspectorOfThrow(); } static inline JSValue checkedReturn(JSValue returnValue) @@ -758,16 +826,16 @@ private: JSValue Interpreter::execute(ProgramExecutable* program, CallFrame* callFrame, JSObject* thisObj) { SamplingScope samplingScope(this); - - JSScope* scope = callFrame->scope(); + + JSScope* scope = thisObj->globalObject()->globalScope(); 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)); @@ -777,7 +845,7 @@ JSValue Interpreter::execute(ProgramExecutable* program, CallFrame* callFrame, J Vector<JSONPData> JSONPData; bool parseResult; - const String programSource = program->source().toString(); + StringView programSource = program->source().view(); if (programSource.isNull()) return jsUndefined(); if (programSource.is8Bit()) { @@ -808,10 +876,10 @@ JSValue Interpreter::execute(ProgramExecutable* program, CallFrame* callFrame, J switch (JSONPPath[i].m_type) { case JSONPPathEntryTypeDot: { if (i == 0) { - PropertySlot slot(globalObject); + PropertySlot slot(globalObject, PropertySlot::InternalMethodType::Get); 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); @@ -874,40 +942,37 @@ 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, scope, CodeForCall)) + if (JSObject* error = program->prepareForExecution(callFrame, nullptr, scope, CodeForCall)) return checkedReturn(callFrame->vm().throwException(callFrame, error)); ProgramCodeBlock* codeBlock = program->codeBlock(); - if (UNLIKELY(vm.watchdog.didFire(callFrame))) + if (UNLIKELY(vm.shouldTriggerTermination(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, 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()); + profiler->willExecute(callFrame, program->sourceURL(), program->firstLine(), program->startColumn()); // Execute the code: JSValue result; { SamplingTool::CallRecord callRecord(m_sampler.get()); - Watchdog::Scope watchdogScope(vm.watchdog); - - result = program->generatedJITCode()->execute(&vm, &protoCallFrame, m_stack.getTopOfStack()); + result = program->generatedJITCode()->execute(&vm, &protoCallFrame); } if (LegacyProfiler* profiler = vm.enabledProfiler()) - profiler->didExecute(callFrame, program->sourceURL(), program->lineNo()); + profiler->didExecute(callFrame, program->sourceURL(), program->firstLine(), program->startColumn()); return checkedReturn(result); } @@ -921,24 +986,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, scope, CodeForCall); + JSObject* compileError = callData.js.functionExecutable->prepareForExecution(callFrame, jsCast<JSFunction*>(function), scope, CodeForCall); if (UNLIKELY(!!compileError)) { return checkedReturn(callFrame->vm().throwException(callFrame, compileError)); } @@ -948,14 +1016,11 @@ JSValue Interpreter::executeCall(CallFrame* callFrame, JSObject* function, CallT } else newCodeBlock = 0; - if (UNLIKELY(vm.watchdog.didFire(callFrame))) + if (UNLIKELY(vm.shouldTriggerTermination(callFrame))) return throwTerminatedExecutionException(callFrame); - if (UNLIKELY(!m_stack.entryCheck(newCodeBlock, argsCount))) - return checkedReturn(throwStackOverflowError(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); @@ -963,13 +1028,15 @@ 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, m_stack.getTopOfStack()); - else - result = JSValue::decode(callToNativeFunction(reinterpret_cast<void*>(callData.native.function), &vm.topCallFrame, &protoCallFrame, m_stack.getTopOfStack())); + 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(); + } } if (LegacyProfiler* profiler = vm.enabledProfiler()) @@ -978,7 +1045,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) +JSObject* Interpreter::executeConstruct(CallFrame* callFrame, JSObject* constructor, ConstructType constructType, const ConstructData& constructData, const ArgList& args, JSValue newTarget) { VM& vm = callFrame->vm(); ASSERT(!callFrame->hadException()); @@ -989,24 +1056,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, scope, CodeForConstruct); + JSObject* compileError = constructData.js.functionExecutable->prepareForExecution(callFrame, jsCast<JSFunction*>(constructor), scope, CodeForConstruct); if (UNLIKELY(!!compileError)) { return checkedReturn(callFrame->vm().throwException(callFrame, compileError)); } @@ -1016,14 +1086,11 @@ JSObject* Interpreter::executeConstruct(CallFrame* callFrame, JSObject* construc } else newCodeBlock = 0; - if (UNLIKELY(vm.watchdog.didFire(callFrame))) + if (UNLIKELY(vm.shouldTriggerTermination(callFrame))) return throwTerminatedExecutionException(callFrame); - if (UNLIKELY(!m_stack.entryCheck(newCodeBlock, argsCount))) - return checkedReturn(throwStackOverflowError(callFrame)); - ProtoCallFrame protoCallFrame; - protoCallFrame.init(newCodeBlock, scope, constructor, jsUndefined(), argsCount, args.data()); + protoCallFrame.init(newCodeBlock, constructor, newTarget, argsCount, args.data()); if (LegacyProfiler* profiler = vm.enabledProfiler()) profiler->willExecute(callFrame, constructor); @@ -1031,13 +1098,12 @@ 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, m_stack.getTopOfStack()); + result = constructData.js.functionExecutable->generatedJITCodeForConstruct()->execute(&vm, &protoCallFrame); else { - result = JSValue::decode(callToNativeFunction(reinterpret_cast<void*>(constructData.native.function), &vm.topCallFrame, &protoCallFrame, m_stack.getTopOfStack())); + result = JSValue::decode(vmEntryToNative(reinterpret_cast<void*>(constructData.native.function), &vm, &protoCallFrame)); if (!callFrame->hadException()) RELEASE_ASSERT(result.isObject()); @@ -1062,7 +1128,7 @@ CallFrameClosure Interpreter::prepareForRepeatCall(FunctionExecutable* functionE return CallFrameClosure(); // Compile the callee: - JSObject* error = functionExecutable->prepareForExecution(callFrame, scope, CodeForCall); + JSObject* error = functionExecutable->prepareForExecution(callFrame, function, scope, CodeForCall); if (error) { callFrame->vm().throwException(callFrame, error); return CallFrameClosure(); @@ -1072,12 +1138,7 @@ CallFrameClosure Interpreter::prepareForRepeatCall(FunctionExecutable* functionE size_t argsCount = argumentCountIncludingThis; - if (UNLIKELY(!m_stack.entryCheck(newCodeBlock, argsCount))) { - throwStackOverflowError(callFrame); - return CallFrameClosure(); - } - - 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; @@ -1089,25 +1150,23 @@ 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.watchdog.didFire(closure.oldCallFrame))) + if (UNLIKELY(vm.shouldTriggerTermination(closure.oldCallFrame))) return throwTerminatedExecutionException(closure.oldCallFrame); // Execute the code: JSValue result; { SamplingTool::CallRecord callRecord(m_sampler.get()); - Watchdog::Scope watchdogScope(vm.watchdog); - - result = closure.functionExecutable->generatedJITCodeForCall()->execute(&vm, closure.protoCallFrame, m_stack.getTopOfStack()); + result = closure.functionExecutable->generatedJITCodeForCall()->execute(&vm, closure.protoCallFrame); } if (LegacyProfiler* profiler = vm.enabledProfiler()) @@ -1124,6 +1183,7 @@ 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(); @@ -1136,27 +1196,55 @@ 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->isGlobalObject()) { variableObject = node; break; + } + if (JSLexicalEnvironment* lexicalEnvironment = jsDynamicCast<JSLexicalEnvironment*>(node)) { + if (lexicalEnvironment->symbolTable()->scopeType() == SymbolTable::ScopeType::VarScope) { + variableObject = node; + break; + } } } } - JSObject* compileError = eval->prepareForExecution(callFrame, scope, CodeForCall); + JSObject* compileError = eval->prepareForExecution(callFrame, nullptr, 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(); + variableObject->globalObject()->varInjectionWatchpoint()->fireAll("Executed eval, fired VarInjection watchpoint"); for (unsigned i = 0; i < numVariables; ++i) { const Identifier& ident = codeBlock->variable(i); @@ -1173,31 +1261,74 @@ JSValue Interpreter::execute(EvalExecutable* eval, CallFrame* callFrame, JSValue } } - if (UNLIKELY(vm.watchdog.didFire(callFrame))) + if (UNLIKELY(vm.shouldTriggerTermination(callFrame))) return throwTerminatedExecutionException(callFrame); ASSERT(codeBlock->numParameters() == 1); // 1 parameter for 'this'. - if (UNLIKELY(!m_stack.entryCheck(codeBlock, 1))) + 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()) 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, scope, 0, thisValue, 1); + protoCallFrame.init(codeBlock, JSCallee::create(vm, scope->globalObject(), scope), jsUndefined(), 1); if (LegacyProfiler* profiler = vm.enabledProfiler()) - profiler->willExecute(callFrame, eval->sourceURL(), eval->lineNo()); + profiler->willExecute(callFrame, executable->sourceURL(), executable->firstLine(), executable->startColumn()); // Execute the code: JSValue result; { SamplingTool::CallRecord callRecord(m_sampler.get()); - Watchdog::Scope watchdogScope(vm.watchdog); - - result = eval->generatedJITCode()->execute(&vm, &protoCallFrame, m_stack.getTopOfStack()); + result = executable->generatedJITCode()->execute(&vm, &protoCallFrame); } if (LegacyProfiler* profiler = vm.enabledProfiler()) - profiler->didExecute(callFrame, eval->sourceURL(), eval->lineNo()); + profiler->didExecute(callFrame, executable->sourceURL(), executable->firstLine(), executable->startColumn()); return checkedReturn(result); } @@ -1207,35 +1338,38 @@ NEVER_INLINE void Interpreter::debug(CallFrame* callFrame, DebugHookID debugHook Debugger* debugger = callFrame->vmEntryGlobalObject()->debugger(); if (!debugger) return; - ASSERT(callFrame->codeBlock()->hasDebuggerRequests() || callFrame->hadException()); + + ASSERT(callFrame->codeBlock()->hasDebuggerRequests()); + ASSERT(!callFrame->hadException()); switch (debugHookID) { case DidEnterCallFrame: debugger->callEvent(callFrame); - return; + break; case WillLeaveCallFrame: debugger->returnEvent(callFrame); - return; + break; case WillExecuteStatement: debugger->atStatement(callFrame); - return; + break; case WillExecuteProgram: debugger->willExecuteProgram(callFrame); - return; + break; case DidExecuteProgram: debugger->didExecuteProgram(callFrame); - return; + break; case DidReachBreakpoint: debugger->didReachBreakpoint(callFrame); - return; + break; } + ASSERT(!callFrame->hadException()); } void Interpreter::enableSampler() { #if ENABLE(OPCODE_SAMPLING) if (!m_sampler) { - m_sampler = adoptPtr(new SamplingTool(this)); + m_sampler = std::make_unique<SamplingTool>(this); m_sampler->setup(); } #endif |