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.cpp224
1 files changed, 222 insertions, 2 deletions
diff --git a/src/script/api/qscriptengine.cpp b/src/script/api/qscriptengine.cpp
index b1f36be..029d3a5 100644
--- a/src/script/api/qscriptengine.cpp
+++ b/src/script/api/qscriptengine.cpp
@@ -340,6 +340,25 @@ public:
JSC::JSValue prototype;
};
+class QScriptProgramPrivate
+{
+public:
+ QScriptProgramPrivate() : refcount(1), hasException(false) { }
+ ~QScriptProgramPrivate() { if (evalNode) evalNode->destroyData(); }
+
+ void addref() { ++refcount; }
+ void release() { if (--refcount) delete this; }
+
+ int refcount;
+
+ bool hasException;
+ QScriptValue exception;
+
+ JSC::SourceCode source;
+ WTF::RefPtr<JSC::EvalNode> evalNode;
+};
+
+
namespace QScript
{
@@ -2113,7 +2132,121 @@ QScriptSyntaxCheckResult QScriptEnginePrivate::checkSyntax(const QString &progra
return QScriptSyntaxCheckResult(p);
}
+QScriptProgram QScriptEngine::compile(const QString &program, const QString &fileName, int lineNumber)
+{
+ Q_D(QScriptEngine);
+
+ QScriptProgram rv;
+ rv.d = new QScriptProgramPrivate;
+
+ JSC::JSLock lock(false); // ### hmmm
+ 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;
+ WTF::PassRefPtr<QScript::UStringSourceProviderWithFeedback> provider
+ = QScript::UStringSourceProviderWithFeedback::create(jscProgram, jscFileName, lineNumber, d);
+ intptr_t sourceId = provider->asID();
+ JSC::SourceCode &source = rv.d->source;
+ source = JSC::SourceCode(provider, lineNumber); //after construction of SourceCode provider variable will be null.
+
+ if (debugger)
+ debugger->evaluateStart(sourceId);
+
+ exec->clearException();
+ JSC::DynamicGlobalObjectScope dynamicGlobalObjectScope(exec, exec->scopeChain()->globalObject());
+
+ int errorLine;
+ JSC::UString errorMessage;
+ WTF::RefPtr<JSC::EvalNode> &evalNode = rv.d->evalNode;
+ evalNode = exec->globalData().parser->parse<JSC::EvalNode>(&exec->globalData(), exec->lexicalGlobalObject()->debugger(), exec, source, &errorLine, &errorMessage);
+ if (!evalNode) {
+ JSC::JSValue exceptionValue = JSC::Error::create(exec, JSC::SyntaxError, errorMessage, errorLine, source.provider()->asID(), source.provider()->url());
+ exec->setException(exceptionValue);
+
+ if (debugger) {
+ debugger->exceptionThrow(JSC::DebuggerCallFrame(exec, exceptionValue), sourceId, false);
+ debugger->evaluateStop(exceptionValue, sourceId);
+ }
+
+ rv.d->hasException = true;
+ rv.d->exception = d->scriptValueFromJSCValue(exceptionValue);
+ } else if (debugger) {
+ debugger->evaluateStop(JSC::JSValue(), sourceId);
+ }
+
+ return rv;
+}
+
+QScriptValue QScriptEngine::evaluate(const QScriptProgram &program)
+{
+ Q_D(QScriptEngine);
+
+ if (0 == program.d)
+ return QScriptValue();
+ else if (program.d->hasException)
+ return program.d->exception;
+ else if (!program.d->evalNode)
+ return QScriptValue();
+
+ JSC::JSLock lock(false); // ### hmmm
+ QBoolBlocker inEval(d->inEval, true);
+ currentContext()->activationObject(); //force the creation of a context for native function;
+
+ JSC::Debugger* debugger = d->originalGlobalObject()->debugger();
+
+ JSC::ExecState* exec = d->currentFrame;
+
+ intptr_t sourceId = program.d->source.provider()->asID();
+
+ if (debugger)
+ debugger->evaluateStart(sourceId);
+
+ exec->clearException();
+ JSC::DynamicGlobalObjectScope dynamicGlobalObjectScope(exec, exec->scopeChain()->globalObject());
+
+ WTF::RefPtr<JSC::EvalNode> &evalNode = program.d->evalNode;
+
+ JSC::EvalExecutable executable(exec, program.d->source);
+ executable.compile(exec, evalNode, exec->scopeChain());
+ JSC::JSValue thisValue = d->thisForContext(exec);
+ JSC::JSObject* thisObject = (!thisValue || thisValue.isUndefinedOrNull()) ? exec->dynamicGlobalObject() : thisValue.toObject(exec);
+ JSC::JSValue exceptionValue;
+ d->timeoutChecker()->setShouldAbort(false);
+ if (d->processEventsInterval > 0)
+ d->timeoutChecker()->reset();
+ JSC::JSValue result = exec->interpreter()->execute(&executable, exec, thisObject, exec->scopeChain(), &exceptionValue);
+
+ if (d->timeoutChecker()->shouldAbort()) {
+ if (d->abortResult.isError())
+ exec->setException(d->scriptValueToJSCValue(d->abortResult));
+
+ if (debugger)
+ debugger->evaluateStop(d->scriptValueToJSCValue(d->abortResult), sourceId);
+
+ return d->abortResult;
+ }
+
+ if (exceptionValue) {
+ exec->setException(exceptionValue);
+
+ if (debugger)
+ debugger->evaluateStop(exceptionValue, sourceId);
+
+ return d->scriptValueFromJSCValue(exceptionValue);
+ }
+
+ if (debugger)
+ debugger->evaluateStop(result, sourceId);
+
+ Q_ASSERT(!exec->hadException());
+ return d->scriptValueFromJSCValue(result);
+}
/*!
Evaluates \a program, using \a lineNumber as the base line number,
@@ -2266,6 +2399,35 @@ QScriptContext *QScriptEngine::pushContext()
return d->contextForFrame(newFrame);
}
+/*!
+ Enters a new execution context and returns the associated
+ QScriptContext object.
+
+ Once you are done with the context, you should call popContext() to
+ restore the old context.
+
+ By default, the `this' object of the new context is the Global Object.
+ The context's \l{QScriptContext::callee()}{callee}() will be invalid.
+
+ Unlike pushContext(), the default scope chain is reset to include
+ only the global object and the QScriptContext's activation object.
+
+ \sa popContext()
+*/
+QScriptContext *QScriptEngine::pushCleanContext()
+{
+ Q_D(QScriptEngine);
+
+ JSC::CallFrame* newFrame = d->pushContext(d->currentFrame, d->currentFrame->globalData().dynamicGlobalObject,
+ JSC::ArgList(), /*callee = */0, false, true);
+
+ if (agent())
+ agent()->contextPush();
+
+ 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.
@@ -2277,7 +2439,8 @@ QScriptContext *QScriptEngine::pushContext()
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, JSC::JSValue _thisObject,
- const JSC::ArgList& args, JSC::JSObject *callee, bool calledAsConstructor)
+ const JSC::ArgList& args, JSC::JSObject *callee, bool calledAsConstructor,
+ bool clearScopeChain)
{
JSC::JSValue thisObject = _thisObject;
if (calledAsConstructor) {
@@ -2311,7 +2474,14 @@ JSC::CallFrame *QScriptEnginePrivate::pushContext(JSC::CallFrame *exec, JSC::JSV
for (it = args.begin(); it != args.end(); ++it)
newCallFrame[++dst] = *it;
newCallFrame += argc + JSC::RegisterFile::CallFrameHeaderSize;
- newCallFrame->init(0, /*vPC=*/0, exec->scopeChain(), exec, flags | ShouldRestoreCallFrame, argc, callee);
+
+ if (!clearScopeChain) {
+ newCallFrame->init(0, /*vPC=*/0, exec->scopeChain(), exec, flags | ShouldRestoreCallFrame, argc, callee);
+ } else {
+ JSC::JSObject *jscObject = originalGlobalObject();
+ JSC::ScopeChainNode *scn = new JSC::ScopeChainNode(0, jscObject, &exec->globalData(), jscObject);
+ newCallFrame->init(0, /*vPC=*/0, scn, exec, flags | ShouldRestoreCallFrame, argc, callee);
+ }
} else {
setContextFlags(newCallFrame, flags);
#if ENABLE(JIT)
@@ -3707,6 +3877,9 @@ QScriptValue QScriptEngine::objectById(qint64 id) const
return const_cast<QScriptEnginePrivate*>(d)->scriptValueFromJSCValue((JSC::JSCell*)id);
}
+
+
+
/*!
\since 4.5
\class QScriptSyntaxCheckResult
@@ -3835,4 +4008,51 @@ Q_AUTOTEST_EXPORT bool qt_script_isJITEnabled()
}
#endif
+QScriptProgram::QScriptProgram()
+: d(0)
+{
+}
+
+QScriptProgram::~QScriptProgram()
+{
+ if (d) d->release();
+}
+
+QScriptProgram::QScriptProgram(const QScriptProgram &c)
+: d(c.d)
+{
+ if (d) d->addref();
+}
+
+QScriptProgram &QScriptProgram::operator=(const QScriptProgram &c)
+{
+ if (c.d) c.d->addref();
+ if (d) d->release();
+ d = c.d;
+ return *this;
+}
+
+bool QScriptProgram::isNull() const
+{
+ return d == 0;
+}
+
+bool QScriptProgram::hasSyntaxError() const
+{
+ if (d) return d->hasException;
+ else return false;
+}
+
+QScriptValue QScriptProgram::syntaxError() const
+{
+ if (d) return d->exception;
+ else return QScriptValue();
+}
+
+QString QScriptProgram::programSource() const
+{
+ if (d) return d->source.toString();
+ else return QString();
+}
+
QT_END_NAMESPACE