V8 fixes, including making debug console work

This commit is contained in:
ksuprynowicz 2022-12-16 09:20:25 +01:00
parent 97137c7b13
commit 0d454eb6e8
6 changed files with 77 additions and 46 deletions

View file

@ -351,12 +351,12 @@ void JSConsole::executeCommand(const QString& command) {
std::weak_ptr<ScriptManager> weakScriptManager = _scriptManager;
auto consoleFileName = _consoleFileName;
QFuture<ScriptValue> future = QtConcurrent::run([weakScriptManager, consoleFileName, command]() -> ScriptValue {
ScriptValue result;
QFuture<QVariant> future = QtConcurrent::run([weakScriptManager, consoleFileName, command]() -> QVariant {
QVariant result;
auto scriptManager = weakScriptManager.lock();
if (scriptManager) {
BLOCKING_INVOKE_METHOD(scriptManager.get(), [&scriptManager, &consoleFileName, &command, &result]() -> void {
result = scriptManager->evaluate(command, consoleFileName);
result = scriptManager->evaluate(command, consoleFileName).toVariant();
});
}
return result;
@ -365,7 +365,7 @@ void JSConsole::executeCommand(const QString& command) {
}
void JSConsole::commandFinished() {
ScriptValue result = _executeWatcher.result();
QVariant result = _executeWatcher.result();
_ui->promptTextEdit->setDisabled(false);
@ -374,9 +374,12 @@ void JSConsole::commandFinished() {
_ui->promptTextEdit->setFocus();
}
bool error = (_scriptManager->engine()->hasUncaughtException() || result.isError());
QString gutter = error ? GUTTER_ERROR : GUTTER_PREVIOUS_COMMAND;
QString resultColor = error ? RESULT_ERROR_STYLE : RESULT_SUCCESS_STYLE;
// V8TODO:
//bool error = (_scriptManager->engine()->hasUncaughtException() || result.isError());
//QString gutter = error ? GUTTER_ERROR : GUTTER_PREVIOUS_COMMAND;
//QString resultColor = error ? RESULT_ERROR_STYLE : RESULT_SUCCESS_STYLE;
QString gutter = GUTTER_PREVIOUS_COMMAND;
QString resultColor = RESULT_SUCCESS_STYLE;
QString resultStr = "<span style='" + resultColor + "'>" + result.toString().toHtmlEscaped() + "</span>";
appendMessage(gutter, resultStr);

View file

@ -72,7 +72,7 @@ private:
QStandardItemModel* getAutoCompleteModel(const QString& memberOf = nullptr);
QFutureWatcher<ScriptValue> _executeWatcher;
QFutureWatcher<QVariant> _executeWatcher;
Ui::Console* _ui;
int _currentCommandInHistory;
QString _savedHistoryFilename;

View file

@ -1968,7 +1968,9 @@ void ScriptManager::entityScriptContentAvailable(const EntityItemID& entityID, c
}
// SANITY/PERFORMANCE CHECK USING SANDBOX
const int SANDBOX_TIMEOUT = 0.25 * MSECS_PER_SECOND;
// V8TODO: can be skipped for now but needs to be implemented before release
/*const int SANDBOX_TIMEOUT = 0.25 * MSECS_PER_SECOND;
ScriptEnginePointer sandbox = newScriptEngine();
sandbox->setProcessEventsInterval(SANDBOX_TIMEOUT);
ScriptValue testConstructor, exception;
@ -2104,7 +2106,7 @@ void ScriptManager::entityScriptContentAvailable(const EntityItemID& entityID, c
setError("Could not find constructor (" + testConstructorType + ")", EntityScriptStatus::ERROR_RUNNING_SCRIPT);
emit unhandledException(err);
return; // done processing script
}
}*/
// (this feeds into refreshFileScript)
int64_t lastModified = 0;

View file

@ -119,7 +119,7 @@ ScriptFunctionContextPointer ScriptContextV8Wrapper::functionContext() const {
ScriptContextPointer ScriptContextV8Wrapper::parentContext() const {
//V8TODO
Q_ASSERT(false);
//Q_ASSERT(false);
//V8ScriptContext* result = _context->parentContext();
//return result ? std::make_shared<ScriptContextV8Wrapper>(_engine, result) : ScriptContextPointer();
return ScriptContextPointer();

View file

@ -981,28 +981,42 @@ Q_INVOKABLE ScriptValue ScriptEngineV8::evaluate(const ScriptProgramPointer& pro
}
Q_ASSERT(!isEvaluating());
_isEvaluating = true;
v8::HandleScope handleScope(_v8Isolate);
v8::Context::Scope contextScope(_v8Context.Get(_v8Isolate));
ScriptProgramV8Wrapper* unwrapped = ScriptProgramV8Wrapper::unwrap(program);
if (!unwrapped) {
auto err = makeError(newValue("could not unwrap program"));
raiseException(err);
maybeEmitUncaughtException("compile");
_isEvaluating = false;
return err;
}
ScriptSyntaxCheckResultPointer syntaxCheck = unwrapped->checkSyntax();
if (syntaxCheck->state() == ScriptSyntaxCheckResult::Error) {
auto err = makeError(newValue(syntaxCheck->errorMessage()));
raiseException(err);
maybeEmitUncaughtException("compile");
_isEvaluating = false;
return err;
bool is_isolate_exit_needed = false;
if(!_v8Isolate->IsCurrent() && !_v8Locker) {
// V8TODO: Theoretically only script thread should access this, so it should be safe
_v8Locker.reset(new v8::Locker(_v8Isolate));
_v8Isolate->Enter();
is_isolate_exit_needed = true;
}
ScriptValue errorValue;
ScriptValue resultValue;
bool hasFailed = false;
{
v8::HandleScope handleScope(_v8Isolate);
v8::Context::Scope contextScope(_v8Context.Get(_v8Isolate));
ScriptProgramV8Wrapper* unwrapped = ScriptProgramV8Wrapper::unwrap(program);
if (!unwrapped) {
errorValue = makeError(newValue("could not unwrap program"));
raiseException(errorValue);
maybeEmitUncaughtException("compile");
hasFailed = true;
}
const V8ScriptProgram& v8Program = unwrapped->toV8Value();
// V8TODO
/*if (qProgram.isNull()) {
if(!hasFailed) {
ScriptSyntaxCheckResultPointer syntaxCheck = unwrapped->checkSyntax();
if (syntaxCheck->state() == ScriptSyntaxCheckResult::Error) {
errorValue = makeError(newValue(syntaxCheck->errorMessage()));
raiseException(errorValue);
maybeEmitUncaughtException("compile");
hasFailed = true;
}
}
v8::Local<v8::Value> result;
if(!hasFailed) {
const V8ScriptProgram& v8Program = unwrapped->toV8Value();
// V8TODO
/*if (qProgram.isNull()) {
// can this happen?
auto err = makeError(newValue("requested program is empty"));
raiseException(err);
@ -1010,20 +1024,31 @@ Q_INVOKABLE ScriptValue ScriptEngineV8::evaluate(const ScriptProgramPointer& pro
return err;
}*/
v8::Local<v8::Value> result;
v8::TryCatch tryCatchRun(getIsolate());
if (!v8Program.constGet()->Run(getContext()).ToLocal(&result)) {
Q_ASSERT(tryCatchRun.HasCaught());
auto runError = tryCatchRun.Message();
ScriptValue errorValue(new ScriptValueV8Wrapper(this, V8ScriptValue(_v8Isolate, runError->Get())));
raiseException(errorValue);
maybeEmitUncaughtException("evaluate");
_isEvaluating = false;
return errorValue;
v8::TryCatch tryCatchRun(getIsolate());
if (!v8Program.constGet()->Run(getContext()).ToLocal(&result)) {
Q_ASSERT(tryCatchRun.HasCaught());
auto runError = tryCatchRun.Message();
errorValue = ScriptValue(new ScriptValueV8Wrapper(this, V8ScriptValue(_v8Isolate, runError->Get())));
raiseException(errorValue);
maybeEmitUncaughtException("evaluate");
hasFailed = true;
}
}
if(!hasFailed) {
V8ScriptValue resultValueV8(_v8Isolate, result);
resultValue = ScriptValue(new ScriptValueV8Wrapper(this, std::move(resultValueV8)));
}
}
V8ScriptValue resultValue(_v8Isolate, result);
_isEvaluating = false;
return ScriptValue(new ScriptValueV8Wrapper(this, std::move(resultValue)));
if (is_isolate_exit_needed) {
_v8Isolate->Exit();
_v8Locker.reset(nullptr);
}
if (hasFailed) {
return errorValue;
} else {
return resultValue;
}
}
@ -1094,6 +1119,7 @@ ScriptProgramPointer ScriptEngineV8::newProgram(const QString& sourceCode, const
//V8TODO: is it used between isolates?
//V8TODO: should it be compiled on creation?
//V8ScriptProgram result(sourceCode, fileName);
v8::HandleScope handleScope(_v8Isolate);
v8::Context::Scope contextScope(_v8Context.Get(_v8Isolate));
return std::make_shared<ScriptProgramV8Wrapper>(this, sourceCode, fileName);

View file

@ -429,9 +429,9 @@ bool ScriptValueV8Wrapper::isBool() const {
bool ScriptValueV8Wrapper::isError() const {
auto isolate = _engine->getIsolate();
Q_ASSERT(isolate->IsCurrent());
v8::HandleScope handleScope(isolate);
v8::Context::Scope contextScope(_engine->getContext());
// Q_ASSERT(isolate->IsCurrent());
// v8::HandleScope handleScope(isolate);
// v8::Context::Scope contextScope(_engine->getContext());
//V8TODO
return false;
//return _value.constGet()->IsError();