Reviewed by Oliver Hunt.
- fixed "REGRESSION (r37297): fast/js/deep-recursion-test takes too long and times out"
https://bugs.webkit.org/show_bug.cgi?id=21375
The problem is that dynamicGlobalObject had become O(N) in number
of call frames, but unwinding the stack for an exception called it
for every call frame, resulting in O(N^2) behavior for an
exception thrown from inside deep recursion.
Instead of doing it that way, stash the dynamic global object in JSGlobalData.
* JavaScriptCore.exp:
* VM/Machine.cpp:
(JSC::DynamicGlobalObjectScope::DynamicGlobalObjectScope): Helper class to temporarily
store and later restore a dynamicGlobalObject in JSGlobalData.
(JSC::DynamicGlobalObjectScope::~DynamicGlobalObjectScope):
(JSC::Machine::execute): In each version, establish a DynamicGlobalObjectScope.
For ProgramNode, always establish set new dynamicGlobalObject, for FunctionBody and Eval,
only if none is currently set.
* VM/Machine.h:
* kjs/ExecState.h:
* kjs/JSGlobalData.cpp:
(JSC::JSGlobalData::JSGlobalData): Ininitalize new dynamicGlobalObject field to 0.
* kjs/JSGlobalData.h:
* kjs/JSGlobalObject.h:
(JSC::ExecState::dynamicGlobalObject): Moved here from ExecState for benefit of inlining.
Return lexical global object if this is a globalExec(), otherwise look in JSGlobalData
for the one stashed there.
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@37323
268f45cc-cd09-0410-ab3c-
d52691b4dbfc
+2008-10-05 Maciej Stachowiak <mjs@apple.com>
+
+ Reviewed by Oliver Hunt.
+
+ - fixed "REGRESSION (r37297): fast/js/deep-recursion-test takes too long and times out"
+ https://bugs.webkit.org/show_bug.cgi?id=21375
+
+ The problem is that dynamicGlobalObject had become O(N) in number
+ of call frames, but unwinding the stack for an exception called it
+ for every call frame, resulting in O(N^2) behavior for an
+ exception thrown from inside deep recursion.
+
+ Instead of doing it that way, stash the dynamic global object in JSGlobalData.
+
+ * JavaScriptCore.exp:
+ * VM/Machine.cpp:
+ (JSC::DynamicGlobalObjectScope::DynamicGlobalObjectScope): Helper class to temporarily
+ store and later restore a dynamicGlobalObject in JSGlobalData.
+ (JSC::DynamicGlobalObjectScope::~DynamicGlobalObjectScope):
+ (JSC::Machine::execute): In each version, establish a DynamicGlobalObjectScope.
+ For ProgramNode, always establish set new dynamicGlobalObject, for FunctionBody and Eval,
+ only if none is currently set.
+ * VM/Machine.h:
+ * kjs/ExecState.h:
+ * kjs/JSGlobalData.cpp:
+ (JSC::JSGlobalData::JSGlobalData): Ininitalize new dynamicGlobalObject field to 0.
+ * kjs/JSGlobalData.h:
+ * kjs/JSGlobalObject.h:
+ (JSC::ExecState::dynamicGlobalObject): Moved here from ExecState for benefit of inlining.
+ Return lexical global object if this is a globalExec(), otherwise look in JSGlobalData
+ for the one stashed there.
+
2008-10-05 Sam Weinig <sam@webkit.org>
Reviewed by Maciej Stachowiak.
__ZN3JSC7CStringD1Ev
__ZN3JSC7CStringaSERKS0_
__ZN3JSC7JSArray4infoE
-__ZN3JSC7Machine14firstCallFrameEPKNS_8RegisterE
__ZN3JSC7Profile10restoreAllEv
__ZN3JSC7Profile5focusEPKNS_11ProfileNodeE
__ZN3JSC7Profile7excludeEPKNS_11ProfileNodeE
return handlerVPC;
}
+class DynamicGlobalObjectScope {
+public:
+ DynamicGlobalObjectScope(ExecState* exec, JSGlobalObject* dynamicGlobalObject)
+ : m_exec(exec)
+ , m_savedGlobalObject(exec->globalData().dynamicGlobalObject)
+ {
+ exec->globalData().dynamicGlobalObject = dynamicGlobalObject;
+ }
+
+ ~DynamicGlobalObjectScope()
+ {
+ m_exec->globalData().dynamicGlobalObject = m_savedGlobalObject;
+ }
+
+private:
+ ExecState* m_exec;
+ JSGlobalObject* m_savedGlobalObject;
+};
+
JSValue* Machine::execute(ProgramNode* programNode, ExecState* exec, ScopeChainNode* scopeChain, JSObject* thisObj, JSValue** exception)
{
ASSERT(!exec->hadException());
return jsNull();
}
+ DynamicGlobalObjectScope globalObjectScope(exec, scopeChain->globalObject());
+
JSGlobalObject* lastGlobalObject = m_registerFile.globalObject();
JSGlobalObject* globalObject = exec->dynamicGlobalObject();
globalObject->copyGlobalsTo(m_registerFile);
lastGlobalObject->copyGlobalsTo(m_registerFile);
m_registerFile.shrink(oldEnd);
+
return result;
}
return jsNull();
}
+ DynamicGlobalObjectScope globalObjectScope(exec, exec->globalData().dynamicGlobalObject ? exec->globalData().dynamicGlobalObject : scopeChain->globalObject());
+
Register* argv = oldEnd;
size_t dst = 0;
argv[dst] = thisObj;
return jsNull();
}
+ DynamicGlobalObjectScope globalObjectScope(exec, exec->globalData().dynamicGlobalObject ? exec->globalData().dynamicGlobalObject : scopeChain->globalObject());
+
EvalCodeBlock* codeBlock = &evalNode->byteCode(scopeChain);
JSVariableObject* variableObject;
function = caller;
}
-const Register* Machine::firstCallFrame(const Register* callFrame)
-{
- const Register* first = 0;
- for (const Register* frame = callFrame; frame; frame = stripHostCallFrameBit(frame[RegisterFile::CallerRegisters].r()))
- first = frame;
- return first;
-}
-
Register* Machine::callFrame(ExecState* exec, InternalFunction* function) const
{
for (Register* r = exec->registers(); r; r = stripHostCallFrameBit(r[RegisterFile::CallerRegisters].r()))
JSValue* retrieveCaller(ExecState*, InternalFunction*) const;
void retrieveLastCaller(ExecState* exec, int& lineNumber, intptr_t& sourceID, UString& sourceURL, JSValue*& function) const;
- static const Register* firstCallFrame(const Register* callFrame);
static ScopeChainNode* scopeChain(const Register* r) { return r[RegisterFile::ScopeChain].scopeChain(); }
static CodeBlock* codeBlock(const Register* r) { return r[RegisterFile::CodeBlock].codeBlock(); }
Register* registers() { return this; }
// Global object in which execution began.
- JSGlobalObject* dynamicGlobalObject()
- {
- return Machine::scopeChain(Machine::firstCallFrame(this))->globalObject();
- }
+ JSGlobalObject* dynamicGlobalObject();
// Global object in which the currently executing code was defined.
// Differs from dynamicGlobalObject() during function calls across web browser frames.
, lexer(new Lexer(this))
, parser(new Parser)
, head(0)
+ , dynamicGlobalObject(0)
, isSharedInstance(isShared)
, clientData(0)
, heap(this)
Parser* parser;
JSGlobalObject* head;
+ JSGlobalObject* dynamicGlobalObject;
bool isSharedInstance;
return exec->lexicalGlobalObject()->numberPrototype();
}
+ inline JSGlobalObject* ExecState::dynamicGlobalObject()
+ {
+ if (this == lexicalGlobalObject()->globalExec())
+ return lexicalGlobalObject();
+
+ // For any ExecState that's not a globalExec, the
+ // dynamic global object must be set since code is running
+ ASSERT(globalData().dynamicGlobalObject);
+ return globalData().dynamicGlobalObject;
+ }
+
} // namespace JSC
#endif // JSGlobalObject_h