summaryrefslogtreecommitdiffstats
path: root/src/script/api/qscriptengine.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/script/api/qscriptengine.cpp')
-rw-r--r--src/script/api/qscriptengine.cpp136
1 files changed, 99 insertions, 37 deletions
diff --git a/src/script/api/qscriptengine.cpp b/src/script/api/qscriptengine.cpp
index 71194d34c6..78bbf5f855 100644
--- a/src/script/api/qscriptengine.cpp
+++ b/src/script/api/qscriptengine.cpp
@@ -348,7 +348,7 @@ struct GlobalClientData : public JSC::JSGlobalData::ClientData
GlobalClientData(QScriptEnginePrivate *e)
: engine(e) {}
virtual ~GlobalClientData() {}
- virtual void mark() { engine->mark(); }
+ virtual void mark(JSC::MarkStack& markStack) { engine->mark(markStack); }
QScriptEnginePrivate *engine;
};
@@ -382,6 +382,65 @@ private:
bool m_shouldAbortEvaluation;
};
+/*Helper class. Main purpose is to give debugger feedback about unloading and loading scripts.
+ It keeps pointer to JSGlobalObject assuming that it is always the same - there is no way to update
+ this data. Class is internal and used as an implementation detail in and only in QScriptEngine::evaluate.*/
+class UStringSourceProviderWithFeedback: public JSC::UStringSourceProvider
+{
+public:
+
+ static PassRefPtr<UStringSourceProviderWithFeedback> create(const JSC::UString& source, const JSC::UString& url, int lineNumber, QScriptEnginePrivate* engine)
+ {
+ return adoptRef(new UStringSourceProviderWithFeedback(source, url, lineNumber, engine));
+ }
+
+ /* Destruction means that there is no more copies of script so create scriptUnload event
+ and unregister script in QScriptEnginePrivate::loadedScripts */
+ virtual ~UStringSourceProviderWithFeedback()
+ {
+ if (m_ptr) {
+ if (JSC::Debugger* debugger = this->debugger())
+ debugger->scriptUnload(asID());
+ m_ptr->loadedScripts.remove(this);
+ }
+ }
+
+ /* set internal QScriptEnginePrivate pointer to null and create unloadScript event, should be called
+ only if QScriptEnginePrivate is about to be destroyed.*/
+ void disconnectFromEngine()
+ {
+ if (JSC::Debugger* debugger = this->debugger())
+ debugger->scriptUnload(asID());
+ m_ptr = 0;
+ }
+
+protected:
+ UStringSourceProviderWithFeedback(const JSC::UString& source, const JSC::UString& url, int lineNumber, QScriptEnginePrivate* engine)
+ : UStringSourceProvider(source, url),
+ m_ptr(engine)
+ {
+ if (JSC::Debugger* debugger = this->debugger())
+ debugger->scriptLoad(asID(), source, url, lineNumber);
+ if (m_ptr)
+ m_ptr->loadedScripts.insert(this);
+ }
+
+ JSC::Debugger* debugger()
+ {
+ //if m_ptr is null it mean that QScriptEnginePrivate was destroyed and scriptUnload was called
+ //else m_ptr is stable and we can use it as normal pointer without hesitation
+ if(!m_ptr)
+ return 0; //we are in ~QScriptEnginePrivate
+ else
+ return m_ptr->originalGlobalObject()->debugger(); //QScriptEnginePrivate is still alive
+ }
+
+ //trace global object and debugger instance
+ QScriptEnginePrivate* m_ptr;
+};
+
+
+
static int toDigit(char c)
{
if ((c >= '0') && (c <= '9'))
@@ -840,8 +899,16 @@ QScriptEnginePrivate::QScriptEnginePrivate()
QScriptEnginePrivate::~QScriptEnginePrivate()
{
+ //disconnect all loadedScripts and generate all jsc::debugger::scriptUnload events
+ QSet<QScript::UStringSourceProviderWithFeedback*>::const_iterator i = loadedScripts.constBegin();
+ while(i!=loadedScripts.constEnd()) {
+ (*i)->disconnectFromEngine();
+ i++;
+ }
+
while (!ownedAgents.isEmpty())
delete ownedAgents.takeFirst();
+
detachAllRegisteredScriptValues();
detachAllRegisteredScriptStrings();
qDeleteAll(m_qobjectData);
@@ -1115,27 +1182,25 @@ void QScriptEnginePrivate::setContextFlags(JSC::ExecState *exec, uint flags)
}
-void QScriptEnginePrivate::mark()
+void QScriptEnginePrivate::mark(JSC::MarkStack& markStack)
{
- if (!originalGlobalObject()->marked())
- originalGlobalObject()->mark();
- if (!globalObject()->marked())
- globalObject()->mark();
- if (originalGlobalObjectProxy && !originalGlobalObjectProxy->marked())
- originalGlobalObjectProxy->mark();
+ markStack.append(originalGlobalObject());
+ markStack.append(globalObject());
+ if (originalGlobalObjectProxy)
+ markStack.append(originalGlobalObjectProxy);
- if (qobjectPrototype && !qobjectPrototype->marked())
- qobjectPrototype->mark();
- if (qmetaobjectPrototype && !qmetaobjectPrototype->marked())
- qmetaobjectPrototype->mark();
- if (variantPrototype && !variantPrototype->marked())
- variantPrototype->mark();
+ if (qobjectPrototype)
+ markStack.append(qobjectPrototype);
+ if (qmetaobjectPrototype)
+ markStack.append(qmetaobjectPrototype);
+ if (variantPrototype)
+ markStack.append(variantPrototype);
{
QScriptValuePrivate *it;
for (it = registeredScriptValues; it != 0; it = it->next) {
- if (it->isJSC() && !it->jscValue.marked())
- it->jscValue.mark();
+ if (it->isJSC())
+ markStack.append(it->jscValue);
}
}
@@ -1144,7 +1209,7 @@ void QScriptEnginePrivate::mark()
QHash<QObject*, QScript::QObjectData*>::const_iterator it;
for (it = m_qobjectData.constBegin(); it != m_qobjectData.constEnd(); ++it) {
QScript::QObjectData *qdata = it.value();
- qdata->mark();
+ qdata->mark(markStack);
}
}
#endif
@@ -1152,8 +1217,8 @@ void QScriptEnginePrivate::mark()
{
QHash<int, QScriptTypeInfo*>::const_iterator it;
for (it = m_typeInfos.constBegin(); it != m_typeInfos.constEnd(); ++it) {
- if ((*it)->prototype && !(*it)->prototype.marked())
- (*it)->prototype.mark();
+ if ((*it)->prototype)
+ markStack.append((*it)->prototype);
}
}
}
@@ -2137,6 +2202,7 @@ QScriptSyntaxCheckResult QScriptEnginePrivate::checkSyntax(const QString &progra
\sa canEvaluate(), hasUncaughtException(), isEvaluating(), abortEvaluation()
*/
+
QScriptValue QScriptEngine::evaluate(const QString &program, const QString &fileName, int lineNumber)
{
Q_D(QScriptEngine);
@@ -2145,41 +2211,40 @@ QScriptValue QScriptEngine::evaluate(const QString &program, const QString &file
QBoolBlocker inEval(d->inEval, true);
currentContext()->activationObject(); //force the creation of a context for native function;
+ JSC::Debugger* debugger = d->originalGlobalObject()->debugger();
+
JSC::UString jscProgram = program;
JSC::UString jscFileName = fileName;
JSC::ExecState* exec = d->currentFrame;
- JSC::SourceCode source = JSC::makeSource(jscProgram, jscFileName, lineNumber);
+ WTF::PassRefPtr<QScript::UStringSourceProviderWithFeedback> provider
+ = QScript::UStringSourceProviderWithFeedback::create(jscProgram, jscFileName, lineNumber, d);
+ intptr_t sourceId = provider->asID();
+ JSC::SourceCode source(provider, lineNumber); //after construction of SourceCode provider variable will be null.
- intptr_t sourceId = source.provider()->asID();
- JSC::Debugger* debugger = d->originalGlobalObject()->debugger();
- exec->globalData().scriptpool->startEvaluating(source);
if (debugger)
debugger->evaluateStart(sourceId);
exec->clearException();
JSC::DynamicGlobalObjectScope dynamicGlobalObjectScope(exec, exec->scopeChain()->globalObject());
- int errorLine;
- JSC::UString errorMessage;
- WTF::RefPtr<JSC::EvalNode> evalNode = exec->globalData().parser->parse<JSC::EvalNode>(exec, exec->dynamicGlobalObject()->debugger(), source, &errorLine, &errorMessage);
- if (!evalNode) {
- JSC::JSValue exceptionValue = JSC::Error::create(exec, JSC::SyntaxError, errorMessage, errorLine, source.provider()->asID(), 0);
- exec->setException(exceptionValue);
+ JSC::EvalExecutable executable(source);
+ JSC::JSObject* error = executable.compile(exec, exec->scopeChain());
+ if (error) {
+ exec->setException(error);
if (debugger) {
- debugger->exceptionThrow(JSC::DebuggerCallFrame(exec, exceptionValue), sourceId, false);
- debugger->evaluateStop(exceptionValue, sourceId);
+ debugger->exceptionThrow(JSC::DebuggerCallFrame(exec, error), sourceId, false);
+ debugger->evaluateStop(error, sourceId);
}
- exec->globalData().scriptpool->stopEvaluating(source);
- return d->scriptValueFromJSCValue(exceptionValue);
+ return d->scriptValueFromJSCValue(error);
}
JSC::JSValue thisValue = d->thisForContext(exec);
JSC::JSObject* thisObject = (!thisValue || thisValue.isUndefinedOrNull()) ? exec->dynamicGlobalObject() : thisValue.toObject(exec);
JSC::JSValue exceptionValue;
d->timeoutChecker()->setShouldAbort(false);
- JSC::JSValue result = exec->interpreter()->execute(evalNode.get(), exec, thisObject, exec->scopeChain(), &exceptionValue);
+ JSC::JSValue result = exec->interpreter()->execute(&executable, exec, thisObject, exec->scopeChain(), &exceptionValue);
if (d->timeoutChecker()->shouldAbort()) {
if (d->abortResult.isError())
@@ -2187,7 +2252,6 @@ QScriptValue QScriptEngine::evaluate(const QString &program, const QString &file
if (debugger)
debugger->evaluateStop(d->scriptValueToJSCValue(d->abortResult), sourceId);
- exec->globalData().scriptpool->stopEvaluating(source);
return d->abortResult;
}
@@ -2197,14 +2261,12 @@ QScriptValue QScriptEngine::evaluate(const QString &program, const QString &file
if (debugger)
debugger->evaluateStop(exceptionValue, sourceId);
- exec->globalData().scriptpool->stopEvaluating(source);
return d->scriptValueFromJSCValue(exceptionValue);
}
if (debugger)
debugger->evaluateStop(result, sourceId);
- exec->globalData().scriptpool->stopEvaluating(source);
Q_ASSERT(!exec->hadException());
return d->scriptValueFromJSCValue(result);