summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/interpreter/Interpreter.cpp
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@digia.com>2012-10-23 10:25:11 +0200
committerSimon Hausmann <simon.hausmann@digia.com>2012-10-23 10:25:11 +0200
commit5ea819f80c6840c492386bfafbffb059c7e2091f (patch)
tree42ad0b1d82eff090d14278a088ea0f4840a0f938 /Source/JavaScriptCore/interpreter/Interpreter.cpp
parent43a42f108af6bcbd91f2672731c3047c26213af1 (diff)
downloadqtwebkit-5ea819f80c6840c492386bfafbffb059c7e2091f.tar.gz
Imported WebKit commit 20434eb8eb95065803473139d8794e98a7672f75 (http://svn.webkit.org/repository/webkit/trunk@132191)
New snapshot that should fix build with latest qtbase and the QPlastiqueStyle removal
Diffstat (limited to 'Source/JavaScriptCore/interpreter/Interpreter.cpp')
-rw-r--r--Source/JavaScriptCore/interpreter/Interpreter.cpp534
1 files changed, 290 insertions, 244 deletions
diff --git a/Source/JavaScriptCore/interpreter/Interpreter.cpp b/Source/JavaScriptCore/interpreter/Interpreter.cpp
index 8c09019da..0d475b416 100644
--- a/Source/JavaScriptCore/interpreter/Interpreter.cpp
+++ b/Source/JavaScriptCore/interpreter/Interpreter.cpp
@@ -48,6 +48,7 @@
#include "JSNameScope.h"
#include "JSNotAnObject.h"
#include "JSPropertyNameIterator.h"
+#include "JSStackInlines.h"
#include "JSString.h"
#include "JSWithScope.h"
#include "LLIntCLoop.h"
@@ -67,6 +68,7 @@
#include <stdio.h>
#include <wtf/StackStats.h>
#include <wtf/Threading.h>
+#include <wtf/WTFThreadData.h>
#include <wtf/text/StringBuilder.h>
#if ENABLE(JIT)
@@ -79,41 +81,131 @@ using namespace std;
namespace JSC {
-static CallFrame* getCallerInfo(JSGlobalData*, CallFrame*, int& lineNumber, unsigned& bytecodeOffset);
-
-// Returns the depth of the scope chain within a given call frame.
-static int depth(CodeBlock* codeBlock, JSScope* sc)
+Interpreter::ErrorHandlingMode::ErrorHandlingMode(ExecState *exec)
+ : m_interpreter(*exec->interpreter())
{
- if (!codeBlock->needsFullScopeChain())
- return 0;
- return sc->localDepth();
+ if (!m_interpreter.m_errorHandlingModeReentry)
+ m_interpreter.stack().enableErrorStackReserve();
+ m_interpreter.m_errorHandlingModeReentry++;
}
-ALWAYS_INLINE CallFrame* Interpreter::slideRegisterWindowForCall(CodeBlock* newCodeBlock, JSStack* stack, CallFrame* callFrame, size_t registerOffset, int argumentCountIncludingThis)
+Interpreter::ErrorHandlingMode::~ErrorHandlingMode()
{
- // This ensures enough space for the worst case scenario of zero arguments passed by the caller.
- if (!stack->grow(callFrame->registers() + registerOffset + newCodeBlock->numParameters() + newCodeBlock->m_numCalleeRegisters))
- return 0;
+ m_interpreter.m_errorHandlingModeReentry--;
+ ASSERT(m_interpreter.m_errorHandlingModeReentry >= 0);
+ if (!m_interpreter.m_errorHandlingModeReentry)
+ m_interpreter.stack().disableErrorStackReserve();
+}
- if (argumentCountIncludingThis >= newCodeBlock->numParameters()) {
- Register* newCallFrame = callFrame->registers() + registerOffset;
- return CallFrame::create(newCallFrame);
- }
- // Too few arguments -- copy arguments, then fill in missing arguments with undefined.
- size_t delta = newCodeBlock->numParameters() - argumentCountIncludingThis;
- CallFrame* newCallFrame = CallFrame::create(callFrame->registers() + registerOffset + delta);
+// 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 cummulative stack used by the interpreter and all code
+// paths sub of it up till leaf functions.
+// 2. the max cummulative 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)
+{
+ int size = stack.size();
+
+ const int DEFAULT_REQUIRED_STACK = 1024 * 1024;
+ const int DEFAULT_MINIMUM_USEABLE_STACK = 128 * 1024;
+ const int 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 requried 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. requiredCapcity can even be 0 if there's not enough stack.
+
+
+ // Policy 1: Normal mode: required = DEFAULT_REQUIRED_STACK.
+ // Policy 2: Erro mode: required = DEFAULT_ERROR_MODE_REQUIRED_STACK.
+ int requiredCapacity = !m_interpreter.m_errorHandlingModeReentry ?
+ DEFAULT_REQUIRED_STACK : DEFAULT_ERROR_MODE_REQUIRED_STACK;
+
+ int useableStack = size - requiredCapacity;
+
+ // 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:
+ // interpreter stack checks:
+ requiredCapacity = size - useableStack;
+ ASSERT((requiredCapacity >= 0) && (requiredCapacity < size));
+
+ m_requiredCapacity = requiredCapacity;
+}
- Register* dst = &newCallFrame->uncheckedR(CallFrame::thisArgumentOffset());
- Register* end = dst - argumentCountIncludingThis;
- for ( ; dst != end; --dst)
- *dst = *(dst - delta);
- end -= delta;
- for ( ; dst != end; --dst)
- *dst = jsUndefined();
+static CallFrame* getCallerInfo(JSGlobalData*, CallFrame*, int& lineNumber, unsigned& bytecodeOffset);
- return newCallFrame;
+// Returns the depth of the scope chain within a given call frame.
+static int depth(CodeBlock* codeBlock, JSScope* sc)
+{
+ if (!codeBlock->needsFullScopeChain())
+ return 0;
+ return sc->localDepth();
}
JSValue eval(CallFrame* callFrame)
@@ -164,7 +256,7 @@ JSValue eval(CallFrame* callFrame)
JSValue thisValue = callerFrame->thisValue();
ASSERT(isValidThisObject(thisValue, callFrame));
Interpreter* interpreter = callFrame->globalData().interpreter;
- return interpreter->execute(eval, callFrame, thisValue, callerScopeChain, callFrame->registers() - interpreter->stack().begin() + 1 + JSStack::CallFrameHeaderSize);
+ return interpreter->execute(eval, callFrame, thisValue, callerScopeChain);
}
CallFrame* loadVarargs(CallFrame* callFrame, JSStack* stack, JSValue thisValue, JSValue arguments, int firstFreeRegister)
@@ -245,9 +337,10 @@ CallFrame* loadVarargs(CallFrame* callFrame, JSStack* stack, JSValue thisValue,
return newCallFrame;
}
-Interpreter::Interpreter()
+Interpreter::Interpreter(JSGlobalData& globalData)
: m_sampleEntryDepth(0)
- , m_reentryDepth(0)
+ , m_stack(globalData)
+ , m_errorHandlingModeReentry(0)
#if !ASSERT_DISABLED
, m_initialized(false)
#endif
@@ -681,26 +774,13 @@ NEVER_INLINE HandlerInfo* Interpreter::throwException(CallFrame*& callFrame, JSV
if (!unwindCallFrame(callFrame, exceptionValue, bytecodeOffset, codeBlock)) {
if (Profiler* profiler = callFrame->globalData().enabledProfiler())
profiler->exceptionUnwind(callFrame);
- callFrame->globalData().topCallFrame = callFrame;
return 0;
}
}
- callFrame->globalData().topCallFrame = callFrame;
if (Profiler* profiler = callFrame->globalData().enabledProfiler())
profiler->exceptionUnwind(callFrame);
- // Shrink the JS stack, in case stack overflow made it huge.
- Register* highWaterMark = 0;
- for (CallFrame* callerFrame = callFrame; callerFrame; callerFrame = callerFrame->callerFrame()->removeHostCallFrameFlag()) {
- CodeBlock* codeBlock = callerFrame->codeBlock();
- if (!codeBlock)
- continue;
- Register* callerHighWaterMark = callerFrame->registers() + codeBlock->m_numCalleeRegisters;
- highWaterMark = max(highWaterMark, callerHighWaterMark);
- }
- m_stack.shrink(highWaterMark);
-
// Unwind the scope chain within the exception handler's call frame.
JSScope* scope = callFrame->scope();
int scopeDelta = 0;
@@ -747,20 +827,24 @@ JSValue Interpreter::execute(ProgramExecutable* program, CallFrame* callFrame, J
SamplingScope samplingScope(this);
JSScope* scope = callFrame->scope();
+ JSGlobalData& globalData = *scope->globalData();
+
ASSERT(isValidThisObject(thisObj, callFrame));
- ASSERT(!scope->globalData()->exception);
- ASSERT(!callFrame->globalData().isCollectorBusy());
- if (callFrame->globalData().isCollectorBusy())
+ ASSERT(!globalData.exception);
+ ASSERT(!globalData.isCollectorBusy());
+ if (globalData.isCollectorBusy())
CRASH();
StackStats::CheckPoint stackCheckPoint;
- if (m_reentryDepth >= MaxSmallThreadReentryDepth && m_reentryDepth >= callFrame->globalData().maxReentryDepth)
+ const StackBounds& nativeStack = wtfThreadData().stack();
+ StackPolicy policy(*this, nativeStack);
+ if (!nativeStack.isSafeToRecurse(policy.requiredCapacity()))
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(*scope->globalData(), scope->globalObject());
+ DynamicGlobalObjectScope globalObjectScope(globalData, scope->globalObject());
Vector<JSONPData> JSONPData;
bool parseResult;
const String programSource = program->source().toString();
@@ -869,20 +953,16 @@ failedJSONP:
return checkedReturn(throwError(callFrame, error));
CodeBlock* codeBlock = &program->generatedBytecode();
- // Reserve stack space for this invocation:
- Register* oldEnd = m_stack.end();
- Register* newEnd = oldEnd + codeBlock->numParameters() + JSStack::CallFrameHeaderSize + codeBlock->m_numCalleeRegisters;
- if (!m_stack.grow(newEnd))
- return checkedReturn(throwStackOverflowError(callFrame));
-
// Push the call frame for this invocation:
- CallFrame* newCallFrame = CallFrame::create(oldEnd + codeBlock->numParameters() + JSStack::CallFrameHeaderSize);
ASSERT(codeBlock->numParameters() == 1); // 1 parameter for 'this'.
- newCallFrame->init(codeBlock, 0, scope, CallFrame::noCaller(), codeBlock->numParameters(), 0);
+ CallFrame* newCallFrame = m_stack.pushFrame(callFrame, codeBlock, scope, 1, 0);
+ if (UNLIKELY(!newCallFrame))
+ return checkedReturn(throwStackOverflowError(callFrame));
+
+ // Set the arguments for the callee:
newCallFrame->setThisValue(thisObj);
- TopCallFrameSetter topCallFrame(callFrame->globalData(), newCallFrame);
- if (Profiler* profiler = callFrame->globalData().enabledProfiler())
+ if (Profiler* profiler = globalData.enabledProfiler())
profiler->willExecute(callFrame, program->sourceURL(), program->lineNo());
// Execute the code:
@@ -890,213 +970,168 @@ failedJSONP:
{
SamplingTool::CallRecord callRecord(m_sampler.get());
- m_reentryDepth++;
#if ENABLE(LLINT_C_LOOP)
result = LLInt::CLoop::execute(newCallFrame, llint_program_prologue);
#elif ENABLE(JIT)
- result = program->generatedJITCode().execute(&m_stack, newCallFrame, scope->globalData());
+ result = program->generatedJITCode().execute(&m_stack, newCallFrame, &globalData);
#endif // ENABLE(JIT)
-
- m_reentryDepth--;
}
- if (Profiler* profiler = callFrame->globalData().enabledProfiler())
+ if (Profiler* profiler = globalData.enabledProfiler())
profiler->didExecute(callFrame, program->sourceURL(), program->lineNo());
- m_stack.shrink(oldEnd);
+ m_stack.popFrame(newCallFrame);
return checkedReturn(result);
}
JSValue Interpreter::executeCall(CallFrame* callFrame, JSObject* function, CallType callType, const CallData& callData, JSValue thisValue, const ArgList& args)
{
+ JSGlobalData& globalData = callFrame->globalData();
ASSERT(isValidThisObject(thisValue, callFrame));
ASSERT(!callFrame->hadException());
- ASSERT(!callFrame->globalData().isCollectorBusy());
- if (callFrame->globalData().isCollectorBusy())
+ ASSERT(!globalData.isCollectorBusy());
+ if (globalData.isCollectorBusy())
return jsNull();
StackStats::CheckPoint stackCheckPoint;
- if (m_reentryDepth >= MaxSmallThreadReentryDepth && m_reentryDepth >= callFrame->globalData().maxReentryDepth)
+ const StackBounds& nativeStack = wtfThreadData().stack();
+ StackPolicy policy(*this, nativeStack);
+ if (!nativeStack.isSafeToRecurse(policy.requiredCapacity()))
return checkedReturn(throwStackOverflowError(callFrame));
- Register* oldEnd = m_stack.end();
- ASSERT(callFrame->frameExtent() <= oldEnd || callFrame == callFrame->scope()->globalObject()->globalExec());
- int argCount = 1 + args.size(); // implicit "this" parameter
- size_t registerOffset = argCount + JSStack::CallFrameHeaderSize;
-
- CallFrame* newCallFrame = CallFrame::create(oldEnd + registerOffset);
- if (!m_stack.grow(newCallFrame->registers()))
- return checkedReturn(throwStackOverflowError(callFrame));
+ bool isJSCall = (callType == CallTypeJS);
+ JSScope* scope;
+ CodeBlock* newCodeBlock;
+ size_t argsCount = 1 + args.size(); // implicit "this" parameter
- newCallFrame->setThisValue(thisValue);
- for (size_t i = 0; i < args.size(); ++i)
- newCallFrame->setArgument(i, args.at(i));
-
- if (callType == CallTypeJS) {
- JSScope* callDataScope = callData.js.scope;
-
- DynamicGlobalObjectScope globalObjectScope(*callDataScope->globalData(), callDataScope->globalObject());
+ if (isJSCall)
+ scope = callData.js.scope;
+ else {
+ ASSERT(callType == CallTypeHost);
+ scope = callFrame->scope();
+ }
+ DynamicGlobalObjectScope globalObjectScope(globalData, scope->globalObject());
- JSObject* compileError = callData.js.functionExecutable->compileForCall(callFrame, callDataScope);
+ if (isJSCall) {
+ // Compile the callee:
+ JSObject* compileError = callData.js.functionExecutable->compileForCall(callFrame, scope);
if (UNLIKELY(!!compileError)) {
- m_stack.shrink(oldEnd);
return checkedReturn(throwError(callFrame, compileError));
}
+ newCodeBlock = &callData.js.functionExecutable->generatedBytecodeForCall();
+ ASSERT(!!newCodeBlock);
+ } else
+ newCodeBlock = 0;
- CodeBlock* newCodeBlock = &callData.js.functionExecutable->generatedBytecodeForCall();
- newCallFrame = slideRegisterWindowForCall(newCodeBlock, &m_stack, newCallFrame, 0, argCount);
- if (UNLIKELY(!newCallFrame)) {
- m_stack.shrink(oldEnd);
- return checkedReturn(throwStackOverflowError(callFrame));
- }
-
- newCallFrame->init(newCodeBlock, 0, callDataScope, callFrame->addHostCallFrameFlag(), argCount, function);
+ CallFrame* newCallFrame = m_stack.pushFrame(callFrame, newCodeBlock, scope, argsCount, function);
+ if (UNLIKELY(!newCallFrame))
+ return checkedReturn(throwStackOverflowError(callFrame));
- TopCallFrameSetter topCallFrame(callFrame->globalData(), newCallFrame);
+ // Set the arguments for the callee:
+ newCallFrame->setThisValue(thisValue);
+ for (size_t i = 0; i < args.size(); ++i)
+ newCallFrame->setArgument(i, args.at(i));
- if (Profiler* profiler = callFrame->globalData().enabledProfiler())
- profiler->willExecute(callFrame, function);
+ if (Profiler* profiler = globalData.enabledProfiler())
+ profiler->willExecute(callFrame, function);
- JSValue result;
- {
- SamplingTool::CallRecord callRecord(m_sampler.get());
+ JSValue result;
+ {
+ SamplingTool::CallRecord callRecord(m_sampler.get(), !isJSCall);
- m_reentryDepth++;
+ // 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, callDataScope->globalData());
+ result = callData.js.functionExecutable->generatedJITCodeForCall().execute(&m_stack, newCallFrame, &globalData);
#endif // ENABLE(JIT)
-
- m_reentryDepth--;
- }
-
- if (Profiler* profiler = callFrame->globalData().enabledProfiler())
- profiler->didExecute(callFrame, function);
-
- m_stack.shrink(oldEnd);
- return checkedReturn(result);
- }
-
- ASSERT(callType == CallTypeHost);
- JSScope* scope = callFrame->scope();
- newCallFrame->init(0, 0, scope, callFrame->addHostCallFrameFlag(), argCount, function);
-
- TopCallFrameSetter topCallFrame(callFrame->globalData(), newCallFrame);
-
- DynamicGlobalObjectScope globalObjectScope(*scope->globalData(), scope->globalObject());
-
- if (Profiler* profiler = callFrame->globalData().enabledProfiler())
- profiler->willExecute(callFrame, function);
-
- JSValue result;
- {
- SamplingTool::HostCallRecord callRecord(m_sampler.get());
- result = JSValue::decode(callData.native.function(newCallFrame));
+ } else
+ result = JSValue::decode(callData.native.function(newCallFrame));
}
- if (Profiler* profiler = callFrame->globalData().enabledProfiler())
+ if (Profiler* profiler = globalData.enabledProfiler())
profiler->didExecute(callFrame, function);
- m_stack.shrink(oldEnd);
+ m_stack.popFrame(newCallFrame);
return checkedReturn(result);
}
JSObject* Interpreter::executeConstruct(CallFrame* callFrame, JSObject* constructor, ConstructType constructType, const ConstructData& constructData, const ArgList& args)
{
+ JSGlobalData& globalData = callFrame->globalData();
ASSERT(!callFrame->hadException());
- ASSERT(!callFrame->globalData().isCollectorBusy());
+ ASSERT(!globalData.isCollectorBusy());
// We throw in this case because we have to return something "valid" but we're
// already in an invalid state.
- if (callFrame->globalData().isCollectorBusy())
+ if (globalData.isCollectorBusy())
return checkedReturn(throwStackOverflowError(callFrame));
StackStats::CheckPoint stackCheckPoint;
- if (m_reentryDepth >= MaxSmallThreadReentryDepth && m_reentryDepth >= callFrame->globalData().maxReentryDepth)
- return checkedReturn(throwStackOverflowError(callFrame));
-
- Register* oldEnd = m_stack.end();
- int argCount = 1 + args.size(); // implicit "this" parameter
- size_t registerOffset = argCount + JSStack::CallFrameHeaderSize;
-
- if (!m_stack.grow(oldEnd + registerOffset))
+ const StackBounds& nativeStack = wtfThreadData().stack();
+ StackPolicy policy(*this, nativeStack);
+ if (!nativeStack.isSafeToRecurse(policy.requiredCapacity()))
return checkedReturn(throwStackOverflowError(callFrame));
- CallFrame* newCallFrame = CallFrame::create(oldEnd + registerOffset);
- newCallFrame->setThisValue(jsUndefined());
- for (size_t i = 0; i < args.size(); ++i)
- newCallFrame->setArgument(i, args.at(i));
+ bool isJSConstruct = (constructType == ConstructTypeJS);
+ JSScope* scope;
+ CodeBlock* newCodeBlock;
+ size_t argsCount = 1 + args.size(); // implicit "this" parameter
- if (constructType == ConstructTypeJS) {
- JSScope* constructDataScope = constructData.js.scope;
+ if (isJSConstruct)
+ scope = constructData.js.scope;
+ else {
+ ASSERT(constructType == ConstructTypeHost);
+ scope = callFrame->scope();
+ }
- DynamicGlobalObjectScope globalObjectScope(*constructDataScope->globalData(), constructDataScope->globalObject());
+ DynamicGlobalObjectScope globalObjectScope(globalData, scope->globalObject());
- JSObject* compileError = constructData.js.functionExecutable->compileForConstruct(callFrame, constructDataScope);
+ if (isJSConstruct) {
+ // Compile the callee:
+ JSObject* compileError = constructData.js.functionExecutable->compileForConstruct(callFrame, scope);
if (UNLIKELY(!!compileError)) {
- m_stack.shrink(oldEnd);
return checkedReturn(throwError(callFrame, compileError));
}
+ newCodeBlock = &constructData.js.functionExecutable->generatedBytecodeForConstruct();
+ ASSERT(!!newCodeBlock);
+ } else
+ newCodeBlock = 0;
- CodeBlock* newCodeBlock = &constructData.js.functionExecutable->generatedBytecodeForConstruct();
- newCallFrame = slideRegisterWindowForCall(newCodeBlock, &m_stack, newCallFrame, 0, argCount);
- if (UNLIKELY(!newCallFrame)) {
- m_stack.shrink(oldEnd);
- return checkedReturn(throwStackOverflowError(callFrame));
- }
-
- newCallFrame->init(newCodeBlock, 0, constructDataScope, callFrame->addHostCallFrameFlag(), argCount, constructor);
+ CallFrame* newCallFrame = m_stack.pushFrame(callFrame, newCodeBlock, scope, argsCount, constructor);
+ if (UNLIKELY(!newCallFrame))
+ return checkedReturn(throwStackOverflowError(callFrame));
- TopCallFrameSetter topCallFrame(callFrame->globalData(), newCallFrame);
+ // Set the arguments for the callee:
+ newCallFrame->setThisValue(jsUndefined());
+ for (size_t i = 0; i < args.size(); ++i)
+ newCallFrame->setArgument(i, args.at(i));
- if (Profiler* profiler = callFrame->globalData().enabledProfiler())
- profiler->willExecute(callFrame, constructor);
+ if (Profiler* profiler = globalData.enabledProfiler())
+ profiler->willExecute(callFrame, constructor);
- JSValue result;
- {
- SamplingTool::CallRecord callRecord(m_sampler.get());
+ JSValue result;
+ {
+ SamplingTool::CallRecord callRecord(m_sampler.get(), !isJSConstruct);
- m_reentryDepth++;
+ // 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, constructDataScope->globalData());
+ result = constructData.js.functionExecutable->generatedJITCodeForConstruct().execute(&m_stack, newCallFrame, &globalData);
#endif // ENABLE(JIT)
- m_reentryDepth--;
+ } else {
+ result = JSValue::decode(constructData.native.function(newCallFrame));
}
-
- if (Profiler* profiler = callFrame->globalData().enabledProfiler())
- profiler->didExecute(callFrame, constructor);
-
- m_stack.shrink(oldEnd);
- if (callFrame->hadException())
- return 0;
- ASSERT(result.isObject());
- return checkedReturn(asObject(result));
- }
-
- ASSERT(constructType == ConstructTypeHost);
- JSScope* scope = callFrame->scope();
- newCallFrame->init(0, 0, scope, callFrame->addHostCallFrameFlag(), argCount, constructor);
-
- TopCallFrameSetter topCallFrame(callFrame->globalData(), newCallFrame);
-
- DynamicGlobalObjectScope globalObjectScope(*scope->globalData(), scope->globalObject());
-
- if (Profiler* profiler = callFrame->globalData().enabledProfiler())
- profiler->willExecute(callFrame, constructor);
-
- JSValue result;
- {
- SamplingTool::HostCallRecord callRecord(m_sampler.get());
- result = JSValue::decode(constructData.native.function(newCallFrame));
}
- if (Profiler* profiler = callFrame->globalData().enabledProfiler())
+ if (Profiler* profiler = globalData.enabledProfiler())
profiler->didExecute(callFrame, constructor);
- m_stack.shrink(oldEnd);
+ m_stack.popFrame(newCallFrame);
+
if (callFrame->hadException())
return 0;
ASSERT(result.isObject());
@@ -1105,101 +1140,118 @@ JSObject* Interpreter::executeConstruct(CallFrame* callFrame, JSObject* construc
CallFrameClosure Interpreter::prepareForRepeatCall(FunctionExecutable* functionExecutable, CallFrame* callFrame, JSFunction* function, int argumentCountIncludingThis, JSScope* scope)
{
- ASSERT(!scope->globalData()->exception);
+ JSGlobalData& globalData = *scope->globalData();
+ ASSERT(!globalData.exception);
- if (callFrame->globalData().isCollectorBusy())
+ if (globalData.isCollectorBusy())
return CallFrameClosure();
StackStats::CheckPoint stackCheckPoint;
- if (m_reentryDepth >= MaxSmallThreadReentryDepth && m_reentryDepth >= callFrame->globalData().maxReentryDepth) {
- throwStackOverflowError(callFrame);
- return CallFrameClosure();
- }
-
- Register* oldEnd = m_stack.end();
- size_t registerOffset = argumentCountIncludingThis + JSStack::CallFrameHeaderSize;
-
- CallFrame* newCallFrame = CallFrame::create(oldEnd + registerOffset);
- if (!m_stack.grow(newCallFrame->registers())) {
+ const StackBounds& nativeStack = wtfThreadData().stack();
+ StackPolicy policy(*this, nativeStack);
+ if (!nativeStack.isSafeToRecurse(policy.requiredCapacity())) {
throwStackOverflowError(callFrame);
return CallFrameClosure();
}
+ // Compile the callee:
JSObject* error = functionExecutable->compileForCall(callFrame, scope);
if (error) {
throwError(callFrame, error);
- m_stack.shrink(oldEnd);
return CallFrameClosure();
}
- CodeBlock* codeBlock = &functionExecutable->generatedBytecodeForCall();
+ CodeBlock* newCodeBlock = &functionExecutable->generatedBytecodeForCall();
- newCallFrame = slideRegisterWindowForCall(codeBlock, &m_stack, newCallFrame, 0, argumentCountIncludingThis);
+ size_t argsCount = argumentCountIncludingThis;
+
+ CallFrame* newCallFrame = m_stack.pushFrame(callFrame, newCodeBlock, scope, argsCount, function);
if (UNLIKELY(!newCallFrame)) {
throwStackOverflowError(callFrame);
- m_stack.shrink(oldEnd);
return CallFrameClosure();
}
- newCallFrame->init(codeBlock, 0, scope, callFrame->addHostCallFrameFlag(), argumentCountIncludingThis, function);
- scope->globalData()->topCallFrame = newCallFrame;
- CallFrameClosure result = { callFrame, newCallFrame, function, functionExecutable, scope->globalData(), oldEnd, scope, codeBlock->numParameters(), argumentCountIncludingThis };
+
+ if (UNLIKELY(!newCallFrame)) {
+ throwStackOverflowError(callFrame);
+ return CallFrameClosure();
+ }
+
+ // Return the successful closure:
+ CallFrameClosure result = { callFrame, newCallFrame, function, functionExecutable, &globalData, scope, newCodeBlock->numParameters(), argumentCountIncludingThis };
return result;
}
JSValue Interpreter::execute(CallFrameClosure& closure)
{
+ JSGlobalData& globalData = *closure.globalData;
SamplingScope samplingScope(this);
- ASSERT(!closure.oldCallFrame->globalData().isCollectorBusy());
- if (closure.oldCallFrame->globalData().isCollectorBusy())
+ ASSERT(!globalData.isCollectorBusy());
+ if (globalData.isCollectorBusy())
return jsNull();
StackStats::CheckPoint stackCheckPoint;
+ m_stack.validateFence(closure.newCallFrame, "BEFORE");
closure.resetCallFrame();
- if (Profiler* profiler = closure.oldCallFrame->globalData().enabledProfiler())
+ m_stack.validateFence(closure.newCallFrame, "STEP 1");
+
+ if (Profiler* profiler = globalData.enabledProfiler())
profiler->willExecute(closure.oldCallFrame, closure.function);
- TopCallFrameSetter topCallFrame(*closure.globalData, closure.newCallFrame);
+ // 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
+ // current repeat frame.
+ //
+ // Hence, we need to preserve the topCallFrame here ourselves before
+ // repeating this call on a second callback function.
+ TopCallFrameSetter topCallFrame(globalData, closure.newCallFrame);
+
+ // Execute the code:
JSValue result;
{
SamplingTool::CallRecord callRecord(m_sampler.get());
- m_reentryDepth++;
#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, closure.globalData);
+ result = closure.functionExecutable->generatedJITCodeForCall().execute(&m_stack, closure.newCallFrame, &globalData);
#endif // ENABLE(JIT)
- m_reentryDepth--;
}
- if (Profiler* profiler = closure.oldCallFrame->globalData().enabledProfiler())
+ if (Profiler* profiler = globalData.enabledProfiler())
profiler->didExecute(closure.oldCallFrame, closure.function);
+
+ m_stack.validateFence(closure.newCallFrame, "AFTER");
return checkedReturn(result);
}
void Interpreter::endRepeatCall(CallFrameClosure& closure)
{
- closure.globalData->topCallFrame = closure.oldCallFrame;
- m_stack.shrink(closure.oldEnd);
+ m_stack.popFrame(closure.newCallFrame);
}
-JSValue Interpreter::execute(EvalExecutable* eval, CallFrame* callFrame, JSValue thisValue, JSScope* scope, int globalRegisterOffset)
+JSValue Interpreter::execute(EvalExecutable* eval, CallFrame* callFrame, JSValue thisValue, JSScope* scope)
{
+ JSGlobalData& globalData = *scope->globalData();
SamplingScope samplingScope(this);
+ ASSERT(scope->globalData() == &callFrame->globalData());
ASSERT(isValidThisObject(thisValue, callFrame));
- ASSERT(!scope->globalData()->exception);
- ASSERT(!callFrame->globalData().isCollectorBusy());
- if (callFrame->globalData().isCollectorBusy())
+ ASSERT(!globalData.exception);
+ ASSERT(!globalData.isCollectorBusy());
+ if (globalData.isCollectorBusy())
return jsNull();
- DynamicGlobalObjectScope globalObjectScope(*scope->globalData(), scope->globalObject());
+ DynamicGlobalObjectScope globalObjectScope(globalData, scope->globalObject());
StackStats::CheckPoint stackCheckPoint;
- if (m_reentryDepth >= MaxSmallThreadReentryDepth && m_reentryDepth >= callFrame->globalData().maxReentryDepth)
+ const StackBounds& nativeStack = wtfThreadData().stack();
+ StackPolicy policy(*this, nativeStack);
+ if (!nativeStack.isSafeToRecurse(policy.requiredCapacity()))
return checkedReturn(throwStackOverflowError(callFrame));
+ // Compile the callee:
JSObject* compileError = eval->compile(callFrame, scope);
if (UNLIKELY(!!compileError))
return checkedReturn(throwError(callFrame, compileError));
@@ -1222,7 +1274,7 @@ JSValue Interpreter::execute(EvalExecutable* eval, CallFrame* callFrame, JSValue
variableObject = scope;
}
// Scope for BatchedTransitionOptimizer
- BatchedTransitionOptimizer optimizer(callFrame->globalData(), variableObject);
+ BatchedTransitionOptimizer optimizer(globalData, variableObject);
for (unsigned i = 0; i < numVariables; ++i) {
const Identifier& ident = codeBlock->variable(i);
@@ -1239,40 +1291,34 @@ JSValue Interpreter::execute(EvalExecutable* eval, CallFrame* callFrame, JSValue
}
}
- Register* oldEnd = m_stack.end();
- Register* newEnd = m_stack.begin() + globalRegisterOffset + codeBlock->m_numCalleeRegisters;
- if (!m_stack.grow(newEnd))
+ // Push the frame:
+ ASSERT(codeBlock->numParameters() == 1); // 1 parameter for 'this'.
+ CallFrame* newCallFrame = m_stack.pushFrame(callFrame, codeBlock, scope, 1, 0);
+ if (UNLIKELY(!newCallFrame))
return checkedReturn(throwStackOverflowError(callFrame));
- CallFrame* newCallFrame = CallFrame::create(m_stack.begin() + globalRegisterOffset);
-
- ASSERT(codeBlock->numParameters() == 1); // 1 parameter for 'this'.
- newCallFrame->init(codeBlock, 0, scope, callFrame->addHostCallFrameFlag(), codeBlock->numParameters(), 0);
+ // Set the arguments for the callee:
newCallFrame->setThisValue(thisValue);
- TopCallFrameSetter topCallFrame(callFrame->globalData(), newCallFrame);
-
- if (Profiler* profiler = callFrame->globalData().enabledProfiler())
+ if (Profiler* profiler = globalData.enabledProfiler())
profiler->willExecute(callFrame, eval->sourceURL(), eval->lineNo());
+ // Execute the code:
JSValue result;
{
SamplingTool::CallRecord callRecord(m_sampler.get());
-
- m_reentryDepth++;
#if ENABLE(LLINT_C_LOOP)
result = LLInt::CLoop::execute(newCallFrame, llint_eval_prologue);
#elif ENABLE(JIT)
- result = eval->generatedJITCode().execute(&m_stack, newCallFrame, scope->globalData());
+ result = eval->generatedJITCode().execute(&m_stack, newCallFrame, &globalData);
#endif // ENABLE(JIT)
- m_reentryDepth--;
}
- if (Profiler* profiler = callFrame->globalData().enabledProfiler())
+ if (Profiler* profiler = globalData.enabledProfiler())
profiler->didExecute(callFrame, eval->sourceURL(), eval->lineNo());
- m_stack.shrink(oldEnd);
+ m_stack.popFrame(newCallFrame);
return checkedReturn(result);
}