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 |
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( |
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 |