} else { QScriptEngine::globalObject().setProperty(name, QScriptValue()); } }} void ScriptEngineQtScript::registerFunction(const QString& name, QScriptEngine::FunctionSignature functionSignature, int numArguments) { if (QThread::currentThread() != QScriptEngine::thread()) {#ifdef THREAD_DEBUGGING qCDebug(scriptengine) << "*** WARNING *** ScriptEngineQtScript::registerFunction() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] name:" << name;#endif QMetaObject::invokeMethod(this, "registerFunction", Q_ARG(const QString&, name), Q_ARG(QScriptEngine::FunctionSignature, functionSignature), Q_ARG(int, numArguments)); return; }#ifdef THREAD_DEBUGGING qCDebug(scriptengine) << "ScriptEngineQtScript::registerFunction() called on thread [" << QThread::currentThread() << "] name:" << name;#endif QScriptValue scriptFun = QScriptEngine::newFunction(functionSignature, numArguments); QScriptEngine::globalObject().setProperty(name, scriptFun);} void ScriptEngineQtScript::registerFunction(const QString& name, ScriptEngine::FunctionSignature functionSignature, int numArguments) { if (QThread::currentThread() != QScriptEngine::thread()) {#ifdef THREAD_DEBUGGING qCDebug(scriptengine) << "*** WARNING *** ScriptEngineQtScript::registerFunction() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] name:" << name;#endif QMetaObject::invokeMethod(this, "registerFunction", Q_ARG(const QString&, name), Q_ARG(ScriptEngine::FunctionSignature, functionSignature), Q_ARG(int, numArguments)); return; }#ifdef THREAD_DEBUGGING qCDebug(scriptengine) << "ScriptEngineQtScript::registerFunction() called on thread [" << QThread::currentThread() << "] name:" << name;#endif auto scriptFun = newFunction(functionSignature, numArguments); globalObject()->setProperty(name, scriptFun);} void ScriptEngineQtScript::registerFunction(const QString& parent, const QString& name, QScriptEngine::FunctionSignature functionSignature, int numArguments) { if (QThread::currentThread() != QScriptEngine::thread()) {#ifdef THREAD_DEBUGGING qCDebug(scriptengine) << "*** WARNING *** ScriptEngineQtScript::registerFunction() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] parent:" << parent << "name:" << name;#endif QMetaObject::invokeMethod(this, "registerFunction", Q_ARG(const QString&, name), Q_ARG(QScriptEngine::FunctionSignature, functionSignature), Q_ARG(int, numArguments)); return; }#ifdef THREAD_DEBUGGING qCDebug(scriptengine) << "ScriptEngineQtScript::registerFunction() called on thread [" << QThread::currentThread() << "] parent:" << parent << "name:" << name;#endif QScriptValue object = QScriptEngine::globalObject().property(parent); if (object.isValid()) { QScriptValue scriptFun = QScriptEngine::newFunction(functionSignature, numArguments); object.setProperty(name, scriptFun); }} void ScriptEngineQtScript::registerFunction(const QString& parent, const QString& name, ScriptEngine::FunctionSignature functionSignature, int numArguments) { if (QThread::currentThread() != QScriptEngine::thread()) {#ifdef THREAD_DEBUGGING qCDebug(scriptengine) << "*** WARNING *** ScriptEngineQtScript::registerFunction() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] parent:" << parent << "name:" << name;#endif QMetaObject::invokeMethod(this, "registerFunction", Q_ARG(const QString&, name), Q_ARG(ScriptEngine::FunctionSignature, functionSignature), Q_ARG(int, numArguments)); return; }#ifdef THREAD_DEBUGGING qCDebug(scriptengine) << "ScriptEngineQtScript::registerFunction() called on thread [" << QThread::currentThread() << "] parent:" << parent << "name:" << name;#endif auto object = globalObject()->property(parent); if (object->isValid()) { auto scriptFun = newFunction(functionSignature, numArguments); object->setProperty(name, scriptFun); }} void ScriptEngineQtScript::registerGetterSetter(const QString& name, QScriptEngine::FunctionSignature getter, QScriptEngine::FunctionSignature setter, const QString& parent) { if (QThread::currentThread() != QScriptEngine::thread()) {#ifdef THREAD_DEBUGGING qCDebug(scriptengine) << "*** WARNING *** ScriptEngineQtScript::registerGetterSetter() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " " name:" << name << "parent:" << parent;#endif QMetaObject::invokeMethod(this, "registerGetterSetter", Q_ARG(const QString&, name), Q_ARG(QScriptEngine::FunctionSignature, getter), Q_ARG(QScriptEngine::FunctionSignature, setter), Q_ARG(const QString&, parent)); return; }#ifdef THREAD_DEBUGGING qCDebug(scriptengine) << "ScriptEngineQtScript::registerGetterSetter() called on thread [" << QThread::currentThread() << "] name:" << name << "parent:" << parent;#endif QScriptValue setterFunction = QScriptEngine::newFunction(setter, 1); QScriptValue getterFunction = QScriptEngine::newFunction(getter); if (!parent.isNull() && !parent.isEmpty()) { QScriptValue object = QScriptEngine::globalObject().property(parent); if (object.isValid()) { object.setProperty(name, setterFunction, QScriptValue::PropertySetter); object.setProperty(name, getterFunction, QScriptValue::PropertyGetter); } } else { QScriptEngine::globalObject().setProperty(name, setterFunction, QScriptValue::PropertySetter); QScriptEngine::globalObject().setProperty(name, getterFunction, QScriptValue::PropertyGetter); }} void ScriptEngineQtScript::registerGetterSetter(const QString& name, ScriptEngine::FunctionSignature getter, ScriptEngine::FunctionSignature setter, const QString& parent) { if (QThread::currentThread() != QScriptEngine::thread()) {#ifdef THREAD_DEBUGGING qCDebug(scriptengine) << "*** WARNING *** ScriptEngineQtScript::registerGetterSetter() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " " name:" << name << "parent:" << parent;#endif QMetaObject::invokeMethod(this, "registerGetterSetter", Q_ARG(const QString&, name), Q_ARG(ScriptEngine::FunctionSignature, getter), Q_ARG(ScriptEngine::FunctionSignature, setter), Q_ARG(const QString&, parent)); return; }#ifdef THREAD_DEBUGGING qCDebug(scriptengine) << "ScriptEngineQtScript::registerGetterSetter() called on thread [" << QThread::currentThread() << "] name:" << name << "parent:" << parent;#endif auto setterFunction = newFunction(setter, 1); auto getterFunction = newFunction(getter); if (!parent.isNull() && !parent.isEmpty()) { auto object = globalObject()->property(parent); if (object->isValid()) { object->setProperty(name, setterFunction, ScriptValue::PropertySetter); object->setProperty(name, getterFunction, ScriptValue::PropertyGetter); } } else { globalObject()->setProperty(name, setterFunction, ScriptValue::PropertySetter); globalObject()->setProperty(name, getterFunction, ScriptValue::PropertyGetter); }} ScriptValuePointer ScriptEngineQtScript::evaluateInClosure(const ScriptValuePointer& _closure, const ScriptProgramPointer& _program) { PROFILE_RANGE(script, "evaluateInClosure"); if (!IS_THREADSAFE_INVOCATION(thread(), __FUNCTION__)) { return nullValue(); } ScriptProgramQtWrapper* unwrappedProgram = ScriptProgramQtWrapper::unwrap(_program); if (unwrappedProgram == nullptr) { return nullValue(); } const QScriptProgram& program = unwrappedProgram->toQtValue(); const auto fileName = program.fileName(); const auto shortName = QUrl(fileName).fileName(); ScriptValueQtWrapper* unwrappedClosure = ScriptValueQtWrapper::unwrap(_closure); if (unwrappedClosure == nullptr) { return nullValue(); } const QScriptValue& closure = unwrappedClosure->toQtValue(); QScriptValue oldGlobal; auto global = closure.property("global"); if (global.isObject()) {#ifdef DEBUG_JS qCDebug(shared) << " setting global = closure.global" << shortName;#endif oldGlobal = QScriptEngine::globalObject(); setGlobalObject(global); } auto context = pushContext(); auto thiz = closure.property("this"); if (thiz.isObject()) {#ifdef DEBUG_JS qCDebug(shared) << " setting this = closure.this" << shortName;#endif context->setThisObject(thiz); } context->pushScope(closure);#ifdef DEBUG_JS qCDebug(shared) << QString("[%1] evaluateInClosure %2").arg(isEvaluating()).arg(shortName);#endif ScriptValuePointer result; { auto qResult = QScriptEngine::evaluate(program); if (hasUncaughtException()) { auto err = cloneUncaughtException(__FUNCTION__);#ifdef DEBUG_JS_EXCEPTIONS qCWarning(shared) << __FUNCTION__ << "---------- hasCaught:" << err.toString() << result.toString(); err.setProperty("_result", result);#endif result = err; } else { result = ScriptValuePointer(new ScriptValueQtWrapper(this, std::move(qResult))); } }#ifdef DEBUG_JS qCDebug(shared) << QString("[%1] //evaluateInClosure %2").arg(isEvaluating()).arg(shortName);#endif popContext(); if (oldGlobal.isValid()) {#ifdef DEBUG_JS qCDebug(shared) << " restoring global" << shortName;#endif setGlobalObject(oldGlobal); } return result;} ScriptValuePointer ScriptEngineQtScript::evaluate(const QString& sourceCode, const QString& fileName) { if (_manager && _manager->isStopped()) { return undefinedValue(); // bail early } if (QThread::currentThread() != QScriptEngine::thread()) { ScriptValuePointer result;#ifdef THREAD_DEBUGGING qCDebug(scriptengine) << "*** WARNING *** ScriptEngineQtScript::evaluate() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " "sourceCode:" << sourceCode << " fileName:" << fileName;#endif BLOCKING_INVOKE_METHOD(this, "evaluate", Q_RETURN_ARG(ScriptValuePointer, result), Q_ARG(const QString&, sourceCode), Q_ARG(const QString&, fileName)); return result; } // Check syntax auto syntaxError = lintScript(sourceCode, fileName); if (syntaxError->isError()) { if (!isEvaluating()) { syntaxError->setProperty("detail", "evaluate"); } raiseException(syntaxError); maybeEmitUncaughtException("lint"); return syntaxError; } QScriptProgram program { sourceCode, fileName, 1 }; if (program.isNull()) { // can this happen? auto err = makeError(newValue("could not create QScriptProgram for " + fileName)); raiseException(err); maybeEmitUncaughtException("compile"); return err; } QScriptValue result = QScriptEngine::evaluate(program); maybeEmitUncaughtException("evaluate"); return ScriptValuePointer(new ScriptValueQtWrapper(this, std::move(result)));} Q_INVOKABLE ScriptValuePointer ScriptEngineQtScript::evaluate(const ScriptProgramPointer& program) { if (_manager && _manager->isStopped()) { return undefinedValue(); // bail early } if (QThread::currentThread() != QScriptEngine::thread()) { ScriptValuePointer result;#ifdef THREAD_DEBUGGING qCDebug(scriptengine) << "*** WARNING *** ScriptEngineQtScript::evaluate() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " "sourceCode:" << sourceCode << " fileName:" << fileName;#endif BLOCKING_INVOKE_METHOD(this, "evaluate", Q_RETURN_ARG(ScriptValuePointer, result), Q_ARG(const ScriptProgramPointer&, program)); return result; } ScriptProgramQtWrapper* unwrapped = ScriptProgramQtWrapper::unwrap(program); if (!unwrapped) { auto err = makeError(newValue("could not unwrap program")); raiseException(err); maybeEmitUncaughtException("compile"); return err; } const QScriptProgram& qProgram = unwrapped->toQtValue(); if (qProgram.isNull()) { // can this happen? auto err = makeError(newValue("requested program is empty")); raiseException(err); maybeEmitUncaughtException("compile"); return err; } QScriptValue result = QScriptEngine::evaluate(qProgram); maybeEmitUncaughtException("evaluate"); return ScriptValuePointer(new ScriptValueQtWrapper(this, std::move(result)));} void ScriptEngineQtScript::updateMemoryCost(const qint64& deltaSize) { if (deltaSize > 0) { // We've patched qt to fix https://highfidelity.atlassian.net/browse/BUGZ-46 on mac and windows only.#if defined(Q_OS_WIN) || defined(Q_OS_MAC) reportAdditionalMemoryCost(deltaSize);#endif }} void ScriptEngineQtScript::print(const QString& message) { QString filename; auto scriptManager = manager(); if (scriptManager) { filename = scriptManager->getFilename(); } emit printedMessage(message, filename);} ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ScriptEngine implementation ScriptValuePointer ScriptEngineQtScript::globalObject() const { QScriptValue global = QScriptEngine::globalObject(); // can't cache the value as it may change return ScriptValuePointer(new ScriptValueQtWrapper(const_cast < ScriptEngineQtScript*>(this), std::move(global)));} ScriptManager* ScriptEngineQtScript::manager() const { return _manager;} ScriptValuePointer ScriptEngineQtScript::newArray(uint length) { QScriptValue result = QScriptEngine::newArray(length); return ScriptValuePointer(new ScriptValueQtWrapper(this, std::move(result)));} ScriptValuePointer ScriptEngineQtScript::newArrayBuffer(const QByteArray& message) { QScriptValue data = QScriptEngine::newVariant(QVariant::fromValue(message)); QScriptValue ctor = QScriptEngine::globalObject().property("ArrayBuffer"); auto array = qscriptvalue_cast<ArrayBufferClass*>(ctor.data()); if (!array) { return undefinedValue(); } QScriptValue result = QScriptEngine::newObject(array, data); return ScriptValuePointer(new ScriptValueQtWrapper(this, std::move(result)));} ScriptValuePointer ScriptEngineQtScript::newObject() { QScriptValue result = QScriptEngine::newObject(); return ScriptValuePointer(new ScriptValueQtWrapper(this, std::move(result)));} ScriptProgramPointer ScriptEngineQtScript::newProgram(const QString& sourceCode, const QString& fileName) { QScriptProgram result(sourceCode, fileName); return ScriptProgramPointer(new ScriptProgramQtWrapper(this, result));} ScriptValuePointer ScriptEngineQtScript::newQObject(QObject* object, ScriptEngine::ValueOwnership ownership, const ScriptEngine::QObjectWrapOptions& options) { QScriptValue result = QScriptEngine::newQObject(object, static_cast<QScriptEngine::ValueOwnership>(ownership), (QScriptEngine::QObjectWrapOptions)((int)options | DEFAULT_QOBJECT_WRAP_OPTIONS)); return ScriptValuePointer(new ScriptValueQtWrapper(this, std::move(result)));} ScriptValuePointer ScriptEngineQtScript::newValue(bool value) { QScriptValue result(this, value); return ScriptValuePointer(new ScriptValueQtWrapper(this, std::move(result)));} ScriptValuePointer ScriptEngineQtScript::newValue(int value) { QScriptValue result(this, value); return ScriptValuePointer(new ScriptValueQtWrapper(this, std::move(result)));} ScriptValuePointer ScriptEngineQtScript::newValue(uint value) { QScriptValue result(this, value); return ScriptValuePointer(new ScriptValueQtWrapper(this, std::move(result)));} ScriptValuePointer ScriptEngineQtScript::newValue(double value) { QScriptValue result(this, value); return ScriptValuePointer(new ScriptValueQtWrapper(this, std::move(result)));} ScriptValuePointer ScriptEngineQtScript::newValue(const QString& value) { QScriptValue result(this, value); return ScriptValuePointer(new ScriptValueQtWrapper(this, std::move(result)));} ScriptValuePointer ScriptEngineQtScript::newValue(const QLatin1String& value) { QScriptValue result(this, value); return ScriptValuePointer(new ScriptValueQtWrapper(this, std::move(result)));} ScriptValuePointer ScriptEngineQtScript::newValue(const char* value) { QScriptValue result(this, value); return ScriptValuePointer(new ScriptValueQtWrapper(this, std::move(result)));} ScriptValuePointer ScriptEngineQtScript::newVariant(const QVariant& value) { QScriptValue result = QScriptEngine::newVariant(value); return ScriptValuePointer(new ScriptValueQtWrapper(this, std::move(result)));} ScriptValuePointer ScriptEngineQtScript::nullValue() { return _nullValue;} void ScriptEngineQtScript::setDefaultPrototype(int metaTypeId, const ScriptValuePointer& prototype){ ScriptValueQtWrapper* unwrappedPrototype = ScriptValueQtWrapper::unwrap(prototype); if (unwrappedPrototype) { QScriptEngine::setDefaultPrototype(metaTypeId, unwrappedPrototype->toQtValue()); }} ScriptValuePointer ScriptEngineQtScript::undefinedValue() { return _undefinedValue;} void ScriptEngineQtScript::abortEvaluation() { QScriptEngine::abortEvaluation();} void ScriptEngineQtScript::clearExceptions() { QScriptEngine::clearExceptions();} ScriptContext* ScriptEngineQtScript::currentContext() const { QScriptContext* localCtx = QScriptEngine::currentContext(); if (!localCtx) { return nullptr; } if (!_currContext || _currContext->toQtValue() != localCtx) { _currContext = ScriptContextQtPointer(new ScriptContextQtWrapper(const_cast<ScriptEngineQtScript*>(this), localCtx)); } return _currContext.get();} bool ScriptEngineQtScript::hasUncaughtException() const { return QScriptEngine::hasUncaughtException();} bool ScriptEngineQtScript::isEvaluating() const { return QScriptEngine::isEvaluating();} ScriptValuePointer ScriptEngineQtScript::newFunction(ScriptEngine::FunctionSignature fun, int length) { auto innerFunc = [](QScriptContext* _context, QScriptEngine* _engine) -> QScriptValue { auto callee = _context->callee(); QVariant funAddr = callee.property("_func").toVariant(); ScriptEngine::FunctionSignature fun = reinterpret_cast<ScriptEngine::FunctionSignature>(funAddr.toULongLong()); ScriptEngineQtScript* engine = static_cast<ScriptEngineQtScript*>(_engine); ScriptContextQtWrapper context(engine, _context); ScriptValuePointer result = fun(&context, engine); ScriptValueQtWrapper* unwrapped = ScriptValueQtWrapper::unwrap(result); return unwrapped ? unwrapped->toQtValue() : QScriptValue(); }; QScriptValue result = QScriptEngine::newFunction(innerFunc, length); auto funAddr = QScriptEngine::newVariant(QVariant(reinterpret_cast<qulonglong>(fun))); result.setProperty("_func", funAddr, QScriptValue::PropertyFlags(QScriptValue::ReadOnly + QScriptValue::Undeletable + QScriptValue::SkipInEnumeration)); return ScriptValuePointer(new ScriptValueQtWrapper(this, std::move(result)));} void ScriptEngineQtScript::setObjectName(const QString& name) { QScriptEngine::setObjectName(name);} bool ScriptEngineQtScript::setProperty(const char* name, const QVariant& value) { return QScriptEngine::setProperty(name, value);} void ScriptEngineQtScript::setProcessEventsInterval(int interval) { QScriptEngine::setProcessEventsInterval(interval);} QThread* ScriptEngineQtScript::thread() const { return QScriptEngine::thread();} ScriptValuePointer ScriptEngineQtScript::uncaughtException() const { QScriptValue result = QScriptEngine::uncaughtException(); return ScriptValuePointer(new ScriptValueQtWrapper(const_cast<ScriptEngineQtScript*>(this), std::move(result)));} Lines 501–1000 of 1037. Previous lines Load more
} else { QScriptEngine::globalObject().setProperty(name, QScriptValue()); } } } void ScriptEngineQtScript::registerFunction(const QString& name, QScriptEngine::FunctionSignature functionSignature, int numArguments) { if (QThread::currentThread() != QScriptEngine::thread()) { #ifdef THREAD_DEBUGGING qCDebug(scriptengine) << "*** WARNING *** ScriptEngineQtScript::registerFunction() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] name:" << name; #endif QMetaObject::invokeMethod(this, "registerFunction", Q_ARG(const QString&, name), Q_ARG(QScriptEngine::FunctionSignature, functionSignature), Q_ARG(int, numArguments)); return; } #ifdef THREAD_DEBUGGING qCDebug(scriptengine) << "ScriptEngineQtScript::registerFunction() called on thread [" << QThread::currentThread() << "] name:" << name; #endif QScriptValue scriptFun = QScriptEngine::newFunction(functionSignature, numArguments); QScriptEngine::globalObject().setProperty(name, scriptFun); } void ScriptEngineQtScript::registerFunction(const QString& name, ScriptEngine::FunctionSignature functionSignature, int numArguments) { if (QThread::currentThread() != QScriptEngine::thread()) { #ifdef THREAD_DEBUGGING qCDebug(scriptengine) << "*** WARNING *** ScriptEngineQtScript::registerFunction() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] name:" << name; #endif QMetaObject::invokeMethod(this, "registerFunction", Q_ARG(const QString&, name), Q_ARG(ScriptEngine::FunctionSignature, functionSignature), Q_ARG(int, numArguments)); return; } #ifdef THREAD_DEBUGGING qCDebug(scriptengine) << "ScriptEngineQtScript::registerFunction() called on thread [" << QThread::currentThread() << "] name:" << name; #endif auto scriptFun = newFunction(functionSignature, numArguments); globalObject()->setProperty(name, scriptFun); } void ScriptEngineQtScript::registerFunction(const QString& parent, const QString& name, QScriptEngine::FunctionSignature functionSignature, int numArguments) { if (QThread::currentThread() != QScriptEngine::thread()) { #ifdef THREAD_DEBUGGING qCDebug(scriptengine) << "*** WARNING *** ScriptEngineQtScript::registerFunction() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] parent:" << parent << "name:" << name; #endif QMetaObject::invokeMethod(this, "registerFunction", Q_ARG(const QString&, name), Q_ARG(QScriptEngine::FunctionSignature, functionSignature), Q_ARG(int, numArguments)); return; } #ifdef THREAD_DEBUGGING qCDebug(scriptengine) << "ScriptEngineQtScript::registerFunction() called on thread [" << QThread::currentThread() << "] parent:" << parent << "name:" << name; #endif QScriptValue object = QScriptEngine::globalObject().property(parent); if (object.isValid()) { QScriptValue scriptFun = QScriptEngine::newFunction(functionSignature, numArguments); object.setProperty(name, scriptFun); } } void ScriptEngineQtScript::registerFunction(const QString& parent, const QString& name, ScriptEngine::FunctionSignature functionSignature, int numArguments) { if (QThread::currentThread() != QScriptEngine::thread()) { #ifdef THREAD_DEBUGGING qCDebug(scriptengine) << "*** WARNING *** ScriptEngineQtScript::registerFunction() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] parent:" << parent << "name:" << name; #endif QMetaObject::invokeMethod(this, "registerFunction", Q_ARG(const QString&, name), Q_ARG(ScriptEngine::FunctionSignature, functionSignature), Q_ARG(int, numArguments)); return; } #ifdef THREAD_DEBUGGING qCDebug(scriptengine) << "ScriptEngineQtScript::registerFunction() called on thread [" << QThread::currentThread() << "] parent:" << parent << "name:" << name; #endif auto object = globalObject()->property(parent); if (object->isValid()) { auto scriptFun = newFunction(functionSignature, numArguments); object->setProperty(name, scriptFun); } } void ScriptEngineQtScript::registerGetterSetter(const QString& name, QScriptEngine::FunctionSignature getter, QScriptEngine::FunctionSignature setter, const QString& parent) { if (QThread::currentThread() != QScriptEngine::thread()) { #ifdef THREAD_DEBUGGING qCDebug(scriptengine) << "*** WARNING *** ScriptEngineQtScript::registerGetterSetter() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " " name:" << name << "parent:" << parent; #endif QMetaObject::invokeMethod(this, "registerGetterSetter", Q_ARG(const QString&, name), Q_ARG(QScriptEngine::FunctionSignature, getter), Q_ARG(QScriptEngine::FunctionSignature, setter), Q_ARG(const QString&, parent)); return; } #ifdef THREAD_DEBUGGING qCDebug(scriptengine) << "ScriptEngineQtScript::registerGetterSetter() called on thread [" << QThread::currentThread() << "] name:" << name << "parent:" << parent; #endif QScriptValue setterFunction = QScriptEngine::newFunction(setter, 1); QScriptValue getterFunction = QScriptEngine::newFunction(getter); if (!parent.isNull() && !parent.isEmpty()) { QScriptValue object = QScriptEngine::globalObject().property(parent); if (object.isValid()) { object.setProperty(name, setterFunction, QScriptValue::PropertySetter); object.setProperty(name, getterFunction, QScriptValue::PropertyGetter); } } else { QScriptEngine::globalObject().setProperty(name, setterFunction, QScriptValue::PropertySetter); QScriptEngine::globalObject().setProperty(name, getterFunction, QScriptValue::PropertyGetter); } } void ScriptEngineQtScript::registerGetterSetter(const QString& name, ScriptEngine::FunctionSignature getter, ScriptEngine::FunctionSignature setter, const QString& parent) { if (QThread::currentThread() != QScriptEngine::thread()) { #ifdef THREAD_DEBUGGING qCDebug(scriptengine) << "*** WARNING *** ScriptEngineQtScript::registerGetterSetter() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " " name:" << name << "parent:" << parent; #endif QMetaObject::invokeMethod(this, "registerGetterSetter", Q_ARG(const QString&, name), Q_ARG(ScriptEngine::FunctionSignature, getter), Q_ARG(ScriptEngine::FunctionSignature, setter), Q_ARG(const QString&, parent)); return; } #ifdef THREAD_DEBUGGING qCDebug(scriptengine) << "ScriptEngineQtScript::registerGetterSetter() called on thread [" << QThread::currentThread() << "] name:" << name << "parent:" << parent; #endif auto setterFunction = newFunction(setter, 1); auto getterFunction = newFunction(getter); if (!parent.isNull() && !parent.isEmpty()) { auto object = globalObject()->property(parent); if (object->isValid()) { object->setProperty(name, setterFunction, ScriptValue::PropertySetter); object->setProperty(name, getterFunction, ScriptValue::PropertyGetter); } } else { globalObject()->setProperty(name, setterFunction, ScriptValue::PropertySetter); globalObject()->setProperty(name, getterFunction, ScriptValue::PropertyGetter); } } ScriptValuePointer ScriptEngineQtScript::evaluateInClosure(const ScriptValuePointer& _closure, const ScriptProgramPointer& _program) { PROFILE_RANGE(script, "evaluateInClosure"); if (!IS_THREADSAFE_INVOCATION(thread(), __FUNCTION__)) { return nullValue(); } ScriptProgramQtWrapper* unwrappedProgram = ScriptProgramQtWrapper::unwrap(_program); if (unwrappedProgram == nullptr) { return nullValue(); } const QScriptProgram& program = unwrappedProgram->toQtValue(); const auto fileName = program.fileName(); const auto shortName = QUrl(fileName).fileName(); ScriptValueQtWrapper* unwrappedClosure = ScriptValueQtWrapper::unwrap(_closure); if (unwrappedClosure == nullptr) { return nullValue(); } const QScriptValue& closure = unwrappedClosure->toQtValue(); QScriptValue oldGlobal; auto global = closure.property("global"); if (global.isObject()) { #ifdef DEBUG_JS qCDebug(shared) << " setting global = closure.global" << shortName; #endif oldGlobal = QScriptEngine::globalObject(); setGlobalObject(global); } auto context = pushContext(); auto thiz = closure.property("this"); if (thiz.isObject()) { #ifdef DEBUG_JS qCDebug(shared) << " setting this = closure.this" << shortName; #endif context->setThisObject(thiz); } context->pushScope(closure); #ifdef DEBUG_JS qCDebug(shared) << QString("[%1] evaluateInClosure %2").arg(isEvaluating()).arg(shortName); #endif ScriptValuePointer result; { auto qResult = QScriptEngine::evaluate(program); if (hasUncaughtException()) { auto err = cloneUncaughtException(__FUNCTION__); #ifdef DEBUG_JS_EXCEPTIONS qCWarning(shared) << __FUNCTION__ << "---------- hasCaught:" << err.toString() << result.toString(); err.setProperty("_result", result); #endif result = err; } else { result = ScriptValuePointer(new ScriptValueQtWrapper(this, std::move(qResult))); } } #ifdef DEBUG_JS qCDebug(shared) << QString("[%1] //evaluateInClosure %2").arg(isEvaluating()).arg(shortName); #endif popContext(); if (oldGlobal.isValid()) { #ifdef DEBUG_JS qCDebug(shared) << " restoring global" << shortName; #endif setGlobalObject(oldGlobal); } return result; } ScriptValuePointer ScriptEngineQtScript::evaluate(const QString& sourceCode, const QString& fileName) { if (_manager && _manager->isStopped()) { return undefinedValue(); // bail early } if (QThread::currentThread() != QScriptEngine::thread()) { ScriptValuePointer result; #ifdef THREAD_DEBUGGING qCDebug(scriptengine) << "*** WARNING *** ScriptEngineQtScript::evaluate() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " "sourceCode:" << sourceCode << " fileName:" << fileName; #endif BLOCKING_INVOKE_METHOD(this, "evaluate", Q_RETURN_ARG(ScriptValuePointer, result), Q_ARG(const QString&, sourceCode), Q_ARG(const QString&, fileName)); return result; } // Check syntax auto syntaxError = lintScript(sourceCode, fileName); if (syntaxError->isError()) { if (!isEvaluating()) { syntaxError->setProperty("detail", "evaluate"); } raiseException(syntaxError); maybeEmitUncaughtException("lint"); return syntaxError; } QScriptProgram program { sourceCode, fileName, 1 }; if (program.isNull()) { // can this happen? auto err = makeError(newValue("could not create QScriptProgram for " + fileName)); raiseException(err); maybeEmitUncaughtException("compile"); return err; } QScriptValue result = QScriptEngine::evaluate(program); maybeEmitUncaughtException("evaluate"); return ScriptValuePointer(new ScriptValueQtWrapper(this, std::move(result))); } Q_INVOKABLE ScriptValuePointer ScriptEngineQtScript::evaluate(const ScriptProgramPointer& program) { if (_manager && _manager->isStopped()) { return undefinedValue(); // bail early } if (QThread::currentThread() != QScriptEngine::thread()) { ScriptValuePointer result; #ifdef THREAD_DEBUGGING qCDebug(scriptengine) << "*** WARNING *** ScriptEngineQtScript::evaluate() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " "sourceCode:" << sourceCode << " fileName:" << fileName; #endif BLOCKING_INVOKE_METHOD(this, "evaluate", Q_RETURN_ARG(ScriptValuePointer, result), Q_ARG(const ScriptProgramPointer&, program)); return result; } ScriptProgramQtWrapper* unwrapped = ScriptProgramQtWrapper::unwrap(program); if (!unwrapped) { auto err = makeError(newValue("could not unwrap program")); raiseException(err); maybeEmitUncaughtException("compile"); return err; } const QScriptProgram& qProgram = unwrapped->toQtValue(); if (qProgram.isNull()) { // can this happen? auto err = makeError(newValue("requested program is empty")); raiseException(err); maybeEmitUncaughtException("compile"); return err; } QScriptValue result = QScriptEngine::evaluate(qProgram); maybeEmitUncaughtException("evaluate"); return ScriptValuePointer(new ScriptValueQtWrapper(this, std::move(result))); } void ScriptEngineQtScript::updateMemoryCost(const qint64& deltaSize) { if (deltaSize > 0) { // We've patched qt to fix https://highfidelity.atlassian.net/browse/BUGZ-46 on mac and windows only. #if defined(Q_OS_WIN) || defined(Q_OS_MAC) reportAdditionalMemoryCost(deltaSize); #endif } } void ScriptEngineQtScript::print(const QString& message) { QString filename; auto scriptManager = manager(); if (scriptManager) { filename = scriptManager->getFilename(); } emit printedMessage(message, filename); } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // ScriptEngine implementation ScriptValuePointer ScriptEngineQtScript::globalObject() const { QScriptValue global = QScriptEngine::globalObject(); // can't cache the value as it may change return ScriptValuePointer(new ScriptValueQtWrapper(const_cast < ScriptEngineQtScript*>(this), std::move(global))); } ScriptManager* ScriptEngineQtScript::manager() const { return _manager; } ScriptValuePointer ScriptEngineQtScript::newArray(uint length) { QScriptValue result = QScriptEngine::newArray(length); return ScriptValuePointer(new ScriptValueQtWrapper(this, std::move(result))); } ScriptValuePointer ScriptEngineQtScript::newArrayBuffer(const QByteArray& message) { QScriptValue data = QScriptEngine::newVariant(QVariant::fromValue(message)); QScriptValue ctor = QScriptEngine::globalObject().property("ArrayBuffer"); auto array = qscriptvalue_cast<ArrayBufferClass*>(ctor.data()); if (!array) { return undefinedValue(); } QScriptValue result = QScriptEngine::newObject(array, data); return ScriptValuePointer(new ScriptValueQtWrapper(this, std::move(result))); } ScriptValuePointer ScriptEngineQtScript::newObject() { QScriptValue result = QScriptEngine::newObject(); return ScriptValuePointer(new ScriptValueQtWrapper(this, std::move(result))); } ScriptProgramPointer ScriptEngineQtScript::newProgram(const QString& sourceCode, const QString& fileName) { QScriptProgram result(sourceCode, fileName); return ScriptProgramPointer(new ScriptProgramQtWrapper(this, result)); } ScriptValuePointer ScriptEngineQtScript::newQObject(QObject* object, ScriptEngine::ValueOwnership ownership, const ScriptEngine::QObjectWrapOptions& options) { QScriptValue result = QScriptEngine::newQObject(object, static_cast<QScriptEngine::ValueOwnership>(ownership), (QScriptEngine::QObjectWrapOptions)((int)options | DEFAULT_QOBJECT_WRAP_OPTIONS)); return ScriptValuePointer(new ScriptValueQtWrapper(this, std::move(result))); } ScriptValuePointer ScriptEngineQtScript::newValue(bool value) { QScriptValue result(this, value); return ScriptValuePointer(new ScriptValueQtWrapper(this, std::move(result))); } ScriptValuePointer ScriptEngineQtScript::newValue(int value) { QScriptValue result(this, value); return ScriptValuePointer(new ScriptValueQtWrapper(this, std::move(result))); } ScriptValuePointer ScriptEngineQtScript::newValue(uint value) { QScriptValue result(this, value); return ScriptValuePointer(new ScriptValueQtWrapper(this, std::move(result))); } ScriptValuePointer ScriptEngineQtScript::newValue(double value) { QScriptValue result(this, value); return ScriptValuePointer(new ScriptValueQtWrapper(this, std::move(result))); } ScriptValuePointer ScriptEngineQtScript::newValue(const QString& value) { QScriptValue result(this, value); return ScriptValuePointer(new ScriptValueQtWrapper(this, std::move(result))); } ScriptValuePointer ScriptEngineQtScript::newValue(const QLatin1String& value) { QScriptValue result(this, value); return ScriptValuePointer(new ScriptValueQtWrapper(this, std::move(result))); } ScriptValuePointer ScriptEngineQtScript::newValue(const char* value) { QScriptValue result(this, value); return ScriptValuePointer(new ScriptValueQtWrapper(this, std::move(result))); } ScriptValuePointer ScriptEngineQtScript::newVariant(const QVariant& value) { QScriptValue result = QScriptEngine::newVariant(value); return ScriptValuePointer(new ScriptValueQtWrapper(this, std::move(result))); } ScriptValuePointer ScriptEngineQtScript::nullValue() { return _nullValue; } void ScriptEngineQtScript::setDefaultPrototype(int metaTypeId, const ScriptValuePointer& prototype){ ScriptValueQtWrapper* unwrappedPrototype = ScriptValueQtWrapper::unwrap(prototype); if (unwrappedPrototype) { QScriptEngine::setDefaultPrototype(metaTypeId, unwrappedPrototype->toQtValue()); } } ScriptValuePointer ScriptEngineQtScript::undefinedValue() { return _undefinedValue; } void ScriptEngineQtScript::abortEvaluation() { QScriptEngine::abortEvaluation(); } void ScriptEngineQtScript::clearExceptions() { QScriptEngine::clearExceptions(); } ScriptContext* ScriptEngineQtScript::currentContext() const { QScriptContext* localCtx = QScriptEngine::currentContext(); if (!localCtx) { return nullptr; } if (!_currContext || _currContext->toQtValue() != localCtx) { _currContext = ScriptContextQtPointer(new ScriptContextQtWrapper(const_cast<ScriptEngineQtScript*>(this), localCtx)); } return _currContext.get(); } bool ScriptEngineQtScript::hasUncaughtException() const { return QScriptEngine::hasUncaughtException(); } bool ScriptEngineQtScript::isEvaluating() const { return QScriptEngine::isEvaluating(); } ScriptValuePointer ScriptEngineQtScript::newFunction(ScriptEngine::FunctionSignature fun, int length) { auto innerFunc = [](QScriptContext* _context, QScriptEngine* _engine) -> QScriptValue { auto callee = _context->callee(); QVariant funAddr = callee.property("_func").toVariant(); ScriptEngine::FunctionSignature fun = reinterpret_cast<ScriptEngine::FunctionSignature>(funAddr.toULongLong()); ScriptEngineQtScript* engine = static_cast<ScriptEngineQtScript*>(_engine); ScriptContextQtWrapper context(engine, _context); ScriptValuePointer result = fun(&context, engine); ScriptValueQtWrapper* unwrapped = ScriptValueQtWrapper::unwrap(result); return unwrapped ? unwrapped->toQtValue() : QScriptValue(); }; QScriptValue result = QScriptEngine::newFunction(innerFunc, length); auto funAddr = QScriptEngine::newVariant(QVariant(reinterpret_cast<qulonglong>(fun))); result.setProperty("_func", funAddr, QScriptValue::PropertyFlags(QScriptValue::ReadOnly + QScriptValue::Undeletable + QScriptValue::SkipInEnumeration)); return ScriptValuePointer(new ScriptValueQtWrapper(this, std::move(result))); } void ScriptEngineQtScript::setObjectName(const QString& name) { QScriptEngine::setObjectName(name); } bool ScriptEngineQtScript::setProperty(const char* name, const QVariant& value) { return QScriptEngine::setProperty(name, value); } void ScriptEngineQtScript::setProcessEventsInterval(int interval) { QScriptEngine::setProcessEventsInterval(interval); } QThread* ScriptEngineQtScript::thread() const { return QScriptEngine::thread(); } ScriptValuePointer ScriptEngineQtScript::uncaughtException() const { QScriptValue result = QScriptEngine::uncaughtException(); return ScriptValuePointer(new ScriptValueQtWrapper(const_cast<ScriptEngineQtScript*>(this), std::move(result))); }