diff options
author | Olivier Goffart <ogoffart@trolltech.com> | 2009-08-11 11:53:04 (GMT) |
---|---|---|
committer | Olivier Goffart <ogoffart@trolltech.com> | 2009-08-12 13:15:23 (GMT) |
commit | 45e2a19b4b75fe94a78161f26862bf3c6f727d74 (patch) | |
tree | a6e698eee514ad28815519f3b2ba5ac592941de3 /src/script/api | |
parent | e806a4e887b6584f1115ced3cb489bb0e9a2de36 (diff) | |
download | Qt-45e2a19b4b75fe94a78161f26862bf3c6f727d74.zip Qt-45e2a19b4b75fe94a78161f26862bf3c6f727d74.tar.gz Qt-45e2a19b4b75fe94a78161f26862bf3c6f727d74.tar.bz2 |
Refactor the way the JS stack are created for native function
The original JavaScriptCore doesn't create stack frame or scope for
native function.
JSC has been patched to support that.
This commit revert our patches to JSC, and implement create the stack
frame from QScript
Reviewed-by: Kent Hansen
Diffstat (limited to 'src/script/api')
-rw-r--r-- | src/script/api/qscriptengine.cpp | 100 | ||||
-rw-r--r-- | src/script/api/qscriptengine_p.h | 22 | ||||
-rw-r--r-- | src/script/api/qscriptvalue.cpp | 1 |
3 files changed, 67 insertions, 56 deletions
diff --git a/src/script/api/qscriptengine.cpp b/src/script/api/qscriptengine.cpp index f59cd99..a0ca6b0 100644 --- a/src/script/api/qscriptengine.cpp +++ b/src/script/api/qscriptengine.cpp @@ -797,24 +797,6 @@ static QScriptValue __setupPackage__(QScriptContext *ctx, QScriptEngine *eng) } #endif -QScriptPushScopeHelper::QScriptPushScopeHelper(JSC::CallFrame *exec, bool calledAsConstructor) -{ - engine = scriptEngineFromExec(exec); - previousFrame = engine->currentFrame; - engine->currentFrame = exec; - QScriptActivationObject *scope = new (exec) QScriptActivationObject(exec); - scope->d_ptr()->calledAsConstructor = calledAsConstructor; - exec->setScopeChain(exec->scopeChain()->copy()->push(scope)); -} - -QScriptPushScopeHelper::~QScriptPushScopeHelper() -{ - JSC::CallFrame *exec = engine->currentFrame; - exec->setScopeChain(exec->scopeChain()->pop()); - exec->scopeChain()->deref(); - engine->currentFrame = previousFrame; -} - } // namespace QScript QScriptEnginePrivate::QScriptEnginePrivate() : idGenerator(1) @@ -2269,26 +2251,55 @@ QScriptContext *QScriptEngine::currentContext() const QScriptContext *QScriptEngine::pushContext() { Q_D(QScriptEngine); - const int argCount = 1; // for 'this' - JSC::RegisterFile ®isterFile = d->currentFrame->interpreter()->registerFile(); - JSC::Register *const newEnd = registerFile.end() + JSC::RegisterFile::CallFrameHeaderSize + argCount; - if (!registerFile.grow(newEnd)) - return 0; - JSC::CallFrame* previousFrame = d->currentFrame; - JSC::JSObject* scope = new (d->currentFrame) QScript::QScriptActivationObject(d->currentFrame); + JSC::CallFrame* newFrame = d->pushContext(d->currentFrame, d->currentFrame->globalData().dynamicGlobalObject, + JSC::ArgList(), /*callee = */0); - d->currentFrame = JSC::CallFrame::create(newEnd); - d->currentFrame->init(0, 0, previousFrame->scopeChain()->copy()->push(scope), - previousFrame, 0, argCount, 0); - QScriptContext *ctx = d->contextForFrame(d->currentFrame); - ctx->setThisObject(globalObject()); - if (agent()) agent()->contextPush(); - return ctx; + + return d->contextForFrame(newFrame); } +/*! \internal + push a context for a native function. + JSC native function doesn't have different stackframe or context. so we need to create one. + + use popContext right after to go back to the previous context the context if no stack overflow has hapenned + + exec is the current top frame. + + return the new top frame. (might be the same as exec if a new stackframe was not needed) or 0 if stack overflow +*/ +JSC::CallFrame *QScriptEnginePrivate::pushContext(JSC::CallFrame *exec, const JSC::JSValue &thisObject, + const JSC::ArgList& args, JSC::JSObject *callee, bool calledAsConstructor) +{ + JSC::CallFrame *newCallFrame = exec; + if (callee == 0 || !(exec->callee() == callee && exec->returnPC() != 0)) { + //We need to check if the Interpreter might have already created a frame for function called from JS. + JSC::Interpreter *interp = exec->interpreter(); + JSC::Register *oldEnd = interp->registerFile().end(); + int argc = args.size() + 1; //add "this" + JSC::Register *newEnd = oldEnd + argc + JSC::RegisterFile::CallFrameHeaderSize; + if (!interp->registerFile().grow(newEnd)) + return 0; //### Stack overflow + newCallFrame = JSC::CallFrame::create(oldEnd); + newCallFrame[0] = thisObject; + int dst = 0; + JSC::ArgList::const_iterator it; + for (it = args.begin(); it != args.end(); ++it) + newCallFrame[++dst] = *it; + newCallFrame += argc + JSC::RegisterFile::CallFrameHeaderSize; + newCallFrame->init(0, /*vPC=*/0, exec->scopeChain(), exec, 0, argc, callee); + } + currentFrame = newCallFrame; + QScript::QScriptActivationObject *scope = new (newCallFrame) QScript::QScriptActivationObject(newCallFrame); + scope->d_ptr()->calledAsConstructor = calledAsConstructor; + newCallFrame->setScopeChain(newCallFrame->scopeChain()->copy()->push(scope)); + return newCallFrame; +} + + /*! Pops the current execution context and restores the previous one. This function must be used in conjunction with pushContext(). @@ -2305,11 +2316,26 @@ void QScriptEngine::popContext() qWarning("QScriptEngine::popContext() doesn't match with pushContext()"); return; } - JSC::RegisterFile ®isterFile = d->currentFrame->interpreter()->registerFile(); - JSC::Register *const newEnd = d->currentFrame->registers() - JSC::RegisterFile::CallFrameHeaderSize - d->currentFrame->argumentCount(); - d->currentFrame->scopeChain()->pop()->deref(); - d->currentFrame = d->currentFrame->callerFrame(); - registerFile.shrink(newEnd); + + d->popContext(); +} + +/*! \internal + counter part of QScriptEnginePrivate::pushContext + */ +void QScriptEnginePrivate::popContext() +{ + if (currentFrame->returnPC() == 0) { //normal case + JSC::RegisterFile ®isterFile = currentFrame->interpreter()->registerFile(); + JSC::Register *const newEnd = currentFrame->registers() - JSC::RegisterFile::CallFrameHeaderSize - currentFrame->argumentCount(); + currentFrame->scopeChain()->pop()->deref(); + currentFrame = currentFrame->callerFrame(); + registerFile.shrink(newEnd); + } else { //the stack frame was created by the Interpreter, we don't need to rewind it. + currentFrame->setScopeChain(currentFrame->scopeChain()->pop()); + currentFrame->scopeChain()->deref(); + } + } /*! diff --git a/src/script/api/qscriptengine_p.h b/src/script/api/qscriptengine_p.h index 1506e7e..572f361 100644 --- a/src/script/api/qscriptengine_p.h +++ b/src/script/api/qscriptengine_p.h @@ -157,6 +157,10 @@ public: JSC::JSValue toUsableValue(JSC::JSValue value); static JSC::JSValue thisForContext(JSC::ExecState *frame); + JSC::CallFrame *pushContext(JSC::CallFrame *exec, const JSC::JSValue &thisObject, const JSC::ArgList& args, + JSC::JSObject *callee, bool calledAsConstructor = false); + void popContext(); + void mark(); bool isCollecting() const; void collectGarbage(); @@ -246,24 +250,6 @@ public: #endif }; -namespace QScript -{ -/*! \internal - Helper class to create QScriptActivationObject. - To be used on the stack -*/ -class QScriptPushScopeHelper -{ - public: - QScriptPushScopeHelper(JSC::CallFrame *newFrame, bool calledAsConstructor = false); - ~QScriptPushScopeHelper(); - private: - QScriptEnginePrivate *engine; - JSC::CallFrame *previousFrame; -}; -} // namespace QScript - - QT_END_NAMESPACE #endif diff --git a/src/script/api/qscriptvalue.cpp b/src/script/api/qscriptvalue.cpp index 9bf4ff2..aa0e8cb 100644 --- a/src/script/api/qscriptvalue.cpp +++ b/src/script/api/qscriptvalue.cpp @@ -889,7 +889,6 @@ void QScriptValue::setPrototype(const QScriptValue &prototype) } nextPrototypeValue = nextPrototype->prototype(); } - JSC::asObject(d->jscValue)->setPrototype(other); } |