Code cleanup

This commit is contained in:
ksuprynowicz 2023-05-01 19:52:19 +02:00
parent d240386a25
commit 5050cc9a4e
29 changed files with 57 additions and 951 deletions

View file

@ -21,7 +21,7 @@
#include "TypedArrays.h"
// V8TODO
// V8TODO Do not remove yet, this will be useful in later PRs
/*static const QString CLASS_NAME = "ArrayBuffer";
// FIXME: Q_DECLARE_METATYPE is global and really belongs in a shared header file, not per .cpp like this

View file

@ -22,8 +22,8 @@
#include "v8.h"
#include <QtCore/QDateTime>
// V8TODO Do not remove yet, this will be useful in later PRs
//#include "V8Types.h"
// V8TODO
/*
class ScriptEngineV8;

View file

@ -23,7 +23,7 @@
static const int QCOMPRESS_HEADER_POSITION = 0;
static const int QCOMPRESS_HEADER_SIZE = 4;
// V8TODO
// V8TODO Do not remove yet, this will be useful in later PRs
/*Q_DECLARE_METATYPE(QByteArray*)
ArrayBufferPrototype::ArrayBufferPrototype(QObject* parent) : QObject(parent) {

View file

@ -17,7 +17,7 @@
#ifndef hifi_ArrayBufferPrototype_h
#define hifi_ArrayBufferPrototype_h
// V8TODO
// V8TODO Do not remove yet, this will be useful in later PRs
/*#include <QtCore/QObject>
#include "../Scriptable.h"

View file

@ -16,7 +16,7 @@
Q_DECLARE_METATYPE(QByteArray*)
// V8TODO
// V8TODO Do not remove yet, this will be useful in later PRs
/*ArrayBufferViewClass::ArrayBufferViewClass(ScriptEngineV8* scriptEngine) :
QObject(scriptEngine),
QScriptClass(scriptEngine),

View file

@ -20,7 +20,7 @@
#include <QtCore/QObject>
#include "V8Types.h"
// V8TODO
// V8TODO Do not remove yet, this will be useful in later PRs
/*class ScriptEngineV8;
static const QString BUFFER_PROPERTY_NAME = "buffer";

View file

@ -13,7 +13,7 @@
#include "DataViewClass.h"
// V8TODO
// V8TODO Do not remove yet, this will be useful in later PRs
/*#include "DataViewPrototype.h"
Q_DECLARE_METATYPE(QByteArray*)

View file

@ -17,7 +17,7 @@
#ifndef hifi_DataViewClass_h
#define hifi_DataViewClass_h
// V8TODO
// V8TODO Do not remove yet, this will be useful in later PRs
/*
#include "ArrayBufferViewClass.h"

View file

@ -22,7 +22,7 @@
#include "ArrayBufferViewClass.h"
// V8TODO
// V8TODO Do not remove yet, this will be useful in later PRs
/*Q_DECLARE_METATYPE(QByteArray*)
DataViewPrototype::DataViewPrototype(QObject* parent) : QObject(parent) {

View file

@ -22,7 +22,7 @@
#include "V8Types.h"
#include "../Scriptable.h"
// V8TODO
// V8TODO Do not remove yet, this will be useful in later PRs
/*/// [V8] The javascript functions associated with a <code><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DataView">DataView</a></code> instance prototype
class DataViewPrototype : public QObject, public Scriptable {
Q_OBJECT

View file

@ -20,22 +20,6 @@
#ifdef CONVERSIONS_OPTIMIZED_FOR_V8
ScriptValue vec3ToScriptValue(ScriptEngine* engine, const glm::vec3& vec3) {
//auto prototype = engine->globalObject().property("__hifi_vec3__");
/*if (!prototype.hasProperty("defined") || !prototype.property("defined").toBool()) {
prototype = engine->evaluate(
"__hifi_vec3__ = Object.defineProperties({}, { "
"defined: { value: true },"
"0: { set: function(nv) { return this.x = nv; }, get: function() { return this.x; } },"
"1: { set: function(nv) { return this.y = nv; }, get: function() { return this.y; } },"
"2: { set: function(nv) { return this.z = nv; }, get: function() { return this.z; } },"
"r: { set: function(nv) { return this.x = nv; }, get: function() { return this.x; } },"
"g: { set: function(nv) { return this.y = nv; }, get: function() { return this.y; } },"
"b: { set: function(nv) { return this.z = nv; }, get: function() { return this.z; } },"
"red: { set: function(nv) { return this.x = nv; }, get: function() { return this.x; } },"
"green: { set: function(nv) { return this.y = nv; }, get: function() { return this.y; } },"
"blue: { set: function(nv) { return this.z = nv; }, get: function() { return this.z; } }"
"})");
}*/
ScriptValue value = engine->newObject();
ScriptValueV8Wrapper *proxy = ScriptValueV8Wrapper::unwrap(value);
@ -106,11 +90,9 @@ ScriptValue vec3ToScriptValue(ScriptEngine* engine, const glm::vec3& vec3) {
Q_ASSERT(false);
}
//auto v8Prototype = ScriptValueV8Wrapper::fullUnwrap(engineV8, prototype);
if (!v8Object->SetPrototype(context, prototype).FromMaybe(false)) {
Q_ASSERT(false);
}
//value.setPrototype(prototype);
return value;
}
@ -143,7 +125,6 @@ bool vec3FromScriptValue(const ScriptValue& object, glm::vec3& vec3) {
}
} else if (v8Value->IsArray()) {
auto array = v8::Local<v8::Array>::Cast(v8Value);
//QVariantList list = object.toVariant().toList();
if (array->Length() == 3) {
v8::Local<v8::Value> xValue,yValue,zValue;
if (!array->Get(context, 0).ToLocal(&xValue)) {
@ -219,11 +200,6 @@ bool vec3FromScriptValue(const ScriptValue& object, glm::vec3& vec3) {
}
}
//f (!x.isValid() || !y.isValid() || !z.isValid()) {
// V8TODO: This breaks the sit script for some reason
//return false;
//}
vec3.x = xValue->NumberValue(context).FromMaybe(0.0);
vec3.y = yValue->NumberValue(context).FromMaybe(0.0);
vec3.z = zValue->NumberValue(context).FromMaybe(0.0);

View file

@ -18,11 +18,6 @@
#include "ScriptValueV8Wrapper.h"
#include "ScriptEngineLoggingV8.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) {
@ -40,6 +35,14 @@ ScriptContextV8Wrapper::ScriptContextV8Wrapper(ScriptEngineV8* engine, const v8:
_context(engine->getIsolate(), context), _parentContext(parent) {
}
ScriptContextV8Wrapper::~ScriptContextV8Wrapper() noexcept {
//V8TODO: what if destructor happens during shutdown and V8 isolate is already disposed of?
auto isolate = _engine->getIsolate();
v8::Locker locker(isolate);
v8::Isolate::Scope isolateScope(isolate);
_context.Reset();
}
ScriptContextV8Wrapper* ScriptContextV8Wrapper::unwrap(ScriptContext* val) {
if (!val) {
return nullptr;
@ -54,11 +57,6 @@ v8::Local<v8::Context> ScriptContextV8Wrapper::toV8Value() const {
}
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);
@ -123,7 +121,6 @@ ScriptValue ScriptContextV8Wrapper::callee() const {
//V8TODO
//Can this be done with CurrentStackTrace?
//V8ScriptValue result = _context->callee();
//return ScriptValue(new ScriptValueV8Wrapper(_engine, std::move(result)));
return _engine->undefinedValue();
}
@ -207,6 +204,14 @@ ScriptFunctionContextV8Wrapper::ScriptFunctionContextV8Wrapper(ScriptEngineV8* e
_context.Reset(engine->getIsolate(), context);
}
ScriptFunctionContextV8Wrapper::~ScriptFunctionContextV8Wrapper() {
//V8TODO: what if destructor happens during shutdown and V8 isolate is already disposed of?
auto isolate = _engine->getIsolate();
v8::Locker locker(isolate);
v8::Isolate::Scope isolateScope(isolate);
_context.Reset();
}
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?
@ -238,7 +243,7 @@ QString ScriptFunctionContextV8Wrapper::functionName() const {
}
ScriptFunctionContext::FunctionType ScriptFunctionContextV8Wrapper::functionType() const {
//V8TODO
//V8TODO: This is only used in debugPrint. Should we remove it?
//return static_cast<ScriptFunctionContext::FunctionType>(_value.functionType());
return ScriptFunctionContext::FunctionType::ScriptFunction;
}

View file

@ -37,7 +37,7 @@ public: // construction
const v8::Local<v8::Context> context, ScriptContextPointer parent);
ScriptContextV8Wrapper(ScriptEngineV8* engine, const v8::PropertyCallbackInfo<v8::Value> *propertyCallbackInfo,
const v8::Local<v8::Context> context, ScriptContextPointer parent);
virtual ~ScriptContextV8Wrapper() {_context.Reset();}
virtual ~ScriptContextV8Wrapper();
static ScriptContextV8Wrapper* unwrap(ScriptContext* val);
@ -60,7 +60,6 @@ private: // storage
const v8::FunctionCallbackInfo<v8::Value> *_functionCallbackInfo;
const v8::PropertyCallbackInfo<v8::Value> *_propertyCallbackInfo;
ScriptEngineV8* _engine;
// V8TODO: custom destructor is needed for v8::Persistent
v8::Persistent<v8::Context> _context;
ScriptContextPointer _parentContext;
Q_DISABLE_COPY(ScriptContextV8Wrapper)
@ -68,9 +67,8 @@ private: // storage
class ScriptFunctionContextV8Wrapper final : public ScriptFunctionContext {
public: // construction
//V8TODO
ScriptFunctionContextV8Wrapper(ScriptEngineV8* engine, const v8::Local<v8::Context> context);
virtual ~ScriptFunctionContextV8Wrapper() {_context.Reset();};
virtual ~ScriptFunctionContextV8Wrapper();
public: // ScriptFunctionContext implementation
virtual QString fileName() const override;
@ -80,9 +78,7 @@ public: // ScriptFunctionContext implementation
private: // storage
ScriptEngineV8* _engine;
// V8TODO: custom destructor is needed for v8::Persistent (check is all other classes using different types of persistent handles have custom destructors too)
v8::Persistent<v8::Context> _context;
//V8ScriptContextInfo _value;
Q_DISABLE_COPY(ScriptFunctionContextV8Wrapper)
};

View file

@ -85,7 +85,7 @@ ScriptValue ScriptEngineV8::makeError(const ScriptValue& _other, const QString&
return nullValue();
}
//V8TODO
//V8TODO: do not remove until ScriptEngineV8::makeError is implemented
/*
auto other = _other;
if (_other.constGet()->IsString()) {
@ -130,14 +130,12 @@ ScriptValue ScriptEngineV8::checkScriptSyntax(ScriptProgramPointer program) {
v8::HandleScope handleScope(_v8Isolate);
v8::Context::Scope contextScope(getContext());
ScriptSyntaxCheckResultPointer syntaxCheck = program->checkSyntax();
//V8TODO
if (syntaxCheck->state() != ScriptSyntaxCheckResult::Valid) {
auto err = globalObject().property("SyntaxError").construct(ScriptValueList({ newValue(syntaxCheck->errorMessage()) }));
err.setProperty("fileName", program->fileName());
err.setProperty("lineNumber", syntaxCheck->errorLineNumber());
err.setProperty("expressionBeginOffset", syntaxCheck->errorColumnNumber());
err.setProperty("stack", syntaxCheck->errorBacktrace());
//err.setProperty("stack", currentContext()->backtrace().join(ScriptManager::SCRIPT_BACKTRACE_SEP));
{
const auto error = syntaxCheck->errorMessage();
const auto line = QString::number(syntaxCheck->errorLineNumber());
@ -150,32 +148,6 @@ ScriptValue ScriptEngineV8::checkScriptSyntax(ScriptProgramPointer program) {
}
return undefinedValue();
}
/*ScriptValue ScriptEngineV8::lintScript(const QString& sourceCode, const QString& fileName, const int lineNumber) {
if (!IS_THREADSAFE_INVOCATION(thread(), __FUNCTION__)) {
return nullValue();
}
//V8TODO
const auto syntaxCheck = checkSyntax(sourceCode);
if (syntaxCheck.state() != QScriptSyntaxCheckResult::Valid) {
auto err = QScriptEngine::globalObject().property("SyntaxError").construct(V8ScriptValueList({ syntaxCheck.errorMessage() }));
err.setProperty("fileName", fileName);
err.setProperty("lineNumber", syntaxCheck.errorLineNumber());
err.setProperty("expressionBeginOffset", syntaxCheck.errorColumnNumber());
err.setProperty("stack", currentContext()->backtrace().join(ScriptManager::SCRIPT_BACKTRACE_SEP));
{
const auto error = syntaxCheck.errorMessage();
const auto line = QString::number(syntaxCheck.errorLineNumber());
const auto column = QString::number(syntaxCheck.errorColumnNumber());
// for compatibility with legacy reporting
const auto message = QString("[SyntaxError] %1 in %2:%3(%4)").arg(error, fileName, line, column);
err.setProperty("formatted", message);
}
return ScriptValue(new ScriptValueV8Wrapper(this, std::move(err)));
}
return undefinedValue();
}*/
// Lambda
/*ScriptValue ScriptEngineV8::newLambdaFunction(std::function<V8ScriptValue(V8ScriptContext*, ScriptEngineV8*)> operation,
@ -264,8 +236,7 @@ v8::Platform* ScriptEngineV8::getV8Platform() {
}
ScriptEngineV8::ScriptEngineV8(ScriptManager *manager) : ScriptEngine(manager), _evaluatingCounter(0)
//V8TODO
//_arrayBufferClass(new ArrayBufferClass(this))
//V8TODO _arrayBufferClass(new ArrayBufferClass(this))
{
_v8InitMutex.lock();
std::call_once ( _v8InitOnceFlag, [ ]{
@ -289,7 +260,6 @@ ScriptEngineV8::ScriptEngineV8(ScriptManager *manager) : ScriptEngine(manager),
#else
v8::V8::SetFlagsFromString("--stack-size=256");
#endif
//v8::V8::SetFlagsFromString("--stack-size=256 --single-threaded");
v8::Platform* platform = getV8Platform();
v8::V8::InitializePlatform(platform);
v8::V8::Initialize(); qCDebug(scriptengine_v8) << "V8 platform initialized";
@ -317,18 +287,10 @@ ScriptEngineV8::ScriptEngineV8(ScriptManager *manager) : ScriptEngine(manager),
registerSystemTypes();
// V8TODO: dispose of isolate on ScriptEngineV8 destruction
//v8::UniquePersistent<v8::Value> null = v8::UniquePersistent<v8::Value>(_v8Isolate, v8::Null(_v8Isolate));
//_nullValue = ScriptValue(new ScriptValueV8Wrapper(this, std::move(null)));
//V8ScriptValue undefined = v8::UniquePersistent<v8::Value>(_v8Isolate,v8::Undefined(_v8Isolate));
//_undefinedValue = ScriptValue(new ScriptValueV8Wrapper(this, std::move(undefined)));
// V8TODO:
//QScriptEngine::setProcessEventsInterval(MSECS_PER_SECOND);
}
//_currentThread = QThread::currentThread();
//if (_scriptManager) {
// V8TODO: port to V8
/*connect(this, &QScriptEngine::signalHandlerException, this, [this](const V8ScriptValue& exception) {
@ -342,8 +304,6 @@ ScriptEngineV8::ScriptEngineV8(ScriptManager *manager) : ScriptEngine(manager),
emit _scriptManager->unhandledException(ScriptValue(new ScriptValueV8Wrapper(this, std::move(thrown))));
}
}, Qt::DirectConnection);*/
//moveToThread(scriptManager->thread());
//setThread(scriptManager->thread());
//}
}
@ -396,16 +356,11 @@ void ScriptEngineV8::registerValue(const QString& valueName, V8ScriptValue value
}
if (createProperty) {
if (partsToGo > 0) {
//This was commented out
//QObject *object = new QObject;
v8::Local<v8::Object> partValue = v8::Object::New(_v8Isolate); //newQObject(object, QScriptEngine::ScriptOwnership);
//V8ScriptValue partValue = QScriptEngine::newArray(); //newQObject(object, QScriptEngine::ScriptOwnership);
v8::Local<v8::Object> partValue = v8::Object::New(_v8Isolate);
if (!partObject->Set(context, pathPartV8, partValue).FromMaybe(false)) {
Q_ASSERT(false);
}
} else {
//partObject = currentPath->ToObject();
//V8TODO: do these still happen if asserts are disabled?
if (!partObject->Set(context, pathPartV8, value.constGet()).FromMaybe(false)) {
Q_ASSERT(false);
}
@ -440,14 +395,6 @@ void ScriptEngineV8::registerGlobalObject(const QString& name, QObject* object)
#ifdef THREAD_DEBUGGING
qCDebug(scriptengine_v8) << "ScriptEngineV8::registerGlobalObject() called on thread [" << QThread::currentThread() << "] name:" << name;
#endif
/*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;
}*/
//{
v8::Locker locker(_v8Isolate);
v8::Isolate::Scope isolateScope(_v8Isolate);
v8::HandleScope handleScope(_v8Isolate);
@ -457,7 +404,6 @@ void ScriptEngineV8::registerGlobalObject(const QString& name, QObject* object)
v8::Local<v8::Object> v8GlobalObject = getContext()->Global();
v8::Local<v8::String> v8Name = v8::String::NewFromUtf8(_v8Isolate, name.toStdString().c_str()).ToLocalChecked();
// V8TODO: Is IsEmpty check enough or IsValid is needed too?
if (!v8GlobalObject->Get(getContext(), v8Name).IsEmpty()) {
if (object) {
V8ScriptValue value = ScriptObjectV8Proxy::newQObject(this, object, ScriptEngine::QtOwnership);
@ -470,16 +416,9 @@ void ScriptEngineV8::registerGlobalObject(const QString& name, QObject* object)
}
}
}
//}
/*if (is_isolate_exit_needed) {
_v8Isolate->Exit();
_v8Locker.reset(nullptr);
}*/
}
void ScriptEngineV8::registerFunction(const QString& name, ScriptEngine::FunctionSignature functionSignature, int numArguments) {
//if (QThread::currentThread() != ) {
//}
if (QThread::currentThread() != thread()) {
#ifdef THREAD_DEBUGGING
qCDebug(scriptengine_v8) << "*** WARNING *** ScriptEngineV8::registerFunction() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] name:" << name;
@ -494,28 +433,13 @@ void ScriptEngineV8::registerFunction(const QString& name, ScriptEngine::Functio
qCDebug(scriptengine_v8) << "ScriptEngineV8::registerFunction() called on thread [" << QThread::currentThread() << "] name:" << name;
#endif
/*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;
}
{*/
//auto scriptFun = static_cast<ScriptValueV8Wrapper*>(newFunction(functionSignature, numArguments).ptr())->toV8Value().constGet();
v8::Locker locker(_v8Isolate);
v8::Isolate::Scope isolateScope(_v8Isolate);
v8::HandleScope handleScope(_v8Isolate);
v8::Context::Scope contextScope(getContext());
auto scriptFun = newFunction(functionSignature, numArguments);
//getContext()->Global().Set();
globalObject().setProperty(name, scriptFun);
/*}
if (is_isolate_exit_needed) {
_v8Isolate->Exit();
_v8Locker.reset(nullptr);
}*/
}
void ScriptEngineV8::registerFunction(const QString& parent, const QString& name, ScriptEngine::FunctionSignature functionSignature, int numArguments) {
@ -533,14 +457,6 @@ void ScriptEngineV8::registerFunction(const QString& parent, const QString& name
qCDebug(scriptengine_v8) << "ScriptEngineV8::registerFunction() called on thread [" << QThread::currentThread() << "] parent:" << parent << "name:" << name;
#endif
/*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;
}
{*/
v8::Locker locker(_v8Isolate);
v8::Isolate::Scope isolateScope(_v8Isolate);
v8::HandleScope handleScope(_v8Isolate);
@ -550,11 +466,6 @@ void ScriptEngineV8::registerFunction(const QString& parent, const QString& name
ScriptValue scriptFun = newFunction(functionSignature, numArguments);
object.setProperty(name, scriptFun);
}
/*}
if (is_isolate_exit_needed) {
_v8Isolate->Exit();
_v8Locker.reset(nullptr);
}*/
}
void ScriptEngineV8::registerGetterSetter(const QString& name, ScriptEngine::FunctionSignature getter,
@ -575,60 +486,17 @@ void ScriptEngineV8::registerGetterSetter(const QString& name, ScriptEngine::Fun
qCDebug(scriptengine_v8) << "ScriptEngineV8::registerGetterSetter() called on thread [" << QThread::currentThread() << "] name:" << name << "parent:" << parent;
#endif
/*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;
}
{*/
v8::Locker locker(_v8Isolate);
v8::Isolate::Scope isolateScope(_v8Isolate);
v8::HandleScope handleScope(_v8Isolate);
v8::Context::Scope contextScope(getContext());
/*auto getterFunction = [](v8::Local<v8::String> property, const v8::PropertyCallbackInfo<v8::Value>& info) {
//V8TODO: is using GetCurrentContext ok, or context wrapper needs to be added?
v8::HandleScope handleScope(info.GetIsolate());
auto context = info.GetIsolate()->GetCurrentContext();
v8::Context::Scope contextScope(context);
auto object = v8::Local<v8::Object>::Cast(info.Data());
Q_ASSERT(object->InternalFieldCount() == 2);
auto function = reinterpret_cast<ScriptEngine::FunctionSignature>
(object->GetAlignedPointerFromInternalField(0));
ScriptEngineV8 *scriptEngine = reinterpret_cast<ScriptEngineV8*>
(object->GetAlignedPointerFromInternalField(1));
ScriptContextV8Wrapper scriptContext(scriptEngine, &info);
//V8TODO: this scriptContext needs to have FunctionCallbackInfo added
ScriptValue result = function(&scriptContext, scriptEngine);
ScriptValueV8Wrapper* unwrapped = ScriptValueV8Wrapper::unwrap(result);
info.GetReturnValue().Set(unwrapped->toV8Value().constGet());
};
auto setterFunction = [](v8::Local<v8::String> property, const v8::PropertyCallbackInfo<v8::Value>& info) {
//V8TODO: is using GetCurrentContext ok, or context wrapper needs to be added?
v8::HandleScope handleScope(info.GetIsolate());
auto context = info.GetIsolate()->GetCurrentContext();
v8::Context::Scope contextScope(context);
auto object = v8::Local<v8::Object>::Cast(info.Data());
Q_ASSERT(object->InternalFieldCount() == 2);
auto function = reinterpret_cast<ScriptEngine::FunctionSignature>
(object->GetAlignedPointerFromInternalField(0));
ScriptEngineV8 *scriptEngine = reinterpret_cast<ScriptEngineV8*>
(object->GetAlignedPointerFromInternalField(1));
ScriptContextV8Wrapper scriptContext(scriptEngine, &info);
//V8TODO: this scriptContext needs to have FunctionCallbackInfo added
ScriptValue result = function(&scriptContext, scriptEngine);
ScriptValueV8Wrapper* unwrapped = ScriptValueV8Wrapper::unwrap(result);
};*/
ScriptValue setterFunction = newFunction(setter, 1);
ScriptValue getterFunction = newFunction(getter);
V8ScriptValue unwrappedGetter = ScriptValueV8Wrapper::fullUnwrap(this, getterFunction);
V8ScriptValue unwrappedSetter = ScriptValueV8Wrapper::fullUnwrap(this, setterFunction);
v8::PropertyDescriptor propertyDescriptor(unwrappedGetter.get(), unwrappedSetter.get());
//V8TODO: Getters/setters are probably done in a different way in V8. Maybe object template is needed?
if (!parent.isNull() && !parent.isEmpty()) {
ScriptValue object = globalObject().property(parent);
if (object.isValid()) {
@ -649,8 +517,6 @@ void ScriptEngineV8::registerGetterSetter(const QString& name, ScriptEngine::Fun
qCDebug(scriptengine_v8) << "DefineProperty failed for registerGetterSetter \"" << name << "\" for parent: \""
<< parent << "\"";
}
//object.setProperty(name, setterFunction, ScriptValue::PropertySetter);
//object.setProperty(name, getterFunction, ScriptValue::PropertyGetter);
} else {
qCDebug(scriptengine_v8) << "Parent object \"" << parent << "\" for registerGetterSetter \"" << name
<< "\" is not valid: ";
@ -661,14 +527,7 @@ void ScriptEngineV8::registerGetterSetter(const QString& name, ScriptEngine::Fun
if (!getContext()->Global()->DefineProperty(getContext(), v8propertyName, propertyDescriptor).FromMaybe(false)) {
qCDebug(scriptengine_v8) << "DefineProperty failed for registerGetterSetter \"" << name << "\" for global object";
}
//globalObject().setProperty(name, setterFunction, ScriptValue::PropertySetter);
//globalObject().setProperty(name, getterFunction, ScriptValue::PropertyGetter);
}
/*}
if (is_isolate_exit_needed) {
_v8Isolate->Exit();
_v8Locker.reset(nullptr);
}*/
}
v8::Local<v8::Context> ScriptEngineV8::getContext() {
@ -721,11 +580,9 @@ ScriptValue ScriptEngineV8::evaluateInClosure(const ScriptValue& _closure,
storeGlobalObjectContents();
v8::Local<v8::Object> closureObject;
//v8::Local<v8::Value> oldGlobal;
v8::Local<v8::Value> closureGlobal;
ScriptValueV8Wrapper* unwrappedClosure;
ScriptProgramV8Wrapper* unwrappedProgram;
//v8::Local<v8::Context> oldContext = getContext();
{
v8::Context::Scope contextScope(getContext());
@ -736,7 +593,6 @@ ScriptValue ScriptEngineV8::evaluateInClosure(const ScriptValue& _closure,
Q_ASSERT(false);
return nullValue();
}
// V8TODO: is another context switch necessary after unwrapping closure?
const auto fileName = unwrappedProgram->fileName();
const auto shortName = QUrl(fileName).fileName();
@ -750,7 +606,6 @@ ScriptValue ScriptEngineV8::evaluateInClosure(const ScriptValue& _closure,
}
const V8ScriptValue& closure = unwrappedClosure->toV8Value();
//const V8ScriptProgram& program = unwrappedProgram->toV8Value();
if (!closure.constGet()->IsObject()) {
_evaluatingCounter--;
qCDebug(scriptengine_v8) << "Unwrapped closure is not an object";
@ -773,28 +628,13 @@ ScriptValue ScriptEngineV8::evaluateInClosure(const ScriptValue& _closure,
Q_ASSERT(false);
return nullValue();
}
//qCDebug(scriptengine_v8) << "Closure global details:" << scriptValueDebugDetailsV8(V8ScriptValue(_v8Isolate, closureGlobal));
}
//oldGlobal = _v8Context.Get(_v8Isolate)->Global();
v8::Local<v8::Context> closureContext;
// V8TODO V8 cannot use arbitrary objects as global objects
/*if (closureGlobal->IsObject()) {
#ifdef DEBUG_JS
qCDebug(shared) << " setting global = closure.global" << shortName;
#endif
closureContext = v8::Context::New(_v8Isolate, nullptr, v8::Local<v8::ObjectTemplate>(), closureGlobal);
closureContext = v8::Context::New(_v8Isolate, nullptr, v8::Local<v8::ObjectTemplate>(), closureGlobal);
//setGlobalObject(global);
} else {
closureContext = v8::Context::New(_v8Isolate);
}*/
closureContext = v8::Context::New(_v8Isolate);
pushContext(closureContext);
ScriptValue result;
//auto context = pushContext();
// V8TODO: a lot of functions rely on _v8Context, which was not updated here
// It might cause trouble
{
@ -809,27 +649,6 @@ ScriptValue ScriptEngineV8::evaluateInClosure(const ScriptValue& _closure,
const V8ScriptProgram& program = unwrappedProgram->toV8Value();
v8::Local<v8::Value> thiz;
// V8TODO: not sure if "this" is used at all here
/*if (!closureObject->Get(closure.constGetContext(), v8::String::NewFromUtf8(_v8Isolate, "this").ToLocalChecked())
.ToLocal(&thiz)) {
_evaluatingCounter--;
qCDebug(scriptengine_v8) << "Empty this object in closure";
Q_ASSERT(false);
return nullValue();
}*/
//thiz = closure.property("this");
//qCDebug(scriptengine_v8) << "Closure this details:" << scriptValueDebugDetailsV8(V8ScriptValue(_v8Isolate, thiz));
// V8TODO:
/*if (thiz->IsObject()) {
#ifdef DEBUG_JS
qCDebug(shared) << " setting this = closure.this" << shortName;
#endif
//V8TODO I don't know how to do this in V8, will adding "this" to global object work?
closureContext->Global()->Set(closureContext, v8::String::NewFromUtf8(_v8Isolate, "this").ToLocalChecked(), thiz);
//context->setThisObject(thiz);
}*/
//context->pushScope(closure);
#ifdef DEBUG_JS
qCDebug(shared) << QString("[%1] evaluateInClosure %2").arg(isEvaluating()).arg(shortName);
#endif
@ -846,51 +665,22 @@ ScriptValue ScriptEngineV8::evaluateInClosure(const ScriptValue& _closure,
}
qCDebug(scriptengine_v8) << "ScriptEngineV8::evaluateInClosure: " << globalMemberNames->Length() << " objects added to global";
/*auto oldGlobalMemberNames = oldContext->Global()->GetPropertyNames(oldContext).ToLocalChecked();
//auto oldGlobalMemberNames = oldContext->Global()->GetPropertyNames(closureContext).ToLocalChecked();
for (size_t i = 0; i < oldGlobalMemberNames->Length(); i++) {
auto name = oldGlobalMemberNames->Get(closureContext, i).ToLocalChecked();
//auto name = oldGlobalMemberNames->Get(oldContext, i).ToLocalChecked();
if(!closureContext->Global()->Set(closureContext, name, oldContext->Global()->Get(oldContext, name).ToLocalChecked()).FromMaybe(false)) {
//if(!closureContext->Global()->Set(closureContext, name, oldContext->Global()->Get(closureContext, name).ToLocalChecked()).FromMaybe(false)) {
Q_ASSERT(false);
}
}*/
// Objects from closure need to be copied to global object too
// V8TODO: I'm not sure which context to use with Get
auto closureMemberNames = closureObject->GetPropertyNames(closureContext).ToLocalChecked();
//auto closureMemberNames = closureObject->GetPropertyNames(oldContext).ToLocalChecked();
for (size_t i = 0; i < closureMemberNames->Length(); i++) {
auto name = closureMemberNames->Get(closureContext, i).ToLocalChecked();
//auto name = closureMemberNames->Get(oldContext, i).ToLocalChecked();
if(!closureContext->Global()->Set(closureContext, name, closureObject->Get(closureContext, name).ToLocalChecked()).FromMaybe(false)) {
//if(!closureContext->Global()->Set(closureContext, name, closureObject->Get(oldContext, name).ToLocalChecked()).FromMaybe(false)) {
Q_ASSERT(false);
}
}
// List members of closure global object
//QString membersString("");
/*if (closureContext->Global()->IsObject()) {
v8::Local<v8::String> membersStringV8;
v8::Local<v8::Object> object = v8::Local<v8::Object>::Cast(closureContext->Global());
auto names = object->GetPropertyNames(closureContext).ToLocalChecked();
if (v8::JSON::Stringify(closureContext, names).ToLocal(&membersStringV8)) {
membersString = QString(*v8::String::Utf8Value(_v8Isolate, membersStringV8));
}
membersString = QString(*v8::String::Utf8Value(_v8Isolate, membersStringV8));
} else {
membersString = QString(" Is not an object");
}*/
//qCDebug(scriptengine_v8) << "Closure global before run:" << membersString;
auto maybeResult = program.constGet()->GetUnboundScript()->BindToCurrentContext()->Run(closureContext);
//qCDebug(scriptengine_v8) << "Closure after run:" << scriptValueDebugDetailsV8(closure);
v8::Local<v8::Value> v8Result;
if (!maybeResult.ToLocal(&v8Result)) {
v8::String::Utf8Value utf8Value(getIsolate(), tryCatch.Exception());
QString errorMessage = QString(*utf8Value);
qCWarning(scriptengine_v8) << __FUNCTION__ << "---------- hasCaught:" << errorMessage;
qCWarning(scriptengine_v8) << __FUNCTION__ << "---------- tryCatch details:" << formatErrorMessageFromTryCatch(tryCatch);
//V8TODO: better error reporting
}
if (hasUncaughtException()) {
@ -908,20 +698,12 @@ ScriptValue ScriptEngineV8::evaluateInClosure(const ScriptValue& _closure,
#endif
popContext();
}
//This is probably unnecessary in V8
/*if (oldGlobal.isValid()) {
#ifdef DEBUG_JS
qCDebug(shared) << " restoring global" << shortName;
#endif
setGlobalObject(oldGlobal);
}*/
_evaluatingCounter--;
return result;
}
ScriptValue ScriptEngineV8::evaluate(const QString& sourceCode, const QString& fileName) {
//V8TODO
if (QThread::currentThread() != thread()) {
ScriptValue result;
@ -936,7 +718,6 @@ ScriptValue ScriptEngineV8::evaluate(const QString& sourceCode, const QString& f
return result;
}
// Compile and check syntax
// V8TODO: Could these all be replaced with checkSyntax function from wrapper?
Q_ASSERT(!_v8Isolate->IsDead());
_evaluatingCounter++;
v8::Locker locker(_v8Isolate);
@ -953,26 +734,6 @@ ScriptValue ScriptEngineV8::evaluate(const QString& sourceCode, const QString& f
return nullValue();
}
}
//qCDebug(scriptengine_v8) << "Script compilation succesful: " << fileName;
//V8TODO
/*auto syntaxError = lintScript(sourceCode, fileName);
if (syntaxError.isError()) {
if (!isEvaluating()) {
syntaxError.setProperty("detail", "evaluate");
}
raiseException(syntaxError);
maybeEmitUncaughtException("lint");
return syntaxError;
}*/
//V8TODO
/*if (script->IsNull()) {
// can this happen?
auto err = makeError(newValue("could not create V8ScriptProgram for " + fileName));
raiseException(err);
maybeEmitUncaughtException("compile");
return err;
}*/
v8::Local<v8::Value> result;
v8::TryCatch tryCatchRun(getIsolate());
@ -981,11 +742,6 @@ ScriptValue ScriptEngineV8::evaluate(const QString& sourceCode, const QString& f
auto runError = tryCatchRun.Message();
ScriptValue errorValue(new ScriptValueV8Wrapper(this, V8ScriptValue(this, runError->Get())));
qCDebug(scriptengine_v8) << "Running script: \"" << fileName << "\" " << formatErrorMessageFromTryCatch(tryCatchRun);
//V8TODO
//raiseException(errorValue);
//maybeEmitUncaughtException("evaluate");
setUncaughtException(tryCatchRun, "script evaluation");
_evaluatingCounter--;
@ -1020,7 +776,6 @@ void ScriptEngineV8::setUncaughtException(const v8::TryCatch &tryCatch, const QS
QString errorMessage = "";
QString errorBacktrace = "";
//v8::String::Utf8Value utf8Value(getIsolate(), tryCatch.Exception());
v8::String::Utf8Value utf8Value(getIsolate(), tryCatch.Message()->Get());
ex->errorMessage = QString(*utf8Value);
@ -1068,7 +823,6 @@ QString ScriptEngineV8::formatErrorMessageFromTryCatch(v8::TryCatch &tryCatch) {
int errorLineNumber = 0;
QString errorMessage = "";
QString errorBacktrace = "";
//v8::String::Utf8Value utf8Value(getIsolate(), tryCatch.Exception());
v8::String::Utf8Value utf8Value(getIsolate(), tryCatch.Message()->Get());
errorMessage = QString(*utf8Value);
v8::Local<v8::Message> exceptionMessage = tryCatch.Message();
@ -1181,13 +935,6 @@ Q_INVOKABLE ScriptValue ScriptEngineV8::evaluate(const ScriptProgramPointer& pro
return result;
}
_evaluatingCounter++;
/*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;
@ -1213,14 +960,6 @@ Q_INVOKABLE ScriptValue ScriptEngineV8::evaluate(const ScriptProgramPointer& pro
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);
maybeEmitUncaughtException("compile");
return err;
}*/
v8::TryCatch tryCatchRun(getIsolate());
if (!v8Program.constGet()->Run(getContext()).ToLocal(&result)) {
@ -1240,10 +979,6 @@ Q_INVOKABLE ScriptValue ScriptEngineV8::evaluate(const ScriptProgramPointer& pro
}
}
_evaluatingCounter--;
/*if (is_isolate_exit_needed) {
_v8Isolate->Exit();
_v8Locker.reset(nullptr);
}*/
if (hasFailed) {
return errorValue;
} else {
@ -1293,6 +1028,7 @@ ScriptValue ScriptEngineV8::newArrayBuffer(const QByteArray& message) {
std::shared_ptr<v8::BackingStore> backingStore(v8::ArrayBuffer::NewBackingStore(_v8Isolate, message.size()));
std::memcpy(backingStore.get()->Data(), message.constData(), message.size());
auto arrayBuffer = v8::ArrayBuffer::New(_v8Isolate, backingStore);
//V8TODO: this needs to be finished and tested
/*V8ScriptValue data = QScriptEngine::newVariant(QVariant::fromValue(message));
V8ScriptValue ctor = QScriptEngine::globalObject().property("ArrayBuffer");
auto array = qscriptvalue_cast<ArrayBufferClass*>(ctor.data());
@ -1304,13 +1040,6 @@ ScriptValue ScriptEngineV8::newArrayBuffer(const QByteArray& message) {
}
ScriptValue ScriptEngineV8::newObject() {
/*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 result;
{
v8::Locker locker(_v8Isolate);
@ -1320,10 +1049,6 @@ ScriptValue ScriptEngineV8::newObject() {
V8ScriptValue resultV8 = V8ScriptValue(this, v8::Object::New(_v8Isolate));
result = ScriptValue(new ScriptValueV8Wrapper(this, std::move(resultV8)));
}
/*if (is_isolate_exit_needed) {
_v8Isolate->Exit();
_v8Locker.reset(nullptr);
}*/
return result;
}
@ -1338,10 +1063,6 @@ ScriptValue ScriptEngineV8::newMethod(QObject* object, V8ScriptValue lifetime,
}
ScriptProgramPointer ScriptEngineV8::newProgram(const QString& sourceCode, const QString& fileName) {
//V8TODO: is it used between isolates?
//V8TODO: should it be compiled on creation?
//V8ScriptProgram result(sourceCode, fileName);
v8::Locker locker(_v8Isolate);
v8::Isolate::Scope isolateScope(_v8Isolate);
v8::HandleScope handleScope(_v8Isolate);
@ -1453,20 +1174,8 @@ void ScriptEngineV8::clearExceptions() {
}
ScriptContext* ScriptEngineV8::currentContext() const {
//V8TODO
/*V8ScriptContext* localCtx = QScriptEngine::currentContext();
if (!localCtx) {
return nullptr;
}
if (!_currContext || _currContext->toV8Value() != localCtx) {
_currContext = std::make_shared<ScriptContextV8Wrapper>(const_cast<ScriptEngineV8*>(this), localCtx);
}*/
//_currContext = std::make_shared<ScriptContextV8Wrapper>(const_cast<ScriptEngineV8*>(this), localCtx);
/*if (!_currContext) {
// I'm not sure how to do this without discarding const
_currContext = std::make_shared<ScriptContextV8Wrapper>(const_cast<ScriptEngineV8*>(this));
}*/
// V8TODO: add FunctionCallbackInfo or PropertyCallbackInfo when necessary
// Is it needed?
return _contexts.last().get();
}
@ -1482,16 +1191,6 @@ bool ScriptEngineV8::isEvaluating() const {
ScriptValue ScriptEngineV8::newFunction(ScriptEngine::FunctionSignature fun, int length) {
//V8TODO is callee() used for anything?
/*auto innerFunc = [](V8ScriptContext* _context, QScriptEngine* _engine) -> V8ScriptValue {
auto callee = _context->callee();
QVariant funAddr = callee.property("_func").toVariant();
ScriptEngine::FunctionSignature fun = reinterpret_cast<ScriptEngine::FunctionSignature>(funAddr.toULongLong());
ScriptEngineV8* engine = static_cast<ScriptEngineV8*>(_engine);
ScriptContextV8Wrapper context(engine, _context);
ScriptValue result = fun(&context, engine);
ScriptValueV8Wrapper* unwrapped = ScriptValueV8Wrapper::unwrap(result);
return unwrapped ? unwrapped->toV8Value() : V8ScriptValue();
};*/
v8::Locker locker(_v8Isolate);
v8::Isolate::Scope isolateScope(_v8Isolate);
@ -1518,23 +1217,12 @@ ScriptValue ScriptEngineV8::newFunction(ScriptEngine::FunctionSignature fun, int
info.GetReturnValue().Set(unwrapped->toV8Value().constGet());
}
};
//auto functionTemplate = v8::FunctionTemplate::New(_v8Isolate, v8FunctionCallback, v8::Local<v8::Value>(), v8::Local<v8::Signature>(), length);
//auto functionData = v8::Object::New(_v8Isolate);
//functionData->setIn
auto functionDataTemplate = getFunctionDataTemplate();
//auto functionDataTemplate = v8::ObjectTemplate::New(_v8Isolate);
//functionDataTemplate->SetInternalFieldCount(2);
auto functionData = functionDataTemplate->NewInstance(getContext()).ToLocalChecked();
functionData->SetAlignedPointerInInternalField(0, reinterpret_cast<void*>(fun));
functionData->SetAlignedPointerInInternalField(1, reinterpret_cast<void*>(this));
//functionData->SetInternalField(3, v8::Null(_v8Isolate));
auto v8Function = v8::Function::New(getContext(), v8FunctionCallback, functionData, length).ToLocalChecked();
//auto functionObjectTemplate = functionTemplate->InstanceTemplate();
//auto function =
V8ScriptValue result(this, v8Function); // = QScriptEngine::newFunction(innerFunc, length);
//auto funAddr = QScriptEngine::newVariant(QVariant(reinterpret_cast<qulonglong>(fun)));
// V8TODO
//result.setProperty("_func", funAddr, V8ScriptValue::PropertyFlags(V8ScriptValue::ReadOnly + V8ScriptValue::Undeletable + V8ScriptValue::SkipInEnumeration));
V8ScriptValue result(this, v8Function);
return ScriptValue(new ScriptValueV8Wrapper(this, std::move(result)));
}
@ -1543,7 +1231,6 @@ void ScriptEngineV8::setObjectName(const QString& name) {
QObject::setObjectName(name);
}
//V8TODO
bool ScriptEngineV8::setProperty(const char* name, const QVariant& value) {
v8::Locker locker(_v8Isolate);
v8::Isolate::Scope isolateScope(_v8Isolate);
@ -1570,24 +1257,10 @@ void ScriptEngineV8::setThread(QThread* thread) {
qCDebug(scriptengine_v8) << "Script engine " << objectName() << " exited isolate";
}
Q_ASSERT(QObject::thread() == QThread::currentThread());
/*if (_v8Locker) {
_v8Locker.reset();
}*/
moveToThread(thread);
qCDebug(scriptengine_v8) << "Moved script engine " << objectName() << " to different thread";
}
/*void ScriptEngineV8::enterIsolateOnThisThread() {
Q_ASSERT(thread() == QThread::currentThread());
Q_ASSERT(!_v8Locker);
_v8Locker.reset(new v8::Locker(_v8Isolate));
if (!_v8Isolate->IsCurrent()) {
_v8Isolate->Enter();
qCDebug(scriptengine_v8) << "Script engine " << objectName() << " entered isolate on a new thread";
}
}*/
std::shared_ptr<ScriptException> ScriptEngineV8::uncaughtException() const {
if (_uncaughtException) {
return _uncaughtException->clone();
@ -1601,8 +1274,7 @@ bool ScriptEngineV8::raiseException(const QString& error, const QString &reason)
}
bool ScriptEngineV8::raiseException(const ScriptValue& exception, const QString &reason) {
//V8TODO
//Q_ASSERT(false);
//V8TODO Im not sure how to finish these
// qCCritical(scriptengine_v8) << "Script exception occurred: " << exception.toString();
// ScriptValueV8Wrapper* unwrapped = ScriptValueV8Wrapper::unwrap(exception);
// V8ScriptValue qException = unwrapped ? unwrapped->toV8Value() : QScriptEngine::newVariant(exception.toVariant());
@ -1626,7 +1298,6 @@ bool ScriptEngineV8::raiseException(const V8ScriptValue& exception) {
_v8Isolate->ThrowException(exception.constGet());
/*if (QScriptEngine::currentContext()) {
// we have an active context / JS stack frame so throw the exception per usual
QScriptEngine::currentContext()->throwValue(makeError(exception));
@ -1741,15 +1412,6 @@ QString ScriptEngineV8::scriptValueDebugDetailsV8(const V8ScriptValue &v8Value)
return parentValueQString + QString(" JSON: ") + JSONQString;
}
/*QStringList ScriptEngineV8::getCurrentStackTrace() {
v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(_v8Isolate, 100);
QStringList backtrace;
for (int n = 0; n < stackTrace->GetFrameCount(); n++) {
v8::Local<v8::StackFrame> stackFrame = stackTrace->GetFrame(_v8Isolate, n);
}
}*/
void ScriptEngineV8::logBacktrace(const QString &title) {
QStringList backtrace = currentContext()->backtrace();
qCDebug(scriptengine_v8) << title;

View file

@ -78,14 +78,12 @@ public: // ScriptEngine implementation
virtual ScriptValue globalObject() override;
virtual bool hasUncaughtException() const override;
virtual bool isEvaluating() const override;
//virtual ScriptValue lintScript(const QString& sourceCode, const QString& fileName, const int lineNumber = 1) override;
virtual ScriptValue checkScriptSyntax(ScriptProgramPointer program) override;
virtual ScriptValue newArray(uint length = 0) override;
virtual ScriptValue newArrayBuffer(const QByteArray& message) override;
virtual ScriptValue newFunction(ScriptEngine::FunctionSignature fun, int length = 0) override;
virtual ScriptValue newObject() override;
//virtual ScriptValue newObject( v8::Local<v8::ObjectTemplate> );
virtual ScriptValue newMethod(QObject* object, V8ScriptValue lifetime,
const QList<QMetaMethod>& metas, int numMaxParams);
virtual ScriptProgramPointer newProgram(const QString& sourceCode, const QString& fileName) override;
@ -124,7 +122,6 @@ public: // ScriptEngine implementation
virtual void setProcessEventsInterval(int interval) override;
virtual QThread* thread() const override;
virtual void setThread(QThread* thread) override;
//Q_INVOKABLE virtual void enterIsolateOnThisThread() override;
virtual ScriptValue undefinedValue() override;
virtual std::shared_ptr<ScriptException> uncaughtException() const override;
virtual void updateMemoryCost(const qint64& deltaSize) override;
@ -153,18 +150,6 @@ protected: // brought over from BaseScriptEngine
static bool IS_THREADSAFE_INVOCATION(const QThread* thread, const QString& method);
public: // public non-interface methods for other QtScript-specific classes to use
/*typedef V8ScriptValue (*FunctionSignature)(v8::Local<v8::Context>, ScriptEngineV8 *);
typedef V8ScriptValue (*FunctionWithArgSignature)(v8::Local<v8::Context>, ScriptEngineV8 *, void *);
/// registers a global getter/setter
Q_INVOKABLE void registerGetterSetter(const QString& name, FunctionSignature getter,
FunctionSignature setter, const QString& parent = QString(""));
/// register a global function
Q_INVOKABLE void registerFunction(const QString& name, FunctionSignature fun, int numArguments = -1);
/// register a function as a method on a previously registered global object
Q_INVOKABLE void registerFunction(const QString& parent, const QString& name, FunctionSignature fun,
int numArguments = -1);*/
/// registers a global object by name
Q_INVOKABLE void registerValue(const QString& valueName, V8ScriptValue value);
@ -193,15 +178,14 @@ public: // not for public use, but I don't like how Qt strings this along with p
const v8::Local<v8::Context> getConstContext() const;
QString formatErrorMessageFromTryCatch(v8::TryCatch &tryCatch);
// Useful for debugging
//QStringList getCurrentStackTrace();
virtual QStringList getCurrentScriptURLs() const override;
using ObjectWrapperMap = QMap<QObject*, QWeakPointer<ScriptObjectV8Proxy>>;
mutable QMutex _qobjectWrapperMapProtect;
ObjectWrapperMap _qobjectWrapperMap;
// Second map, from which wrappers are removed by script engine upon deletion
// V8TODO add a V8 callback that removes pointer from the map so that it gets deleted
QMap<QObject*, QSharedPointer<ScriptObjectV8Proxy>> _qobjectWrapperMapV8;
// V8TODO: maybe just a single map can be used instead to increase performance?
// Used by ScriptObjectV8Proxy to create JS objects referencing C++ ones
v8::Local<v8::ObjectTemplate> getObjectProxyTemplate();
@ -219,17 +203,9 @@ public: // not for public use, but I don't like how Qt strings this along with p
void decrementScriptValueCounter() { scriptValueCount--; };
void incrementScriptValueProxyCounter() { scriptValueProxyCount++; };
void decrementScriptValueProxyCounter() { scriptValueProxyCount--; };
//V8TODO: do the same for other proxy objects
#endif
protected:
// like `newFunction`, but allows mapping inline C++ lambdas with captures as callable V8ScriptValues
// even though the context/engine parameters are redundant in most cases, the function signature matches `newFunction`
// anyway so that newLambdaFunction can be used to rapidly prototype / test utility APIs and then if becoming
// permanent more easily promoted into regular static newFunction scenarios.
/*ScriptValue newLambdaFunction(std::function<V8ScriptValue(V8ScriptContext* context, ScriptEngineV8* engine)> operation,
const V8ScriptValue& data,
const ValueOwnership& ownership = AutoOwnership);*/
void registerSystemTypes();
@ -249,7 +225,6 @@ protected:
// V8TODO: clean up isolate when script engine is destroyed?
v8::Isolate* _v8Isolate;
//v8::UniquePersistent<v8::Context> _v8Context;
struct CustomMarshal {
ScriptEngine::MarshalFunction marshalFunc;
@ -263,7 +238,6 @@ protected:
CustomPrototypeMap _customPrototypes;
ScriptValue _nullValue;
ScriptValue _undefinedValue;
//mutable ScriptContextV8Pointer _currContext;
// Current context stack. Main context is first on the list and current one is last.
QList<ScriptContextV8Pointer> _contexts;
// V8TODO: release in destructor

View file

@ -53,15 +53,6 @@ void ScriptEngineV8::registerCustomType(int type,
Q_DECLARE_METATYPE(ScriptValue);
Q_DECLARE_METATYPE(QVariantMap);
/*static V8ScriptValue ScriptValueToV8ScriptValue(ScriptEngineV8* engine, const ScriptValue& src) {
return ScriptValueV8Wrapper::fullUnwrap(static_cast<ScriptEngineV8*>(engine), src);
}*/
/*static void ScriptValueFromV8ScriptValue(ScriptEngineV8* engine, const V8ScriptValue& src, ScriptValue& dest) {
//ScriptEngineV8* engine = static_cast<ScriptEngineV8*>(src.engine());
dest = ScriptValue(new ScriptValueV8Wrapper(engine, src));
}*/
static ScriptValue StringListToScriptValue(ScriptEngine* engine, const QStringList& src) {
int len = src.length();
ScriptValue dest = engine->newArray(len);
@ -189,9 +180,6 @@ static bool JsonArrayFromScriptValue(const ScriptValue& src, QJsonArray& dest) {
// QMetaType::QJsonArray
void ScriptEngineV8::registerSystemTypes() {
// V8TODO: why is this commented out?
//qScriptRegisterMetaType(this, ScriptValueToV8ScriptValue, ScriptValueFromV8ScriptValue);
scriptRegisterMetaType<QStringList, StringListToScriptValue, StringListFromScriptValue>(static_cast<ScriptEngine*>(this));
scriptRegisterMetaType<QVariantList, VariantListToScriptValue, VariantListFromScriptValue>(this);
scriptRegisterMetaType<QVariantMap, VariantMapToScriptValue, VariantMapFromScriptValue>(this);
@ -308,12 +296,6 @@ bool ScriptEngineV8::castValueToVariant(const V8ScriptValue& v8Val, QVariant& de
v8::Context::Scope contextScope(context);
const v8::Local<v8::Value> val = v8Val.constGet();
// Conversion debugging:
/*if (destTypeId == QMetaType::QVariant && val->IsBoolean()) {
//It's for placing breakpoint here
qCDebug(scriptengine_v8) << "Conversion Debug: " << scriptValueDebugDetailsV8(v8Val);
}*/
// if we're not particularly interested in a specific type, try to detect if we're dealing with a registered type
if (destTypeId == QMetaType::UnknownType) {
QObject* obj = ScriptObjectV8Proxy::unwrap(v8Val);
@ -346,10 +328,8 @@ bool ScriptEngineV8::castValueToVariant(const V8ScriptValue& v8Val, QVariant& de
_customTypeProtect.unlock();
}
if (demarshalFunc) {
//dest = QVariant(destTypeId, static_cast<void*>(NULL));
dest = QVariant();
ScriptValue wrappedVal(new ScriptValueV8Wrapper(this, v8Val));
//Q_ASSERT(dest.constData() != nullptr);
bool success = demarshalFunc(wrappedVal, dest);
if(!success) dest = QVariant();
return success;
@ -374,7 +354,6 @@ bool ScriptEngineV8::castValueToVariant(const V8ScriptValue& v8Val, QVariant& de
v8::String::Utf8Value string(_v8Isolate, val);
Q_ASSERT(*string != nullptr);
dest = QVariant::fromValue(QString(*string));
//dest = QVariant::fromValue(val->ToString(_v8Context.Get(_v8Isolate)).ToLocalChecked()->);
break;
}
if (val->IsNumber()) {
@ -406,12 +385,12 @@ bool ScriptEngineV8::castValueToVariant(const V8ScriptValue& v8Val, QVariant& de
break;
}
}
// V8TODO
errorMessage = QString() + "Conversion failure: " + QString(*v8::String::Utf8Value(_v8Isolate, val->ToDetailString(getConstContext()).ToLocalChecked()))
+ "to variant. Destination type: " + QMetaType::typeName(destTypeId) +" details: "+ scriptValueDebugDetailsV8(v8Val);
qCDebug(scriptengine_v8) << errorMessage;
//Q_ASSERT(false);
// V8TODO
//dest = val->ToVariant();
break;
case QMetaType::Bool:
@ -489,16 +468,13 @@ bool ScriptEngineV8::castValueToVariant(const V8ScriptValue& v8Val, QVariant& de
return true;
}
if (val->IsBoolean()) {
//V8TODO is it right isolate? What if value from different script engine is used here
dest = QVariant::fromValue(val->BooleanValue(_v8Isolate));
return true;
}
if (val->IsString()) {
//V8TODO is it right context? What if value from different script engine is used here
v8::String::Utf8Value string(_v8Isolate, val);
Q_ASSERT(*string != nullptr);
dest = QVariant::fromValue(QString(*string));
//dest = QVariant::fromValue(val->ToString(_v8Context.Get(_v8Isolate)).ToLocalChecked()->);
return true;
}
if (val->IsNumber()) {
@ -529,7 +505,6 @@ bool ScriptEngineV8::castValueToVariant(const V8ScriptValue& v8Val, QVariant& de
return true;
}
}
//V8TODO is v8::Array to QVariant conversion used anywhere?
errorMessage = QString() + "Conversion to variant failed: " + QString(*v8::String::Utf8Value(_v8Isolate, val->ToDetailString(getConstContext()).ToLocalChecked()))
+ " Destination type: " + QMetaType::typeName(destTypeId) + " Value details: " + scriptValueDebugDetailsV8(v8Val);
qCDebug(scriptengine_v8) << errorMessage;
@ -640,14 +615,12 @@ bool ScriptEngineV8::convertJSObjectToVariant(v8::Local<v8::Object> object, QVar
}
QString ScriptEngineV8::valueType(const V8ScriptValue& v8Val) {
// V8TODO I'm not sure why is there a TODO here
v8::Locker locker(_v8Isolate);
v8::Isolate::Scope isolateScope(_v8Isolate);
v8::HandleScope handleScope(_v8Isolate);
v8::Local<v8::Context> context = getContext();
v8::Context::Scope contextScope(context);
//v8::HandleScope handleScope(const_cast<v8::Isolate*>(v8Val.constGetIsolate()));
const v8::Local<v8::Value> val = v8Val.constGet();
if (val->IsUndefined()) {
@ -684,7 +657,6 @@ QString ScriptEngineV8::valueType(const V8ScriptValue& v8Val) {
return dest.typeName();
}
qCDebug(scriptengine_v8) << "Cast to variant failed";
// V8TODO: what to return here?
return "undefined";
}
@ -765,7 +737,7 @@ V8ScriptValue ScriptEngineV8::castVariantToValue(const QVariant& val) {
}
default:
// check to see if this is a pointer to a QObject-derived object
// V8TODO: WeakPointerToQObject and SharedPointerToQObject were causing trouble here because some values are handled by custom prototypes instead
// WeakPointerToQObject and SharedPointerToQObject were causing trouble here because some values are handled by custom prototypes instead
if (QMetaType::typeFlags(valTypeId) & (QMetaType::PointerToQObject | QMetaType::TrackingPointerToQObject)) {
QObject* obj = val.value<QObject*>();
if (obj == nullptr) return V8ScriptValue(this, v8::Null(_v8Isolate));

View file

@ -24,12 +24,7 @@
#include "ScriptValueV8Wrapper.h"
#include "ScriptEngineLoggingV8.h"
//V8TODO: is this needed for anything? It could cause trouble with multithreading if V8ScriptContext is v8::Persistent
//Q_DECLARE_METATYPE(V8ScriptContext*)
Q_DECLARE_METATYPE(ScriptValue)
//V8TODO: default constructor would be needed
//Q_DECLARE_METATYPE(V8ScriptValue)
Q_DECLARE_METATYPE(QSharedPointer<ScriptObjectV8Proxy>)
Q_DECLARE_METATYPE(QSharedPointer<ScriptVariantV8Proxy>)
@ -76,7 +71,6 @@ private: // storage
ScriptObjectV8Proxy::ScriptObjectV8Proxy(ScriptEngineV8* engine, QObject* object, bool ownsObject, const ScriptEngine::QObjectWrapOptions& options) :
_engine(engine), _wrapOptions(options), _ownsObject(ownsObject), _object(object) {
//_v8ObjectTemplate(engine->getIsolate(), v8::ObjectTemplate::New(engine->getIsolate())
Q_ASSERT(_engine != nullptr);
investigate();
}
@ -90,11 +84,9 @@ V8ScriptValue ScriptObjectV8Proxy::newQObject(ScriptEngineV8* engine, QObject* o
ScriptEngineV8::ObjectWrapperMap::const_iterator lookup = engine->_qobjectWrapperMap.find(object);
if (lookup != engine->_qobjectWrapperMap.end()) {
QSharedPointer<ScriptObjectV8Proxy> proxy = lookup.value().lock();
// V8TODO: is conversion to QVariant and back needed?
if (proxy) {
return V8ScriptValue(engine, proxy.get()->toV8Value());
}
//if (proxy) return engine->newObject(proxy.get(), engine->newVariant(QVariant::fromValue(proxy)));;
}
}
@ -125,12 +117,10 @@ V8ScriptValue ScriptObjectV8Proxy::newQObject(ScriptEngineV8* engine, QObject* o
ScriptEngineV8::ObjectWrapperMap::const_iterator lookup = engine->_qobjectWrapperMap.find(object);
if (lookup != engine->_qobjectWrapperMap.end()) {
QSharedPointer<ScriptObjectV8Proxy> proxy = lookup.value().lock();
//if (proxy) return qengine->newObject(proxy.get(), qengine->newVariant(QVariant::fromValue(proxy)));;
if (proxy) {
return V8ScriptValue(engine, proxy.get()->toV8Value());
}
}
// V8TODO add a V8 callback that removes pointer for the script engine owned ob from the map so that it gets deleted
// register the wrapper with the engine and make sure it cleans itself up
engine->_qobjectWrapperMap.insert(object, proxy);
engine->_qobjectWrapperMapV8.insert(object, proxy);
@ -146,13 +136,10 @@ V8ScriptValue ScriptObjectV8Proxy::newQObject(ScriptEngineV8* engine, QObject* o
if (lookupV8 != enginePtr->_qobjectWrapperMapV8.end()) {
enginePtr->_qobjectWrapperMapV8.erase(lookupV8);
}
//qDebug() << "ScriptObjectV8Proxy::newQObject object deleted, object count: " << enginePtr->_qobjectWrapperMapV8.size();
});
//qDebug() << "ScriptObjectV8Proxy::newQObject object count: " << engine->_qobjectWrapperMapV8.size();
}
return V8ScriptValue(engine, proxy.get()->toV8Value());
//return qengine->newObject(proxy.get(), qengine->newVariant(QVariant::fromValue(proxy)));
}
ScriptObjectV8Proxy* ScriptObjectV8Proxy::unwrapProxy(const V8ScriptValue& val) {
@ -162,20 +149,17 @@ ScriptObjectV8Proxy* ScriptObjectV8Proxy::unwrapProxy(const V8ScriptValue& val)
v8::HandleScope handleScope(isolate);
v8::Local<v8::Context> context = val.constGetContext();
v8::Context::Scope contextScope(context);
//V8TODO This shouldn't cause problems but I'm not sure if it's ok
//v8::HandleScope handleScope(const_cast<v8::Isolate*>(val.constGetIsolate()));
auto v8Value = val.constGet();
Q_ASSERT(!v8Value.IsEmpty());
if (v8Value->IsNullOrUndefined()) {
return nullptr;
}
if (!v8Value->IsObject()) {
//qCDebug(scriptengine_v8) << "Cannot unwrap proxy - value is not an object";
return nullptr;
}
v8::Local<v8::Object> v8Object = v8::Local<v8::Object>::Cast(v8Value);
if (v8Object->InternalFieldCount() != 3) {
//qCDebug(scriptengine_v8) << "Cannot unwrap proxy - wrong number of internal fields";
return nullptr;
}
if (v8Object->GetAlignedPointerFromInternalField(0) != internalPointsToQObjectProxy) {
@ -189,20 +173,16 @@ ScriptObjectV8Proxy* ScriptObjectV8Proxy::unwrapProxy(v8::Isolate* isolate, v8::
v8::Locker locker(isolate);
v8::Isolate::Scope isolateScope(isolate);
v8::HandleScope handleScope(isolate);
//V8TODO: shouldn't there be context scope here?
//v8::Local<v8::Context> context = val.constGetContext();
//v8::Context::Scope contextScope(context);
//V8TODO: should there be context scope here?
if (value->IsNullOrUndefined()) {
//qCDebug(scriptengine_v8) << "Cannot unwrap proxy - value is not an object";
return nullptr;
}
if (!value->IsObject()) {
//qCDebug(scriptengine_v8) << "Cannot unwrap proxy - value is not an object";
return nullptr;
}
v8::Local<v8::Object> v8Object = v8::Local<v8::Object>::Cast(value);
if (v8Object->InternalFieldCount() != 3) {
//qCDebug(scriptengine_v8) << "Cannot unwrap proxy - wrong number of internal fields";
return nullptr;
}
if (v8Object->GetAlignedPointerFromInternalField(0) != internalPointsToQObjectProxy) {
@ -257,13 +237,8 @@ void ScriptObjectV8Proxy::investigate() {
const QMetaObject* metaObject = qobject->metaObject();
//auto objectTemplate = _v8ObjectTemplate.Get(_engine->getIsolate());
auto objectTemplate = _engine->getObjectProxyTemplate();
/*auto objectTemplate = v8::ObjectTemplate::New(_engine->getIsolate());
objectTemplate->SetInternalFieldCount(3);
objectTemplate->SetHandler(v8::NamedPropertyHandlerConfiguration(v8Get, v8Set, nullptr, nullptr, v8GetPropertyNames));*/
//qCDebug(scriptengine_v8) << "Investigate: " << metaObject->className();
if (QString("ConsoleScriptingInterface") == metaObject->className()) {
printf("ConsoleScriptingInterface");
}
@ -274,7 +249,6 @@ void ScriptObjectV8Proxy::investigate() {
QMetaProperty prop = metaObject->property(idx);
if (!prop.isScriptable()) continue;
//qCDebug(scriptengine_v8) << "Investigate: " << metaObject->className() << " Property: " << prop.name();
// always exclude child objects (at least until we decide otherwise)
int metaTypeId = prop.userType();
if (metaTypeId != QMetaType::UnknownType) {
@ -284,7 +258,6 @@ void ScriptObjectV8Proxy::investigate() {
}
}
//auto v8Name = v8::String::NewFromUtf8(_engine->getIsolate(), prop.name()).ToLocalChecked();
PropertyDef& propDef = _props.insert(idx, PropertyDef(prop.name(), idx)).value();
_propNameMap.insert(prop.name(), &propDef);
propDef.flags = ScriptValue::Undeletable | ScriptValue::PropertyGetter | ScriptValue::PropertySetter |
@ -298,7 +271,6 @@ void ScriptObjectV8Proxy::investigate() {
QHash<QString, int> methodNames;
for (int idx = startIdx; idx < num; ++idx) {
QMetaMethod method = metaObject->method(idx);
//qCDebug(scriptengine_v8) << "Investigate: " << metaObject->className() << " Method: " << method.name();
// perhaps keep this comment? Calls (like AudioScriptingInterface::playSound) seem to expect non-public methods to be script-accessible
/* if (method.access() != QMetaMethod::Public) continue;*/
@ -333,9 +305,6 @@ void ScriptObjectV8Proxy::investigate() {
signalDef.name = szName;
signalDef.signal = method;
_signalNameMap.insert(szName, &signalDef);
//qCDebug(scriptengine_v8) << "Utf8Value 1: " << QString(*v8::String::Utf8Value(const_cast<v8::Isolate*>(_engine->getIsolate()), nameString));
//qCDebug(scriptengine_v8) << "Utf8Value 2: " << QString(*v8::String::Utf8Value(const_cast<v8::Isolate*>(_engine->getIsolate()), name.constGet()));
//qCDebug(scriptengine_v8) << "toQString: " << name.toQString();
methodNames.insert(szName, idx);
} else {
int originalMethodId = nameLookup.value();
@ -376,10 +345,6 @@ void ScriptObjectV8Proxy::investigate() {
}
v8::Local<v8::Object> v8Object = objectTemplate->NewInstance(_engine->getContext()).ToLocalChecked();
/*if (QString(metaObject->className()) == QString("TestQObject")) {
//qDebug() << "TestQObject investigate: _methods.size: " << _methods.size();
return;
}*/
v8Object->SetAlignedPointerInInternalField(0, const_cast<void*>(internalPointsToQObjectProxy));
v8Object->SetAlignedPointerInInternalField(1, reinterpret_cast<void*>(this));
@ -406,9 +371,6 @@ void ScriptObjectV8Proxy::investigate() {
}
void ScriptObjectV8Proxy::weakHandleCallback(const v8::WeakCallbackInfo<ScriptObjectV8Proxy>& info) {
//V8TODO: does the object need to be moved to script engine thread?
//V8TODO: why does this never get called?
//qDebug(scriptengine_v8) << "ScriptObjectV8Proxy::weakHandleCallback";
auto proxy = info.GetParameter();
proxy->_v8Object.Reset();
info.GetParameter()->_object->deleteLater();
@ -423,41 +385,24 @@ QString ScriptObjectV8Proxy::name() const {
return _object->metaObject()->className();
}
// V8TODO: check if it would be more optimal to use V8ScriptString& name or QString name
ScriptObjectV8Proxy::QueryFlags ScriptObjectV8Proxy::queryProperty(const V8ScriptValue& object, const V8ScriptString& name, QueryFlags flags, uint* id) {
auto isolate = _engine->getIsolate();
v8::Locker locker(isolate);
v8::Isolate::Scope isolateScope(isolate);
v8::HandleScope handleScope(isolate);
// V8TODO: this might be inefficient when there's large number of properties
v8::Local<v8::Context> context = _engine->getContext();
v8::Context::Scope contextScope(context);
QString nameStr(*v8::String::Utf8Value(isolate, name.constGet()));
// check for methods
/*for (MethodDefMap::const_iterator trans = _methods.cbegin(); trans != _methods.cend(); ++trans) {
v8::String::Utf8Value methodNameStr(isolate, trans.value().name.constGet());
//qCDebug(scriptengine_v8) << "queryProperty : " << *nameStr << " method: " << *methodNameStr;
if (!(trans.value().name == name)) continue;
*id = trans.key() | METHOD_TYPE;
return flags & (HandlesReadAccess | HandlesWriteAccess);
}*/
MethodNameMap::const_iterator method = _methodNameMap.find(nameStr);
if (method != _methodNameMap.cend()) {
//v8::String::Utf8Value methodNameStr(isolate, trans.value().name.constGet());
//qCDebug(scriptengine_v8) << "queryProperty : " << *nameStr << " method: " << *methodNameStr;
const MethodDef* methodDef = method.value();
*id = methodDef->_id | METHOD_TYPE;
return flags & (HandlesReadAccess | HandlesWriteAccess);
}
// check for properties
/*for (PropertyDefMap::const_iterator trans = _props.cbegin(); trans != _props.cend(); ++trans) {
const PropertyDef& propDef = trans.value();
if (!(propDef.name == name)) continue;
*id = trans.key() | PROPERTY_TYPE;
return flags & (HandlesReadAccess | HandlesWriteAccess);
}*/
PropertyNameMap::const_iterator prop = _propNameMap.find(nameStr);
if (prop != _propNameMap.cend()) {
const PropertyDef* propDef = prop.value();
@ -505,9 +450,7 @@ ScriptValue::PropertyFlags ScriptObjectV8Proxy::propertyFlags(const V8ScriptValu
void ScriptObjectV8Proxy::v8Get(v8::Local<v8::Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
v8::HandleScope handleScope(info.GetIsolate());
//V8TODO: should there be a context scope here?
v8::String::Utf8Value utf8Value(info.GetIsolate(), name);
//qCDebug(scriptengine_v8) << "Get: " << *utf8Value;
v8::Local<v8::Value> objectV8 = info.This();
ScriptObjectV8Proxy *proxy = ScriptObjectV8Proxy::unwrapProxy(info.GetIsolate(), objectV8);
if (!proxy) {
@ -521,17 +464,7 @@ void ScriptObjectV8Proxy::v8Get(v8::Local<v8::Name> name, const v8::PropertyCall
Q_ASSERT(false);
}
v8::Local<v8::String> v8NameString;
/*if (name->IsString()) {
v8NameString = v8::Local<v8::String>::Cast(name);
} else {
if (!name->ToString(info.GetIsolate()->GetCurrentContext()).ToLocal(&v8NameString)) {
Q_ASSERT(false);
}
}
if (name->IsSymbol()) {
qCDebug(scriptengine_v8) << "ScriptObjectV8Proxy::v8Set: symbol: " + nameString.toQString();
}*/
if (name->IsString()) {
V8ScriptString nameString(proxy->_engine, v8::Local<v8::String>::Cast(name));
uint id;
@ -553,9 +486,7 @@ void ScriptObjectV8Proxy::v8Get(v8::Local<v8::Name> name, const v8::PropertyCall
void ScriptObjectV8Proxy::v8Set(v8::Local<v8::Name> name, v8::Local<v8::Value> value, const v8::PropertyCallbackInfo<v8::Value>& info) {
v8::HandleScope handleScope(info.GetIsolate());
//V8TODO: should there be a context scope here?
v8::String::Utf8Value utf8Value(info.GetIsolate(), name);
//qCDebug(scriptengine_v8) << "Set: " << *utf8Value;
v8::Local<v8::Value> objectV8 = info.This();
ScriptObjectV8Proxy *proxy = ScriptObjectV8Proxy::unwrapProxy(info.GetIsolate(), objectV8);
if (!proxy) {
@ -568,18 +499,7 @@ void ScriptObjectV8Proxy::v8Set(v8::Local<v8::Name> name, v8::Local<v8::Value> v
qCDebug(scriptengine_v8) << notStringMessage;
Q_ASSERT(false);
}
/*v8::Local<v8::String> v8NameString;
if (name->IsString()) {
v8NameString = v8::Local<v8::String>::Cast(name);
} else {
if (!name->ToString(info.GetIsolate()->GetCurrentContext()).ToLocal(&v8NameString)) {
Q_ASSERT(false);
}
}
if (name->IsSymbol()) {
qCDebug(scriptengine_v8) << "ScriptObjectV8Proxy::v8Set: symbol: " + nameString.toQString();
}*/
//V8ScriptString nameString(info.GetIsolate(), name->ToString(proxy->_engine->getContext()).ToLocalChecked());
if (name->IsString()) {
V8ScriptString nameString(proxy->_engine, v8::Local<v8::String>::Cast(name));
uint id;
@ -590,7 +510,7 @@ void ScriptObjectV8Proxy::v8Set(v8::Local<v8::Name> name, v8::Local<v8::Value> v
return;
}
}
// V8TODO: Should it be v8::Object or v8::Local<v8::Object>?
if (info.This()->GetInternalField(2).As<v8::Object>()->Set(proxy->_engine->getContext(), name, value).FromMaybe(false)) {
info.GetReturnValue().Set(value);
} else {
@ -599,7 +519,6 @@ void ScriptObjectV8Proxy::v8Set(v8::Local<v8::Name> name, v8::Local<v8::Value> v
}
void ScriptObjectV8Proxy::v8GetPropertyNames(const v8::PropertyCallbackInfo<v8::Array>& info) {
//qCDebug(scriptengine_v8) << "ScriptObjectV8Proxy::v8GetPropertyNames called";
v8::HandleScope handleScope(info.GetIsolate());
auto context = info.GetIsolate()->GetCurrentContext();
v8::Context::Scope contextScope(context);
@ -610,7 +529,6 @@ void ScriptObjectV8Proxy::v8GetPropertyNames(const v8::PropertyCallbackInfo<v8::
return;
}
V8ScriptValue object(proxy->_engine, objectV8);
//uint id;
v8::Local<v8::Array> properties = proxy->getPropertyNames();
v8::Local<v8::Array> objectProperties;
uint32_t propertiesLength = properties->Length();
@ -695,7 +613,6 @@ V8ScriptValue ScriptObjectV8Proxy::property(const V8ScriptValue& object, const V
qCDebug(scriptengine_v8) << "Method with QMetaType::UnknownType " << metaObject->className() << " " << (*iter).name();
}
} //V8TODO: is new method created during every call? It needs to be cached instead
//bool isMethodDefined = false;
v8::Local<v8::Value> property;
if(_v8Object.Get(isolate)->GetInternalField(2).As<v8::Object>()->Get(_engine->getContext(), name.constGet()).ToLocal(&property)) {
if (!property->IsUndefined()) {
@ -725,7 +642,6 @@ V8ScriptValue ScriptObjectV8Proxy::property(const V8ScriptValue& object, const V
// It's not necessarily new, newQObject looks for it first in object wrapper map
// V8TODO: won't ScriptEngine::ScriptOwnership cause trouble here?
return ScriptObjectV8Proxy::newQObject(_engine, proxy, ScriptEngine::ScriptOwnership, options);
//return _engine->newQObject(proxy, ScriptEngine::ScriptOwnership, options);
}
}
return V8ScriptValue(_engine, v8::Null(isolate));
@ -777,8 +693,6 @@ ScriptVariantV8Proxy::ScriptVariantV8Proxy(ScriptEngineV8* engine, const QVarian
v8::HandleScope handleScope(isolate);
v8::Context::Scope contextScope(engine->getContext());
auto variantDataTemplate = _engine->getVariantDataTemplate();
//auto variantDataTemplate = v8::ObjectTemplate::New(isolate);
//variantDataTemplate->SetInternalFieldCount(2);
auto variantData = variantDataTemplate->NewInstance(engine->getContext()).ToLocalChecked();
variantData->SetAlignedPointerInInternalField(0, const_cast<void*>(internalPointsToQVariantInProxy));
// Internal field doesn't point directly to QVariant, because then alignment would need to be guaranteed in all compilers
@ -793,7 +707,6 @@ ScriptVariantV8Proxy::~ScriptVariantV8Proxy() {
v8::Isolate::Scope isolateScope(isolate);
v8::HandleScope handleScope(isolate);
// V8TODO: Add similar deletion handling as for object proxy
//_v8ObjectTemplate.Reset();
_v8Object.Reset();
}
@ -814,9 +727,6 @@ V8ScriptValue ScriptVariantV8Proxy::newVariant(ScriptEngineV8* engine, const QVa
auto proxy = new ScriptVariantV8Proxy(engine, variant, proto, protoProxy);
auto variantProxyTemplate = engine->getVariantProxyTemplate();
//auto variantProxyTemplate = v8::ObjectTemplate::New(isolate);
//variantProxyTemplate->SetInternalFieldCount(2);
//variantProxyTemplate->SetHandler(v8::NamedPropertyHandlerConfiguration(v8Get, v8Set, nullptr, nullptr, v8GetPropertyNames));
auto variantProxy = variantProxyTemplate->NewInstance(engine->getContext()).ToLocalChecked();
variantProxy->SetAlignedPointerInInternalField(0, const_cast<void*>(internalPointsToQVariantProxy));
variantProxy->SetAlignedPointerInInternalField(1, reinterpret_cast<void*>(proxy));
@ -905,13 +815,6 @@ void ScriptVariantV8Proxy::v8Get(v8::Local<v8::Name> name, const v8::PropertyCal
}
qCDebug(scriptengine_v8) << "Value not found: " << *utf8Name;
// V8TODO: this is done differently for variant proxy - use internal field of _v8Object instead?
/*v8::Local<v8::Value> property;
if(info.This()->GetInternalField(2).As<v8::Object>()->Get(proxy->_engine->getContext(), name).ToLocal(&property)) {
info.GetReturnValue().Set(property);
} else {
qCDebug(scriptengine_v8) << "Value not found: " << *utf8Value;
}*/
}
void ScriptVariantV8Proxy::v8Set(v8::Local<v8::Name> name, v8::Local<v8::Value> value, const v8::PropertyCallbackInfo<v8::Value>& info) {
@ -941,18 +844,11 @@ void ScriptVariantV8Proxy::v8Set(v8::Local<v8::Name> name, v8::Local<v8::Value>
return;
}
}
// V8TODO: this is done differently for variant proxy - use internal field of _v8Object instead?
/*if (info.This()->GetInternalField(2).As<v8::Object>()->Set(proxy->_engine->getContext(), name, value).FromMaybe(false)) {
info.GetReturnValue().Set(value);
} else {
qCDebug(scriptengine_v8) << "Set failed: " << *utf8Name;
}*/
qCDebug(scriptengine_v8) << "Set failed: " << *utf8Name;
}
void ScriptVariantV8Proxy::v8GetPropertyNames(const v8::PropertyCallbackInfo<v8::Array>& info) {
//V8TODO: Only methods from the prototype should be listed.
//qCDebug(scriptengine_v8) << "ScriptObjectV8Proxy::v8GetPropertyNames called";
v8::HandleScope handleScope(info.GetIsolate());
auto context = info.GetIsolate()->GetCurrentContext();
v8::Context::Scope contextScope(context);
@ -965,15 +861,6 @@ void ScriptVariantV8Proxy::v8GetPropertyNames(const v8::PropertyCallbackInfo<v8:
V8ScriptValue object(proxy->_engine, objectV8);
v8::Local<v8::Array> properties = proxy->_proto->getPropertyNames();
v8::Local<v8::Array> objectProperties;
// V8TODO: this is done differently for variant proxy - use internal field of _v8Object instead?
/*uint32_t propertiesLength = properties->Length();
if (info.This()->GetInternalField(2).As<v8::Object>()->GetPropertyNames(context).ToLocal(&objectProperties)) {
for (uint32_t n = 0; n < objectProperties->Length(); n++) {
if(!properties->Set(context, propertiesLength+n, objectProperties->Get(context, n).ToLocalChecked()).FromMaybe(false)) {
qCDebug(scriptengine_v8) << "ScriptObjectV8Proxy::v8GetPropertyNames: Cannot add member name";
}
}
}*/
info.GetReturnValue().Set(properties);
}
@ -996,7 +883,6 @@ ScriptMethodV8Proxy::ScriptMethodV8Proxy(ScriptEngineV8* engine, QObject* object
}
ScriptMethodV8Proxy::~ScriptMethodV8Proxy() {
//qCDebug(scriptengine_v8) << "ScriptMethodV8Proxy destroyed";
auto isolate = _engine->getIsolate();
v8::Locker locker(isolate);
v8::Isolate::Scope isolateScope(isolate);
@ -1005,7 +891,6 @@ ScriptMethodV8Proxy::~ScriptMethodV8Proxy() {
}
void ScriptMethodV8Proxy::weakHandleCallback(const v8::WeakCallbackInfo<ScriptMethodV8Proxy>& info) {
//qDebug(scriptengine_v8) << "ScriptMethodV8Proxy::weakHandleCallback";
auto proxy = info.GetParameter();
proxy->_objectLifetime.Reset();
info.GetParameter()->deleteLater();
@ -1019,12 +904,8 @@ V8ScriptValue ScriptMethodV8Proxy::newMethod(ScriptEngineV8* engine, QObject* ob
v8::HandleScope handleScope(isolate);
v8::Context::Scope contextScope(engine->getContext());
auto methodDataTemplate = engine->getMethodDataTemplate();
//auto methodDataTemplate = v8::ObjectTemplate::New(isolate);
//methodDataTemplate->SetInternalFieldCount(2);
auto methodData = methodDataTemplate->NewInstance(engine->getContext()).ToLocalChecked();
methodData->SetAlignedPointerInInternalField(0, const_cast<void*>(internalPointsToMethodProxy));
// V8TODO it needs to be deleted somehow on object destruction
// weak persistent callback would do this
methodData->SetAlignedPointerInInternalField(1, reinterpret_cast<void*>(new ScriptMethodV8Proxy(engine, object, lifetime, metas, numMaxParams)));
auto v8Function = v8::Function::New(engine->getContext(), callback, methodData, numMaxParams).ToLocalChecked();
return V8ScriptValue(engine, v8Function);
@ -1042,31 +923,16 @@ QString ScriptMethodV8Proxy::fullName() const {
return QString("%1::%2").arg(_object->metaObject()->className(), firstMethod.name());
}
// V8TODO
/*bool ScriptMethodV8Proxy::supportsExtension(Extension extension) const {
switch (extension) {
case Callable:
return true;
default:
return false;
}
}*/
void ScriptMethodV8Proxy::callback(const v8::FunctionCallbackInfo<v8::Value>& arguments) {
v8::Locker locker(arguments.GetIsolate());
v8::Isolate::Scope isolateScope(arguments.GetIsolate());
v8::HandleScope handleScope(arguments.GetIsolate());
//Q_ASSERT(!arguments.GetIsolate()->GetCurrentContext().IsEmpty());
v8::Context::Scope contextScope(arguments.GetIsolate()->GetCurrentContext());
if (!arguments.Data()->IsObject()) {
arguments.GetIsolate()->ThrowError("Method value is not an object");
return;
}
v8::Local<v8::Object> data = v8::Local<v8::Object>::Cast(arguments.Data());
/*if (!arguments.Data()->IsCallable()) {
arguments.GetIsolate()->ThrowError("Method value is not callable");
return;
}*/
if (data->InternalFieldCount() != 2) {
arguments.GetIsolate()->ThrowError("Incorrect number of internal fields during method call");
return;
@ -1092,8 +958,6 @@ void ScriptMethodV8Proxy::call(const v8::FunctionCallbackInfo<v8::Value>& argume
return;
}
//v8::HandleScope handleScope(_engine->getIsolate());
int scriptNumArgs = arguments.Length();
int numArgs = std::min(scriptNumArgs, _numMaxParams);
@ -1113,7 +977,6 @@ void ScriptMethodV8Proxy::call(const v8::FunctionCallbackInfo<v8::Value>& argume
int bestMeta = 0;
int bestConversionPenaltyScore = 0;
for (int i = 0; i < num_metas; i++) {
const QMetaMethod& meta = _metas[i];
int methodNumArgs = meta.parameterCount();
@ -1208,16 +1071,6 @@ void ScriptMethodV8Proxy::call(const v8::FunctionCallbackInfo<v8::Value>& argume
return;
} else if (returnTypeId == scriptValueTypeId) {
ScriptValue result;
/*if (_metas.front().name() == "createGarbageCollectorDebuggingObject") {
//qDebug() << "createGarbageCollectorDebuggingObject";
return;
}*/
/*const char* typeName = meta.typeName();
QVariant qRetVal(returnTypeId, static_cast<void*>(NULL));
QGenericReturnArgument sRetVal(typeName, const_cast<void*>(qRetVal.constData()));
bool success = meta.invoke(qobject, Qt::DirectConnection, sRetVal, qGenArgs[0],
qGenArgs[1], qGenArgs[2], qGenArgs[3], qGenArgs[4], qGenArgs[5], qGenArgs[6],
qGenArgs[7], qGenArgs[8], qGenArgs[9]);*/
bool success = meta.invoke(qobject, Qt::DirectConnection, Q_RETURN_ARG(ScriptValue, result), qGenArgs[0],
qGenArgs[1], qGenArgs[2], qGenArgs[3], qGenArgs[4], qGenArgs[5], qGenArgs[6],
qGenArgs[7], qGenArgs[8], qGenArgs[9]);
@ -1226,7 +1079,6 @@ void ScriptMethodV8Proxy::call(const v8::FunctionCallbackInfo<v8::Value>& argume
return;
}
V8ScriptValue v8Result = ScriptValueV8Wrapper::fullUnwrap(_engine, result);
//V8ScriptValue v8Result = _engine->castVariantToValue(qRetVal);
arguments.GetReturnValue().Set(v8Result.get());
return;
} else {
@ -1271,8 +1123,6 @@ void ScriptMethodV8Proxy::call(const v8::FunctionCallbackInfo<v8::Value>& argume
.arg(fullName()).arg(arg+1).arg(argTypeName, methodTypeName);
qCDebug(scriptengine_v8) << errorMessage << "\n Backtrace:" << _engine->currentContext()->backtrace();
isolate->ThrowError(v8::String::NewFromUtf8(isolate, errorMessage.toStdString().c_str()).ToLocalChecked());
//context->throwError(V8ScriptContext::TypeError, QString("Native call of %1 failed: Cannot convert parameter %2 from %3 to %4")
// .arg(fullName()).arg(arg+1).arg(argTypeName, methodTypeName));
return;
}
}
@ -1280,179 +1130,10 @@ void ScriptMethodV8Proxy::call(const v8::FunctionCallbackInfo<v8::Value>& argume
QString errorMessage = QString("Native call of %1 failed: could not locate an overload with the requested arguments").arg(fullName());
qCDebug(scriptengine_v8) << errorMessage;
isolate->ThrowError(v8::String::NewFromUtf8(isolate, errorMessage.toStdString().c_str()).ToLocalChecked());
// V8TODO: it happens sometimes for some reason
Q_ASSERT(false); // really shouldn't have gotten here -- it didn't work before and it's working now?
return;
}
//V8TODO: was this used anywhere?
/*QVariant ScriptMethodV8Proxy::extension(Extension extension, const QVariant& argument) {
if (extension != Callable) return QVariant();
V8ScriptContext* context = qvariant_cast<V8ScriptContext*>(argument);
QObject* qobject = _object;
if (!qobject) {
context->throwError(V8ScriptContext::ReferenceError, "Referencing deleted native object");
return QVariant();
}
int scriptNumArgs = context->argumentCount();
int numArgs = std::min(scriptNumArgs, _numMaxParams);
const int scriptValueTypeId = qMetaTypeId<ScriptValue>();
int parameterConversionFailureId = 0;
int parameterConversionFailureCount = 0;
int num_metas = _metas.size();
QVector< QList<ScriptValue> > qScriptArgLists;
QVector< QVector <QGenericArgument> > qGenArgsVectors;
QVector< QList<QVariant> > qVarArgLists;
qScriptArgLists.resize(num_metas);
qGenArgsVectors.resize(num_metas);
qVarArgLists.resize(num_metas);
bool isValidMetaSelected = false;
int bestMeta = 0;
int bestConversionPenaltyScore = 0;
for (int i = 0; i < num_metas; i++) {
const QMetaMethod& meta = _metas[i];
int methodNumArgs = meta.parameterCount();
if (methodNumArgs != numArgs) {
continue;
}
qGenArgsVectors[i].resize(10);
int conversionPenaltyScore = 0;
int conversionFailures = 0;
for (int arg = 0; arg < numArgs; ++arg) {
int methodArgTypeId = meta.parameterType(arg);
Q_ASSERT(methodArgTypeId != QMetaType::UnknownType);
V8ScriptValue argVal = context->argument(arg);
if (methodArgTypeId == scriptValueTypeId) {
qScriptArgLists[i].append(ScriptValue(new ScriptValueV8Wrapper(_engine, argVal)));
qGenArgsVectors[i][arg] = Q_ARG(ScriptValue, qScriptArgLists[i].back());
} else if (methodArgTypeId == QMetaType::QVariant) {
qVarArgLists[i].append(argVal.toVariant());
qGenArgsVectors[i][arg] = Q_ARG(QVariant, qVarArgLists[i].back());
} else {
QVariant varArgVal;
if (!_engine->castValueToVariant(argVal, varArgVal, methodArgTypeId)) {
conversionFailures++;
} else {
qVarArgLists[i].append(varArgVal);
const QVariant& converted = qVarArgLists[i].back();
conversionPenaltyScore = _engine->computeCastPenalty(argVal, methodArgTypeId);
// a lot of type conversion assistance thanks to https://stackoverflow.com/questions/28457819/qt-invoke-method-with-qvariant
// A const_cast is needed because calling data() would detach the QVariant.
qGenArgsVectors[i][arg] =
QGenericArgument(QMetaType::typeName(converted.userType()), const_cast<void*>(converted.constData()));
}
}
}
if (conversionFailures) {
if (conversionFailures < parameterConversionFailureCount || !parameterConversionFailureCount) {
parameterConversionFailureCount = conversionFailures;
parameterConversionFailureId = meta.methodIndex();
}
continue;
}
if (!isValidMetaSelected) {
isValidMetaSelected = true;
bestMeta = i;
bestConversionPenaltyScore = conversionPenaltyScore;
}
if (isValidMetaSelected && bestConversionPenaltyScore > conversionPenaltyScore) {
bestMeta = i;
bestConversionPenaltyScore = conversionPenaltyScore;
}
}
if (isValidMetaSelected) {
ScriptContextV8Wrapper ourContext(_engine, context);
ScriptContextGuard guard(&ourContext);
const QMetaMethod& meta = _metas[bestMeta];
int returnTypeId = meta.returnType();
QVector <QGenericArgument> &qGenArgs = qGenArgsVectors[bestMeta];
// The Qt MOC engine will automatically call qRegisterMetaType on invokable parameters and properties, but there's
// nothing in there for return values so these need to be explicitly runtime-registered!
Q_ASSERT(returnTypeId != QMetaType::UnknownType);
if (returnTypeId == QMetaType::UnknownType) {
_engine->getIsolate()->ThrowError(v8::String::NewFromUtf8(_engine->getIsolate(), QString("Cannot call native function %1, its return value has not been registered with Qt").arg(fullName()).toStdString().c_str()).ToLocalChecked());
return QVariant();
} else if (returnTypeId == QMetaType::Void) {
bool success = meta.invoke(qobject, Qt::DirectConnection, qGenArgs[0], qGenArgs[1], qGenArgs[2], qGenArgs[3],
qGenArgs[4], qGenArgs[5], qGenArgs[6], qGenArgs[7], qGenArgs[8], qGenArgs[9]);
if (!success) {
_engine->getIsolate()->ThrowError(v8::String::NewFromUtf8(_engine->getIsolate(), QString("Unexpected: Native call of %1 failed").arg(fullName()).toStdString().c_str()).ToLocalChecked());
}
return QVariant();
} else if (returnTypeId == scriptValueTypeId) {
ScriptValue result;
bool success = meta.invoke(qobject, Qt::DirectConnection, Q_RETURN_ARG(ScriptValue, result), qGenArgs[0],
qGenArgs[1], qGenArgs[2], qGenArgs[3], qGenArgs[4], qGenArgs[5], qGenArgs[6],
qGenArgs[7], qGenArgs[8], qGenArgs[9]);
if (!success) {
_engine->getIsolate()->ThrowError(v8::String::NewFromUtf8(_engine->getIsolate(), QString("Unexpected: Native call of %1 failed").arg(fullName()).toStdString().c_str()).ToLocalChecked());
return QVariant();
}
V8ScriptValue qResult = ScriptValueV8Wrapper::fullUnwrap(_engine, result);
return QVariant::fromValue(qResult);
} else {
// a lot of type conversion assistance thanks to https://stackoverflow.com/questions/28457819/qt-invoke-method-with-qvariant
const char* typeName = meta.typeName();
QVariant qRetVal(returnTypeId, static_cast<void*>(NULL));
QGenericReturnArgument sRetVal(typeName, const_cast<void*>(qRetVal.constData()));
bool success =
meta.invoke(qobject, Qt::DirectConnection, sRetVal, qGenArgs[0], qGenArgs[1], qGenArgs[2], qGenArgs[3],
qGenArgs[4], qGenArgs[5], qGenArgs[6], qGenArgs[7], qGenArgs[8], qGenArgs[9]);
if (!success) {
_engine->getIsolate()->ThrowError(v8::String::NewFromUtf8(_engine->getIsolate(), QString("Unexpected: Native call of %1 failed").arg(fullName()).toStdString().c_str()).ToLocalChecked());
return QVariant();
}
V8ScriptValue qResult = _engine->castVariantToValue(qRetVal);
return QVariant::fromValue(qResult);
}
}
// we failed to convert the call to C++, try to create a somewhat sane error message
if (parameterConversionFailureCount == 0) {
_engine->getIsolate()->ThrowError(v8::String::NewFromUtf8(_engine->getIsolate(), QString("Native call of %1 failed: unexpected parameter count").arg(fullName()).toStdString().c_str()).ToLocalChecked());
return QVariant();
}
const QMetaMethod& meta = _object->metaObject()->method(parameterConversionFailureId);
int methodNumArgs = meta.parameterCount();
Q_ASSERT(methodNumArgs == numArgs);
for (int arg = 0; arg < numArgs; ++arg) {
int methodArgTypeId = meta.parameterType(arg);
Q_ASSERT(methodArgTypeId != QMetaType::UnknownType);
V8ScriptValue argVal = context->argument(arg);
if (methodArgTypeId != scriptValueTypeId && methodArgTypeId != QMetaType::QVariant) {
QVariant varArgVal;
if (!_engine->castValueToVariant(argVal, varArgVal, methodArgTypeId)) {
QByteArray methodTypeName = QMetaType(methodArgTypeId).name();
QByteArray argTypeName = _engine->valueType(argVal).toLatin1();
_engine->getIsolate()->ThrowError(v8::String::NewFromUtf8(_engine->getIsolate(), QString("Native call of %1 failed: Cannot convert parameter %2 from %3 to %4")
.arg(fullName()).arg(arg+1).arg(argTypeName, methodTypeName).toStdString().c_str()).ToLocalChecked());
context->throwError(V8ScriptContext::TypeError, QString("Native call of %1 failed: Cannot convert parameter %2 from %3 to %4")
.arg(fullName()).arg(arg+1).arg(argTypeName, methodTypeName));
return QVariant();
}
}
}
context->throwError(QString("Native call of %1 failed: could not locate an overload with the requested arguments").arg(fullName()));
Q_ASSERT(false); // really shouldn't have gotten here -- it didn't work before and it's working now?
return QVariant();
}*/
ScriptSignalV8Proxy::ScriptSignalV8Proxy(ScriptEngineV8* engine, QObject* object, V8ScriptValue lifetime, const QMetaMethod& meta) :
_engine(engine), _object(object), _meta(meta), _metaCallId(discoverMetaCallIdx()) {
auto isolate = _engine->getIsolate();
@ -1475,7 +1156,6 @@ ScriptSignalV8Proxy::~ScriptSignalV8Proxy() {
}
void ScriptSignalV8Proxy::weakHandleCallback(const v8::WeakCallbackInfo<ScriptSignalV8Proxy>& info) {
//qDebug(scriptengine_v8) << "ScriptSignalV8Proxy::weakHandleCallback";
auto proxy = info.GetParameter();
proxy->_objectLifetime.Reset();
proxy->deleteLater();
@ -1512,17 +1192,6 @@ int ScriptSignalV8Proxy::qt_metacall(QMetaObject::Call call, int id, void** argu
v8::Locker locker(isolate);
v8::Isolate::Scope isolateScope(isolate);
//V8ScriptValueList args(isolate, v8::Null(isolate));
// Moved to inside of the lock - could it cause crashes if left here?
/*v8::Local<v8::Value> args[Q_METAMETHOD_INVOKE_MAX_ARGS];
int numArgs = _meta.parameterCount();
for (int arg = 0; arg < numArgs; ++arg) {
int methodArgTypeId = _meta.parameterType(arg);
Q_ASSERT(methodArgTypeId != QMetaType::UnknownType);
QVariant argValue(methodArgTypeId, arguments[arg+1]);
args[arg] = _engine->castVariantToValue(argValue).get();
}*/
QList<Connection> connections;
withReadLock([&]{
connections = _connections;
@ -1530,9 +1199,7 @@ int ScriptSignalV8Proxy::qt_metacall(QMetaObject::Call call, int id, void** argu
// V8TODO: this may cause deadlocks on connect/disconnect, so the connect/disconnect procedure needs to be reworked.
// It should probably add events to a separate list that would be processed before and after all the events for the signal.
//withReadLock([&]{
{
// V8TODO: check all other lambda functions to make sure they have handle scope - could they cause crashes otherwise?
v8::HandleScope handleScope(isolate);
// V8TODO: should we use function creation context, or context in which connect happened?
auto context = _engine->getContext();
@ -1545,23 +1212,9 @@ int ScriptSignalV8Proxy::qt_metacall(QMetaObject::Call call, int id, void** argu
QVariant argValue(methodArgTypeId, arguments[arg + 1]);
args[arg] = _engine->castVariantToValue(argValue).get();
}
//for (ConnectionList::iterator iter = _connections.begin(); iter != _connections.end(); ++iter) {
for (ConnectionList::iterator iter = connections.begin(); iter != connections.end(); ++iter) {
Connection& conn = *iter;
{
/*if (!conn.callback.get()->IsFunction()) {
auto stringV8 = conn.callback.get()->ToDetailString(context).ToLocalChecked();
QString error = *v8::String::Utf8Value(_engine->getIsolate(), stringV8);
qCDebug(scriptengine_v8) << error;
Q_ASSERT(false);
}
v8::Local<v8::Function> callback = v8::Local<v8::Function>::Cast(conn.callback.get());
auto functionContext = callback->CreationContext();
v8::Context::Scope functionContextScope(functionContext);
_engine->pushContext(functionContext);*/
/*auto functionContext = _v8Context.Get(_engine->getIsolate());
_engine->pushContext(functionContext);
v8::Context::Scope functionContextScope(functionContext);*/
auto functionContext = context;
Q_ASSERT(!conn.callback.get().IsEmpty());
@ -1595,11 +1248,9 @@ int ScriptSignalV8Proxy::qt_metacall(QMetaObject::Call call, int id, void** argu
_engine->setUncaughtException(tryCatch, "Error in signal proxy");
}
//_engine->popContext();
}
}
}
//});
#ifdef SCRIPT_EVENT_PERFORMANCE_STATISTICS
_totalCallTime_s += callTimer.elapsed() / 1000.0f;
@ -1630,10 +1281,6 @@ ScriptSignalV8Proxy::ConnectionList::iterator ScriptSignalV8Proxy::findConnectio
return iterOut;
}
/*void ScriptSignalV8Proxy::connect(ScriptValue arg0) {
connect(arg0, ScriptValue(_engine->getIsolate(), v8::Undefined(_engine->getIsolate())));
}*/
void ScriptSignalV8Proxy::connect(ScriptValue arg0, ScriptValue arg1) {
v8::Isolate *isolate = _engine->getIsolate();
v8::Locker locker(isolate);
@ -1646,8 +1293,6 @@ void ScriptSignalV8Proxy::connect(ScriptValue arg0, ScriptValue arg1) {
return;
}
//v8::HandleScope handleScope(isolate);
// untangle the arguments
V8ScriptValue callback(_engine, v8::Null(isolate));
V8ScriptValue callbackThis(_engine, v8::Null(isolate));
@ -1697,15 +1342,12 @@ void ScriptSignalV8Proxy::connect(ScriptValue arg0, ScriptValue arg1) {
ScriptSignalV8Proxy* thisProxy = dynamic_cast<ScriptSignalV8Proxy*>(ScriptObjectV8Proxy::unwrapProxy(v8ThisObject)->toQObject());
Q_ASSERT(thisProxy);
qCDebug(scriptengine_v8) << "ScriptSignalV8Proxy::connect: " << thisProxy->fullName() << " fullName: " << fullName();
//Q_ASSERT(destFunction->InternalFieldCount() == 4);
//Q_ASSERT(destData.get()->IsArray());
//v8::Local<v8::Value> destData = destFunction->GetInternalField(3);
if (!destFunction->Get(destFunctionContext, destDataName).ToLocal(&destData)) {
Q_ASSERT(false);
}
if (destData->IsArray()) {
v8::Local<v8::Array> destArray = v8::Local<v8::Array>::Cast(destData);
int length = destArray->Length();//destData.property("length").toInteger();
int length = destArray->Length();
// V8TODO: Maybe copying array is unnecessary?
v8::Local<v8::Array> newArray = v8::Array::New(isolate, length + 1);
bool foundIt = false;
@ -1726,7 +1368,6 @@ void ScriptSignalV8Proxy::connect(ScriptValue arg0, ScriptValue arg1) {
}
}
if (!newArray->Set(destFunctionContext, length, v8ThisObject.get()).FromMaybe(false)) {
//if (!newArray->Set(destFunctionContext, length, v8ThisObject.get()).FromMaybe(false)) {
Q_ASSERT(false);
}
if (!destFunction->Set(destFunctionContext, destDataName, newArray).FromMaybe(false)) {
@ -1741,16 +1382,9 @@ void ScriptSignalV8Proxy::connect(ScriptValue arg0, ScriptValue arg1) {
Q_ASSERT(false);
}
}
/*{
V8ScriptValueList args;
args << thisObject();
destData.property("push").call(destData, args);
}*/
// add this to our internal list of connections
Connection newConnection(callbackThis, callback);
//newConn.callback = callback;
//newConn.thisValue = callbackThis;
withWriteLock([&]{
_connections.append(newConnection);
@ -1764,10 +1398,6 @@ void ScriptSignalV8Proxy::connect(ScriptValue arg0, ScriptValue arg1) {
}
}
/*void ScriptSignalV8Proxy::disconnect(ScriptValue arg0) {
disconnect(arg0, V8ScriptValue(_engine->getIsolate(), v8::Undefined(_engine->getIsolate())));
}*/
void ScriptSignalV8Proxy::disconnect(ScriptValue arg0, ScriptValue arg1) {
QObject* qobject = _object;
v8::Isolate *isolate = _engine->getIsolate();
@ -1832,18 +1462,15 @@ void ScriptSignalV8Proxy::disconnect(ScriptValue arg0, ScriptValue arg1) {
ScriptSignalV8Proxy* thisProxy = dynamic_cast<ScriptSignalV8Proxy*>(ScriptObjectV8Proxy::unwrapProxy(v8ThisObject)->toQObject());
Q_ASSERT(thisProxy);
qCDebug(scriptengine_v8) << "ScriptSignalV8Proxy::disconnect: " << thisProxy->fullName() << " fullName: " << fullName();
//V8ScriptValue destData = callback.data();
//Q_ASSERT(destData->IsArray());
if (!destFunction->Get(destFunctionContext, destDataName).ToLocal(&destData)) {
Q_ASSERT(false);
}
if (destData->IsArray()) {
v8::Local<v8::Array> destArray = v8::Local<v8::Array>::Cast(destData);
int length = destArray->Length();//destData.property("length").toInteger();
int length = destArray->Length();
v8::Local<v8::Array> newArray = v8::Array::New(isolate, length - 1);
bool foundIt = false;
int newIndex = 0;
//for (int idx = 0; idx < length && !foundIt; ++idx) {
for (int idx = 0; idx < length; ++idx) {
v8::Local<v8::Value> entry = destArray->Get(destFunctionContext, idx).ToLocalChecked();
// For debugging:
@ -1863,9 +1490,6 @@ void ScriptSignalV8Proxy::disconnect(ScriptValue arg0, ScriptValue arg1) {
//V8TODO: compare proxies instead?
foundIt = true;
qCDebug(scriptengine_v8) << "ScriptSignalV8Proxy::disconnect foundIt";
//V8ScriptValueList args;
//args << idx << 1;
//destData.property("splice").call(destData, args);
} else {
if (!newArray->Set(destFunctionContext, newIndex, entry).FromMaybe(false)) {
Q_ASSERT(false);

View file

@ -133,11 +133,7 @@ private: // storage
const bool _ownsObject;
QPointer<QObject> _object;
// Handle for its own object
// V8TODO Maybe depending on object ownership it should be different type of handles? For example weak persistent would allow
// script engine-owned objects to be garbage collected. This will also need adding a garbage collector callback from V8
// to let proxy know that it is not valid anymore
v8::Persistent<v8::Object> _v8Object;
int pointerCorruptionTest = 12345678;
Q_DISABLE_COPY(ScriptObjectV8Proxy)
};
@ -171,7 +167,6 @@ public: // construction
static QVariant* unwrapQVariantPointer(v8::Isolate* isolate, const v8::Local<v8::Value> &value);
static QVariant unwrap(const V8ScriptValue& val);
inline QVariant toQVariant() const { return _variant; }
//inline QVariant toV8Value() const { return _variant; }
inline v8::Local<v8::Object> toV8Value() const {
v8::EscapableHandleScope handleScope(_engine->getIsolate());
return handleScope.Escape(_v8Object.Get(_engine->getIsolate()));
@ -188,9 +183,6 @@ public: // QScriptClass implementation
virtual ScriptValue::PropertyFlags propertyFlags(const V8ScriptValue& object, const V8ScriptString& name, uint id) {
return _proto->propertyFlags(object, name, id);
}
/*virtual QueryFlags queryProperty(const V8ScriptValue& object, const V8ScriptString& name, QueryFlags flags, uint* id) {
return _proto->queryProperty(object, name, flags, id);
}*/
virtual void setProperty(V8ScriptValue& object, const V8ScriptString& name, uint id, const V8ScriptValue& value) {
return _proto->setProperty(object, name, id, value);
}
@ -204,7 +196,6 @@ private:
V8ScriptValue _scriptProto;
ScriptObjectV8Proxy* _proto;
QString _name;
//v8::UniquePersistent<v8::ObjectTemplate> _v8ObjectTemplate;
v8::UniquePersistent<v8::Object> _v8Object;
Q_DISABLE_COPY(ScriptVariantV8Proxy)
@ -219,10 +210,8 @@ public: // construction
public: // QScriptClass implementation
virtual QString name() const { return fullName(); }
//virtual bool supportsExtension(Extension extension) const;
static void callback(const v8::FunctionCallbackInfo<v8::Value>& arguments);
void call(const v8::FunctionCallbackInfo<v8::Value>& arguments);
//virtual QVariant extension(Extension extension, const QVariant& argument = QVariant());
static V8ScriptValue newMethod(ScriptEngineV8* engine, QObject* object, V8ScriptValue lifetime,
const QList<QMetaMethod>& metas, int numMaxParams);
@ -250,8 +239,6 @@ public: // API
// arg1 was had Null default value, but that needs isolate pointer in V8
Q_INVOKABLE virtual void connect(ScriptValue arg0, ScriptValue arg1 = ScriptValue()) = 0;
Q_INVOKABLE virtual void disconnect(ScriptValue arg0, ScriptValue arg1 = ScriptValue()) = 0;
//Q_INVOKABLE virtual void connect(ScriptValue arg0) = 0;
//Q_INVOKABLE virtual void disconnect(ScriptValue arg0) = 0;
};
class ScriptSignalV8Proxy final : public ScriptSignalV8ProxyBase, public ReadWriteLockable {
@ -284,9 +271,6 @@ public: // API
//Moved to public temporarily for debugging:
QString fullName() const;
//virtual void connect(V8ScriptValue arg0) override;
//virtual void disconnect(V8ScriptValue arg0) override;
private: // storage
ScriptEngineV8* _engine;

View file

@ -35,8 +35,6 @@ ScriptSyntaxCheckResultPointer ScriptProgramV8Wrapper::checkSyntax() {
bool ScriptProgramV8Wrapper::compile() {
if (_isCompiled) {
// V8TODO is there a case where source code changes later and needs to be compiled again?
// V8TODO is same program used from multiple isolates
return true;
}
auto isolate = _engine->getIsolate();
@ -49,7 +47,6 @@ bool ScriptProgramV8Wrapper::compile() {
int errorLineNumber = 0;
QString errorMessage = "";
QString errorBacktrace = "";
//ScriptSyntaxCheckResult::State state;
v8::TryCatch tryCatch(isolate);
v8::ScriptOrigin scriptOrigin(isolate, v8::String::NewFromUtf8(isolate, _url.toStdString().c_str()).ToLocalChecked());
v8::Local<v8::Script> script;
@ -77,7 +74,6 @@ bool ScriptProgramV8Wrapper::compile() {
}
}
}
//V8TODO
_compileResult = ScriptSyntaxCheckResultV8Wrapper(ScriptSyntaxCheckResult::Error, errorColumnNumber, errorLineNumber, errorMessage, errorBacktrace);
return false;
}

View file

@ -51,10 +51,6 @@ private: // storage
/// [V8] Implements ScriptProgram for V8 and translates calls for V8ScriptProgram
class ScriptProgramV8Wrapper final : public ScriptProgram {
public: // construction
/*inline ScriptProgramV8Wrapper(ScriptEngineV8* engine, const V8ScriptProgram& value) :
_engine(engine), _value(value) {}*/
//inline ScriptProgramV8Wrapper(ScriptEngineV8* engine, V8ScriptProgram&& value) :
// _engine(engine), _value(std::move(value)) {}
inline ScriptProgramV8Wrapper(ScriptEngineV8* engine, QString source, QString url) :
_engine(engine), _source(source), _url(url), _value(_engine) {
auto isolate = _engine->getIsolate();
@ -62,10 +58,6 @@ public: // construction
v8::Isolate::Scope isolateScope(isolate);
v8::HandleScope handleScope(isolate);
v8::Context::Scope contextScope(_engine->getContext());
// V8TODO: In implicit copy assignment operator for 'V8ScriptValueTemplate<v8::Script>'
// first required here /home/ksuprynowicz/overte/overte_v8/libraries/script-engine/src/v8/V8Types.h:45:5:
// warning: definition of implicit copy assignment operator for 'V8ScriptValueTemplate<v8::Script>' is deprecated
// because it has a user-provided copy constructor
_value = V8ScriptProgram(engine, v8::Local<v8::Script>());
}
static ScriptProgramV8Wrapper* unwrap(ScriptProgramPointer val);
@ -84,7 +76,6 @@ private: // storage
V8ScriptProgram _value;
bool _isCompiled = false;
ScriptSyntaxCheckResultV8Wrapper _compileResult;
//V8TODO: how to make program run on multiple isolates?
};
#endif // hifi_ScriptValueV8Wrapper_h

View file

@ -20,7 +20,6 @@ V8ScriptValueIterator::V8ScriptValueIterator(ScriptEngineV8* engine, v8::Local<v
v8::Locker locker(isolate);
v8::Isolate::Scope isolateScope(isolate);
v8::HandleScope handleScope(isolate);
// V8TODO Is this necessary?
_context.Reset(isolate, _engine->getContext());
auto context = _context.Get(isolate);
v8::Context::Scope contextScope(context);
@ -83,7 +82,6 @@ V8ScriptValue V8ScriptValueIterator::value() {
if (!_object.Get(isolate)->Get(context, propertyName->ToString(context).ToLocalChecked()).ToLocal(&v8Value)) {
Q_ASSERT(false);
}
//V8TODO: sometimes no value gets written to v8Value. This needs to be investigated and fixed.
if (v8Value.IsEmpty()) {
qDebug() << "V8ScriptValueIterator::value: value handle is empty for key: " << *v8::String::Utf8Value(isolate, propertyName->ToString(context).ToLocalChecked());
v8Value = v8::Undefined(isolate);
@ -93,7 +91,6 @@ V8ScriptValue V8ScriptValueIterator::value() {
ScriptValue::PropertyFlags ScriptValueIteratorV8Wrapper::flags() const {
//V8TODO
//return (ScriptValue::PropertyFlags)(int)_value.flags();
return ScriptValue::PropertyFlags();
}

View file

@ -33,7 +33,6 @@ public:
void next();
V8ScriptValue value();
private:
// V8TODO: maybe these should be WeakPersistent?
v8::UniquePersistent<v8::Array> _propertyNames;
v8::UniquePersistent<v8::Object> _object;
v8::UniquePersistent<v8::Context> _context;

View file

@ -21,7 +21,7 @@
void ScriptValueV8Wrapper::release() {
// V8TODO: maybe add an assert to check if it happens on script engine thread?
// With v8::Locker in V8ScriptValue such requirement shouldn't be necessary but deleting on different thread can cause deadlocks sometimes
// With v8::Locker in V8ScriptValue such requirement shouldn't be necessary but could deleting it on different thread cause deadlocks sometimes?
delete this;
}
@ -45,7 +45,6 @@ V8ScriptValue ScriptValueV8Wrapper::fullUnwrap(const ScriptValue& value) const {
ScriptValueV8Wrapper* unwrapped = unwrap(value);
if (unwrapped) {
if (unwrapped->engine().get() != _engine) {
//return _engine->toScriptValue(unwrapped->toVariant());
return _engine->castVariantToValue(unwrapped->toVariant());
} else {
return unwrapped->toV8Value();
@ -59,7 +58,6 @@ V8ScriptValue ScriptValueV8Wrapper::fullUnwrap(ScriptEngineV8* engine, const Scr
ScriptValueV8Wrapper* unwrapped = unwrap(value);
if (unwrapped) {
if (unwrapped->engine().get() != engine) {
//return static_cast<QScriptEngine*>(engine)->toScriptValue(unwrapped->toVariant());
return engine->castVariantToValue(unwrapped->toVariant());
} else {
return unwrapped->toV8Value();
@ -78,9 +76,7 @@ ScriptValue ScriptValueV8Wrapper::call(const ScriptValue& thisObject, const Scri
auto context = _engine->getContext();
v8::Context::Scope contextScope(context);
V8ScriptValue v8This = fullUnwrap(thisObject);
//V8ScriptValueList qArgs;
Q_ASSERT(args.length() <= Q_METAMETHOD_INVOKE_MAX_ARGS);
//V8TODO I'm not sure how else to do this since v8::Local should probably be on stack, not heap
v8::Local<v8::Value> v8Args[Q_METAMETHOD_INVOKE_MAX_ARGS];
int argIndex = 0;
for (ScriptValueList::const_iterator iter = args.begin(); iter != args.end(); ++iter) {
@ -92,15 +88,10 @@ ScriptValue ScriptValueV8Wrapper::call(const ScriptValue& thisObject, const Scri
v8::Local<v8::Value> recv;
if (v8This.get()->IsObject()) {
recv = v8This.get();
//qCDebug(scriptengine_v8) << "V8 This: " << _engine->scriptValueDebugDetailsV8(v8This);
}else{
recv = _engine->getContext()->Global();
//recv = v8::Null(isolate);
//qCDebug(scriptengine_v8) << "global";
}
//qCDebug(scriptengine_v8) << "V8 Call: " << *v8::String::Utf8Value(isolate, v8This.get()->TypeOf(isolate));
auto maybeResult = v8Function->Call(_engine->getContext(), recv, args.length(), v8Args);
// V8TODO: Exceptions don't seem to actually be caught here?
if (tryCatch.HasCaught()) {
qCDebug(scriptengine_v8) << "Function call failed: \"" << _engine->formatErrorMessageFromTryCatch(tryCatch);
}
@ -126,6 +117,7 @@ ScriptValue ScriptValueV8Wrapper::call(const ScriptValue& thisObject, const Scri
// V8TODO should there be a v8 try-catch here?
// IsFunction check should be here probably
// V8TODO I'm not sure in what format arguments are yet, backtrace will show how it is used
// V8TODO: this seems to never be used?
Q_ASSERT(false);
return _engine->undefinedValue();
/*v8::Local<v8::Function> v8Function = v8::Local<v8::Function>::Cast(_value.get());
@ -148,7 +140,6 @@ ScriptValue ScriptValueV8Wrapper::construct(const ScriptValueList& args) {
v8::HandleScope handleScope(isolate);
v8::Context::Scope contextScope(_engine->getContext());
Q_ASSERT(args.length() <= Q_METAMETHOD_INVOKE_MAX_ARGS);
//V8TODO I'm not sure how else to do this since v8::Local should probably be on stack, not heap
v8::Local<v8::Value> v8Args[Q_METAMETHOD_INVOKE_MAX_ARGS];
int argIndex = 0;
for (ScriptValueList::const_iterator iter = args.begin(); iter != args.end(); ++iter) {
@ -174,6 +165,7 @@ ScriptValue ScriptValueV8Wrapper::construct(const ScriptValueList& args) {
}
}
// V8TODO: this seems to never be used?
ScriptValue ScriptValueV8Wrapper::construct(const ScriptValue& arguments) {
auto isolate = _engine->getIsolate();
v8::Locker locker(isolate);
@ -287,7 +279,6 @@ ScriptValue ScriptValueV8Wrapper::property(const QString& name, const ScriptValu
const v8::Local<v8::Object> object = v8::Local<v8::Object>::Cast(_value.constGet());
//V8TODO: Which context?
if (object->Get(_engine->getContext(), key).ToLocal(&resultLocal)) {
//if (object->Get(_value.constGetContext(), key).ToLocal(&resultLocal)) {
V8ScriptValue result(_engine, resultLocal);
return ScriptValue(new ScriptValueV8Wrapper(_engine, std::move(result)));
} else {
@ -302,15 +293,7 @@ ScriptValue ScriptValueV8Wrapper::property(const QString& name, const ScriptValu
if (name == QString("x")) {
printf("x");
}
//This displays too many messages during correct operation, but is useful for debugging
//qCDebug(scriptengine_v8) << "Failed to get property, parent of value: " << name << " is not a V8 object, reported type: " << QString(*v8::String::Utf8Value(isolate, _value.constGet()->TypeOf(isolate)));
//qCDebug(scriptengine_v8) << "Backtrace: " << _engine->currentContext()->backtrace();
return _engine->undefinedValue();
/*v8::Local<v8::Value> nullValue = v8::Null(_engine->getIsolate());
V8ScriptValue nullScriptValue(_engine->getIsolate(), std::move(nullValue));
return ScriptValue(new ScriptValueV8Wrapper(_engine, nullScriptValue));*/
//V8ScriptValue result = _value.property(name, (V8ScriptValue::ResolveFlags)(int)mode);
//return ScriptValue(new ScriptValueV8Wrapper(_engine, std::move(result)));
}
ScriptValue ScriptValueV8Wrapper::property(quint32 arrayIndex, const ScriptValue::ResolveFlags& mode) const {
@ -343,7 +326,6 @@ void ScriptValueV8Wrapper::setData(const ScriptValue& value) {
v8::HandleScope handleScope(isolate);
v8::Context::Scope contextScope(_engine->getContext());
V8ScriptValue unwrapped = fullUnwrap(value);
// V8TODO Check if it uses same isolate. Would pointer check be enough?
// Private properties are an experimental feature for now on V8, so we are using regular value for now
if (_value.constGet()->IsNullOrUndefined()) {
qCDebug(scriptengine_v8) << "ScriptValueV8Wrapper::setData() was called on a value that is null or undefined";
@ -377,9 +359,6 @@ void ScriptValueV8Wrapper::setProperty(const QString& name, const ScriptValue& v
v8::Local<v8::String> key = v8::String::NewFromUtf8(isolate, name.toStdString().c_str(),v8::NewStringType::kNormal).ToLocalChecked();
Q_ASSERT(_value.get()->IsObject());
auto object = v8::Local<v8::Object>::Cast(_value.get());
// V8TODO: What if value context and current context is different?
//v8::Maybe<bool> retVal = object->Set(_value.getContext(), key, unwrapped.constGet());
//v8::Maybe<bool> retVal = object->Set(_engine->getContext(), key, unwrapped.constGet());
v8::Maybe<bool> retVal = object->Set(isolate->GetCurrentContext(), key, unwrapped.constGet());
if (retVal.IsJust() ? !retVal.FromJust() : true){
qCDebug(scriptengine_v8) << "Failed to set property";
@ -413,7 +392,6 @@ void ScriptValueV8Wrapper::setProperty(quint32 arrayIndex, const ScriptValue& va
auto object = v8::Local<v8::Object>::Cast(_value.get());
//V8TODO: I don't know which context to use here
v8::Maybe<bool> retVal(object->Set(_engine->getContext(), arrayIndex, unwrapped.constGet()));
//v8::Maybe<bool> retVal(object->Set(_value.getContext(), arrayIndex, unwrapped.constGet()));
if (retVal.IsJust() ? !retVal.FromJust() : true){
qCDebug(scriptengine_v8) << "Failed to set property";
}
@ -440,7 +418,6 @@ void ScriptValueV8Wrapper::setPrototype(const ScriptValue& prototype) {
auto object = v8::Local<v8::Object>::Cast(_value.get());
//V8TODO: I don't know which context to use here
v8::Maybe<bool> retVal = object->SetPrototype(context, unwrappedPrototype->toV8Value().constGet());
//v8::Maybe<bool> retVal = object->SetPrototype(_value.getContext(), unwrappedPrototype->toV8Value().constGet());
if (retVal.IsJust() ? !retVal.FromJust() : true){
qCDebug(scriptengine_v8) << "Failed to assign prototype";
}
@ -604,23 +581,15 @@ bool ScriptValueV8Wrapper::equals(const ScriptValue& other) const {
v8::HandleScope handleScope(isolate);
v8::Context::Scope contextScope(_engine->getContext());
ScriptValueV8Wrapper* unwrappedOther = unwrap(other);
//V8TODO: is this used with different isolates?
// in such case conversion will probably be necessary
Q_ASSERT(_engine->getIsolate() == unwrappedOther->_engine->getIsolate());
if (!unwrappedOther) {
return false;
}else{
// V8TODO: which context needs to be used here?
if (_value.constGet()->Equals(_engine->getContext(), unwrappedOther->toV8Value().constGet()).IsNothing()) {
return false;
} else {
return _value.constGet()->Equals(_engine->getContext(), unwrappedOther->toV8Value().constGet()).FromJust();
}
/*if (_value.constGet()->Equals(unwrappedOther->toV8Value().constGetContext(), unwrappedOther->toV8Value().constGet()).IsNothing()) {
return false;
} else {
return _value.constGet()->Equals(unwrappedOther->toV8Value().constGetContext(), unwrappedOther->toV8Value().constGet()).FromJust();
}*/
}
}
@ -719,7 +688,7 @@ bool ScriptValueV8Wrapper::isValid() const {
}
bool ScriptValueV8Wrapper::isVariant() const {
//V8TODO
//V8TODO: check if it's variant proxy? I'm not sure though.
auto isolate = _engine->getIsolate();
v8::Locker locker(isolate);
v8::Isolate::Scope isolateScope(isolate);

View file

@ -17,7 +17,7 @@
#include "TypedArrays.h"
// V8TODO
// V8TODO Do not remove yet, this will be useful in later PRs
/*Q_DECLARE_METATYPE(QByteArray*)
TypedArrayPrototype::TypedArrayPrototype(QObject* parent) : QObject(parent) {

View file

@ -22,7 +22,7 @@
#include "V8Types.h"
#include "../Scriptable.h"
// V8TODO
// V8TODO Do not remove yet, this will be useful in later PRs
/// [V8] The javascript functions associated with a <code><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray">TypedArray</a></code> instance prototype
/*class TypedArrayPrototype : public QObject, public Scriptable {
Q_OBJECT

View file

@ -23,7 +23,7 @@
#include "ScriptEngineV8.h"
#include "TypedArrayPrototype.h"
// V8TODO
// V8TODO Do not remove yet, this will be useful in later PRs
/*Q_DECLARE_METATYPE(QByteArray*)
TypedArray::TypedArray(ScriptEngineV8* scriptEngine, QString name) : ArrayBufferViewClass(scriptEngine) {

View file

@ -17,7 +17,7 @@
#ifndef hifi_TypedArrays_h
#define hifi_TypedArrays_h
// V8TODO
// V8TODO Do not remove yet, this will be useful in later PRs
/*#include "ArrayBufferViewClass.h"
static const QString BYTES_PER_ELEMENT_PROPERTY_NAME = "BYTES_PER_ELEMENT";

View file

@ -22,6 +22,7 @@
// Lambda helps create callable V8ScriptValues out of std::functions:
// (just meant for use from within the script engine itself)
// V8TODO: this looks like it can be safely removed?
class Lambda : public QObject {
Q_OBJECT
public:

View file

@ -25,28 +25,11 @@ class V8ScriptValueTemplate {
public:
V8ScriptValueTemplate() = delete;
/*enum class Ownership {
Script = 0,
Value = 1
};*/
//V8ScriptValueTemplate(v8::Isolate *isolate, v8::Local<T> value) : _isolate(isolate) {
//_value.reset(v8::UniquePersistent<T>::New(_isolate, value));
//};
// V8TODO: Persistent handles need to be constructed and destructed in the same thread
// Adding asserts might be a good idea
V8ScriptValueTemplate(ScriptEngineV8 *engine, const v8::Local<T> value/*, V8ScriptValueTemplate::Ownership ownership*/) : _engine(engine) {
v8::Locker locker(_engine->getIsolate());
v8::Isolate::Scope isolateScope(_engine->getIsolate());
v8::HandleScope handleScope(_engine->getIsolate());
v8::Context::Scope(_engine->getContext());
/*if (ownership == V8ScriptValueTemplate::Ownership::Script) {
_value.reset(new v8::WeakPersistent<T>(_engine->getIsolate(), value));
return;
} else if (ownership == V8ScriptValueTemplate::Ownership::Value) {
_value.reset(new v8::UniquePersistent<T>(_engine->getIsolate(), value));
return;
}
Q_ASSERT(false);*/
#ifdef OVERTE_V8_MEMORY_DEBUG
_engine->incrementScriptValueCounter();
#endif
@ -60,7 +43,6 @@ public:
v8::Context::Scope(_engine->getContext());
_engine = source.getEngine();
_value.reset(new v8::UniquePersistent<T>(_engine->getIsolate(), source.constGet()));
//_value.reset(new v8::UniquePersistent<T>(_engine->getIsolate(), source.constGet()));
return *this;
};
@ -69,7 +51,6 @@ public:
v8::Isolate::Scope isolateScope(_engine->getIsolate());
v8::HandleScope handleScope(_engine->getIsolate());
v8::Context::Scope(_engine->getContext());
//_value.reset(new v8::UniquePersistent<T>(_engine->getIsolate(), v8::Local<T>()));
#ifdef OVERTE_V8_MEMORY_DEBUG
_engine->incrementScriptValueCounter();
#endif
@ -81,7 +62,6 @@ public:
v8::Isolate::Scope isolateScope(_engine->getIsolate());
v8::HandleScope handleScope(_engine->getIsolate());
v8::Context::Scope(_engine->getContext());
//_value.reset(new v8::UniquePersistent<T>(_engine->getIsolate(), copied.constGet()));
#ifdef OVERTE_V8_MEMORY_DEBUG
_engine->incrementScriptValueCounter();
#endif
@ -100,31 +80,21 @@ public:
return handleScope.Escape(_value.get()->Get(_engine->getIsolate()));
};
/*V8ScriptValueTemplate<T>&& copy() const {
Q_ASSERT(_engine->getIsolate()->IsCurrent());
v8::HandleScope handleScope(_engine->getIsolate());
return new V8ScriptValueTemplate(_engine->getIsolate(), v8::Local<T>::New(_engine->getIsolate(), constGet()));
};*/
const v8::Local<v8::Context> constGetContext() const {
Q_ASSERT(_engine->getIsolate()->IsCurrent());
v8::EscapableHandleScope handleScope(_engine->getIsolate());
return handleScope.Escape(_engine->getIsolate()->GetCurrentContext());
//return handleScope.Escape(_context.Get(_isolate));
};
const v8::Isolate* constGetIsolate() const { return _engine->getIsolate(); };
v8::Isolate* getIsolate() { return _engine->getIsolate();};
//v8::Persistent<v8::Context, v8::CopyablePersistentTraits<v8::Context>>& getContext() { return _context;};
ScriptEngineV8* getEngine() const { return _engine; };
v8::Local<v8::Context> getContext() {
Q_ASSERT(_engine->getIsolate()->IsCurrent());
v8::EscapableHandleScope handleScope(_engine->getIsolate());
return handleScope.Escape(_engine->getIsolate()->GetCurrentContext());
//return handleScope.Escape(_context.Get(_isolate));
};
void reset(v8::Isolate *isolate, v8::Local<T>) {
@ -144,19 +114,9 @@ public:
private:
std::shared_ptr<v8::UniquePersistent<T>> _value;
// V8TODO: maybe make it weak
// does it need , CopyablePersistentTraits<Value>?
// V8TODO: is context needed at all?
//v8::Isolate *_isolate;
ScriptEngineV8 *_engine;
//v8::Persistent<v8::Context, v8::CopyablePersistentTraits<v8::Context>> _context;
};
//typedef V8ScriptValueTemplate<v8::Value> V8ScriptValue;
//typedef V8ScriptValueTemplate<v8::Script> V8ScriptProgram;
// V8TODO: Maybe weak?
//typedef v8::Persistent<v8::Context> V8ScriptContext;
class V8ScriptString : public V8ScriptValueTemplate<v8::String> {
public:
V8ScriptString() = delete;
@ -165,7 +125,7 @@ public:
v8::Locker locker(getEngine()->getIsolate());
v8::Isolate::Scope isolateScope(getEngine()->getIsolate());
v8::HandleScope handleScope(getEngine()->getIsolate());
v8::Context::Scope(getEngine()->getContext());
v8::Context::Scope contextScope(getEngine()->getContext());
Q_ASSERT(constGet()->IsString());
return QString(*v8::String::Utf8Value(const_cast<v8::Isolate*>(constGetIsolate()), constGet()));
};
@ -173,7 +133,7 @@ public:
v8::Locker locker(getEngine()->getIsolate());
v8::Isolate::Scope isolateScope(getEngine()->getIsolate());
v8::HandleScope handleScope(getEngine()->getIsolate());
v8::Context::Scope(getEngine()->getContext());
v8::Context::Scope contextScope(getEngine()->getContext());
Q_ASSERT(constGet()->IsString());
return constGet()->StringEquals(string.constGet());
}