diff options
author | Allan Sandfeld Jensen <allan.jensen@digia.com> | 2013-09-13 12:51:20 +0200 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2013-09-19 20:50:05 +0200 |
commit | d441d6f39bb846989d95bcf5caf387b42414718d (patch) | |
tree | e367e64a75991c554930278175d403c072de6bb8 /Source/JavaScriptCore/interpreter/Interpreter.cpp | |
parent | 0060b2994c07842f4c59de64b5e3e430525c4b90 (diff) | |
download | qtwebkit-d441d6f39bb846989d95bcf5caf387b42414718d.tar.gz |
Import Qt5x2 branch of QtWebkit for Qt 5.2
Importing a new snapshot of webkit.
Change-Id: I2d01ad12cdc8af8cb015387641120a9d7ea5f10c
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@digia.com>
Diffstat (limited to 'Source/JavaScriptCore/interpreter/Interpreter.cpp')
-rw-r--r-- | Source/JavaScriptCore/interpreter/Interpreter.cpp | 538 |
1 files changed, 259 insertions, 279 deletions
diff --git a/Source/JavaScriptCore/interpreter/Interpreter.cpp b/Source/JavaScriptCore/interpreter/Interpreter.cpp index 7d9e6f92e..844f5f252 100644 --- a/Source/JavaScriptCore/interpreter/Interpreter.cpp +++ b/Source/JavaScriptCore/interpreter/Interpreter.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008, 2009, 2010, 2012 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 @@ -52,21 +52,23 @@ #include "JSString.h" #include "JSWithScope.h" #include "LLIntCLoop.h" +#include "LegacyProfiler.h" #include "LiteralParser.h" #include "NameInstance.h" #include "ObjectPrototype.h" #include "Operations.h" #include "Parser.h" -#include "Profiler.h" #include "RegExpObject.h" #include "RegExpPrototype.h" #include "Register.h" #include "SamplingTool.h" #include "StrictEvalActivation.h" #include "StrongInlines.h" +#include "VMStackBounds.h" #include <limits.h> #include <stdio.h> #include <wtf/StackStats.h> +#include <wtf/StringPrintStream.h> #include <wtf/Threading.h> #include <wtf/WTFThreadData.h> #include <wtf/text/StringBuilder.h> @@ -97,108 +99,7 @@ Interpreter::ErrorHandlingMode::~ErrorHandlingMode() m_interpreter.stack().disableErrorStackReserve(); } - -// The Interpreter::StackPolicy class is used to compute a stack capacity -// requirement to ensure that we have enough room on the native stack for: -// 1. the max cumulative stack used by the interpreter and all code -// paths sub of it up till leaf functions. -// 2. the max cumulative stack used by the interpreter before it reaches -// the next checkpoint (execute...() function) in the interpreter. -// -// The interpreter can be run on different threads and hence, different -// native stacks (with different sizes) before exiting out of the first -// frame. Hence, the required capacity needs to be re-computed on every -// entry into the interpreter. -// -// Currently the requiredStack is computed based on a policy. See comments -// in StackPolicy::StackPolicy() for details. - -Interpreter::StackPolicy::StackPolicy(Interpreter& interpreter, const StackBounds& stack) - : m_interpreter(interpreter) -{ - const size_t size = stack.size(); - - const size_t DEFAULT_REQUIRED_STACK = 1024 * 1024; - const size_t DEFAULT_MINIMUM_USEABLE_STACK = 128 * 1024; - const size_t DEFAULT_ERROR_MODE_REQUIRED_STACK = 32 * 1024; - - // Here's the policy in a nutshell: - // - // 1. If we have a large stack, let JS use as much stack as possible - // but require that we have at least DEFAULT_REQUIRED_STACK capacity - // remaining on the stack: - // - // stack grows this way --> - // --------------------------------------------------------- - // | ... | <-- DEFAULT_REQUIRED_STACK --> | ... - // --------------------------------------------------------- - // ^ ^ - // start current sp - // - // 2. In event that we're re-entering the interpreter to handle - // exceptions (in error mode), we'll be a little more generous and - // require less stack capacity for the interpreter to be re-entered. - // - // This is needed because we may have just detected an eminent stack - // overflow based on the normally computed required stack capacity. - // However, the normal required capacity far exceeds what is needed - // for exception handling work. Hence, in error mode, we only require - // DEFAULT_ERROR_MODE_REQUIRED_STACK capacity. - // - // stack grows this way --> - // ----------------------------------------------------------------- - // | ... | <-- DEFAULT_ERROR_MODE_REQUIRED_STACK --> | ... - // ----------------------------------------------------------------- - // ^ ^ - // start current sp - // - // This smaller required capacity also means that we won't re-trigger - // a stack overflow for processing the exception caused by the original - // StackOverflowError. - // - // 3. If the stack is not large enough, give JS at least a minimum - // amount of useable stack: - // - // stack grows this way --> - // -------------------------------------------------------------------- - // | <-- DEFAULT_MINIMUM_USEABLE_STACK --> | <-- requiredCapacity --> | - // -------------------------------------------------------------------- - // ^ ^ - // start current sp - // - // The minimum useable capacity is DEFAULT_MINIMUM_USEABLE_STACK. - // In this case, the requiredCapacity is whatever is left of the - // total stack capacity after we have give JS its minimum stack - // i.e. requiredCapacity can even be 0 if there's not enough stack. - - - // Policy 1: Normal mode: required = DEFAULT_REQUIRED_STACK. - // Policy 2: Error mode: required = DEFAULT_ERROR_MODE_REQUIRED_STACK. - size_t requiredCapacity = !m_interpreter.m_errorHandlingModeReentry ? - DEFAULT_REQUIRED_STACK : DEFAULT_ERROR_MODE_REQUIRED_STACK; - - size_t useableStack = (requiredCapacity <= size) ? - size - requiredCapacity : DEFAULT_MINIMUM_USEABLE_STACK; - - // Policy 3: Ensure the useable stack is not too small: - if (useableStack < DEFAULT_MINIMUM_USEABLE_STACK) - useableStack = DEFAULT_MINIMUM_USEABLE_STACK; - - // Sanity check: Make sure we do not use more space than the stack's - // total capacity: - if (useableStack > size) - useableStack = size; - - // Re-compute the requiredCapacity based on the adjusted useable stack - // size: - requiredCapacity = size - useableStack; - ASSERT(requiredCapacity < size); - - m_requiredCapacity = requiredCapacity; -} - - -static CallFrame* getCallerInfo(JSGlobalData*, CallFrame*, int& lineNumber, unsigned& bytecodeOffset); +static CallFrame* getCallerInfo(VM*, CallFrame*, unsigned& bytecodeOffset, CodeBlock*& callerOut); // Returns the depth of the scope chain within a given call frame. static int depth(CodeBlock* codeBlock, JSScope* sc) @@ -217,7 +118,7 @@ JSValue eval(CallFrame* callFrame) if (!program.isString()) return program; - TopCallFrameSetter topCallFrame(callFrame->globalData(), callFrame); + TopCallFrameSetter topCallFrame(callFrame->vm(), callFrame); String programSource = asString(program)->value(callFrame); if (callFrame->hadException()) return JSValue(); @@ -243,10 +144,10 @@ JSValue eval(CallFrame* callFrame) } // If the literal parser bailed, it should not have thrown exceptions. - ASSERT(!callFrame->globalData().exception); + ASSERT(!callFrame->vm().exception); JSValue exceptionValue; - eval = callerCodeBlock->evalCodeCache().getSlow(callFrame, callerCodeBlock->ownerExecutable(), callerCodeBlock->isStrictMode(), programSource, callerScopeChain, exceptionValue); + eval = callerCodeBlock->evalCodeCache().getSlow(callFrame, callerCodeBlock->unlinkedCodeBlock()->codeCacheForEval().get(), callerCodeBlock->ownerExecutable(), callerCodeBlock->isStrictMode(), programSource, callerScopeChain, exceptionValue); ASSERT(!eval == exceptionValue); if (UNLIKELY(!eval)) @@ -255,7 +156,7 @@ JSValue eval(CallFrame* callFrame) JSValue thisValue = callerFrame->thisValue(); ASSERT(isValidThisObject(thisValue, callFrame)); - Interpreter* interpreter = callFrame->globalData().interpreter; + Interpreter* interpreter = callFrame->vm().interpreter; return interpreter->execute(eval, callFrame, thisValue, callerScopeChain); } @@ -265,7 +166,7 @@ CallFrame* loadVarargs(CallFrame* callFrame, JSStack* stack, JSValue thisValue, unsigned argumentCountIncludingThis = callFrame->argumentCountIncludingThis(); CallFrame* newCallFrame = CallFrame::create(callFrame->registers() + firstFreeRegister + argumentCountIncludingThis + JSStack::CallFrameHeaderSize); if (argumentCountIncludingThis > Arguments::MaxArguments + 1 || !stack->grow(newCallFrame->registers())) { - callFrame->globalData().exception = createStackOverflowError(callFrame); + callFrame->vm().exception = createStackOverflowError(callFrame); return 0; } @@ -279,7 +180,7 @@ CallFrame* loadVarargs(CallFrame* callFrame, JSStack* stack, JSValue thisValue, if (arguments.isUndefinedOrNull()) { CallFrame* newCallFrame = CallFrame::create(callFrame->registers() + firstFreeRegister + 1 + JSStack::CallFrameHeaderSize); if (!stack->grow(newCallFrame->registers())) { - callFrame->globalData().exception = createStackOverflowError(callFrame); + callFrame->vm().exception = createStackOverflowError(callFrame); return 0; } newCallFrame->setArgumentCountIncludingThis(1); @@ -288,7 +189,7 @@ CallFrame* loadVarargs(CallFrame* callFrame, JSStack* stack, JSValue thisValue, } if (!arguments.isObject()) { - callFrame->globalData().exception = createInvalidParamError(callFrame, "Function.prototype.apply", arguments); + callFrame->vm().exception = createInvalidParameterError(callFrame, "Function.prototype.apply", arguments); return 0; } @@ -297,7 +198,7 @@ CallFrame* loadVarargs(CallFrame* callFrame, JSStack* stack, JSValue thisValue, 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->globalData().exception = createStackOverflowError(callFrame); + callFrame->vm().exception = createStackOverflowError(callFrame); return 0; } newCallFrame->setArgumentCountIncludingThis(argCount + 1); @@ -311,7 +212,7 @@ CallFrame* loadVarargs(CallFrame* callFrame, JSStack* stack, JSValue thisValue, unsigned argCount = array->length(); CallFrame* newCallFrame = CallFrame::create(callFrame->registers() + firstFreeRegister + CallFrame::offsetFor(argCount + 1)); if (argCount > Arguments::MaxArguments || !stack->grow(newCallFrame->registers())) { - callFrame->globalData().exception = createStackOverflowError(callFrame); + callFrame->vm().exception = createStackOverflowError(callFrame); return 0; } newCallFrame->setArgumentCountIncludingThis(argCount + 1); @@ -324,22 +225,22 @@ CallFrame* loadVarargs(CallFrame* callFrame, JSStack* stack, JSValue thisValue, 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->globalData().exception = createStackOverflowError(callFrame); + callFrame->vm().exception = createStackOverflowError(callFrame); return 0; } 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->globalData().exception)) + if (UNLIKELY(callFrame->vm().exception)) return 0; } return newCallFrame; } -Interpreter::Interpreter(JSGlobalData& globalData) +Interpreter::Interpreter(VM& vm) : m_sampleEntryDepth(0) - , m_stack(globalData) + , m_stack(vm) , m_errorHandlingModeReentry(0) #if !ASSERT_DISABLED , m_initialized(false) @@ -401,7 +302,7 @@ void Interpreter::dumpRegisters(CallFrame* callFrame) JSValue v = it->jsValue(); int registerNumber = it - callFrame->registers(); String name = codeBlock->nameForRegister(registerNumber); - dataLogF("[r% 3d %14s] | %10p | %-16s 0x%lld \n", registerNumber, name.ascii().data(), it, v.description(), (long long)JSValue::encode(v)); + dataLogF("[r% 3d %14s] | %10p | %-16s 0x%lld \n", registerNumber, name.ascii().data(), it, toCString(v).data(), (long long)JSValue::encode(v)); it++; } @@ -415,13 +316,15 @@ void Interpreter::dumpRegisters(CallFrame* callFrame) dataLogF("[ScopeChain] | %10p | %p \n", it, callFrame->scope()); ++it; #if ENABLE(JIT) - AbstractPC pc = callFrame->abstractReturnPC(callFrame->globalData()); + AbstractPC pc = callFrame->abstractReturnPC(callFrame->vm()); if (pc.hasJITReturnAddress()) dataLogF("[ReturnJITPC] | %10p | %p \n", it, pc.jitReturnAddress().value()); #endif unsigned bytecodeOffset = 0; int line = 0; - getCallerInfo(&callFrame->globalData(), callFrame, line, bytecodeOffset); + CodeBlock* callerCodeBlock = 0; + getCallerInfo(&callFrame->vm(), callFrame, bytecodeOffset, callerCodeBlock); + line = callerCodeBlock->lineNumberForBytecodeOffset(bytecodeOffset); dataLogF("[ReturnVPC] | %10p | %d (line %d)\n", it, bytecodeOffset, line); ++it; dataLogF("[CodeBlock] | %10p | %p \n", it, callFrame->codeBlock()); @@ -436,7 +339,7 @@ void Interpreter::dumpRegisters(CallFrame* callFrame) JSValue v = it->jsValue(); int registerNumber = it - callFrame->registers(); String name = codeBlock->nameForRegister(registerNumber); - dataLogF("[r% 3d %14s] | %10p | %-16s 0x%lld \n", registerNumber, name.ascii().data(), it, v.description(), (long long)JSValue::encode(v)); + dataLogF("[r% 3d %14s] | %10p | %-16s 0x%lld \n", registerNumber, name.ascii().data(), it, toCString(v).data(), (long long)JSValue::encode(v)); ++it; ++registerCount; } while (it != end); @@ -447,7 +350,7 @@ void Interpreter::dumpRegisters(CallFrame* callFrame) if (it != end) { do { JSValue v = (*it).jsValue(); - dataLogF("[r% 3d] | %10p | %-16s 0x%lld \n", registerCount, it, v.description(), (long long)JSValue::encode(v)); + dataLogF("[r% 3d] | %10p | %-16s 0x%lld \n", registerCount, it, toCString(v).data(), (long long)JSValue::encode(v)); ++it; ++registerCount; } while (it != end); @@ -489,7 +392,7 @@ NEVER_INLINE bool Interpreter::unwindCallFrame(CallFrame*& callFrame, JSValue ex if (oldCodeBlock->codeType() == FunctionCode && oldCodeBlock->needsActivation()) { activation = callFrame->uncheckedR(oldCodeBlock->activationRegister()).jsValue(); if (activation) - jsCast<JSActivation*>(activation)->tearOff(*scope->globalData()); + jsCast<JSActivation*>(activation)->tearOff(*scope->vm()); } if (oldCodeBlock->codeType() == FunctionCode && oldCodeBlock->usesArguments()) { @@ -502,20 +405,10 @@ NEVER_INLINE bool Interpreter::unwindCallFrame(CallFrame*& callFrame, JSValue ex } CallFrame* callerFrame = callFrame->callerFrame(); - callFrame->globalData().topCallFrame = callerFrame; + callFrame->vm().topCallFrame = callerFrame; if (callerFrame->hasHostCallFrameFlag()) return false; - - codeBlock = callerFrame->codeBlock(); - - // Because of how the JIT records call site->bytecode offset - // information the JIT reports the bytecodeOffset for the returnPC - // to be at the beginning of the opcode that has caused the call. -#if ENABLE(JIT) || ENABLE(LLINT) - bytecodeOffset = codeBlock->bytecodeOffset(callerFrame, callFrame->returnPC()); -#endif - - callFrame = callerFrame; + callFrame = getCallerInfo(&callFrame->vm(), callFrame, bytecodeOffset, codeBlock); return true; } @@ -529,9 +422,11 @@ static void appendSourceToError(CallFrame* callFrame, ErrorInstance* exception, int startOffset = 0; int endOffset = 0; int divotPoint = 0; + unsigned line = 0; + unsigned column = 0; CodeBlock* codeBlock = callFrame->codeBlock(); - codeBlock->expressionRangeForBytecodeOffset(bytecodeOffset, divotPoint, startOffset, endOffset); + codeBlock->expressionRangeForBytecodeOffset(bytecodeOffset, divotPoint, startOffset, endOffset, line, column); int expressionStart = divotPoint - startOffset; int expressionStop = divotPoint + endOffset; @@ -540,8 +435,8 @@ static void appendSourceToError(CallFrame* callFrame, ErrorInstance* exception, if (!expressionStop || expressionStart > static_cast<int>(sourceString.length())) return; - JSGlobalData* globalData = &callFrame->globalData(); - JSValue jsMessage = exception->getDirect(*globalData, globalData->propertyNames->message); + VM* vm = &callFrame->vm(); + JSValue jsMessage = exception->getDirect(*vm, vm->propertyNames->message); if (!jsMessage || !jsMessage.isString()) return; @@ -568,64 +463,54 @@ static void appendSourceToError(CallFrame* callFrame, ErrorInstance* exception, message = makeString(message, " (near '...", codeBlock->source()->getRange(start, stop), "...')"); } - exception->putDirect(*globalData, globalData->propertyNames->message, jsString(globalData, message)); + exception->putDirect(*vm, vm->propertyNames->message, jsString(vm, message)); } -static int getLineNumberForCallFrame(JSGlobalData* globalData, CallFrame* callFrame) +static unsigned getBytecodeOffsetForCallFrame(CallFrame* callFrame) { - UNUSED_PARAM(globalData); callFrame = callFrame->removeHostCallFrameFlag(); CodeBlock* codeBlock = callFrame->codeBlock(); if (!codeBlock) - return -1; -#if ENABLE(JIT) || ENABLE(LLINT) + return 0; #if ENABLE(DFG_JIT) if (codeBlock->getJITType() == JITCode::DFGJIT) - return codeBlock->lineNumberForBytecodeOffset(codeBlock->codeOrigin(callFrame->codeOriginIndexForDFG()).bytecodeIndex); -#endif - return codeBlock->lineNumberForBytecodeOffset(callFrame->bytecodeOffsetForNonDFGCode()); + return codeBlock->codeOrigin(callFrame->codeOriginIndexForDFG()).bytecodeIndex; #endif + return callFrame->bytecodeOffsetForNonDFGCode(); } -static CallFrame* getCallerInfo(JSGlobalData* globalData, CallFrame* callFrame, int& lineNumber, unsigned& bytecodeOffset) +static CallFrame* getCallerInfo(VM* vm, CallFrame* callFrame, unsigned& bytecodeOffset, CodeBlock*& caller) { - UNUSED_PARAM(globalData); + ASSERT_UNUSED(vm, vm); bytecodeOffset = 0; - lineNumber = -1; ASSERT(!callFrame->hasHostCallFrameFlag()); - CallFrame* callerFrame = callFrame->codeBlock() ? callFrame->trueCallerFrame() : callFrame->callerFrame()->removeHostCallFrameFlag(); - bool callframeIsHost = callerFrame->addHostCallFrameFlag() == callFrame->callerFrame(); - ASSERT(!callerFrame->hasHostCallFrameFlag()); + CallFrame* trueCallerFrame = callFrame->trueCallerFrame(); + bool wasCalledByHost = callFrame->callerFrame()->hasHostCallFrameFlag(); + ASSERT(!trueCallerFrame->hasHostCallFrameFlag()); - if (callerFrame == CallFrame::noCaller() || !callerFrame || !callerFrame->codeBlock()) - return callerFrame; + if (trueCallerFrame == CallFrame::noCaller() || !trueCallerFrame || !trueCallerFrame->codeBlock()) { + caller = 0; + return trueCallerFrame; + } - CodeBlock* callerCodeBlock = callerFrame->codeBlock(); + CodeBlock* callerCodeBlock = trueCallerFrame->codeBlock(); -#if ENABLE(JIT) || ENABLE(LLINT) if (!callFrame->hasReturnPC()) - callframeIsHost = true; -#endif -#if ENABLE(DFG_JIT) - if (callFrame->isInlineCallFrame()) - callframeIsHost = false; -#endif + wasCalledByHost = true; - if (callframeIsHost) { - // Don't need to deal with inline callframes here as by definition we haven't - // inlined a call with an intervening native call frame. -#if ENABLE(JIT) || ENABLE(LLINT) + if (wasCalledByHost) { #if ENABLE(DFG_JIT) if (callerCodeBlock && callerCodeBlock->getJITType() == JITCode::DFGJIT) { - unsigned codeOriginIndex = callerFrame->codeOriginIndexForDFG(); - bytecodeOffset = callerCodeBlock->codeOrigin(codeOriginIndex).bytecodeIndex; + unsigned codeOriginIndex = callFrame->callerFrame()->removeHostCallFrameFlag()->codeOriginIndexForDFG(); + CodeOrigin origin = callerCodeBlock->codeOrigin(codeOriginIndex); + bytecodeOffset = origin.bytecodeIndex; + if (InlineCallFrame* inlineCallFrame = origin.inlineCallFrame) + callerCodeBlock = inlineCallFrame->baselineCodeBlock(); } else #endif - bytecodeOffset = callerFrame->bytecodeOffsetForNonDFGCode(); -#endif + bytecodeOffset = trueCallerFrame->bytecodeOffsetForNonDFGCode(); } else { -#if ENABLE(JIT) || ENABLE(LLINT) - #if ENABLE(DFG_JIT) +#if ENABLE(DFG_JIT) if (callFrame->isInlineCallFrame()) { InlineCallFrame* icf = callFrame->inlineCallFrame(); bytecodeOffset = icf->caller.bytecodeIndex; @@ -638,8 +523,14 @@ static CallFrame* getCallerInfo(JSGlobalData* globalData, CallFrame* callFrame, } } else if (callerCodeBlock && callerCodeBlock->getJITType() == JITCode::DFGJIT) { CodeOrigin origin; - if (!callerCodeBlock->codeOriginForReturn(callFrame->returnPC(), origin)) + if (!callerCodeBlock->codeOriginForReturn(callFrame->returnPC(), origin)) { + // This should not be possible, but we're seeing cases where it does happen + // CallFrame already has robustness against bogus stack walks, so + // we'll extend that to here as well. ASSERT_NOT_REACHED(); + caller = 0; + return 0; + } bytecodeOffset = origin.bytecodeIndex; if (InlineCallFrame* icf = origin.inlineCallFrame) { FunctionExecutable* executable = static_cast<FunctionExecutable*>(icf->executable.get()); @@ -649,13 +540,16 @@ static CallFrame* getCallerInfo(JSGlobalData* globalData, CallFrame* callFrame, callerCodeBlock = newCodeBlock; } } else - #endif - bytecodeOffset = callerCodeBlock->bytecodeOffset(callerFrame, callFrame->returnPC()); #endif + { + RELEASE_ASSERT(callerCodeBlock); + bytecodeOffset = callerCodeBlock->bytecodeOffset(trueCallerFrame, callFrame->returnPC()); + } } - lineNumber = callerCodeBlock->lineNumberForBytecodeOffset(bytecodeOffset); - return callerFrame; + RELEASE_ASSERT(callerCodeBlock); + caller = callerCodeBlock; + return trueCallerFrame; } static ALWAYS_INLINE const String getSourceURLFromCallFrame(CallFrame* callFrame) @@ -676,52 +570,118 @@ static StackFrameCodeType getStackFrameCodeType(CallFrame* callFrame) case GlobalCode: return StackFrameGlobalCode; } - ASSERT_NOT_REACHED(); + RELEASE_ASSERT_NOT_REACHED(); return StackFrameGlobalCode; } -void Interpreter::getStackTrace(JSGlobalData* globalData, Vector<StackFrame>& results) +void StackFrame::computeLineAndColumn(unsigned& line, unsigned& column) { - CallFrame* callFrame = globalData->topCallFrame->removeHostCallFrameFlag(); - if (!callFrame || callFrame == CallFrame::noCaller()) + if (!codeBlock) { + line = 0; + column = 0; return; - int line = getLineNumberForCallFrame(globalData, callFrame); + } + int divot = 0; + int unusedStartOffset = 0; + int unusedEndOffset = 0; + unsigned divotLine = 0; + unsigned divotColumn = 0; + expressionInfo(divot, unusedStartOffset, unusedEndOffset, divotLine, divotColumn); + + line = divotLine + lineOffset; + column = divotColumn + (divotLine ? 1 : firstLineColumnOffset); +} + +void StackFrame::expressionInfo(int& divot, int& startOffset, int& endOffset, unsigned& line, unsigned& column) +{ + codeBlock->expressionRangeForBytecodeOffset(bytecodeOffset, divot, startOffset, endOffset, line, column); + divot += characterOffset; +} + +String StackFrame::toString(CallFrame* callFrame) +{ + StringBuilder traceBuild; + String functionName = friendlyFunctionName(callFrame); + String sourceURL = friendlySourceURL(); + traceBuild.append(functionName); + if (!sourceURL.isEmpty()) { + if (!functionName.isEmpty()) + traceBuild.append('@'); + traceBuild.append(sourceURL); + if (codeType != StackFrameNativeCode) { + unsigned line; + unsigned column; + computeLineAndColumn(line, column); + + traceBuild.append(':'); + traceBuild.appendNumber(line); + traceBuild.append(':'); + traceBuild.appendNumber(column); + } + } + return traceBuild.toString().impl(); +} + +void Interpreter::getStackTrace(VM* vm, Vector<StackFrame>& results, size_t maxStackSize) +{ + CallFrame* callFrame = vm->topCallFrame->removeHostCallFrameFlag(); + if (!callFrame || callFrame == CallFrame::noCaller()) + return; + unsigned bytecodeOffset = getBytecodeOffsetForCallFrame(callFrame); callFrame = callFrame->trueCallFrameFromVMCode(); + if (!callFrame) + return; + CodeBlock* callerCodeBlock = callFrame->codeBlock(); - while (callFrame && callFrame != CallFrame::noCaller()) { + while (callFrame && callFrame != CallFrame::noCaller() && maxStackSize--) { String sourceURL; - if (callFrame->codeBlock()) { + if (callerCodeBlock) { sourceURL = getSourceURLFromCallFrame(callFrame); - StackFrame s = { Strong<JSObject>(*globalData, callFrame->callee()), getStackFrameCodeType(callFrame), Strong<ExecutableBase>(*globalData, callFrame->codeBlock()->ownerExecutable()), line, sourceURL}; + StackFrame s = { + Strong<JSObject>(*vm, callFrame->callee()), + getStackFrameCodeType(callFrame), + Strong<ExecutableBase>(*vm, callerCodeBlock->ownerExecutable()), + Strong<UnlinkedCodeBlock>(*vm, callerCodeBlock->unlinkedCodeBlock()), + callerCodeBlock->source(), + callerCodeBlock->ownerExecutable()->lineNo(), + callerCodeBlock->firstLineColumnOffset(), + callerCodeBlock->sourceOffset(), + bytecodeOffset, + sourceURL + }; + results.append(s); } else { - StackFrame s = { Strong<JSObject>(*globalData, callFrame->callee()), StackFrameNativeCode, Strong<ExecutableBase>(), -1, String()}; + StackFrame s = { Strong<JSObject>(*vm, callFrame->callee()), StackFrameNativeCode, Strong<ExecutableBase>(), Strong<UnlinkedCodeBlock>(), 0, 0, 0, 0, 0, String()}; results.append(s); } - unsigned unusedBytecodeOffset = 0; - callFrame = getCallerInfo(globalData, callFrame, line, unusedBytecodeOffset); + callFrame = getCallerInfo(vm, callFrame, bytecodeOffset, callerCodeBlock); } } -void Interpreter::addStackTraceIfNecessary(CallFrame* callFrame, JSObject* error) +void Interpreter::addStackTraceIfNecessary(CallFrame* callFrame, JSValue error) { - JSGlobalData* globalData = &callFrame->globalData(); - ASSERT(callFrame == globalData->topCallFrame || callFrame == callFrame->lexicalGlobalObject()->globalExec() || callFrame == callFrame->dynamicGlobalObject()->globalExec()); - if (error->hasProperty(callFrame, globalData->propertyNames->stack)) - return; + VM* vm = &callFrame->vm(); + ASSERT(callFrame == vm->topCallFrame || callFrame == callFrame->lexicalGlobalObject()->globalExec() || callFrame == callFrame->dynamicGlobalObject()->globalExec()); - Vector<StackFrame> stackTrace; - getStackTrace(&callFrame->globalData(), stackTrace); + if (error.isObject()) { + if (asObject(error)->hasProperty(callFrame, vm->propertyNames->stack)) + return; + } - if (stackTrace.isEmpty()) + Vector<StackFrame> stackTrace; + getStackTrace(&callFrame->vm(), stackTrace); + vm->exceptionStack() = RefCountedArray<StackFrame>(stackTrace); + if (stackTrace.isEmpty() || !error.isObject()) return; - + + JSObject* errorObject = asObject(error); JSGlobalObject* globalObject = 0; - if (isTerminatedExecutionException(error) || isInterruptedExecutionException(error)) - globalObject = globalData->dynamicGlobalObject; + if (isTerminatedExecutionException(error)) + globalObject = vm->dynamicGlobalObject; else - globalObject = error->globalObject(); + globalObject = errorObject->globalObject(); // FIXME: JSStringJoiner could be more efficient than StringBuilder here. StringBuilder builder; @@ -730,14 +690,14 @@ void Interpreter::addStackTraceIfNecessary(CallFrame* callFrame, JSObject* error if (i != stackTrace.size() - 1) builder.append('\n'); } - - error->putDirect(*globalData, globalData->propertyNames->stack, jsString(globalData, builder.toString()), ReadOnly | DontDelete); + + errorObject->putDirect(*vm, vm->propertyNames->stack, jsString(vm, builder.toString()), ReadOnly | DontDelete); } NEVER_INLINE HandlerInfo* Interpreter::throwException(CallFrame*& callFrame, JSValue& exceptionValue, unsigned bytecodeOffset) { CodeBlock* codeBlock = callFrame->codeBlock(); - bool isInterrupt = false; + bool isTermination = false; ASSERT(!exceptionValue.isEmpty()); ASSERT(!exceptionValue.isCell() || exceptionValue.asCell()); @@ -759,7 +719,13 @@ NEVER_INLINE HandlerInfo* Interpreter::throwException(CallFrame*& callFrame, JSV addErrorInfo(callFrame, exception, codeBlock->lineNumberForBytecodeOffset(bytecodeOffset), codeBlock->ownerExecutable()->source()); } - isInterrupt = isInterruptedExecutionException(exception) || isTerminatedExecutionException(exception); + isTermination = isTerminatedExecutionException(exception); + } else { + if (!callFrame->vm().exceptionStack().size()) { + Vector<StackFrame> stack; + Interpreter::getStackTrace(&callFrame->vm(), stack); + callFrame->vm().exceptionStack() = RefCountedArray<StackFrame>(stack); + } } if (Debugger* debugger = callFrame->dynamicGlobalObject()->debugger()) { @@ -770,15 +736,15 @@ NEVER_INLINE HandlerInfo* Interpreter::throwException(CallFrame*& callFrame, JSV // Calculate an exception handler vPC, unwinding call frames as necessary. HandlerInfo* handler = 0; - while (isInterrupt || !(handler = codeBlock->handlerForBytecodeOffset(bytecodeOffset))) { + while (isTermination || !(handler = codeBlock->handlerForBytecodeOffset(bytecodeOffset))) { if (!unwindCallFrame(callFrame, exceptionValue, bytecodeOffset, codeBlock)) { - if (Profiler* profiler = callFrame->globalData().enabledProfiler()) + if (LegacyProfiler* profiler = callFrame->vm().enabledProfiler()) profiler->exceptionUnwind(callFrame); return 0; } } - if (Profiler* profiler = callFrame->globalData().enabledProfiler()) + if (LegacyProfiler* profiler = callFrame->vm().enabledProfiler()) profiler->exceptionUnwind(callFrame); // Unwind the scope chain within the exception handler's call frame. @@ -789,7 +755,7 @@ NEVER_INLINE HandlerInfo* Interpreter::throwException(CallFrame*& callFrame, JSV int currentDepth = depth(codeBlock, scope); int targetDepth = handler->scopeDepth; scopeDelta = currentDepth - targetDepth; - ASSERT(scopeDelta >= 0); + RELEASE_ASSERT(scopeDelta >= 0); } while (scopeDelta--) scope = scope->next(); @@ -830,24 +796,23 @@ JSValue Interpreter::execute(ProgramExecutable* program, CallFrame* callFrame, J SamplingScope samplingScope(this); JSScope* scope = callFrame->scope(); - JSGlobalData& globalData = *scope->globalData(); + VM& vm = *scope->vm(); ASSERT(isValidThisObject(thisObj, callFrame)); - ASSERT(!globalData.exception); - ASSERT(!globalData.isCollectorBusy()); - if (globalData.isCollectorBusy()) - CRASH(); + ASSERT(!vm.exception); + ASSERT(!vm.isCollectorBusy()); + if (vm.isCollectorBusy()) + return jsNull(); StackStats::CheckPoint stackCheckPoint; - const StackBounds& nativeStack = wtfThreadData().stack(); - StackPolicy policy(*this, nativeStack); - if (!nativeStack.isSafeToRecurse(policy.requiredCapacity())) + const VMStackBounds vmStackBounds(vm, wtfThreadData().stack()); + if (!vmStackBounds.isSafeToRecurse()) return checkedReturn(throwStackOverflowError(callFrame)); // First check if the "program" is actually just a JSON object. If so, // we'll handle the JSON object here. Else, we'll handle real JS code // below at failedJSONP. - DynamicGlobalObjectScope globalObjectScope(globalData, scope->globalObject()); + DynamicGlobalObjectScope globalObjectScope(vm, scope->globalObject()); Vector<JSONPData> JSONPData; bool parseResult; const String programSource = program->source().toString(); @@ -904,7 +869,7 @@ JSValue Interpreter::execute(ProgramExecutable* program, CallFrame* callFrame, J continue; } default: - ASSERT_NOT_REACHED(); + RELEASE_ASSERT_NOT_REACHED(); return jsUndefined(); } } @@ -939,7 +904,7 @@ JSValue Interpreter::execute(ProgramExecutable* program, CallFrame* callFrame, J break; } default: - ASSERT_NOT_REACHED(); + RELEASE_ASSERT_NOT_REACHED(); return jsUndefined(); } result = JSONPValue; @@ -951,7 +916,7 @@ failedJSONP: // object. // Compile source to bytecode if necessary: - if (JSObject* error = program->initalizeGlobalProperties(globalData, callFrame, scope)) + if (JSObject* error = program->initializeGlobalProperties(vm, callFrame, scope)) return checkedReturn(throwError(callFrame, error)); if (JSObject* error = program->compile(callFrame, scope)) @@ -959,6 +924,9 @@ failedJSONP: ProgramCodeBlock* codeBlock = &program->generatedBytecode(); + if (UNLIKELY(vm.watchdog.didFire(callFrame))) + return throwTerminatedExecutionException(callFrame); + // Push the call frame for this invocation: ASSERT(codeBlock->numParameters() == 1); // 1 parameter for 'this'. CallFrame* newCallFrame = m_stack.pushFrame(callFrame, codeBlock, scope, 1, 0); @@ -968,22 +936,23 @@ failedJSONP: // Set the arguments for the callee: newCallFrame->setThisValue(thisObj); - if (Profiler* profiler = globalData.enabledProfiler()) + if (LegacyProfiler* profiler = vm.enabledProfiler()) profiler->willExecute(callFrame, program->sourceURL(), program->lineNo()); // Execute the code: JSValue result; { SamplingTool::CallRecord callRecord(m_sampler.get()); + Watchdog::Scope watchdogScope(vm.watchdog); #if ENABLE(LLINT_C_LOOP) result = LLInt::CLoop::execute(newCallFrame, llint_program_prologue); #elif ENABLE(JIT) - result = program->generatedJITCode().execute(&m_stack, newCallFrame, &globalData); + result = program->generatedJITCode().execute(&m_stack, newCallFrame, &vm); #endif // ENABLE(JIT) } - if (Profiler* profiler = globalData.enabledProfiler()) + if (LegacyProfiler* profiler = vm.enabledProfiler()) profiler->didExecute(callFrame, program->sourceURL(), program->lineNo()); m_stack.popFrame(newCallFrame); @@ -993,17 +962,16 @@ failedJSONP: JSValue Interpreter::executeCall(CallFrame* callFrame, JSObject* function, CallType callType, const CallData& callData, JSValue thisValue, const ArgList& args) { - JSGlobalData& globalData = callFrame->globalData(); + VM& vm = callFrame->vm(); ASSERT(isValidThisObject(thisValue, callFrame)); ASSERT(!callFrame->hadException()); - ASSERT(!globalData.isCollectorBusy()); - if (globalData.isCollectorBusy()) + ASSERT(!vm.isCollectorBusy()); + if (vm.isCollectorBusy()) return jsNull(); StackStats::CheckPoint stackCheckPoint; - const StackBounds& nativeStack = wtfThreadData().stack(); - StackPolicy policy(*this, nativeStack); - if (!nativeStack.isSafeToRecurse(policy.requiredCapacity())) + const VMStackBounds vmStackBounds(vm, wtfThreadData().stack()); + if (!vmStackBounds.isSafeToRecurse()) return checkedReturn(throwStackOverflowError(callFrame)); bool isJSCall = (callType == CallTypeJS); @@ -1017,7 +985,7 @@ JSValue Interpreter::executeCall(CallFrame* callFrame, JSObject* function, CallT ASSERT(callType == CallTypeHost); scope = callFrame->scope(); } - DynamicGlobalObjectScope globalObjectScope(globalData, scope->globalObject()); + DynamicGlobalObjectScope globalObjectScope(vm, scope->globalObject()); if (isJSCall) { // Compile the callee: @@ -1030,6 +998,9 @@ JSValue Interpreter::executeCall(CallFrame* callFrame, JSObject* function, CallT } else newCodeBlock = 0; + if (UNLIKELY(vm.watchdog.didFire(callFrame))) + return throwTerminatedExecutionException(callFrame); + CallFrame* newCallFrame = m_stack.pushFrame(callFrame, newCodeBlock, scope, argsCount, function); if (UNLIKELY(!newCallFrame)) return checkedReturn(throwStackOverflowError(callFrame)); @@ -1039,25 +1010,26 @@ JSValue Interpreter::executeCall(CallFrame* callFrame, JSObject* function, CallT for (size_t i = 0; i < args.size(); ++i) newCallFrame->setArgument(i, args.at(i)); - if (Profiler* profiler = globalData.enabledProfiler()) + if (LegacyProfiler* profiler = vm.enabledProfiler()) profiler->willExecute(callFrame, function); JSValue result; { SamplingTool::CallRecord callRecord(m_sampler.get(), !isJSCall); + Watchdog::Scope watchdogScope(vm.watchdog); // Execute the code: if (isJSCall) { #if ENABLE(LLINT_C_LOOP) result = LLInt::CLoop::execute(newCallFrame, llint_function_for_call_prologue); #elif ENABLE(JIT) - result = callData.js.functionExecutable->generatedJITCodeForCall().execute(&m_stack, newCallFrame, &globalData); + result = callData.js.functionExecutable->generatedJITCodeForCall().execute(&m_stack, newCallFrame, &vm); #endif // ENABLE(JIT) } else result = JSValue::decode(callData.native.function(newCallFrame)); } - if (Profiler* profiler = globalData.enabledProfiler()) + if (LegacyProfiler* profiler = vm.enabledProfiler()) profiler->didExecute(callFrame, function); m_stack.popFrame(newCallFrame); @@ -1066,18 +1038,17 @@ JSValue Interpreter::executeCall(CallFrame* callFrame, JSObject* function, CallT JSObject* Interpreter::executeConstruct(CallFrame* callFrame, JSObject* constructor, ConstructType constructType, const ConstructData& constructData, const ArgList& args) { - JSGlobalData& globalData = callFrame->globalData(); + VM& vm = callFrame->vm(); ASSERT(!callFrame->hadException()); - ASSERT(!globalData.isCollectorBusy()); + ASSERT(!vm.isCollectorBusy()); // We throw in this case because we have to return something "valid" but we're // already in an invalid state. - if (globalData.isCollectorBusy()) + if (vm.isCollectorBusy()) return checkedReturn(throwStackOverflowError(callFrame)); StackStats::CheckPoint stackCheckPoint; - const StackBounds& nativeStack = wtfThreadData().stack(); - StackPolicy policy(*this, nativeStack); - if (!nativeStack.isSafeToRecurse(policy.requiredCapacity())) + const VMStackBounds vmStackBounds(vm, wtfThreadData().stack()); + if (!vmStackBounds.isSafeToRecurse()) return checkedReturn(throwStackOverflowError(callFrame)); bool isJSConstruct = (constructType == ConstructTypeJS); @@ -1092,7 +1063,7 @@ JSObject* Interpreter::executeConstruct(CallFrame* callFrame, JSObject* construc scope = callFrame->scope(); } - DynamicGlobalObjectScope globalObjectScope(globalData, scope->globalObject()); + DynamicGlobalObjectScope globalObjectScope(vm, scope->globalObject()); if (isJSConstruct) { // Compile the callee: @@ -1105,6 +1076,9 @@ JSObject* Interpreter::executeConstruct(CallFrame* callFrame, JSObject* construc } else newCodeBlock = 0; + if (UNLIKELY(vm.watchdog.didFire(callFrame))) + return throwTerminatedExecutionException(callFrame); + CallFrame* newCallFrame = m_stack.pushFrame(callFrame, newCodeBlock, scope, argsCount, constructor); if (UNLIKELY(!newCallFrame)) return checkedReturn(throwStackOverflowError(callFrame)); @@ -1114,26 +1088,26 @@ JSObject* Interpreter::executeConstruct(CallFrame* callFrame, JSObject* construc for (size_t i = 0; i < args.size(); ++i) newCallFrame->setArgument(i, args.at(i)); - if (Profiler* profiler = globalData.enabledProfiler()) + if (LegacyProfiler* profiler = vm.enabledProfiler()) profiler->willExecute(callFrame, constructor); JSValue result; { SamplingTool::CallRecord callRecord(m_sampler.get(), !isJSConstruct); + Watchdog::Scope watchdogScope(vm.watchdog); // Execute the code. if (isJSConstruct) { #if ENABLE(LLINT_C_LOOP) result = LLInt::CLoop::execute(newCallFrame, llint_function_for_construct_prologue); #elif ENABLE(JIT) - result = constructData.js.functionExecutable->generatedJITCodeForConstruct().execute(&m_stack, newCallFrame, &globalData); + result = constructData.js.functionExecutable->generatedJITCodeForConstruct().execute(&m_stack, newCallFrame, &vm); #endif // ENABLE(JIT) - } else { + } else result = JSValue::decode(constructData.native.function(newCallFrame)); - } } - if (Profiler* profiler = globalData.enabledProfiler()) + if (LegacyProfiler* profiler = vm.enabledProfiler()) profiler->didExecute(callFrame, constructor); m_stack.popFrame(newCallFrame); @@ -1146,16 +1120,15 @@ JSObject* Interpreter::executeConstruct(CallFrame* callFrame, JSObject* construc CallFrameClosure Interpreter::prepareForRepeatCall(FunctionExecutable* functionExecutable, CallFrame* callFrame, JSFunction* function, int argumentCountIncludingThis, JSScope* scope) { - JSGlobalData& globalData = *scope->globalData(); - ASSERT(!globalData.exception); + VM& vm = *scope->vm(); + ASSERT(!vm.exception); - if (globalData.isCollectorBusy()) + if (vm.isCollectorBusy()) return CallFrameClosure(); StackStats::CheckPoint stackCheckPoint; - const StackBounds& nativeStack = wtfThreadData().stack(); - StackPolicy policy(*this, nativeStack); - if (!nativeStack.isSafeToRecurse(policy.requiredCapacity())) { + const VMStackBounds vmStackBounds(vm, wtfThreadData().stack()); + if (!vmStackBounds.isSafeToRecurse()) { throwStackOverflowError(callFrame); return CallFrameClosure(); } @@ -1182,17 +1155,17 @@ CallFrameClosure Interpreter::prepareForRepeatCall(FunctionExecutable* functionE } // Return the successful closure: - CallFrameClosure result = { callFrame, newCallFrame, function, functionExecutable, &globalData, scope, newCodeBlock->numParameters(), argumentCountIncludingThis }; + CallFrameClosure result = { callFrame, newCallFrame, function, functionExecutable, &vm, scope, newCodeBlock->numParameters(), argumentCountIncludingThis }; return result; } JSValue Interpreter::execute(CallFrameClosure& closure) { - JSGlobalData& globalData = *closure.globalData; + VM& vm = *closure.vm; SamplingScope samplingScope(this); - ASSERT(!globalData.isCollectorBusy()); - if (globalData.isCollectorBusy()) + ASSERT(!vm.isCollectorBusy()); + if (vm.isCollectorBusy()) return jsNull(); StackStats::CheckPoint stackCheckPoint; @@ -1200,9 +1173,12 @@ JSValue Interpreter::execute(CallFrameClosure& closure) closure.resetCallFrame(); m_stack.validateFence(closure.newCallFrame, "STEP 1"); - if (Profiler* profiler = globalData.enabledProfiler()) + if (LegacyProfiler* profiler = vm.enabledProfiler()) profiler->willExecute(closure.oldCallFrame, closure.function); + if (UNLIKELY(vm.watchdog.didFire(closure.oldCallFrame))) + return throwTerminatedExecutionException(closure.oldCallFrame); + // The code execution below may push more frames and point the topCallFrame // to those newer frames, or it may pop to the top frame to the caller of // the current repeat frame, or it may leave the top frame pointing to the @@ -1211,21 +1187,22 @@ JSValue Interpreter::execute(CallFrameClosure& closure) // Hence, we need to preserve the topCallFrame here ourselves before // repeating this call on a second callback function. - TopCallFrameSetter topCallFrame(globalData, closure.newCallFrame); + TopCallFrameSetter topCallFrame(vm, closure.newCallFrame); // Execute the code: JSValue result; { SamplingTool::CallRecord callRecord(m_sampler.get()); - + Watchdog::Scope watchdogScope(vm.watchdog); + #if ENABLE(LLINT_C_LOOP) result = LLInt::CLoop::execute(closure.newCallFrame, llint_function_for_call_prologue); #elif ENABLE(JIT) - result = closure.functionExecutable->generatedJITCodeForCall().execute(&m_stack, closure.newCallFrame, &globalData); + result = closure.functionExecutable->generatedJITCodeForCall().execute(&m_stack, closure.newCallFrame, &vm); #endif // ENABLE(JIT) } - if (Profiler* profiler = globalData.enabledProfiler()) + if (LegacyProfiler* profiler = vm.enabledProfiler()) profiler->didExecute(closure.oldCallFrame, closure.function); m_stack.validateFence(closure.newCallFrame, "AFTER"); @@ -1239,22 +1216,21 @@ void Interpreter::endRepeatCall(CallFrameClosure& closure) JSValue Interpreter::execute(EvalExecutable* eval, CallFrame* callFrame, JSValue thisValue, JSScope* scope) { - JSGlobalData& globalData = *scope->globalData(); + VM& vm = *scope->vm(); SamplingScope samplingScope(this); - ASSERT(scope->globalData() == &callFrame->globalData()); + ASSERT(scope->vm() == &callFrame->vm()); ASSERT(isValidThisObject(thisValue, callFrame)); - ASSERT(!globalData.exception); - ASSERT(!globalData.isCollectorBusy()); - if (globalData.isCollectorBusy()) + ASSERT(!vm.exception); + ASSERT(!vm.isCollectorBusy()); + if (vm.isCollectorBusy()) return jsNull(); - DynamicGlobalObjectScope globalObjectScope(globalData, scope->globalObject()); + DynamicGlobalObjectScope globalObjectScope(vm, scope->globalObject()); StackStats::CheckPoint stackCheckPoint; - const StackBounds& nativeStack = wtfThreadData().stack(); - StackPolicy policy(*this, nativeStack); - if (!nativeStack.isSafeToRecurse(policy.requiredCapacity())) + const VMStackBounds vmStackBounds(vm, wtfThreadData().stack()); + if (!vmStackBounds.isSafeToRecurse()) return checkedReturn(throwStackOverflowError(callFrame)); // Compile the callee: @@ -1265,7 +1241,7 @@ JSValue Interpreter::execute(EvalExecutable* eval, CallFrame* callFrame, JSValue JSObject* variableObject; for (JSScope* node = scope; ; node = node->next()) { - ASSERT(node); + RELEASE_ASSERT(node); if (node->isVariableObject() && !node->isNameScopeObject()) { variableObject = node; break; @@ -1280,7 +1256,7 @@ JSValue Interpreter::execute(EvalExecutable* eval, CallFrame* callFrame, JSValue variableObject = scope; } // Scope for BatchedTransitionOptimizer - BatchedTransitionOptimizer optimizer(globalData, variableObject); + BatchedTransitionOptimizer optimizer(vm, variableObject); for (unsigned i = 0; i < numVariables; ++i) { const Identifier& ident = codeBlock->variable(i); @@ -1297,6 +1273,9 @@ JSValue Interpreter::execute(EvalExecutable* eval, CallFrame* callFrame, JSValue } } + if (UNLIKELY(vm.watchdog.didFire(callFrame))) + return throwTerminatedExecutionException(callFrame); + // Push the frame: ASSERT(codeBlock->numParameters() == 1); // 1 parameter for 'this'. CallFrame* newCallFrame = m_stack.pushFrame(callFrame, codeBlock, scope, 1, 0); @@ -1306,22 +1285,23 @@ JSValue Interpreter::execute(EvalExecutable* eval, CallFrame* callFrame, JSValue // Set the arguments for the callee: newCallFrame->setThisValue(thisValue); - if (Profiler* profiler = globalData.enabledProfiler()) + if (LegacyProfiler* profiler = vm.enabledProfiler()) profiler->willExecute(callFrame, eval->sourceURL(), eval->lineNo()); // Execute the code: JSValue result; { SamplingTool::CallRecord callRecord(m_sampler.get()); - + Watchdog::Scope watchdogScope(vm.watchdog); + #if ENABLE(LLINT_C_LOOP) result = LLInt::CLoop::execute(newCallFrame, llint_eval_prologue); #elif ENABLE(JIT) - result = eval->generatedJITCode().execute(&m_stack, newCallFrame, &globalData); + result = eval->generatedJITCode().execute(&m_stack, newCallFrame, &vm); #endif // ENABLE(JIT) } - if (Profiler* profiler = globalData.enabledProfiler()) + if (LegacyProfiler* profiler = vm.enabledProfiler()) profiler->didExecute(callFrame, eval->sourceURL(), eval->lineNo()); m_stack.popFrame(newCallFrame); @@ -1362,7 +1342,7 @@ JSValue Interpreter::retrieveArgumentsFromVMCode(CallFrame* callFrame, JSFunctio if (!functionCallFrame) return jsNull(); - Arguments* arguments = Arguments::create(functionCallFrame->globalData(), functionCallFrame); + Arguments* arguments = Arguments::create(functionCallFrame->vm(), functionCallFrame); arguments->tearOff(functionCallFrame); return JSValue(arguments); } @@ -1374,9 +1354,9 @@ JSValue Interpreter::retrieveCallerFromVMCode(CallFrame* callFrame, JSFunction* if (!functionCallFrame) return jsNull(); - int lineNumber; unsigned bytecodeOffset; - CallFrame* callerFrame = getCallerInfo(&callFrame->globalData(), functionCallFrame, lineNumber, bytecodeOffset); + CodeBlock* unusedCallerCodeBlock = 0; + CallFrame* callerFrame = getCallerInfo(&callFrame->vm(), functionCallFrame, bytecodeOffset, unusedCallerCodeBlock); if (!callerFrame) return jsNull(); JSValue caller = callerFrame->callee(); @@ -1386,7 +1366,7 @@ JSValue Interpreter::retrieveCallerFromVMCode(CallFrame* callFrame, JSFunction* // Skip over function bindings. ASSERT(caller.isObject()); while (asObject(caller)->inherits(&JSBoundFunction::s_info)) { - callerFrame = getCallerInfo(&callFrame->globalData(), callerFrame, lineNumber, bytecodeOffset); + callerFrame = getCallerInfo(&callFrame->vm(), callerFrame, bytecodeOffset, unusedCallerCodeBlock); if (!callerFrame) return jsNull(); caller = callerFrame->callee(); |