summaryrefslogtreecommitdiffstats
path: root/src/script/api
diff options
context:
space:
mode:
authorOlivier Goffart <ogoffart@trolltech.com>2009-08-11 11:53:04 (GMT)
committerOlivier Goffart <ogoffart@trolltech.com>2009-08-12 13:15:23 (GMT)
commit45e2a19b4b75fe94a78161f26862bf3c6f727d74 (patch)
treea6e698eee514ad28815519f3b2ba5ac592941de3 /src/script/api
parente806a4e887b6584f1115ced3cb489bb0e9a2de36 (diff)
downloadQt-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.cpp100
-rw-r--r--src/script/api/qscriptengine_p.h22
-rw-r--r--src/script/api/qscriptvalue.cpp1
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 &registerFile = 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 &registerFile = 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 &registerFile = 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);
}