overte-JulianGro/libraries/script-engine/src/v8/ScriptContextV8Wrapper.cpp

253 lines
11 KiB
C++

//
// ScriptContextV8Wrapper.cpp
// libraries/script-engine/src/v8
//
// Created by Heather Anderson on 5/22/21.
// Modified for V8 by dr Karol Suprynowicz on 2022/10/08
// Copyright 2021 Vircadia contributors.
// Copyright 2022 Overte e.V.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "ScriptContextV8Wrapper.h"
#include "ScriptEngineV8.h"
#include "ScriptValueV8Wrapper.h"
/*ScriptContextV8Wrapper::ScriptContextV8Wrapper(ScriptEngineV8* engine, const v8::Local<v8::Context> context) : _functionCallbackInfo(nullptr), _propertyCallbackInfo(nullptr), _engine(engine) {
_context.Reset(_engine->getIsolate(), context);
}*/
ScriptContextV8Wrapper::ScriptContextV8Wrapper(ScriptEngineV8* engine, const v8::Local<v8::Context> context, ScriptContextPointer parent) :
_functionCallbackInfo(nullptr), _propertyCallbackInfo(nullptr), _engine(engine),
_context(engine->getIsolate(), context), _parentContext(parent) {
}
ScriptContextV8Wrapper::ScriptContextV8Wrapper(ScriptEngineV8* engine, const v8::FunctionCallbackInfo<v8::Value> *functionCallbackInfo,
const v8::Local<v8::Context> context, ScriptContextPointer parent) :
_functionCallbackInfo(functionCallbackInfo), _propertyCallbackInfo(nullptr), _engine(engine),
_context(engine->getIsolate(), context), _parentContext(parent) {
}
ScriptContextV8Wrapper::ScriptContextV8Wrapper(ScriptEngineV8* engine, const v8::PropertyCallbackInfo<v8::Value> *propertyCallbackInfo,
const v8::Local<v8::Context> context, ScriptContextPointer parent) :
_functionCallbackInfo(nullptr), _propertyCallbackInfo(propertyCallbackInfo), _engine(engine),
_context(engine->getIsolate(), context), _parentContext(parent) {
}
ScriptContextV8Wrapper* ScriptContextV8Wrapper::unwrap(ScriptContext* val) {
if (!val) {
return nullptr;
}
return dynamic_cast<ScriptContextV8Wrapper*>(val);
}
v8::Local<v8::Context> ScriptContextV8Wrapper::toV8Value() const {
v8::EscapableHandleScope handleScope(_engine->getIsolate());
return handleScope.Escape(_context.Get(_engine->getIsolate()));
}
int ScriptContextV8Wrapper::argumentCount() const {
/*auto isolate = _engine->getIsolate();
Q_ASSERT(isolate->IsCurrent());
v8::HandleScope handleScope(isolate);
v8::Context::Scope contextScope(_engine->getContext());*/
//Q_ASSERT(_functionCallbackInfo);A
// V8TODO
auto isolate = _engine->getIsolate();
v8::Locker locker(isolate);
v8::Isolate::Scope isolateScope(isolate);
v8::HandleScope handleScope(isolate);
v8::Context::Scope contextScope(_context.Get(isolate));
if (_functionCallbackInfo) {
return _functionCallbackInfo->Length();
} else if (_propertyCallbackInfo) {
return 0;
} else {
return Q_METAMETHOD_INVOKE_MAX_ARGS;
}
// This was wrong, in function registration it seems to be used as maximum number od arguments instead?
// Is it also used for something else?
//return _functionCallbackInfo->Length();
}
ScriptValue ScriptContextV8Wrapper::argument(int index) const {
if (_functionCallbackInfo) {
auto isolate = _engine->getIsolate();
v8::Locker locker(isolate);
v8::Isolate::Scope isolateScope(isolate);
v8::HandleScope handleScope(isolate);
v8::Context::Scope contextScope(_context.Get(isolate));
v8::Local<v8::Value> result = (*_functionCallbackInfo)[index];
if (index < _functionCallbackInfo->kArgsLength) {
return ScriptValue(new ScriptValueV8Wrapper(_engine, V8ScriptValue(_engine, result)));
} else {
return _engine->undefinedValue();
}
} else if (_propertyCallbackInfo) {
return _engine->undefinedValue();
} else {
return _engine->undefinedValue();
}
}
QStringList ScriptContextV8Wrapper::backtrace() const {
auto isolate = _engine->getIsolate();
v8::Locker locker(isolate);
v8::Isolate::Scope isolateScope(isolate);
v8::HandleScope handleScope(isolate);
v8::Context::Scope contextScope(_context.Get(isolate));
v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(isolate, 40);
QStringList backTrace;
//V8TODO nicer formatting
for (int i = 0; i < stackTrace->GetFrameCount(); i++) {
v8::Local<v8::StackFrame> stackFrame = stackTrace->GetFrame(isolate, i);
backTrace.append(QString(*v8::String::Utf8Value(isolate, stackFrame->GetScriptNameOrSourceURL())) +
QString(" ") +
QString(*v8::String::Utf8Value(isolate, stackFrame->GetFunctionName())) +
QString(":") +
QStringLiteral("%1").arg(stackFrame->GetLineNumber())
);
}
return backTrace;
}
ScriptValue ScriptContextV8Wrapper::callee() const {
Q_ASSERT(false);
//V8TODO
//Can this be done with CurrentStackTrace?
//V8ScriptValue result = _context->callee();
//return ScriptValue(new ScriptValueV8Wrapper(_engine, std::move(result)));
return _engine->undefinedValue();
}
ScriptEnginePointer ScriptContextV8Wrapper::engine() const {
return _engine->shared_from_this();
}
ScriptFunctionContextPointer ScriptContextV8Wrapper::functionContext() const {
auto isolate = _engine->getIsolate();
v8::Locker locker(isolate);
v8::Isolate::Scope isolateScope(isolate);
v8::HandleScope handleScope(isolate);
v8::Context::Scope contextScope(_context.Get(isolate));
auto scriptFunctionContextPointer = std::make_shared<ScriptFunctionContextV8Wrapper>(_engine, _context.Get(_engine->getIsolate()));
return scriptFunctionContextPointer;
}
ScriptContextPointer ScriptContextV8Wrapper::parentContext() const {
return _parentContext;
}
ScriptValue ScriptContextV8Wrapper::thisObject() const {
if (_functionCallbackInfo) {
auto isolate = _engine->getIsolate();
v8::Locker locker(isolate);
v8::Isolate::Scope isolateScope(isolate);
v8::HandleScope handleScope(isolate);
v8::Context::Scope contextScope(_context.Get(isolate));
v8::Local<v8::Value> result = _functionCallbackInfo->This();
return ScriptValue(new ScriptValueV8Wrapper(_engine, V8ScriptValue(_engine, result)));
} else if (_propertyCallbackInfo) {
auto isolate = _engine->getIsolate();
v8::Locker locker(isolate);
v8::Isolate::Scope isolateScope(isolate);
v8::HandleScope handleScope(isolate);
v8::Context::Scope contextScope(_context.Get(isolate));
v8::Local<v8::Value> result = _propertyCallbackInfo->This();
return ScriptValue(new ScriptValueV8Wrapper(_engine, V8ScriptValue(_engine, result)));
} else {
return _engine->undefinedValue();
}
}
ScriptValue ScriptContextV8Wrapper::throwError(const QString& text) {
auto isolate = _engine->getIsolate();
// V8TODO: I have no idea how to do this yet because it happens on another thread
if(isolate->IsCurrent()) {
v8::Locker locker(isolate);
v8::Isolate::Scope isolateScope(isolate);
v8::HandleScope handleScope(isolate);
v8::Context::Scope contextScope(_context.Get(isolate));
V8ScriptValue result(_engine,
_engine->getIsolate()->ThrowError(
v8::String::NewFromUtf8(_engine->getIsolate(), text.toStdString().c_str()).ToLocalChecked()));
return ScriptValue(new ScriptValueV8Wrapper(_engine, std::move(result)));
} else {
qWarning() << "throwError on a different thread not implemented yet, error value: " << text;
return _engine->undefinedValue();
}
}
ScriptValue ScriptContextV8Wrapper::throwValue(const ScriptValue& value) {
auto isolate = _engine->getIsolate();
v8::Locker locker(isolate);
v8::Isolate::Scope isolateScope(isolate);
v8::HandleScope handleScope(isolate);
v8::Context::Scope contextScope(_context.Get(isolate));
ScriptValueV8Wrapper* unwrapped = ScriptValueV8Wrapper::unwrap(value);
if (!unwrapped) {
return _engine->undefinedValue();
}
V8ScriptValue result(_engine, _engine->getIsolate()->ThrowException(unwrapped->toV8Value().constGet()));
return ScriptValue(new ScriptValueV8Wrapper(_engine, std::move(result)));
}
ScriptFunctionContextV8Wrapper::ScriptFunctionContextV8Wrapper(ScriptEngineV8* engine, const v8::Local<v8::Context> context) : _engine(engine) {
v8::Locker locker();
v8::Isolate::Scope isolateScope(engine->getIsolate());
v8::HandleScope handleScope(engine->getIsolate());
_context.Reset(engine->getIsolate(), context);
}
QString ScriptFunctionContextV8Wrapper::fileName() const {
//V8TODO: It's not exactly like in QtScript, because there's no such context object in V8, let's return the current one for now
//Maybe fetch data on creation or store stack frame?
auto isolate = _engine->getIsolate();
v8::Locker locker(isolate);
v8::Isolate::Scope isolateScope(isolate);
v8::HandleScope handleScope(isolate);
v8::Context::Scope contextScope(_context.Get(isolate));
// V8TODO: does this work for context selected with contextScope?
v8::Local<v8::String> name = v8::StackTrace::CurrentScriptNameOrSourceURL(_engine->getIsolate());
v8::String::Utf8Value nameUTF(_engine->getIsolate(), name);
return QString(*nameUTF);
}
QString ScriptFunctionContextV8Wrapper::functionName() const {
//V8TODO: It's not exactly like in QtScript, because there's no such context object in V8, let's return the current one for now
//Maybe fetch data on creation?
auto isolate = _engine->getIsolate();
v8::Locker locker(isolate);
v8::Isolate::Scope isolateScope(isolate);
v8::HandleScope handleScope(isolate);
v8::Context::Scope contextScope(_context.Get(isolate));
// V8TODO: does this work for context selected with contextScope?
v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(_engine->getIsolate(), 1);
v8::Local<v8::StackFrame> stackFrame = stackTrace->GetFrame(_engine->getIsolate(), 0);
v8::Local<v8::String> name = stackFrame->GetFunctionName();
v8::String::Utf8Value nameUTF(_engine->getIsolate(), name);
return QString(*nameUTF);
}
ScriptFunctionContext::FunctionType ScriptFunctionContextV8Wrapper::functionType() const {
//V8TODO
//return static_cast<ScriptFunctionContext::FunctionType>(_value.functionType());
return ScriptFunctionContext::FunctionType::ScriptFunction;
}
int ScriptFunctionContextV8Wrapper::lineNumber() const {
//V8TODO: It's not exactly like in QtScript, because there's no such context object in V8, let's return the current one for now
//Maybe fetch data on creation?
auto isolate = _engine->getIsolate();
v8::Locker locker(isolate);
v8::Isolate::Scope isolateScope(isolate);
v8::HandleScope handleScope(isolate);
v8::Context::Scope contextScope(_context.Get(isolate));
v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(_engine->getIsolate(), 1);
v8::Local<v8::StackFrame> stackFrame = stackTrace->GetFrame(_engine->getIsolate(), 0);
return stackFrame->GetLineNumber();
}