* Get rid of maybeEmitUncaughtException * Mostly get rid of makeError * Introduce exception hierarchy, change exceptions to shared_ptr * Simplify exception throwing code
Showing the changes to libraries/script-engine/src/ScriptManager.cpp (1 of 10 files). Show all
Unified · Split
| @@ -282,6 +282,11 @@ ScriptManager::ScriptManager(Context context, const QString& scriptContents, con · 281 unmodified lines | |||
| 282 | processLevelMaxRetries = 1; | 282 | processLevelMaxRetries = 1; |
| 283 | } | 283 | } |
| 284 | 284 | ||
| 285 | |||
| 286 | #if 0 | ||
| 287 | // V8TODO: Is this actually needed? Exceptions will already be logged on the | ||
| 288 | // script engine side. | ||
| 289 | |||
| 285 | // this is where all unhandled exceptions end up getting logged | 290 | // this is where all unhandled exceptions end up getting logged |
| 286 | connect(this, &ScriptManager::unhandledException, this, [this](const ScriptValue& err) { | 291 | connect(this, &ScriptManager::unhandledException, this, [this](const ScriptValue& err) { |
| 287 | qCCritical(scriptengine) << "Caught exception"; | 292 | qCCritical(scriptengine) << "Caught exception"; |
| @@ -296,6 +301,7 @@ ScriptManager::ScriptManager(Context context, const QString& scriptContents, con · 8 unmodified lines | |||
| 296 | 301 | ||
| 297 | logException(output); | 302 | logException(output); |
| 298 | }); | 303 | }); |
| 304 | #endif | ||
| 299 | 305 | ||
| 300 | if (_type == Type::ENTITY_CLIENT || _type == Type::ENTITY_SERVER) { | 306 | if (_type == Type::ENTITY_CLIENT || _type == Type::ENTITY_SERVER) { |
| 301 | QObject::connect(this, &ScriptManager::update, this, [this]() { | 307 | QObject::connect(this, &ScriptManager::update, this, [this]() { |
| @@ -891,13 +897,11 @@ void ScriptManager::run() { · 589 unmodified lines | |||
| 891 | { | 897 | { |
| 892 | PROFILE_RANGE(script, _fileNameString); | 898 | PROFILE_RANGE(script, _fileNameString); |
| 893 | _returnValue = _engine->evaluate(_scriptContents, _fileNameString); | 899 | _returnValue = _engine->evaluate(_scriptContents, _fileNameString); |
| 894 | _engine->maybeEmitUncaughtException(__FUNCTION__); | ||
| 895 | 900 | ||
| 896 | if (_engine->hasUncaughtException()) { | 901 | if (_engine->hasUncaughtException()) { |
| 897 | 902 | ||
| 898 | qCWarning(scriptengine) << "Engine has uncaught exception, stopping"; | 903 | qCWarning(scriptengine) << "Engine has uncaught exception, stopping"; |
| 899 | stop(); | 904 | stop(); |
| 900 | emit unhandledException(_engine->cloneUncaughtException(__FUNCTION__)); | ||
| 901 | _engine->clearExceptions(); | 905 | _engine->clearExceptions(); |
| 902 | } | 906 | } |
| 903 | } | 907 | } |
| @@ -1023,7 +1027,7 @@ void ScriptManager::run() { · 119 unmodified lines | |||
| 1023 | if (!_engine->isEvaluating() && _engine->hasUncaughtException()) { | 1027 | if (!_engine->isEvaluating() && _engine->hasUncaughtException()) { |
| 1024 | qCWarning(scriptengine) << __FUNCTION__ << "---------- UNCAUGHT EXCEPTION --------"; | 1028 | qCWarning(scriptengine) << __FUNCTION__ << "---------- UNCAUGHT EXCEPTION --------"; |
| 1025 | qCWarning(scriptengine) << "runInThread" << _engine->uncaughtException(); | 1029 | qCWarning(scriptengine) << "runInThread" << _engine->uncaughtException(); |
| 1026 | emit unhandledException(_engine->cloneUncaughtException(__FUNCTION__)); | 1030 | emit unhandledException(_engine->uncaughtException()); |
| 1027 | _engine->clearExceptions(); | 1031 | _engine->clearExceptions(); |
| 1028 | } | 1032 | } |
| 1029 | } | 1033 | } |
| @@ -1258,9 +1262,8 @@ QString ScriptManager::_requireResolve(const QString& moduleId, const QString& r · 228 unmodified lines | |||
| 1258 | } | 1262 | } |
| 1259 | auto message = QString("Cannot find module '%1' (%2)").arg(displayId); | 1263 | auto message = QString("Cannot find module '%1' (%2)").arg(displayId); |
| 1260 | 1264 | ||
| 1261 | auto throwResolveError = [&](const ScriptValue& error) -> QString { | 1265 | auto throwResolveError = [&](const QString& error, const QString &details = QString()) -> QString { |
| 1262 | _engine->raiseException(error); | 1266 | _engine->raiseException(error, "require.resolve: " + details); |
| 1263 | _engine->maybeEmitUncaughtException("require.resolve"); | ||
| 1264 | return QString(); | 1267 | return QString(); |
| 1265 | }; | 1268 | }; |
| 1266 | 1269 | ||
| @@ -1269,7 +1272,7 @@ QString ScriptManager::_requireResolve(const QString& moduleId, const QString& r · 2 unmodified lines | |||
| 1269 | if (idLength < 1 || idLength > MAX_MODULE_ID_LENGTH) { | 1272 | if (idLength < 1 || idLength > MAX_MODULE_ID_LENGTH) { |
| 1270 | auto details = QString("rejecting invalid module id size (%1 chars [1,%2])") | 1273 | auto details = QString("rejecting invalid module id size (%1 chars [1,%2])") |
| 1271 | .arg(idLength).arg(MAX_MODULE_ID_LENGTH); | 1274 | .arg(idLength).arg(MAX_MODULE_ID_LENGTH); |
| 1272 | return throwResolveError(_engine->makeError(_engine->newValue(message.arg(details)), "RangeError")); | 1275 | return throwResolveError(details, "RangeError"); |
| 1273 | } | 1276 | } |
| 1274 | 1277 | ||
| 1275 | // this regex matches: absolute, dotted or path-like URLs | 1278 | // this regex matches: absolute, dotted or path-like URLs |
| @@ -1296,15 +1299,15 @@ QString ScriptManager::_requireResolve(const QString& moduleId, const QString& r · 20 unmodified lines | |||
| 1296 | if (QFileInfo(unanchoredUrl.toLocalFile()).isFile()) { | 1299 | if (QFileInfo(unanchoredUrl.toLocalFile()).isFile()) { |
| 1297 | auto msg = QString("relative module ids must be anchored; use './%1' instead") | 1300 | auto msg = QString("relative module ids must be anchored; use './%1' instead") |
| 1298 | .arg(moduleId); | 1301 | .arg(moduleId); |
| 1299 | return throwResolveError(_engine->makeError(_engine->newValue(message.arg(msg)))); | 1302 | return throwResolveError(message.arg(msg)); |
| 1300 | } | 1303 | } |
| 1301 | } | 1304 | } |
| 1302 | return throwResolveError(_engine->makeError(_engine->newValue(message.arg("system module not found")))); | 1305 | return throwResolveError(message.arg("system module not found")); |
| 1303 | } | 1306 | } |
| 1304 | } | 1307 | } |
| 1305 | 1308 | ||
| 1306 | if (url.isRelative()) { | 1309 | if (url.isRelative()) { |
| 1307 | return throwResolveError(_engine->makeError(_engine->newValue(message.arg("could not resolve module id")))); | 1310 | return throwResolveError(message.arg("could not resolve module id")); |
| 1308 | } | 1311 | } |
| 1309 | 1312 | ||
| 1310 | // if it looks like a local file, verify that it's an allowed path and really a file | 1313 | // if it looks like a local file, verify that it's an allowed path and really a file |
| @@ -1317,22 +1320,21 @@ QString ScriptManager::_requireResolve(const QString& moduleId, const QString& r · 6 unmodified lines | |||
| 1317 | 1320 | ||
| 1318 | bool disallowOutsideFiles = !PathUtils::defaultScriptsLocation().isParentOf(canonical) && !currentSandboxURL.isLocalFile(); | 1321 | bool disallowOutsideFiles = !PathUtils::defaultScriptsLocation().isParentOf(canonical) && !currentSandboxURL.isLocalFile(); |
| 1319 | if (disallowOutsideFiles && !PathUtils::isDescendantOf(canonical, currentSandboxURL)) { | 1322 | if (disallowOutsideFiles && !PathUtils::isDescendantOf(canonical, currentSandboxURL)) { |
| 1320 | return throwResolveError(_engine->makeError(_engine->newValue(message.arg( | 1323 | return throwResolveError(message.arg( |
| 1321 | QString("path '%1' outside of origin script '%2' '%3'") | 1324 | QString("path '%1' outside of origin script '%2' '%3'") |
| 1322 | .arg(PathUtils::stripFilename(url)) | 1325 | .arg(PathUtils::stripFilename(url)) |
| 1323 | .arg(PathUtils::stripFilename(currentSandboxURL)) | 1326 | .arg(PathUtils::stripFilename(currentSandboxURL)) |
| 1324 | .arg(canonical.toString()) | 1327 | .arg(canonical.toString()) |
| 1325 | )))); | 1328 | )); |
| 1326 | } | 1329 | } |
| 1327 | if (!file.exists()) { | 1330 | if (!file.exists()) { |
| 1328 | return throwResolveError(_engine->makeError(_engine->newValue(message.arg("path does not exist: " + url.toLocalFile())))); | 1331 | return throwResolveError(message.arg("path does not exist: " + url.toLocalFile())); |
| 1329 | } | 1332 | } |
| 1330 | if (!file.isFile()) { | 1333 | if (!file.isFile()) { |
| 1331 | return throwResolveError(_engine->makeError(_engine->newValue(message.arg("path is not a file: " + url.toLocalFile())))); | 1334 | return throwResolveError(message.arg("path is not a file: " + url.toLocalFile())); |
| 1332 | } | 1335 | } |
| 1333 | } | 1336 | } |
| 1334 | 1337 | ||
| 1335 | _engine->maybeEmitUncaughtException(__FUNCTION__); | ||
| 1336 | return url.toString(); | 1338 | return url.toString(); |
| 1337 | } | 1339 | } |
| 1338 | 1340 | ||
| @@ -1488,7 +1490,7 @@ ScriptValue ScriptManager::instantiateModule(const ScriptValue& module, const QS · 149 unmodified lines | |||
| 1488 | //_engine->scriptValueDebugDetails(module); | 1490 | //_engine->scriptValueDebugDetails(module); |
| 1489 | result = _engine->evaluateInClosure(closure, _engine->newProgram( sourceCode, modulePath )); | 1491 | result = _engine->evaluateInClosure(closure, _engine->newProgram( sourceCode, modulePath )); |
| 1490 | } | 1492 | } |
| 1491 | _engine->maybeEmitUncaughtException(__FUNCTION__); | 1493 | |
| 1492 | return result; | 1494 | return result; |
| 1493 | } | 1495 | } |
| 1494 | 1496 | ||
| @@ -1510,9 +1512,8 @@ ScriptValue ScriptManager::require(const QString& moduleId) { · 15 unmodified lines | |||
| 1510 | #ifdef DEBUG_JS_MODULES | 1512 | #ifdef DEBUG_JS_MODULES |
| 1511 | qCWarning(scriptengine_module) << "throwing module error:" << error.toString() << modulePath << error.property("stack").toString(); | 1513 | qCWarning(scriptengine_module) << "throwing module error:" << error.toString() << modulePath << error.property("stack").toString(); |
| 1512 | #endif | 1514 | #endif |
| 1513 | _engine->raiseException(error); | 1515 | _engine->raiseException(error, "module error"); |
| 1514 | } | 1516 | } |
| 1515 | _engine->maybeEmitUncaughtException("module"); | ||
| 1516 | return _engine->nullValue(); | 1517 | return _engine->nullValue(); |
| 1517 | }; | 1518 | }; |
| 1518 | 1519 | ||
| @@ -1520,7 +1521,6 @@ ScriptValue ScriptManager::require(const QString& moduleId) { · 1 unmodified line | |||
| 1520 | QString modulePath = _requireResolve(moduleId); | 1521 | QString modulePath = _requireResolve(moduleId); |
| 1521 | if (modulePath.isNull() || _engine->hasUncaughtException()) { | 1522 | if (modulePath.isNull() || _engine->hasUncaughtException()) { |
| 1522 | // the resolver already threw an exception -- bail early | 1523 | // the resolver already threw an exception -- bail early |
| 1523 | _engine->maybeEmitUncaughtException(__FUNCTION__); | ||
| 1524 | return _engine->nullValue(); | 1524 | return _engine->nullValue(); |
| 1525 | } | 1525 | } |
| 1526 | 1526 | ||
| @@ -1546,7 +1546,6 @@ ScriptValue ScriptManager::require(const QString& moduleId) { · 19 unmodified lines | |||
| 1546 | qCDebug(scriptengine_module) << QString("require - using cached module for '%1' (loaded: %2)") | 1546 | qCDebug(scriptengine_module) << QString("require - using cached module for '%1' (loaded: %2)") |
| 1547 | .arg(moduleId).arg(module.property("loaded").toString()); | 1547 | .arg(moduleId).arg(module.property("loaded").toString()); |
| 1548 | registerModuleWithParent(module, parent); | 1548 | registerModuleWithParent(module, parent); |
| 1549 | _engine->maybeEmitUncaughtException("cached module"); | ||
| 1550 | return exports; | 1549 | return exports; |
| 1551 | } | 1550 | } |
| 1552 | 1551 | ||
| @@ -1594,7 +1593,6 @@ ScriptValue ScriptManager::require(const QString& moduleId) { · 41 unmodified lines | |||
| 1594 | 1593 | ||
| 1595 | //qCDebug(scriptengine_module) << "//ScriptManager::require(" << moduleId << ")"; | 1594 | //qCDebug(scriptengine_module) << "//ScriptManager::require(" << moduleId << ")"; |
| 1596 | 1595 | ||
| 1597 | _engine->maybeEmitUncaughtException(__FUNCTION__); | ||
| 1598 | //qCDebug(scriptengine_module) << "Exports: " << _engine->scriptValueDebugDetails(module.property("exports")); | 1596 | //qCDebug(scriptengine_module) << "Exports: " << _engine->scriptValueDebugDetails(module.property("exports")); |
| 1599 | return module.property("exports"); | 1597 | return module.property("exports"); |
| 1600 | } | 1598 | } |
| @@ -1670,7 +1668,9 @@ void ScriptManager::include(const QStringList& includeFiles, const ScriptValue& · 69 unmodified lines | |||
| 1670 | 1668 | ||
| 1671 | doWithEnvironment(capturedEntityIdentifier, capturedSandboxURL, operation); | 1669 | doWithEnvironment(capturedEntityIdentifier, capturedSandboxURL, operation); |
| 1672 | if(_engine->hasUncaughtException()) { | 1670 | if(_engine->hasUncaughtException()) { |
| 1673 | emit unhandledException(_engine->cloneUncaughtException("evaluateInclude")); | 1671 | auto ex = _engine->uncaughtException(); |
| 1672 | ex->additionalInfo += "; evaluateInClosure"; | ||
| 1673 | emit unhandledException(ex); | ||
| 1674 | _engine->clearExceptions(); | 1674 | _engine->clearExceptions(); |
| 1675 | } | 1675 | } |
| 1676 | } else { | 1676 | } else { |
| @@ -1995,11 +1995,14 @@ void ScriptManager::entityScriptContentAvailable(const EntityItemID& entityID, c · 318 unmodified lines | |||
| 1995 | //syntaxError.setProperty("detail", entityID.toString()); | 1995 | //syntaxError.setProperty("detail", entityID.toString()); |
| 1996 | //V8TODO | 1996 | //V8TODO |
| 1997 | //emit unhandledException(syntaxError); | 1997 | //emit unhandledException(syntaxError); |
| 1998 | |||
| 1998 | return; | 1999 | return; |
| 1999 | } | 2000 | } |
| 2000 | if (!program) { | 2001 | if (!program) { |
| 2001 | setError("Bad program (isNull)", EntityScriptStatus::ERROR_RUNNING_SCRIPT); | 2002 | setError("Bad program (isNull)", EntityScriptStatus::ERROR_RUNNING_SCRIPT); |
| 2002 | emit unhandledException(_engine->makeError(_engine->newValue("program.isNull"))); | 2003 | std::shared_ptr<ScriptException> ex = std::make_shared<ScriptEngineException>("Program is Null", "Bad program in entityScriptContentAvailable"); |
| 2004 | emit unhandledException(ex); | ||
| 2005 | |||
| 2003 | return; // done processing script | 2006 | return; // done processing script |
| 2004 | } | 2007 | } |
| 2005 | 2008 | ||
| @@ -2163,7 +2166,10 @@ void ScriptManager::entityScriptContentAvailable(const EntityItemID& entityID, c · 157 unmodified lines | |||
| 2163 | entityScriptObject = entityScriptConstructor.construct(); | 2166 | entityScriptObject = entityScriptConstructor.construct(); |
| 2164 | 2167 | ||
| 2165 | if (_engine->hasUncaughtException()) { | 2168 | if (_engine->hasUncaughtException()) { |
| 2166 | entityScriptObject = _engine->cloneUncaughtException("(construct " + entityID.toString() + ")"); | 2169 | // V8TODO: Why were we copying the uncaught exception here? Does anything |
| 2170 | // actually make use of that? | ||
| 2171 | // entityScriptObject = _engine->cloneUncaughtException("(construct " + entityID.toString() + ")"); | ||
| 2172 | entityScriptObject = _engine->nullValue(); | ||
| 2167 | _engine->clearExceptions(); | 2173 | _engine->clearExceptions(); |
| 2168 | } | 2174 | } |
| 2169 | }; | 2175 | }; |
| @@ -2171,9 +2177,10 @@ void ScriptManager::entityScriptContentAvailable(const EntityItemID& entityID, c · 1 unmodified line | |||
| 2171 | doWithEnvironment(entityID, sandboxURL, initialization); | 2177 | doWithEnvironment(entityID, sandboxURL, initialization); |
| 2172 | 2178 | ||
| 2173 | if (entityScriptObject.isError()) { | 2179 | if (entityScriptObject.isError()) { |
| 2174 | auto exception = entityScriptObject; | 2180 | // auto exception = entityScriptObject; |
| 2175 | setError(formatException(exception, _enableExtendedJSExceptions.get()), EntityScriptStatus::ERROR_RUNNING_SCRIPT); | 2181 | // setError(formatException(exception, _enableExtendedJSExceptions.get()), EntityScriptStatus::ERROR_RUNNING_SCRIPT); |
| 2176 | emit unhandledException(exception); | 2182 | // emit unhandledException(exception); |
| 2183 | // V8TODO: Is this needed? Wouldn't the ScriptManager have already emitted the exception? | ||
| 2177 | return; | 2184 | return; |
| 2178 | } | 2185 | } |
| 2179 | 2186 | ||
| @@ -2340,7 +2347,6 @@ void ScriptManager::doWithEnvironment(const EntityItemID& entityID, const QUrl& · 160 unmodified lines | |||
| 2340 | #else | 2347 | #else |
| 2341 | operation(); | 2348 | operation(); |
| 2342 | #endif | 2349 | #endif |
| 2343 | _engine->maybeEmitUncaughtException(!entityID.isNull() ? entityID.toString() : __FUNCTION__); | ||
| 2344 | currentEntityIdentifier = oldIdentifier; | 2350 | currentEntityIdentifier = oldIdentifier; |
| 2345 | currentSandboxURL = oldSandboxURL; | 2351 | currentSandboxURL = oldSandboxURL; |
| 2346 | } | 2352 | } |