diff options
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); } |