1613 lines · 71.6 KB · C++
RawDownload
    if (!name->IsString() && !name->IsSymbol()) {        QString notStringMessage("ScriptObjectV8Proxy::v8Get: " + proxy->_engine->scriptValueDebugDetailsV8(V8ScriptValue(proxy->_engine, name)));        qCDebug(scriptengine_v8) << notStringMessage;        Q_ASSERT(false);    }    v8::Local<v8::String> v8NameString;     ContextScopeV8 contextScopeV8(proxy->_engine);     if (name->IsString()) {        V8ScriptString nameString(proxy->_engine, v8::Local<v8::String>::Cast(name));        uint id;        QueryFlags flags = proxy->queryProperty(object, nameString, HandlesReadAccess, &id);        if (flags) {            V8ScriptValue value = proxy->property(object, nameString, id);            info.GetReturnValue().Set(value.get());            return;        }    }     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 ScriptObjectV8Proxy::v8Set(v8::Local<v8::Name> name, v8::Local<v8::Value> value, const v8::PropertyCallbackInfo<v8::Value>& info) {    v8::HandleScope handleScope(info.GetIsolate());    v8::String::Utf8Value utf8Value(info.GetIsolate(), name);    v8::Local<v8::Value> objectV8 = info.This();    ScriptObjectV8Proxy *proxy = ScriptObjectV8Proxy::unwrapProxy(info.GetIsolate(), objectV8);    if (!proxy) {        qCDebug(scriptengine_v8) << "Proxy object not found when setting: " << *utf8Value;        return;    }    V8ScriptValue object(proxy->_engine, objectV8);    if (!name->IsString() && !name->IsSymbol()) {        QString notStringMessage("ScriptObjectV8Proxy::v8Set: " + proxy->_engine->scriptValueDebugDetailsV8(V8ScriptValue(proxy->_engine, name)));        qCDebug(scriptengine_v8) << notStringMessage;        Q_ASSERT(false);    }     ContextScopeV8 contextScopeV8(proxy->_engine);     if (name->IsString()) {        V8ScriptString nameString(proxy->_engine, v8::Local<v8::String>::Cast(name));        uint id;        QueryFlags flags = proxy->queryProperty(object, nameString, HandlesWriteAccess, &id);        if (flags) {            proxy->setProperty(object, nameString, id, V8ScriptValue(proxy->_engine, value));            info.GetReturnValue().Set(value);            return;        }    }     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: " << *utf8Value;    }} void ScriptObjectV8Proxy::v8GetPropertyNames(const v8::PropertyCallbackInfo<v8::Array>& info) {    v8::HandleScope handleScope(info.GetIsolate());    auto context = info.GetIsolate()->GetCurrentContext();    v8::Context::Scope contextScope(context);    v8::Local<v8::Value> objectV8 = info.This();    ScriptObjectV8Proxy *proxy = ScriptObjectV8Proxy::unwrapProxy(info.GetIsolate(), objectV8);    if (!proxy) {        qCDebug(scriptengine_v8) << "ScriptObjectV8Proxy::v8GetPropertyNames: Proxy object not found when listing";        return;    }    V8ScriptValue object(proxy->_engine, objectV8);    v8::Local<v8::Array> properties = proxy->getPropertyNames();    v8::Local<v8::Array> objectProperties;    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);} v8::Local<v8::Array> ScriptObjectV8Proxy::getPropertyNames() {    auto isolate = _engine->getIsolate();    v8::Locker locker(isolate);    v8::Isolate::Scope isolateScope(isolate);    v8::EscapableHandleScope handleScope(_engine->getIsolate());    auto context = _engine->getContext();    v8::Context::Scope contextScope(context);     //V8TODO: this is really slow. It could be cached if this is called often.    v8::Local<v8::Array> properties = v8::Array::New(isolate, _props.size() + _methods.size() + _signals.size());    uint32_t position = 0;    for (PropertyDefMap::const_iterator i = _props.begin(); i != _props.end(); i++){        v8::Local<v8::String> name = v8::String::NewFromUtf8(isolate, i.value().name.toStdString().c_str()).ToLocalChecked();        if(!properties->Set(context, position++, name).FromMaybe(false)) {            qCDebug(scriptengine_v8) << "ScriptObjectV8Proxy::getPropertyNames: Cannot add property member name";        }    }    for (MethodDefMap::const_iterator i = _methods.begin(); i != _methods.end(); i++){        v8::Local<v8::String> name = v8::String::NewFromUtf8(isolate, i.value().name.toStdString().c_str()).ToLocalChecked();        if(!properties->Set(context, position++, name).FromMaybe(false)) {            qCDebug(scriptengine_v8) << "ScriptObjectV8Proxy::getPropertyNames: Cannot add property member name";        }    }    for (SignalDefMap::const_iterator i = _signals.begin(); i != _signals.end(); i++){        v8::Local<v8::String> name = v8::String::NewFromUtf8(isolate, i.value().name.toStdString().c_str()).ToLocalChecked();        if(!properties->Set(context, position++, name).FromMaybe(false)) {            qCDebug(scriptengine_v8) << "ScriptObjectV8Proxy::getPropertyNames: Cannot add property member name";        }    }    return handleScope.Escape(properties);}  V8ScriptValue ScriptObjectV8Proxy::property(const V8ScriptValue& object, const V8ScriptString& name, uint id) {    auto isolate = _engine->getIsolate();    v8::Locker locker(isolate);    v8::Isolate::Scope isolateScope(isolate);    v8::HandleScope handleScope(isolate);    auto context = _engine->getContext();    v8::Context::Scope contextScope(context);    QObject* qobject = _object;    if (!qobject) {        _engine->getIsolate()->ThrowError("Referencing deleted native object");        return V8ScriptValue(_engine, v8::Null(isolate));    }     const QMetaObject* metaObject = qobject->metaObject();     switch (id & TYPE_MASK) {        case PROPERTY_TYPE: {            int propId = id & ~TYPE_MASK;            PropertyDefMap::const_iterator lookup = _props.find(propId);            if (lookup == _props.cend()) return V8ScriptValue(_engine, v8::Null(isolate));             QMetaProperty prop = metaObject->property(propId);            ScriptValue scriptThis = ScriptValue(new ScriptValueV8Wrapper(_engine, object));            ScriptPropertyContextV8Wrapper ourContext(scriptThis, _engine->currentContext());            ScriptContextGuard guard(&ourContext);             QVariant varValue = prop.read(qobject);            return _engine->castVariantToValue(varValue);        }        case METHOD_TYPE: {            int methodId = id & ~TYPE_MASK;            MethodDefMap::const_iterator lookup = _methods.find(methodId);            if (lookup == _methods.cend()) return V8ScriptValue(_engine, v8::Null(isolate));            const MethodDef& methodDef = lookup.value();            for (auto iter = methodDef.methods.begin(); iter != methodDef.methods.end(); iter++ ) {                if((*iter).returnType() == QMetaType::UnknownType) {                    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            v8::Local<v8::Value> property;            if(_v8Object.Get(isolate)->GetInternalField(2).As<v8::Object>()->Get(context, name.constGet()).ToLocal(&property)) {                if (!property->IsUndefined()) {                    return V8ScriptValue(_engine, property);                }            }            Q_ASSERT(false);            qCDebug(scriptengine_v8) << "(This should not happen) Creating new method object for " << metaObject->className() << " " << name.toQString();            return ScriptMethodV8Proxy::newMethod(_engine, qobject, object, methodDef.methods, methodDef.numMaxParams);        }        case SIGNAL_TYPE: {            int signalId = id & ~TYPE_MASK;            SignalDefMap::const_iterator defLookup = _signals.find(signalId);            if (defLookup == _signals.cend()) return V8ScriptValue(_engine, v8::Null(isolate));             InstanceMap::const_iterator instLookup = _signalInstances.find(signalId);            if (instLookup == _signalInstances.cend() || instLookup.value().isNull()) {                instLookup = _signalInstances.insert(signalId,                    new ScriptSignalV8Proxy(_engine, qobject, object, defLookup.value().signal));                Q_ASSERT(instLookup != _signalInstances.cend());            }            ScriptSignalV8Proxy* proxy = instLookup.value();             ScriptEngine::QObjectWrapOptions options = ScriptEngine::ExcludeSuperClassContents |                                                        //V8TODO ScriptEngine::ExcludeDeleteLater |                                                        ScriptEngine::PreferExistingWrapperObject;            // 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 V8ScriptValue(_engine, v8::Null(isolate));} void ScriptObjectV8Proxy::setProperty(V8ScriptValue& object, const V8ScriptString& name, uint id, const V8ScriptValue& value) {    auto isolate = _engine->getIsolate();    v8::Locker locker(isolate);    v8::Isolate::Scope isolateScope(isolate);    v8::HandleScope handleScope(isolate);    v8::Context::Scope contextScope(_engine->getContext());    if (!(id & PROPERTY_TYPE)) return;    QObject* qobject = _object;    if (!qobject) {        _engine->getIsolate()->ThrowError("Referencing deleted native object");        return;    }     int propId = id & ~TYPE_MASK;    PropertyDefMap::const_iterator lookup = _props.find(propId);    if (lookup == _props.cend()) return;    const PropertyDef& propDef = lookup.value();    if (propDef.flags & ScriptValue::ReadOnly) return;     const QMetaObject* metaObject = qobject->metaObject();    QMetaProperty prop = metaObject->property(propId);     ScriptValue scriptThis = ScriptValue(new ScriptValueV8Wrapper(_engine, object));    ScriptPropertyContextV8Wrapper ourContext(scriptThis, _engine->currentContext());    ScriptContextGuard guard(&ourContext);     int propTypeId = prop.userType();    Q_ASSERT(propTypeId != QMetaType::UnknownType);    QVariant varValue;    if(!_engine->castValueToVariant(value, varValue, propTypeId)) {        QByteArray propTypeName = QMetaType(propTypeId).name();        QByteArray valTypeName = _engine->valueType(value).toLatin1();        isolate->ThrowError(v8::String::NewFromUtf8(isolate, QString("Cannot convert %1 to %2").arg(valTypeName, propTypeName).toStdString().c_str()).ToLocalChecked());        return;    }    prop.write(qobject, varValue);} ScriptVariantV8Proxy::ScriptVariantV8Proxy(ScriptEngineV8* engine, const QVariant& variant, V8ScriptValue scriptProto, ScriptObjectV8Proxy* proto) :    _engine(engine), _variant(variant), _scriptProto(scriptProto), _proto(proto) {    auto isolate = engine->getIsolate();    v8::Locker locker(isolate);    v8::Isolate::Scope isolateScope(isolate);    v8::HandleScope handleScope(isolate);    auto context = engine->getContext();    v8::Context::Scope contextScope(context);    auto variantDataTemplate = _engine->getVariantDataTemplate();    auto variantData = variantDataTemplate->NewInstance(context).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    variantData->SetAlignedPointerInInternalField(1, reinterpret_cast<void*>(this));    _v8Object.Reset(isolate, v8::Local<v8::Object>::Cast(variantData));    _name = QString::fromLatin1(variant.typeName());} ScriptVariantV8Proxy::~ScriptVariantV8Proxy() {    auto isolate = _engine->getIsolate();    v8::Locker locker(isolate);    v8::Isolate::Scope isolateScope(isolate);    v8::HandleScope handleScope(isolate);    // V8TODO: Add similar deletion handling as for object proxy    _v8Object.Reset();} V8ScriptValue ScriptVariantV8Proxy::newVariant(ScriptEngineV8* engine, const QVariant& variant, V8ScriptValue proto) {    qDebug() << "ScriptVariantV8Proxy::newVariant";    auto isolate = engine->getIsolate();    v8::Locker locker(isolate);    v8::Isolate::Scope isolateScope(isolate);    v8::HandleScope handleScope(isolate);    auto context = engine->getContext();    v8::Context::Scope contextScope(context);    ScriptObjectV8Proxy* protoProxy = ScriptObjectV8Proxy::unwrapProxy(proto);    if (!protoProxy) {        Q_ASSERT(protoProxy);        //return engine->newVariant(variant);        return V8ScriptValue(engine, v8::Undefined(isolate));    }    // V8TODO probably needs connection to be deleted    auto proxy = new ScriptVariantV8Proxy(engine, variant, proto, protoProxy);     auto variantProxyTemplate = engine->getVariantProxyTemplate();    auto variantProxy = variantProxyTemplate->NewInstance(context).ToLocalChecked();    variantProxy->SetAlignedPointerInInternalField(0, const_cast<void*>(internalPointsToQVariantProxy));    variantProxy->SetAlignedPointerInInternalField(1, reinterpret_cast<void*>(proxy));    return V8ScriptValue(engine, variantProxy);} ScriptVariantV8Proxy* ScriptVariantV8Proxy::unwrapProxy(const V8ScriptValue& val) {    auto isolate = val.getEngine()->getIsolate();    v8::Locker locker(isolate);    v8::Isolate::Scope isolateScope(isolate);    v8::HandleScope handleScope(isolate);    v8::Context::Scope contextScope(val.getEngine()->getContext());     auto v8Value = val.constGet();    if (!v8Value->IsObject()) {        return nullptr;    }    v8::Local<v8::Object> v8Object = v8::Local<v8::Object>::Cast(v8Value);    if (v8Object->InternalFieldCount() != 2) {        return nullptr;    }    if (v8Object->GetAlignedPointerFromInternalField(0) != internalPointsToQVariantProxy) {        return nullptr;    }    return reinterpret_cast<ScriptVariantV8Proxy*>(v8Object->GetAlignedPointerFromInternalField(1));} ScriptVariantV8Proxy* ScriptVariantV8Proxy::unwrapProxy(v8::Isolate* isolate, v8::Local<v8::Value> &value) {    v8::Locker locker(isolate);    v8::Isolate::Scope isolateScope(isolate);    v8::HandleScope handleScope(isolate);     if (!value->IsObject()) {        return nullptr;    }    v8::Local<v8::Object> v8Object = v8::Local<v8::Object>::Cast(value);    if (v8Object->InternalFieldCount() != 2) {        return nullptr;    }    if (v8Object->GetAlignedPointerFromInternalField(0) != internalPointsToQVariantProxy) {        return nullptr;    }    return reinterpret_cast<ScriptVariantV8Proxy*>(v8Object->GetAlignedPointerFromInternalField(1));} QVariant* ScriptVariantV8Proxy::unwrapQVariantPointer(v8::Isolate* isolate, const v8::Local<v8::Value> &value) {    v8::Locker locker(isolate);    v8::Isolate::Scope isolateScope(isolate);    v8::HandleScope handleScope(isolate);     if (!value->IsObject()) {        return nullptr;    }    v8::Local<v8::Object> v8Object = v8::Local<v8::Object>::Cast(value);    if (v8Object->InternalFieldCount() != 2) {        return nullptr;    }    if (v8Object->GetAlignedPointerFromInternalField(0) != internalPointsToQVariantInProxy) {        return nullptr;    }    auto proxy = reinterpret_cast<ScriptVariantV8Proxy*>(v8Object->GetAlignedPointerFromInternalField(1));    return &(proxy->_variant);}  void ScriptVariantV8Proxy::v8Get(v8::Local<v8::Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {    v8::HandleScope handleScope(info.GetIsolate());    v8::String::Utf8Value utf8Name(info.GetIsolate(), name);    v8::Local<v8::Value> objectV8 = info.This();    ScriptVariantV8Proxy *proxy = ScriptVariantV8Proxy::unwrapProxy(info.GetIsolate(), objectV8);    if (!proxy) {        qCDebug(scriptengine_v8) << "Proxy object not found when getting: " << *utf8Name;        return;    }    V8ScriptValue object(proxy->_engine, proxy->_v8Object.Get(info.GetIsolate()));     ContextScopeV8 contextScopeV8(proxy->_engine);     if (name->IsString()) {        V8ScriptString nameString(proxy->_engine, v8::Local<v8::String>::Cast(name));        uint id;        ScriptObjectV8Proxy::QueryFlags flags = proxy->_proto->queryProperty(object, nameString, ScriptObjectV8Proxy::HandlesReadAccess, &id);        if (flags) {            V8ScriptValue value = proxy->property(object, nameString, id);            info.GetReturnValue().Set(value.get());            return;        }    }     qCDebug(scriptengine_v8) << "Value not found: " << *utf8Name;} void ScriptVariantV8Proxy::v8Set(v8::Local<v8::Name> name, v8::Local<v8::Value> value, const v8::PropertyCallbackInfo<v8::Value>& info) {    v8::HandleScope handleScope(info.GetIsolate());    v8::String::Utf8Value utf8Name(info.GetIsolate(), name);    v8::Local<v8::Value> objectV8 = info.This();    ScriptVariantV8Proxy *proxy = ScriptVariantV8Proxy::unwrapProxy(info.GetIsolate(), objectV8);    if (!proxy) {        qCDebug(scriptengine_v8) << "Proxy object not found when getting: " << *utf8Name;        return;    }     V8ScriptValue object(proxy->_engine, objectV8);    if (!name->IsString() && !name->IsSymbol()) {        QString notStringMessage("ScriptObjectV8Proxy::v8Set: " + proxy->_engine->scriptValueDebugDetailsV8(V8ScriptValue(proxy->_engine, name)));        qCDebug(scriptengine_v8) << notStringMessage;        Q_ASSERT(false);    }     ContextScopeV8 contextScopeV8(proxy->_engine);    if (name->IsString()) {        V8ScriptString nameString(proxy->_engine, v8::Local<v8::String>::Cast(name));        uint id;        ScriptObjectV8Proxy::QueryFlags flags = proxy->_proto->queryProperty(object, nameString, ScriptObjectV8Proxy::HandlesWriteAccess, &id);        if (flags) {            proxy->setProperty(object, nameString, id, V8ScriptValue(proxy->_engine, value));            info.GetReturnValue().Set(value);            return;        }    }    qCDebug(scriptengine_v8) << "Set failed: " << *utf8Name;} void ScriptVariantV8Proxy::v8GetPropertyNames(const v8::PropertyCallbackInfo<v8::Array>& info) {    //V8TODO: Only methods from the prototype should be listed.    v8::HandleScope handleScope(info.GetIsolate());    auto context = info.GetIsolate()->GetCurrentContext();    v8::Context::Scope contextScope(context);    v8::Local<v8::Value> objectV8 = info.This();    ScriptVariantV8Proxy *proxy = ScriptVariantV8Proxy::unwrapProxy(info.GetIsolate(), objectV8);    if (!proxy) {        qCDebug(scriptengine_v8) << "ScriptObjectV8Proxy::v8GetPropertyNames: Proxy object not found when listing";        return;    }    V8ScriptValue object(proxy->_engine, objectV8);    v8::Local<v8::Array> properties = proxy->_proto->getPropertyNames();    v8::Local<v8::Array> objectProperties;    info.GetReturnValue().Set(properties);} QVariant ScriptVariantV8Proxy::unwrap(const V8ScriptValue& val) {    ScriptVariantV8Proxy* proxy = unwrapProxy(val);    return proxy ? proxy->toQVariant() : QVariant();    // V8TODO} ScriptMethodV8Proxy::ScriptMethodV8Proxy(ScriptEngineV8* engine, QObject* object, V8ScriptValue lifetime,                               const QList<QMetaMethod>& metas, int numMaxParams) :    _numMaxParams(numMaxParams), _engine(engine), _object(object), /*_objectLifetime(lifetime),*/ _metas(metas) {    auto isolate = engine->getIsolate();    v8::Locker locker(isolate);    v8::Isolate::Scope isolateScope(isolate);    v8::HandleScope handleScope(isolate);    v8::Context::Scope contextScope(engine->getContext());    _objectLifetime.Reset(isolate, lifetime.get());    _objectLifetime.SetWeak(this, weakHandleCallback, v8::WeakCallbackType::kParameter);} ScriptMethodV8Proxy::~ScriptMethodV8Proxy() {    auto isolate = _engine->getIsolate();    v8::Locker locker(isolate);    v8::Isolate::Scope isolateScope(isolate);    v8::HandleScope handleScope(isolate);    _objectLifetime.Reset();} void ScriptMethodV8Proxy::weakHandleCallback(const v8::WeakCallbackInfo<ScriptMethodV8Proxy>& info) {    auto proxy = info.GetParameter();    proxy->_objectLifetime.Reset();    info.GetParameter()->deleteLater();} V8ScriptValue ScriptMethodV8Proxy::newMethod(ScriptEngineV8* engine, QObject* object, V8ScriptValue lifetime,                               const QList<QMetaMethod>& metas, int numMaxParams) {    auto isolate = engine->getIsolate();    v8::Locker locker(isolate);    v8::Isolate::Scope isolateScope(isolate);    v8::HandleScope handleScope(isolate);    auto context = engine->getContext();    v8::Context::Scope contextScope(context);    auto methodDataTemplate = engine->getMethodDataTemplate();    auto methodData = methodDataTemplate->NewInstance(context).ToLocalChecked();    methodData->SetAlignedPointerInInternalField(0, const_cast<void*>(internalPointsToMethodProxy));    methodData->SetAlignedPointerInInternalField(1, reinterpret_cast<void*>(new ScriptMethodV8Proxy(engine, object, lifetime, metas, numMaxParams)));    auto v8Function = v8::Function::New(context, callback, methodData, numMaxParams).ToLocalChecked();    return V8ScriptValue(engine, v8Function);} QString ScriptMethodV8Proxy::fullName() const {    Q_ASSERT(_object);    if (!_object) return "";    Q_ASSERT(!_metas.isEmpty());    const QMetaMethod& firstMethod = _metas.front();    QString objectName = _object->objectName();    if (!objectName.isEmpty()) {        return QString("%1.%2").arg(objectName, firstMethod.name());    }    return QString("%1::%2").arg(_object->metaObject()->className(), firstMethod.name());} 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());    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 (data->InternalFieldCount() != 2) {        arguments.GetIsolate()->ThrowError("Incorrect number of internal fields during method call");        return;    }    if (data->GetAlignedPointerFromInternalField(0) != internalPointsToMethodProxy) {        arguments.GetIsolate()->ThrowError("Internal field 0 of ScriptMethodV8Proxy V8 object has wrong value");        return;    }    ScriptMethodV8Proxy *proxy = reinterpret_cast<ScriptMethodV8Proxy*>(data->GetAlignedPointerFromInternalField(1));     ContextScopeV8 contextScopeV8(proxy->_engine);    proxy->call(arguments);} 

Lines 501–1000 of 1613. Previous lines