* 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 | 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 | 290 | // this is where all unhandled exceptions end up getting logged |
| 286 | 291 | connect(this, &ScriptManager::unhandledException, this, [this](const ScriptValue& err) { |
| 287 | 292 | qCCritical(scriptengine) << "Caught exception"; |
| @@ -296,6 +301,7 @@ ScriptManager::ScriptManager(Context context, const QString& scriptContents, con · 8 unmodified lines | ||
| 296 | 301 | |
| 297 | 302 | logException(output); |
| 298 | 303 | }); |
| 304 | +#endif | |
| 299 | 305 | |
| 300 | 306 | if (_type == Type::ENTITY_CLIENT || _type == Type::ENTITY_SERVER) { |
| 301 | 307 | QObject::connect(this, &ScriptManager::update, this, [this]() { |
| @@ -891,13 +897,11 @@ void ScriptManager::run() { · 589 unmodified lines | ||
| 891 | 897 | { |
| 892 | 898 | PROFILE_RANGE(script, _fileNameString); |
| 893 | 899 | _returnValue = _engine->evaluate(_scriptContents, _fileNameString); |
| 894 | − _engine->maybeEmitUncaughtException(__FUNCTION__); | |
| 895 | 900 | |
| 896 | 901 | if (_engine->hasUncaughtException()) { |
| 897 | 902 | |
| 898 | 903 | qCWarning(scriptengine) << "Engine has uncaught exception, stopping"; |
| 899 | 904 | stop(); |
| 900 | − emit unhandledException(_engine->cloneUncaughtException(__FUNCTION__)); | |
| 901 | 905 | _engine->clearExceptions(); |
| 902 | 906 | } |
| 903 | 907 | } |
| @@ -1023,7 +1027,7 @@ void ScriptManager::run() { · 119 unmodified lines | ||
| 1023 | 1027 | if (!_engine->isEvaluating() && _engine->hasUncaughtException()) { |
| 1024 | 1028 | qCWarning(scriptengine) << __FUNCTION__ << "---------- UNCAUGHT EXCEPTION --------"; |
| 1025 | 1029 | qCWarning(scriptengine) << "runInThread" << _engine->uncaughtException(); |
| 1026 | − emit unhandledException(_engine->cloneUncaughtException(__FUNCTION__)); | |
| 1030 | + emit unhandledException(_engine->uncaughtException()); | |
| 1027 | 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 | 1263 | auto message = QString("Cannot find module '%1' (%2)").arg(displayId); |
| 1260 | 1264 | |
| 1261 | − auto throwResolveError = [&](const ScriptValue& error) -> QString { | |
| 1262 | − _engine->raiseException(error); | |
| 1263 | − _engine->maybeEmitUncaughtException("require.resolve"); | |
| 1265 | + auto throwResolveError = [&](const QString& error, const QString &details = QString()) -> QString { | |
| 1266 | + _engine->raiseException(error, "require.resolve: " + details); | |
| 1264 | 1267 | return QString(); |
| 1265 | 1268 | }; |
| 1266 | 1269 | |
| @@ -1269,7 +1272,7 @@ QString ScriptManager::_requireResolve(const QString& moduleId, const QString& r · 2 unmodified lines | ||
| 1269 | 1272 | if (idLength < 1 || idLength > MAX_MODULE_ID_LENGTH) { |
| 1270 | 1273 | auto details = QString("rejecting invalid module id size (%1 chars [1,%2])") |
| 1271 | 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 | 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 | 1299 | if (QFileInfo(unanchoredUrl.toLocalFile()).isFile()) { |
| 1297 | 1300 | auto msg = QString("relative module ids must be anchored; use './%1' instead") |
| 1298 | 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 | 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 | 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 | 1321 | bool disallowOutsideFiles = !PathUtils::defaultScriptsLocation().isParentOf(canonical) && !currentSandboxURL.isLocalFile(); |
| 1319 | 1322 | if (disallowOutsideFiles && !PathUtils::isDescendantOf(canonical, currentSandboxURL)) { |
| 1320 | − return throwResolveError(_engine->makeError(_engine->newValue(message.arg( | |
| 1323 | + return throwResolveError(message.arg( | |
| 1321 | 1324 | QString("path '%1' outside of origin script '%2' '%3'") |
| 1322 | 1325 | .arg(PathUtils::stripFilename(url)) |
| 1323 | 1326 | .arg(PathUtils::stripFilename(currentSandboxURL)) |
| 1324 | 1327 | .arg(canonical.toString()) |
| 1325 | − )))); | |
| 1328 | + )); | |
| 1326 | 1329 | } |
| 1327 | 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 | 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 | 1338 | return url.toString(); |
| 1337 | 1339 | } |
| 1338 | 1340 | |
| @@ -1488,7 +1490,7 @@ ScriptValue ScriptManager::instantiateModule(const ScriptValue& module, const QS · 149 unmodified lines | ||
| 1488 | 1490 | //_engine->scriptValueDebugDetails(module); |
| 1489 | 1491 | result = _engine->evaluateInClosure(closure, _engine->newProgram( sourceCode, modulePath )); |
| 1490 | 1492 | } |
| 1491 | − _engine->maybeEmitUncaughtException(__FUNCTION__); | |
| 1493 | + | |
| 1492 | 1494 | return result; |
| 1493 | 1495 | } |
| 1494 | 1496 | |
| @@ -1510,9 +1512,8 @@ ScriptValue ScriptManager::require(const QString& moduleId) { · 15 unmodified lines | ||
| 1510 | 1512 | #ifdef DEBUG_JS_MODULES |
| 1511 | 1513 | qCWarning(scriptengine_module) << "throwing module error:" << error.toString() << modulePath << error.property("stack").toString(); |
| 1512 | 1514 | #endif |
| 1513 | − _engine->raiseException(error); | |
| 1515 | + _engine->raiseException(error, "module error"); | |
| 1514 | 1516 | } |
| 1515 | − _engine->maybeEmitUncaughtException("module"); | |
| 1516 | 1517 | return _engine->nullValue(); |
| 1517 | 1518 | }; |
| 1518 | 1519 | |
| @@ -1520,7 +1521,6 @@ ScriptValue ScriptManager::require(const QString& moduleId) { · 1 unmodified line | ||
| 1520 | 1521 | QString modulePath = _requireResolve(moduleId); |
| 1521 | 1522 | if (modulePath.isNull() || _engine->hasUncaughtException()) { |
| 1522 | 1523 | // the resolver already threw an exception -- bail early |
| 1523 | − _engine->maybeEmitUncaughtException(__FUNCTION__); | |
| 1524 | 1524 | return _engine->nullValue(); |
| 1525 | 1525 | } |
| 1526 | 1526 | |
| @@ -1546,7 +1546,6 @@ ScriptValue ScriptManager::require(const QString& moduleId) { · 19 unmodified lines | ||
| 1546 | 1546 | qCDebug(scriptengine_module) << QString("require - using cached module for '%1' (loaded: %2)") |
| 1547 | 1547 | .arg(moduleId).arg(module.property("loaded").toString()); |
| 1548 | 1548 | registerModuleWithParent(module, parent); |
| 1549 | − _engine->maybeEmitUncaughtException("cached module"); | |
| 1550 | 1549 | return exports; |
| 1551 | 1550 | } |
| 1552 | 1551 | |
| @@ -1594,7 +1593,6 @@ ScriptValue ScriptManager::require(const QString& moduleId) { · 41 unmodified lines | ||
| 1594 | 1593 | |
| 1595 | 1594 | //qCDebug(scriptengine_module) << "//ScriptManager::require(" << moduleId << ")"; |
| 1596 | 1595 | |
| 1597 | − _engine->maybeEmitUncaughtException(__FUNCTION__); | |
| 1598 | 1596 | //qCDebug(scriptengine_module) << "Exports: " << _engine->scriptValueDebugDetails(module.property("exports")); |
| 1599 | 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 | 1669 | doWithEnvironment(capturedEntityIdentifier, capturedSandboxURL, operation); |
| 1672 | 1670 | if(_engine->hasUncaughtException()) { |
| 1673 | − emit unhandledException(_engine->cloneUncaughtException("evaluateInclude")); | |
| 1671 | + auto ex = _engine->uncaughtException(); | |
| 1672 | + ex->additionalInfo += "; evaluateInClosure"; | |
| 1673 | + emit unhandledException(ex); | |
| 1674 | 1674 | _engine->clearExceptions(); |
| 1675 | 1675 | } |
| 1676 | 1676 | } else { |
| @@ -1995,11 +1995,14 @@ void ScriptManager::entityScriptContentAvailable(const EntityItemID& entityID, c · 318 unmodified lines | ||
| 1995 | 1995 | //syntaxError.setProperty("detail", entityID.toString()); |
| 1996 | 1996 | //V8TODO |
| 1997 | 1997 | //emit unhandledException(syntaxError); |
| 1998 | + | |
| 1998 | 1999 | return; |
| 1999 | 2000 | } |
| 2000 | 2001 | if (!program) { |
| 2001 | 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 | 2006 | return; // done processing script |
| 2004 | 2007 | } |
| 2005 | 2008 | |
| @@ -2163,7 +2166,10 @@ void ScriptManager::entityScriptContentAvailable(const EntityItemID& entityID, c · 157 unmodified lines | ||
| 2163 | 2166 | entityScriptObject = entityScriptConstructor.construct(); |
| 2164 | 2167 | |
| 2165 | 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 | 2173 | _engine->clearExceptions(); |
| 2168 | 2174 | } |
| 2169 | 2175 | }; |
| @@ -2171,9 +2177,10 @@ void ScriptManager::entityScriptContentAvailable(const EntityItemID& entityID, c · 1 unmodified line | ||
| 2171 | 2177 | doWithEnvironment(entityID, sandboxURL, initialization); |
| 2172 | 2178 | |
| 2173 | 2179 | if (entityScriptObject.isError()) { |
| 2174 | − auto exception = entityScriptObject; | |
| 2175 | − setError(formatException(exception, _enableExtendedJSExceptions.get()), EntityScriptStatus::ERROR_RUNNING_SCRIPT); | |
| 2176 | − emit unhandledException(exception); | |
| 2180 | + // auto exception = entityScriptObject; | |
| 2181 | + // setError(formatException(exception, _enableExtendedJSExceptions.get()), EntityScriptStatus::ERROR_RUNNING_SCRIPT); | |
| 2182 | + // emit unhandledException(exception); | |
| 2183 | + // V8TODO: Is this needed? Wouldn't the ScriptManager have already emitted the exception? | |
| 2177 | 2184 | return; |
| 2178 | 2185 | } |
| 2179 | 2186 | |
| @@ -2340,7 +2347,6 @@ void ScriptManager::doWithEnvironment(const EntityItemID& entityID, const QUrl& · 160 unmodified lines | ||
| 2340 | 2347 | #else |
| 2341 | 2348 | operation(); |
| 2342 | 2349 | #endif |
| 2343 | − _engine->maybeEmitUncaughtException(!entityID.isNull() ? entityID.toString() : __FUNCTION__); | |
| 2344 | 2350 | currentEntityIdentifier = oldIdentifier; |
| 2345 | 2351 | currentSandboxURL = oldSandboxURL; |
| 2346 | 2352 | } |