src/script/api/qscriptengine.cpp
changeset 3 41300fa6a67c
parent 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
2:56cd8111b7f7 3:41300fa6a67c
     4 ** All rights reserved.
     4 ** All rights reserved.
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
     6 **
     6 **
     7 ** This file is part of the QtScript module of the Qt Toolkit.
     7 ** This file is part of the QtScript module of the Qt Toolkit.
     8 **
     8 **
     9 ** $QT_BEGIN_LICENSE:LGPL$
     9 ** $QT_BEGIN_LICENSE:LGPL-ONLY$
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
    10 ** GNU Lesser General Public License Usage
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
    11 ** This file may be used under the terms of the GNU Lesser
    18 ** General Public License version 2.1 as published by the Free Software
    12 ** General Public License version 2.1 as published by the Free Software
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
    13 ** Foundation and appearing in the file LICENSE.LGPL included in the
    20 ** packaging of this file.  Please review the following information to
    14 ** packaging of this file.  Please review the following information to
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
    15 ** ensure the GNU Lesser General Public License version 2.1 requirements
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
    16 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
    23 **
    17 **
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
    18 ** If you have questions regarding the use of this file, please contact
    29 ** Nokia at qt-info@nokia.com.
    19 ** Nokia at qt-info@nokia.com.
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
    20 ** $QT_END_LICENSE$
    39 **
    21 **
    40 ****************************************************************************/
    22 ****************************************************************************/
    41 
    23 
    42 #include "config.h"
    24 #include "config.h"
    49 #include "qscriptcontext_p.h"
    31 #include "qscriptcontext_p.h"
    50 #include "qscriptstring_p.h"
    32 #include "qscriptstring_p.h"
    51 #include "qscriptvalue_p.h"
    33 #include "qscriptvalue_p.h"
    52 #include "qscriptvalueiterator.h"
    34 #include "qscriptvalueiterator.h"
    53 #include "qscriptclass.h"
    35 #include "qscriptclass.h"
       
    36 #include "qscriptcontextinfo.h"
       
    37 #include "qscriptprogram.h"
       
    38 #include "qscriptprogram_p.h"
    54 #include "qdebug.h"
    39 #include "qdebug.h"
    55 
    40 
    56 #include <QtCore/qstringlist.h>
    41 #include <QtCore/qstringlist.h>
    57 #include <QtCore/qmetaobject.h>
    42 #include <QtCore/qmetaobject.h>
    58 
    43 
   712         return JSC::throwError(exec, JSC::GeneralError, "qsTr(): second argument (comment) must be a string");
   697         return JSC::throwError(exec, JSC::GeneralError, "qsTr(): second argument (comment) must be a string");
   713     if ((args.size() > 2) && !args.at(2).isNumber())
   698     if ((args.size() > 2) && !args.at(2).isNumber())
   714         return JSC::throwError(exec, JSC::GeneralError, "qsTranslate(): third argument (n) must be a number");
   699         return JSC::throwError(exec, JSC::GeneralError, "qsTranslate(): third argument (n) must be a number");
   715 #ifndef QT_NO_QOBJECT
   700 #ifndef QT_NO_QOBJECT
   716     QString context;
   701     QString context;
   717 // ### implement context resolution
   702     QScriptContext *ctx = QScriptEnginePrivate::contextForFrame(exec);
   718 //    if (ctx->parentContext())
   703     if (ctx && ctx->parentContext())
   719 //        context = QFileInfo(ctx->parentContext()->fileName()).baseName();
   704         context = QFileInfo(QScriptContextInfo(ctx->parentContext()).fileName()).baseName();
   720 #endif
   705 #endif
   721     QString text(args.at(0).toString(exec));
   706     QString text(args.at(0).toString(exec));
   722 #ifndef QT_NO_QOBJECT
   707 #ifndef QT_NO_QOBJECT
   723     QString comment;
   708     QString comment;
   724     if (args.size() > 1)
   709     if (args.size() > 1)
   790     qMetaTypeId<QList<int> >();
   775     qMetaTypeId<QList<int> >();
   791 #ifndef QT_NO_QOBJECT
   776 #ifndef QT_NO_QOBJECT
   792     qMetaTypeId<QObjectList>();
   777     qMetaTypeId<QObjectList>();
   793 #endif
   778 #endif
   794 
   779 
   795     JSC::initializeThreading(); // ### hmmm
   780     if (!QCoreApplication::instance()) {
       
   781         qFatal("QScriptEngine: Must construct a Q(Core)Application before a QScriptEngine");
       
   782         return;
       
   783     }
       
   784     JSC::initializeThreading();
   796 
   785 
   797     globalData = JSC::JSGlobalData::create().releaseRef();
   786     globalData = JSC::JSGlobalData::create().releaseRef();
   798     globalData->clientData = new QScript::GlobalClientData(this);
   787     globalData->clientData = new QScript::GlobalClientData(this);
   799     JSC::JSGlobalObject *globalObject = new (globalData)QScript::GlobalObject();
   788     JSC::JSGlobalObject *globalObject = new (globalData)QScript::GlobalObject();
   800 
   789 
  1089 }
  1078 }
  1090 
  1079 
  1091 
  1080 
  1092 void QScriptEnginePrivate::mark(JSC::MarkStack& markStack)
  1081 void QScriptEnginePrivate::mark(JSC::MarkStack& markStack)
  1093 {
  1082 {
       
  1083     Q_Q(QScriptEngine);
       
  1084 
  1094     markStack.append(originalGlobalObject());
  1085     markStack.append(originalGlobalObject());
  1095     markStack.append(globalObject());
  1086     markStack.append(globalObject());
  1096     if (originalGlobalObjectProxy)
  1087     if (originalGlobalObjectProxy)
  1097         markStack.append(originalGlobalObjectProxy);
  1088         markStack.append(originalGlobalObjectProxy);
  1098 
  1089 
  1109             if (it->isJSC())
  1100             if (it->isJSC())
  1110                 markStack.append(it->jscValue);
  1101                 markStack.append(it->jscValue);
  1111         }
  1102         }
  1112     }
  1103     }
  1113 
  1104 
       
  1105     {
       
  1106         QHash<int, QScriptTypeInfo*>::const_iterator it;
       
  1107         for (it = m_typeInfos.constBegin(); it != m_typeInfos.constEnd(); ++it) {
       
  1108             if ((*it)->prototype)
       
  1109                 markStack.append((*it)->prototype);
       
  1110         }
       
  1111     }
       
  1112 
       
  1113     {
       
  1114         QScriptContext *context = q->currentContext();
       
  1115 
       
  1116         while (context) {
       
  1117             JSC::ScopeChainNode *node = frameForContext(context)->scopeChain();
       
  1118             JSC::ScopeChainIterator it(node);
       
  1119             for (it = node->begin(); it != node->end(); ++it) {
       
  1120                 JSC::JSObject *object = *it;
       
  1121                 if (object)
       
  1122                     markStack.append(object);
       
  1123             }
       
  1124 
       
  1125             context = context->parentContext();
       
  1126         }
       
  1127     }
       
  1128 
  1114 #ifndef QT_NO_QOBJECT
  1129 #ifndef QT_NO_QOBJECT
       
  1130     markStack.drain(); // make sure everything is marked before marking qobject data
  1115     {
  1131     {
  1116         QHash<QObject*, QScript::QObjectData*>::const_iterator it;
  1132         QHash<QObject*, QScript::QObjectData*>::const_iterator it;
  1117         for (it = m_qobjectData.constBegin(); it != m_qobjectData.constEnd(); ++it) {
  1133         for (it = m_qobjectData.constBegin(); it != m_qobjectData.constEnd(); ++it) {
  1118             QScript::QObjectData *qdata = it.value();
  1134             QScript::QObjectData *qdata = it.value();
  1119             qdata->mark(markStack);
  1135             qdata->mark(markStack);
  1120         }
  1136         }
  1121     }
  1137     }
  1122 #endif
  1138 #endif
  1123 
       
  1124     {
       
  1125         QHash<int, QScriptTypeInfo*>::const_iterator it;
       
  1126         for (it = m_typeInfos.constBegin(); it != m_typeInfos.constEnd(); ++it) {
       
  1127             if ((*it)->prototype)
       
  1128                 markStack.append((*it)->prototype);
       
  1129         }
       
  1130     }
       
  1131 }
  1139 }
  1132 
  1140 
  1133 bool QScriptEnginePrivate::isCollecting() const
  1141 bool QScriptEnginePrivate::isCollecting() const
  1134 {
  1142 {
  1135     return globalData->heap.isBusy();
  1143     return globalData->heap.isBusy();
  1151     ownedAgents.removeOne(agent);
  1159     ownedAgents.removeOne(agent);
  1152     if (activeAgent == agent) {
  1160     if (activeAgent == agent) {
  1153         QScriptEngineAgentPrivate::get(agent)->detach();
  1161         QScriptEngineAgentPrivate::get(agent)->detach();
  1154         activeAgent = 0;
  1162         activeAgent = 0;
  1155     }
  1163     }
       
  1164 }
       
  1165 
       
  1166 JSC::JSValue QScriptEnginePrivate::evaluateHelper(JSC::ExecState *exec, intptr_t sourceId,
       
  1167                                                   JSC::EvalExecutable *executable,
       
  1168                                                   bool &compile)
       
  1169 {
       
  1170     Q_Q(QScriptEngine);
       
  1171     JSC::JSLock lock(false); // ### hmmm
       
  1172     QBoolBlocker inEvalBlocker(inEval, true);
       
  1173     q->currentContext()->activationObject(); //force the creation of a context for native function;
       
  1174 
       
  1175     JSC::Debugger* debugger = originalGlobalObject()->debugger();
       
  1176     if (debugger)
       
  1177         debugger->evaluateStart(sourceId);
       
  1178 
       
  1179     q->clearExceptions();
       
  1180     JSC::DynamicGlobalObjectScope dynamicGlobalObjectScope(exec, exec->scopeChain()->globalObject());
       
  1181 
       
  1182     if (compile) {
       
  1183         JSC::JSObject* error = executable->compile(exec, exec->scopeChain());
       
  1184         if (error) {
       
  1185             compile = false;
       
  1186             exec->setException(error);
       
  1187 
       
  1188             if (debugger) {
       
  1189                 debugger->exceptionThrow(JSC::DebuggerCallFrame(exec, error), sourceId, false);
       
  1190                 debugger->evaluateStop(error, sourceId);
       
  1191             }
       
  1192 
       
  1193             return error;
       
  1194         }
       
  1195     }
       
  1196 
       
  1197     JSC::JSValue thisValue = thisForContext(exec);
       
  1198     JSC::JSObject* thisObject = (!thisValue || thisValue.isUndefinedOrNull())
       
  1199                                 ? exec->dynamicGlobalObject() : thisValue.toObject(exec);
       
  1200     JSC::JSValue exceptionValue;
       
  1201     timeoutChecker()->setShouldAbort(false);
       
  1202     if (processEventsInterval > 0)
       
  1203         timeoutChecker()->reset();
       
  1204 
       
  1205     JSC::JSValue result = exec->interpreter()->execute(executable, exec, thisObject, exec->scopeChain(), &exceptionValue);
       
  1206 
       
  1207     if (timeoutChecker()->shouldAbort()) {
       
  1208         if (abortResult.isError())
       
  1209             exec->setException(scriptValueToJSCValue(abortResult));
       
  1210 
       
  1211         if (debugger)
       
  1212             debugger->evaluateStop(scriptValueToJSCValue(abortResult), sourceId);
       
  1213 
       
  1214         return scriptValueToJSCValue(abortResult);
       
  1215     }
       
  1216 
       
  1217     if (exceptionValue) {
       
  1218         exec->setException(exceptionValue);
       
  1219 
       
  1220         if (debugger)
       
  1221             debugger->evaluateStop(exceptionValue, sourceId);
       
  1222 
       
  1223         return exceptionValue;
       
  1224     }
       
  1225 
       
  1226     if (debugger)
       
  1227         debugger->evaluateStop(result, sourceId);
       
  1228 
       
  1229     Q_ASSERT(!exec->hadException());
       
  1230     return result;
  1156 }
  1231 }
  1157 
  1232 
  1158 #ifndef QT_NO_QOBJECT
  1233 #ifndef QT_NO_QOBJECT
  1159 
  1234 
  1160 JSC::JSValue QScriptEnginePrivate::newQObject(
  1235 JSC::JSValue QScriptEnginePrivate::newQObject(
  1231         return it.value();
  1306         return it.value();
  1232 
  1307 
  1233     QScript::QObjectData *data = new QScript::QObjectData(this);
  1308     QScript::QObjectData *data = new QScript::QObjectData(this);
  1234     m_qobjectData.insert(object, data);
  1309     m_qobjectData.insert(object, data);
  1235     QObject::connect(object, SIGNAL(destroyed(QObject*)),
  1310     QObject::connect(object, SIGNAL(destroyed(QObject*)),
  1236                      q_func(), SLOT(_q_objectDestroyed(QObject *)));
  1311                      q_func(), SLOT(_q_objectDestroyed(QObject*)));
  1237     return data;
  1312     return data;
  1238 }
  1313 }
  1239 
  1314 
  1240 void QScriptEnginePrivate::_q_objectDestroyed(QObject *object)
  1315 void QScriptEnginePrivate::_q_objectDestroyed(QObject *object)
  1241 {
  1316 {
  2113 */
  2188 */
  2114 
  2189 
  2115 QScriptValue QScriptEngine::evaluate(const QString &program, const QString &fileName, int lineNumber)
  2190 QScriptValue QScriptEngine::evaluate(const QString &program, const QString &fileName, int lineNumber)
  2116 {
  2191 {
  2117     Q_D(QScriptEngine);
  2192     Q_D(QScriptEngine);
  2118 
       
  2119     JSC::JSLock lock(false); // ### hmmm
       
  2120     QBoolBlocker inEval(d->inEval, true);
       
  2121     currentContext()->activationObject(); //force the creation of a context for native function;
       
  2122 
       
  2123     JSC::Debugger* debugger = d->originalGlobalObject()->debugger();
       
  2124 
       
  2125     JSC::UString jscProgram = program;
       
  2126     JSC::UString jscFileName = fileName;
       
  2127     JSC::ExecState* exec = d->currentFrame;
       
  2128     WTF::PassRefPtr<QScript::UStringSourceProviderWithFeedback> provider
  2193     WTF::PassRefPtr<QScript::UStringSourceProviderWithFeedback> provider
  2129             = QScript::UStringSourceProviderWithFeedback::create(jscProgram, jscFileName, lineNumber, d);
  2194             = QScript::UStringSourceProviderWithFeedback::create(program, fileName, lineNumber, d);
  2130     intptr_t sourceId = provider->asID();
  2195     intptr_t sourceId = provider->asID();
  2131     JSC::SourceCode source(provider, lineNumber); //after construction of SourceCode provider variable will be null.
  2196     JSC::SourceCode source(provider, lineNumber); //after construction of SourceCode provider variable will be null.
  2132 
  2197 
  2133     if (debugger)
  2198     JSC::ExecState* exec = d->currentFrame;
  2134         debugger->evaluateStart(sourceId);
       
  2135 
       
  2136     clearExceptions();
       
  2137     JSC::DynamicGlobalObjectScope dynamicGlobalObjectScope(exec, exec->scopeChain()->globalObject());
       
  2138 
       
  2139     JSC::EvalExecutable executable(exec, source);
  2199     JSC::EvalExecutable executable(exec, source);
  2140     JSC::JSObject* error = executable.compile(exec, exec->scopeChain());
  2200     bool compile = true;
  2141     if (error) {
  2201     return d->scriptValueFromJSCValue(d->evaluateHelper(exec, sourceId, &executable, compile));
  2142         exec->setException(error);
  2202 }
  2143 
  2203 
  2144         if (debugger) {
  2204 /*!
  2145             debugger->exceptionThrow(JSC::DebuggerCallFrame(exec, error), sourceId, false);
  2205   \internal
  2146             debugger->evaluateStop(error, sourceId);
  2206   \since 4.6
  2147         }
  2207 
  2148 
  2208   Evaluates the given \a program and returns the result of the
  2149         return d->scriptValueFromJSCValue(error);
  2209   evaluation.
  2150     }
  2210 */
  2151 
  2211 QScriptValue QScriptEngine::evaluate(const QScriptProgram &program)
  2152     JSC::JSValue thisValue = d->thisForContext(exec);
  2212 {
  2153     JSC::JSObject* thisObject = (!thisValue || thisValue.isUndefinedOrNull()) ? exec->dynamicGlobalObject() : thisValue.toObject(exec);
  2213     Q_D(QScriptEngine);
  2154     JSC::JSValue exceptionValue;
  2214     QScriptProgramPrivate *program_d = QScriptProgramPrivate::get(program);
  2155     d->timeoutChecker()->setShouldAbort(false);
  2215     if (!program_d)
  2156     if (d->processEventsInterval > 0)
  2216         return QScriptValue();
  2157         d->timeoutChecker()->reset();
  2217 
  2158     JSC::JSValue result = exec->interpreter()->execute(&executable, exec, thisObject, exec->scopeChain(), &exceptionValue);
  2218     JSC::ExecState* exec = d->currentFrame;
  2159 
  2219     JSC::EvalExecutable *executable = program_d->executable(exec, d);
  2160     if (d->timeoutChecker()->shouldAbort()) {
  2220     bool compile = !program_d->isCompiled;
  2161         if (d->abortResult.isError())
  2221     JSC::JSValue result = d->evaluateHelper(exec, program_d->sourceId,
  2162             exec->setException(d->scriptValueToJSCValue(d->abortResult));
  2222                                             executable, compile);
  2163 
  2223     if (compile)
  2164         if (debugger)
  2224         program_d->isCompiled = true;
  2165             debugger->evaluateStop(d->scriptValueToJSCValue(d->abortResult), sourceId);
       
  2166 
       
  2167         return d->abortResult;
       
  2168     }
       
  2169 
       
  2170     if (exceptionValue) {
       
  2171         exec->setException(exceptionValue);
       
  2172 
       
  2173         if (debugger)
       
  2174             debugger->evaluateStop(exceptionValue, sourceId);
       
  2175 
       
  2176         return d->scriptValueFromJSCValue(exceptionValue);
       
  2177     }
       
  2178 
       
  2179     if (debugger)
       
  2180         debugger->evaluateStop(result, sourceId);
       
  2181 
       
  2182     Q_ASSERT(!exec->hadException());
       
  2183     return d->scriptValueFromJSCValue(result);
  2225     return d->scriptValueFromJSCValue(result);
  2184 }
  2226 }
  2185 
       
  2186 
  2227 
  2187 /*!
  2228 /*!
  2188   Returns the current context.
  2229   Returns the current context.
  2189 
  2230 
  2190   The current context is typically accessed to retrieve the arguments
  2231   The current context is typically accessed to retrieve the arguments
  2244    exec is the current top frame.
  2285    exec is the current top frame.
  2245 
  2286 
  2246    return the new top frame. (might be the same as exec if a new stackframe was not needed) or 0 if stack overflow
  2287    return the new top frame. (might be the same as exec if a new stackframe was not needed) or 0 if stack overflow
  2247 */
  2288 */
  2248 JSC::CallFrame *QScriptEnginePrivate::pushContext(JSC::CallFrame *exec, JSC::JSValue _thisObject,
  2289 JSC::CallFrame *QScriptEnginePrivate::pushContext(JSC::CallFrame *exec, JSC::JSValue _thisObject,
  2249                                                   const JSC::ArgList& args, JSC::JSObject *callee, bool calledAsConstructor)
  2290                                                   const JSC::ArgList& args, JSC::JSObject *callee, bool calledAsConstructor,
       
  2291                                                   bool clearScopeChain)
  2250 {
  2292 {
  2251     JSC::JSValue thisObject = _thisObject;
  2293     JSC::JSValue thisObject = _thisObject;
  2252     if (calledAsConstructor) {
  2294     if (calledAsConstructor) {
  2253         //JSC doesn't create default created object for native functions. so we do it
  2295         //JSC doesn't create default created object for native functions. so we do it
  2254         JSC::JSValue prototype = callee->get(exec, exec->propertyNames().prototype);
  2296         JSC::JSValue prototype = callee->get(exec, exec->propertyNames().prototype);
  2278         int dst = 0;
  2320         int dst = 0;
  2279         JSC::ArgList::const_iterator it;
  2321         JSC::ArgList::const_iterator it;
  2280         for (it = args.begin(); it != args.end(); ++it)
  2322         for (it = args.begin(); it != args.end(); ++it)
  2281             newCallFrame[++dst] = *it;
  2323             newCallFrame[++dst] = *it;
  2282         newCallFrame += argc + JSC::RegisterFile::CallFrameHeaderSize;
  2324         newCallFrame += argc + JSC::RegisterFile::CallFrameHeaderSize;
  2283         newCallFrame->init(0, /*vPC=*/0, exec->scopeChain(), exec, flags | ShouldRestoreCallFrame, argc, callee);
  2325 
       
  2326         if (!clearScopeChain) {
       
  2327             newCallFrame->init(0, /*vPC=*/0, exec->scopeChain(), exec, flags | ShouldRestoreCallFrame, argc, callee);
       
  2328         } else {
       
  2329             JSC::JSObject *jscObject = originalGlobalObject();
       
  2330             JSC::ScopeChainNode *scn = new JSC::ScopeChainNode(0, jscObject, &exec->globalData(), jscObject);
       
  2331             newCallFrame->init(0, /*vPC=*/0, scn, exec, flags | ShouldRestoreCallFrame, argc, callee);
       
  2332         }
  2284     } else {
  2333     } else {
  2285         setContextFlags(newCallFrame, flags);
  2334         setContextFlags(newCallFrame, flags);
  2286 #if ENABLE(JIT)
  2335 #if ENABLE(JIT)
  2287         exec->registers()[JSC::RegisterFile::Callee] = JSC::JSValue(callee); //JIT let the callee set the 'callee'
  2336         exec->registers()[JSC::RegisterFile::Callee] = JSC::JSValue(callee); //JIT let the callee set the 'callee'
  2288 #endif
  2337 #endif