History

Fixed method calls

ksuprynowicz committed 3 years ago

Commit e680b5d1 parent 640cee05 files · +108 −33Browse files

Showing the changes to libraries/script-engine/src/v8/ScriptObjectV8Proxy.cpp (1 of 5 files). Show all

Unified · Split

libraries/script-engine/src/v8/ScriptObjectV8Proxy.cpp+93−30
@@ -33,7 +33,7 @@ Q_DECLARE_METATYPE(QSharedPointer<ScriptVariantV8Proxy>) · 32 unmodified lines
33static const void *internalPointsToQObjectProxy = (void *)0x13370000;33static const void *internalPointsToQObjectProxy = (void *)0x13370000;
34static const void *internalPointsToQVariantProxy = (void *)0x13371000;34static const void *internalPointsToQVariantProxy = (void *)0x13371000;
35static const void *internalPointsToSignalProxy = (void *)0x13372000;35static const void *internalPointsToSignalProxy = (void *)0x13372000;
36static const void *internalPointsToMethodProxy = (void *)0x13372000;36static const void *internalPointsToMethodProxy = (void *)0x13373000;
37 37
38// Used strictly to replace the "this" object value for property access. May expand to a full context element38// Used strictly to replace the "this" object value for property access. May expand to a full context element
39// if we find it necessary to, but hopefully not needed39// if we find it necessary to, but hopefully not needed
@@ -114,9 +114,10 @@ V8ScriptValue ScriptObjectV8Proxy::newQObject(ScriptEngineV8* engine, QObject* o · 74 unmodified lines
114 return V8ScriptValue(engine->getIsolate(), proxy.get()->toV8Value());114 return V8ScriptValue(engine->getIsolate(), proxy.get()->toV8Value());
115 }115 }
116 }116 }
117 117 // V8TODO add a V8 callback that removes pointer from the map so that it gets deleted
118 // register the wrapper with the engine and make sure it cleans itself up118 // register the wrapper with the engine and make sure it cleans itself up
119 engine->_qobjectWrapperMap.insert(object, proxy);119 engine->_qobjectWrapperMap.insert(object, proxy);
120 engine->_qobjectWrapperMapV8.insert(object, proxy);
120 QPointer<ScriptEngineV8> enginePtr = engine;121 QPointer<ScriptEngineV8> enginePtr = engine;
121 object->connect(object, &QObject::destroyed, engine, [enginePtr, object]() {122 object->connect(object, &QObject::destroyed, engine, [enginePtr, object]() {
122 if (!enginePtr) return;123 if (!enginePtr) return;
@@ -137,13 +138,16 @@ ScriptObjectV8Proxy* ScriptObjectV8Proxy::unwrapProxy(const V8ScriptValue& val) · 14 unmodified lines
137 v8::HandleScope handleScope(const_cast<v8::Isolate*>(val.constGetIsolate()));138 v8::HandleScope handleScope(const_cast<v8::Isolate*>(val.constGetIsolate()));
138 auto v8Value = val.constGet();139 auto v8Value = val.constGet();
139 if (!v8Value->IsObject()) {140 if (!v8Value->IsObject()) {
141 qDebug(scriptengine) << "Cannot unwrap proxy - value is not an object";
140 return nullptr;142 return nullptr;
141 }143 }
142 v8::Local<v8::Object> v8Object = v8::Local<v8::Object>::Cast(v8Value);144 v8::Local<v8::Object> v8Object = v8::Local<v8::Object>::Cast(v8Value);
143 if (v8Object->InternalFieldCount() != 2) {145 if (v8Object->InternalFieldCount() != 2) {
146 qDebug(scriptengine) << "Cannot unwrap proxy - wrong number of internal fields";
144 return nullptr;147 return nullptr;
145 }148 }
146 if (v8Object->GetAlignedPointerFromInternalField(0) == internalPointsToQObjectProxy) {149 if (v8Object->GetAlignedPointerFromInternalField(0) != internalPointsToQObjectProxy) {
150 qDebug(scriptengine) << "Cannot unwrap proxy - internal fields don't point to object proxy";
147 return nullptr;151 return nullptr;
148 }152 }
149 return reinterpret_cast<ScriptObjectV8Proxy*>(v8Object->GetAlignedPointerFromInternalField(1));153 return reinterpret_cast<ScriptObjectV8Proxy*>(v8Object->GetAlignedPointerFromInternalField(1));
@@ -155,6 +159,7 @@ QObject* ScriptObjectV8Proxy::unwrap(const V8ScriptValue& val) { · 5 unmodified lines
155}159}
156 160
157ScriptObjectV8Proxy::~ScriptObjectV8Proxy() {161ScriptObjectV8Proxy::~ScriptObjectV8Proxy() {
162 qDebug(scriptengine) << "Deleting object proxy: " << name();
158 if (_ownsObject) {163 if (_ownsObject) {
159 QObject* qobject = _object;164 QObject* qobject = _object;
160 if(qobject) qobject->deleteLater();165 if(qobject) qobject->deleteLater();
@@ -170,11 +175,18 @@ void ScriptObjectV8Proxy::investigate() { · 9 unmodified lines
170 v8::Context::Scope contextScope(_engine->getContext());175 v8::Context::Scope contextScope(_engine->getContext());
171 176
172 auto objectTemplate = _v8ObjectTemplate.Get(_engine->getIsolate());177 auto objectTemplate = _v8ObjectTemplate.Get(_engine->getIsolate());
173 objectTemplate->SetInternalFieldCount(3);178 objectTemplate->SetInternalFieldCount(2);
174 objectTemplate->SetHandler(v8::NamedPropertyHandlerConfiguration(v8Get, v8Set));179 objectTemplate->SetHandler(v8::NamedPropertyHandlerConfiguration(v8Get, v8Set));
175 180
176 const QMetaObject* metaObject = qobject->metaObject();181 const QMetaObject* metaObject = qobject->metaObject();
177 182
183 qDebug(scriptengine) << "Investigate: " << metaObject->className();
184 if (QString("Vec3") == metaObject->className()) {
185 printf("Vec3");
186 }
187 if (QString("ConsoleScriptingInterface") == metaObject->className()) {
188 printf("ConsoleScriptingInterface");
189 }
178 // discover properties190 // discover properties
179 int startIdx = _wrapOptions & ScriptEngine::ExcludeSuperClassProperties ? metaObject->propertyOffset() : 0;191 int startIdx = _wrapOptions & ScriptEngine::ExcludeSuperClassProperties ? metaObject->propertyOffset() : 0;
180 int num = metaObject->propertyCount();192 int num = metaObject->propertyCount();
@@ -182,6 +194,7 @@ void ScriptObjectV8Proxy::investigate() { · 1 unmodified line
182 QMetaProperty prop = metaObject->property(idx);194 QMetaProperty prop = metaObject->property(idx);
183 if (!prop.isScriptable()) continue;195 if (!prop.isScriptable()) continue;
184 196
197 qDebug(scriptengine) << "Investigate: " << metaObject->className() << " Property: " << prop.name();
185 // always exclude child objects (at least until we decide otherwise)198 // always exclude child objects (at least until we decide otherwise)
186 int metaTypeId = prop.userType();199 int metaTypeId = prop.userType();
187 if (metaTypeId != QMetaType::UnknownType) {200 if (metaTypeId != QMetaType::UnknownType) {
@@ -204,6 +217,7 @@ void ScriptObjectV8Proxy::investigate() { · 16 unmodified lines
204 QHash<V8ScriptString, int> methodNames;217 QHash<V8ScriptString, int> methodNames;
205 for (int idx = startIdx; idx < num; ++idx) {218 for (int idx = startIdx; idx < num; ++idx) {
206 QMetaMethod method = metaObject->method(idx);219 QMetaMethod method = metaObject->method(idx);
220 qDebug(scriptengine) << "Investigate: " << metaObject->className() << " Method: " << method.name();
207 221
208 // perhaps keep this comment? Calls (like AudioScriptingInterface::playSound) seem to expect non-public methods to be script-accessible222 // perhaps keep this comment? Calls (like AudioScriptingInterface::playSound) seem to expect non-public methods to be script-accessible
209 /* if (method.access() != QMetaMethod::Public) continue;*/223 /* if (method.access() != QMetaMethod::Public) continue;*/
@@ -281,7 +295,7 @@ void ScriptObjectV8Proxy::investigate() { · 71 unmodified lines
281 v8::Local<v8::Object> v8Object = objectTemplate->NewInstance(_engine->getContext()).ToLocalChecked();295 v8::Local<v8::Object> v8Object = objectTemplate->NewInstance(_engine->getContext()).ToLocalChecked();
282 v8Object->SetAlignedPointerInInternalField(0, const_cast<void*>(internalPointsToQObjectProxy));296 v8Object->SetAlignedPointerInInternalField(0, const_cast<void*>(internalPointsToQObjectProxy));
283 v8Object->SetAlignedPointerInInternalField(1, reinterpret_cast<void*>(this));297 v8Object->SetAlignedPointerInInternalField(1, reinterpret_cast<void*>(this));
284 298
285 _v8Object.Reset(_engine->getIsolate(), v8Object);299 _v8Object.Reset(_engine->getIsolate(), v8Object);
286}300}
287 301
@@ -295,24 +309,31 @@ QString ScriptObjectV8Proxy::name() const { · 7 unmodified lines
295}309}
296 310
297ScriptObjectV8Proxy::QueryFlags ScriptObjectV8Proxy::queryProperty(const V8ScriptValue& object, const V8ScriptString& name, QueryFlags flags, uint* id) {311ScriptObjectV8Proxy::QueryFlags ScriptObjectV8Proxy::queryProperty(const V8ScriptValue& object, const V8ScriptString& name, QueryFlags flags, uint* id) {
298 // check for properties312 v8::HandleScope handleScope(_engine->getIsolate());
299 for (PropertyDefMap::const_iterator trans = _props.cbegin(); trans != _props.cend(); ++trans) {313 // V8TODO: this might be inefficient when there's large number of properties
300 const PropertyDef& propDef = trans.value();314 v8::Local<v8::Context> context = _engine->getContext();
301 if (propDef.name.constGet() != name.constGet()) continue;315 v8::String::Utf8Value nameStr(_engine->getIsolate(), name.constGet());
302 *id = trans.key() | PROPERTY_TYPE;
303 return flags & (HandlesReadAccess | HandlesWriteAccess);
304 }
305 316
306 // check for methods317 // check for methods
307 for (MethodDefMap::const_iterator trans = _methods.cbegin(); trans != _methods.cend(); ++trans) {318 for (MethodDefMap::const_iterator trans = _methods.cbegin(); trans != _methods.cend(); ++trans) {
308 if (trans.value().name.constGet() != name.constGet()) continue;319 v8::String::Utf8Value methodNameStr(_engine->getIsolate(), trans.value().name.constGet());
320 qDebug(scriptengine) << "queryProperty : " << *nameStr << " method: " << *methodNameStr;
321 if (!(trans.value().name == name)) continue;
309 *id = trans.key() | METHOD_TYPE;322 *id = trans.key() | METHOD_TYPE;
310 return flags & (HandlesReadAccess | HandlesWriteAccess);323 return flags & (HandlesReadAccess | HandlesWriteAccess);
311 }324 }
312 325
326 // check for properties
327 for (PropertyDefMap::const_iterator trans = _props.cbegin(); trans != _props.cend(); ++trans) {
328 const PropertyDef& propDef = trans.value();
329 if (!(propDef.name == name)) continue;
330 *id = trans.key() | PROPERTY_TYPE;
331 return flags & (HandlesReadAccess | HandlesWriteAccess);
332 }
333
313 // check for signals334 // check for signals
314 for (SignalDefMap::const_iterator trans = _signals.cbegin(); trans != _signals.cend(); ++trans) {335 for (SignalDefMap::const_iterator trans = _signals.cbegin(); trans != _signals.cend(); ++trans) {
315 if (trans.value().name.constGet() != name.constGet()) continue;336 if (!(trans.value().name == name)) continue;
316 *id = trans.key() | SIGNAL_TYPE;337 *id = trans.key() | SIGNAL_TYPE;
317 return flags & (HandlesReadAccess | HandlesWriteAccess);338 return flags & (HandlesReadAccess | HandlesWriteAccess);
318 }339 }
@@ -348,17 +369,51 @@ ScriptValue::PropertyFlags ScriptObjectV8Proxy::propertyFlags(const V8ScriptValu · 29 unmodified lines
348}369}
349 370
350void ScriptObjectV8Proxy::v8Get(v8::Local<v8::Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {371void ScriptObjectV8Proxy::v8Get(v8::Local<v8::Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
351 // V8TODO372 v8::HandleScope handleScope(info.GetIsolate());
352 //info.GetReturnValue().Set();373 v8::String::Utf8Value utf8Value(info.GetIsolate(), name);
374 qDebug(scriptengine) << "Get: " << *utf8Value;
375 V8ScriptValue object(info.GetIsolate(), info.This());
376 ScriptObjectV8Proxy *proxy = ScriptObjectV8Proxy::unwrapProxy(object);
377 if (!proxy) {
378 qDebug(scriptengine) << "Proxy object not found when getting: " << *utf8Value;
379 return;
380 }
381 V8ScriptString nameString(info.GetIsolate(), v8::Local<v8::String>::Cast(name));
382 uint id;
383 QueryFlags flags = proxy->queryProperty(object, nameString, HandlesReadAccess, &id);
384 if (flags) {
385 V8ScriptValue value = proxy->property(object, nameString, id);
386 info.GetReturnValue().Set(value.get());
387 } else {
388 qDebug(scriptengine) << "Value not found: " << *utf8Value;
389 }
353}390}
354 391
355void ScriptObjectV8Proxy::v8Set(v8::Local<v8::Name> name, v8::Local<v8::Value> value, const v8::PropertyCallbackInfo<v8::Value>& info) {392void ScriptObjectV8Proxy::v8Set(v8::Local<v8::Name> name, v8::Local<v8::Value> value, const v8::PropertyCallbackInfo<v8::Value>& info) {
356 // V8TODO393 v8::HandleScope handleScope(info.GetIsolate());
357 info.GetReturnValue().Set(value);394 v8::String::Utf8Value utf8Value(info.GetIsolate(), name);
395 qDebug(scriptengine) << "Set: " << *utf8Value;
396 V8ScriptValue object(info.GetIsolate(), info.This());
397 ScriptObjectV8Proxy *proxy = ScriptObjectV8Proxy::unwrapProxy(object);
398 if (!proxy) {
399 qDebug(scriptengine) << "Proxy object not found when setting: " << *utf8Value;
400 return;
401 }
402 V8ScriptString nameString(info.GetIsolate(), v8::Local<v8::String>::Cast(name));
403 //V8ScriptString nameString(info.GetIsolate(), name->ToString(proxy->_engine->getContext()).ToLocalChecked());
404 uint id;
405 QueryFlags flags = proxy->queryProperty(object, nameString, HandlesWriteAccess, &id);
406 if (flags) {
407 proxy->setProperty(object, nameString, id, V8ScriptValue(info.GetIsolate(), value));
408 info.GetReturnValue().Set(value);
409 } else {
410 qDebug(scriptengine) << "Value not found: " << *utf8Value;
411 }
358}412}
359 413
360 414
361V8ScriptValue ScriptObjectV8Proxy::property(const V8ScriptValue& object, const V8ScriptString& name, uint id) {415V8ScriptValue ScriptObjectV8Proxy::property(const V8ScriptValue& object, const V8ScriptString& name, uint id) {
416 v8::HandleScope handleScope(_engine->getIsolate());
362 QObject* qobject = _object;417 QObject* qobject = _object;
363 if (!qobject) {418 if (!qobject) {
364 _engine->getIsolate()->ThrowError("Referencing deleted native object");419 _engine->getIsolate()->ThrowError("Referencing deleted native object");
@@ -390,7 +445,7 @@ V8ScriptValue ScriptObjectV8Proxy::property(const V8ScriptValue& object, const V · 25 unmodified lines
390 if((*iter).returnType() == QMetaType::UnknownType) {445 if((*iter).returnType() == QMetaType::UnknownType) {
391 qDebug(scriptengine) << "Method with QMetaType::UnknownType " << metaObject->className() << " " << (*iter).name();446 qDebug(scriptengine) << "Method with QMetaType::UnknownType " << metaObject->className() << " " << (*iter).name();
392 }447 }
393 }448 } //V8TODO: is new method created during every call? It needs to be cached instead
394 return ScriptMethodV8Proxy::newMethod(_engine, qobject, object, methodDef.methods, methodDef.numMaxParms);449 return ScriptMethodV8Proxy::newMethod(_engine, qobject, object, methodDef.methods, methodDef.numMaxParms);
395 }450 }
396 case SIGNAL_TYPE: {451 case SIGNAL_TYPE: {
@@ -417,6 +472,7 @@ V8ScriptValue ScriptObjectV8Proxy::property(const V8ScriptValue& object, const V · 20 unmodified lines
417}472}
418 473
419void ScriptObjectV8Proxy::setProperty(V8ScriptValue& object, const V8ScriptString& name, uint id, const V8ScriptValue& value) {474void ScriptObjectV8Proxy::setProperty(V8ScriptValue& object, const V8ScriptString& name, uint id, const V8ScriptValue& value) {
475 v8::HandleScope handleScope(_engine->getIsolate());
420 if (!(id & PROPERTY_TYPE)) return;476 if (!(id & PROPERTY_TYPE)) return;
421 QObject* qobject = _object;477 QObject* qobject = _object;
422 if (!qobject) {478 if (!qobject) {
@@ -483,7 +539,7 @@ ScriptVariantV8Proxy* ScriptVariantV8Proxy::unwrapProxy(const V8ScriptValue& val · 60 unmodified lines
483 if (v8Object->InternalFieldCount() != 2) {539 if (v8Object->InternalFieldCount() != 2) {
484 return nullptr;540 return nullptr;
485 }541 }
486 if (v8Object->GetAlignedPointerFromInternalField(0) == internalPointsToQVariantProxy) {542 if (v8Object->GetAlignedPointerFromInternalField(0) != internalPointsToQVariantProxy) {
487 return nullptr;543 return nullptr;
488 }544 }
489 return reinterpret_cast<ScriptVariantV8Proxy*>(v8Object->GetAlignedPointerFromInternalField(1));545 return reinterpret_cast<ScriptVariantV8Proxy*>(v8Object->GetAlignedPointerFromInternalField(1));
@@ -495,8 +551,13 @@ QVariant ScriptVariantV8Proxy::unwrap(const V8ScriptValue& val) { · 5 unmodified lines
495}551}
496 552
497ScriptMethodV8Proxy::ScriptMethodV8Proxy(ScriptEngineV8* engine, QObject* object, V8ScriptValue lifetime,553ScriptMethodV8Proxy::ScriptMethodV8Proxy(ScriptEngineV8* engine, QObject* object, V8ScriptValue lifetime,
498 const QList<QMetaMethod>& metas, int numMaxParms) :554 const QList<QMetaMethod>& metas, int numMaxParams) :
499 _numMaxParms(numMaxParms), _engine(engine), _object(object), _objectLifetime(lifetime), _metas(metas) {555 _numMaxParams(numMaxParams), _engine(engine), _object(object), _objectLifetime(lifetime), _metas(metas) {
556}
557
558ScriptMethodV8Proxy::~ScriptMethodV8Proxy() {
559 qDebug(scriptengine) << "ScriptMethodV8Proxy destroyed";
560 printf("ScriptMethodV8Proxy destroyed");
500}561}
501 562
502V8ScriptValue ScriptMethodV8Proxy::newMethod(ScriptEngineV8* engine, QObject* object, V8ScriptValue lifetime,563V8ScriptValue ScriptMethodV8Proxy::newMethod(ScriptEngineV8* engine, QObject* object, V8ScriptValue lifetime,
@@ -534,23 +595,25 @@ QString ScriptMethodV8Proxy::fullName() const { · 31 unmodified lines
534}*/595}*/
535 596
536void ScriptMethodV8Proxy::callback(const v8::FunctionCallbackInfo<v8::Value>& arguments) {597void ScriptMethodV8Proxy::callback(const v8::FunctionCallbackInfo<v8::Value>& arguments) {
537 if (!arguments.This()->IsObject()) {598 v8::HandleScope handleScope(arguments.GetIsolate());
599 if (!arguments.Data()->IsObject()) {
538 arguments.GetIsolate()->ThrowError("Method value is not an object");600 arguments.GetIsolate()->ThrowError("Method value is not an object");
539 return;601 return;
540 }602 }
541 if (!arguments.This()->IsCallable()) {603 v8::Local<v8::Object> data = v8::Local<v8::Object>::Cast(arguments.Data());
604 /*if (!arguments.Data()->IsCallable()) {
542 arguments.GetIsolate()->ThrowError("Method value is not callable");605 arguments.GetIsolate()->ThrowError("Method value is not callable");
543 return;606 return;
544 }607 }*/
545 if (arguments.This()->InternalFieldCount() != 2) {608 if (data->InternalFieldCount() != 2) {
546 arguments.GetIsolate()->ThrowError("Incorrect number of internal fields during method call");609 arguments.GetIsolate()->ThrowError("Incorrect number of internal fields during method call");
547 return;610 return;
548 }611 }
549 if (arguments.This()->GetAlignedPointerFromInternalField(0) == internalPointsToMethodProxy) {612 if (data->GetAlignedPointerFromInternalField(0) != internalPointsToMethodProxy) {
550 arguments.GetIsolate()->ThrowError("Internal field 0 of ScriptMethodV8Proxy V8 object has wrong value");613 arguments.GetIsolate()->ThrowError("Internal field 0 of ScriptMethodV8Proxy V8 object has wrong value");
551 return;614 return;
552 }615 }
553 ScriptMethodV8Proxy *proxy = reinterpret_cast<ScriptMethodV8Proxy*>(arguments.This()->GetAlignedPointerFromInternalField(1));616 ScriptMethodV8Proxy *proxy = reinterpret_cast<ScriptMethodV8Proxy*>(data->GetAlignedPointerFromInternalField(1));
554 proxy->call(arguments);617 proxy->call(arguments);
555}618}
556 619
@@ -565,7 +628,7 @@ void ScriptMethodV8Proxy::call(const v8::FunctionCallbackInfo<v8::Value>& argume · 8 unmodified lines
565 v8::HandleScope handleScope(_engine->getIsolate());628 v8::HandleScope handleScope(_engine->getIsolate());
566 629
567 int scriptNumArgs = arguments.Length();630 int scriptNumArgs = arguments.Length();
568 int numArgs = std::min(scriptNumArgs, _numMaxParms);631 int numArgs = std::min(scriptNumArgs, _numMaxParams);
569 632
570 const int scriptValueTypeId = qMetaTypeId<ScriptValue>();633 const int scriptValueTypeId = qMetaTypeId<ScriptValue>();
571 634
@@ -739,7 +802,7 @@ void ScriptMethodV8Proxy::call(const v8::FunctionCallbackInfo<v8::Value>& argume · 167 unmodified lines
739 }802 }
740 803
741 int scriptNumArgs = context->argumentCount();804 int scriptNumArgs = context->argumentCount();
742 int numArgs = std::min(scriptNumArgs, _numMaxParms);805 int numArgs = std::min(scriptNumArgs, _numMaxParams);
743 806
744 const int scriptValueTypeId = qMetaTypeId<ScriptValue>();807 const int scriptValueTypeId = qMetaTypeId<ScriptValue>();
745 808