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
3333 static const void *internalPointsToQObjectProxy = (void *)0x13370000;
3434 static const void *internalPointsToQVariantProxy = (void *)0x13371000;
3535 static const void *internalPointsToSignalProxy = (void *)0x13372000;
36−static const void *internalPointsToMethodProxy = (void *)0x13372000;
36+static const void *internalPointsToMethodProxy = (void *)0x13373000;
3737
3838 // Used strictly to replace the "this" object value for property access. May expand to a full context element
3939 // if we find it necessary to, but hopefully not needed
@@ -114,9 +114,10 @@ V8ScriptValue ScriptObjectV8Proxy::newQObject(ScriptEngineV8* engine, QObject* o · 74 unmodified lines
114114 return V8ScriptValue(engine->getIsolate(), proxy.get()->toV8Value());
115115 }
116116 }
117−
117+ // V8TODO add a V8 callback that removes pointer from the map so that it gets deleted
118118 // register the wrapper with the engine and make sure it cleans itself up
119119 engine->_qobjectWrapperMap.insert(object, proxy);
120+ engine->_qobjectWrapperMapV8.insert(object, proxy);
120121 QPointer<ScriptEngineV8> enginePtr = engine;
121122 object->connect(object, &QObject::destroyed, engine, [enginePtr, object]() {
122123 if (!enginePtr) return;
@@ -137,13 +138,16 @@ ScriptObjectV8Proxy* ScriptObjectV8Proxy::unwrapProxy(const V8ScriptValue& val) · 14 unmodified lines
137138 v8::HandleScope handleScope(const_cast<v8::Isolate*>(val.constGetIsolate()));
138139 auto v8Value = val.constGet();
139140 if (!v8Value->IsObject()) {
141+ qDebug(scriptengine) << "Cannot unwrap proxy - value is not an object";
140142 return nullptr;
141143 }
142144 v8::Local<v8::Object> v8Object = v8::Local<v8::Object>::Cast(v8Value);
143145 if (v8Object->InternalFieldCount() != 2) {
146+ qDebug(scriptengine) << "Cannot unwrap proxy - wrong number of internal fields";
144147 return nullptr;
145148 }
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";
147151 return nullptr;
148152 }
149153 return reinterpret_cast<ScriptObjectV8Proxy*>(v8Object->GetAlignedPointerFromInternalField(1));
@@ -155,6 +159,7 @@ QObject* ScriptObjectV8Proxy::unwrap(const V8ScriptValue& val) { · 5 unmodified lines
155159 }
156160
157161 ScriptObjectV8Proxy::~ScriptObjectV8Proxy() {
162+ qDebug(scriptengine) << "Deleting object proxy: " << name();
158163 if (_ownsObject) {
159164 QObject* qobject = _object;
160165 if(qobject) qobject->deleteLater();
@@ -170,11 +175,18 @@ void ScriptObjectV8Proxy::investigate() { · 9 unmodified lines
170175 v8::Context::Scope contextScope(_engine->getContext());
171176
172177 auto objectTemplate = _v8ObjectTemplate.Get(_engine->getIsolate());
173− objectTemplate->SetInternalFieldCount(3);
178+ objectTemplate->SetInternalFieldCount(2);
174179 objectTemplate->SetHandler(v8::NamedPropertyHandlerConfiguration(v8Get, v8Set));
175180
176181 const QMetaObject* metaObject = qobject->metaObject();
177182
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+ }
178190 // discover properties
179191 int startIdx = _wrapOptions & ScriptEngine::ExcludeSuperClassProperties ? metaObject->propertyOffset() : 0;
180192 int num = metaObject->propertyCount();
@@ -182,6 +194,7 @@ void ScriptObjectV8Proxy::investigate() { · 1 unmodified line
182194 QMetaProperty prop = metaObject->property(idx);
183195 if (!prop.isScriptable()) continue;
184196
197+ qDebug(scriptengine) << "Investigate: " << metaObject->className() << " Property: " << prop.name();
185198 // always exclude child objects (at least until we decide otherwise)
186199 int metaTypeId = prop.userType();
187200 if (metaTypeId != QMetaType::UnknownType) {
@@ -204,6 +217,7 @@ void ScriptObjectV8Proxy::investigate() { · 16 unmodified lines
204217 QHash<V8ScriptString, int> methodNames;
205218 for (int idx = startIdx; idx < num; ++idx) {
206219 QMetaMethod method = metaObject->method(idx);
220+ qDebug(scriptengine) << "Investigate: " << metaObject->className() << " Method: " << method.name();
207221
208222 // perhaps keep this comment? Calls (like AudioScriptingInterface::playSound) seem to expect non-public methods to be script-accessible
209223 /* if (method.access() != QMetaMethod::Public) continue;*/
@@ -281,7 +295,7 @@ void ScriptObjectV8Proxy::investigate() { · 71 unmodified lines
281295 v8::Local<v8::Object> v8Object = objectTemplate->NewInstance(_engine->getContext()).ToLocalChecked();
282296 v8Object->SetAlignedPointerInInternalField(0, const_cast<void*>(internalPointsToQObjectProxy));
283297 v8Object->SetAlignedPointerInInternalField(1, reinterpret_cast<void*>(this));
284−
298+
285299 _v8Object.Reset(_engine->getIsolate(), v8Object);
286300 }
287301
@@ -295,24 +309,31 @@ QString ScriptObjectV8Proxy::name() const { · 7 unmodified lines
295309 }
296310
297311 ScriptObjectV8Proxy::QueryFlags ScriptObjectV8Proxy::queryProperty(const V8ScriptValue& object, const V8ScriptString& name, QueryFlags flags, uint* id) {
298− // check for properties
299− for (PropertyDefMap::const_iterator trans = _props.cbegin(); trans != _props.cend(); ++trans) {
300− const PropertyDef& propDef = trans.value();
301− if (propDef.name.constGet() != name.constGet()) continue;
302− *id = trans.key() | PROPERTY_TYPE;
303− return flags & (HandlesReadAccess | HandlesWriteAccess);
304− }
312+ v8::HandleScope handleScope(_engine->getIsolate());
313+ // V8TODO: this might be inefficient when there's large number of properties
314+ v8::Local<v8::Context> context = _engine->getContext();
315+ v8::String::Utf8Value nameStr(_engine->getIsolate(), name.constGet());
305316
306317 // check for methods
307318 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;
309322 *id = trans.key() | METHOD_TYPE;
310323 return flags & (HandlesReadAccess | HandlesWriteAccess);
311324 }
312325
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+
313334 // check for signals
314335 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;
316337 *id = trans.key() | SIGNAL_TYPE;
317338 return flags & (HandlesReadAccess | HandlesWriteAccess);
318339 }
@@ -348,17 +369,51 @@ ScriptValue::PropertyFlags ScriptObjectV8Proxy::propertyFlags(const V8ScriptValu · 29 unmodified lines
348369 }
349370
350371 void ScriptObjectV8Proxy::v8Get(v8::Local<v8::Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
351− // V8TODO
352− //info.GetReturnValue().Set();
372+ v8::HandleScope handleScope(info.GetIsolate());
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+ }
353390 }
354391
355392 void ScriptObjectV8Proxy::v8Set(v8::Local<v8::Name> name, v8::Local<v8::Value> value, const v8::PropertyCallbackInfo<v8::Value>& info) {
356− // V8TODO
357− info.GetReturnValue().Set(value);
393+ v8::HandleScope handleScope(info.GetIsolate());
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+ }
358412 }
359413
360414
361415 V8ScriptValue ScriptObjectV8Proxy::property(const V8ScriptValue& object, const V8ScriptString& name, uint id) {
416+ v8::HandleScope handleScope(_engine->getIsolate());
362417 QObject* qobject = _object;
363418 if (!qobject) {
364419 _engine->getIsolate()->ThrowError("Referencing deleted native object");
@@ -390,7 +445,7 @@ V8ScriptValue ScriptObjectV8Proxy::property(const V8ScriptValue& object, const V · 25 unmodified lines
390445 if((*iter).returnType() == QMetaType::UnknownType) {
391446 qDebug(scriptengine) << "Method with QMetaType::UnknownType " << metaObject->className() << " " << (*iter).name();
392447 }
393− }
448+ } //V8TODO: is new method created during every call? It needs to be cached instead
394449 return ScriptMethodV8Proxy::newMethod(_engine, qobject, object, methodDef.methods, methodDef.numMaxParms);
395450 }
396451 case SIGNAL_TYPE: {
@@ -417,6 +472,7 @@ V8ScriptValue ScriptObjectV8Proxy::property(const V8ScriptValue& object, const V · 20 unmodified lines
417472 }
418473
419474 void ScriptObjectV8Proxy::setProperty(V8ScriptValue& object, const V8ScriptString& name, uint id, const V8ScriptValue& value) {
475+ v8::HandleScope handleScope(_engine->getIsolate());
420476 if (!(id & PROPERTY_TYPE)) return;
421477 QObject* qobject = _object;
422478 if (!qobject) {
@@ -483,7 +539,7 @@ ScriptVariantV8Proxy* ScriptVariantV8Proxy::unwrapProxy(const V8ScriptValue& val · 60 unmodified lines
483539 if (v8Object->InternalFieldCount() != 2) {
484540 return nullptr;
485541 }
486− if (v8Object->GetAlignedPointerFromInternalField(0) == internalPointsToQVariantProxy) {
542+ if (v8Object->GetAlignedPointerFromInternalField(0) != internalPointsToQVariantProxy) {
487543 return nullptr;
488544 }
489545 return reinterpret_cast<ScriptVariantV8Proxy*>(v8Object->GetAlignedPointerFromInternalField(1));
@@ -495,8 +551,13 @@ QVariant ScriptVariantV8Proxy::unwrap(const V8ScriptValue& val) { · 5 unmodified lines
495551 }
496552
497553 ScriptMethodV8Proxy::ScriptMethodV8Proxy(ScriptEngineV8* engine, QObject* object, V8ScriptValue lifetime,
498− const QList<QMetaMethod>& metas, int numMaxParms) :
499− _numMaxParms(numMaxParms), _engine(engine), _object(object), _objectLifetime(lifetime), _metas(metas) {
554+ const QList<QMetaMethod>& metas, int numMaxParams) :
555+ _numMaxParams(numMaxParams), _engine(engine), _object(object), _objectLifetime(lifetime), _metas(metas) {
556+}
557+
558+ScriptMethodV8Proxy::~ScriptMethodV8Proxy() {
559+ qDebug(scriptengine) << "ScriptMethodV8Proxy destroyed";
560+ printf("ScriptMethodV8Proxy destroyed");
500561 }
501562
502563 V8ScriptValue ScriptMethodV8Proxy::newMethod(ScriptEngineV8* engine, QObject* object, V8ScriptValue lifetime,
@@ -534,23 +595,25 @@ QString ScriptMethodV8Proxy::fullName() const { · 31 unmodified lines
534595 }*/
535596
536597 void ScriptMethodV8Proxy::callback(const v8::FunctionCallbackInfo<v8::Value>& arguments) {
537− if (!arguments.This()->IsObject()) {
598+ v8::HandleScope handleScope(arguments.GetIsolate());
599+ if (!arguments.Data()->IsObject()) {
538600 arguments.GetIsolate()->ThrowError("Method value is not an object");
539601 return;
540602 }
541− if (!arguments.This()->IsCallable()) {
603+ v8::Local<v8::Object> data = v8::Local<v8::Object>::Cast(arguments.Data());
604+ /*if (!arguments.Data()->IsCallable()) {
542605 arguments.GetIsolate()->ThrowError("Method value is not callable");
543606 return;
544− }
545− if (arguments.This()->InternalFieldCount() != 2) {
607+ }*/
608+ if (data->InternalFieldCount() != 2) {
546609 arguments.GetIsolate()->ThrowError("Incorrect number of internal fields during method call");
547610 return;
548611 }
549− if (arguments.This()->GetAlignedPointerFromInternalField(0) == internalPointsToMethodProxy) {
612+ if (data->GetAlignedPointerFromInternalField(0) != internalPointsToMethodProxy) {
550613 arguments.GetIsolate()->ThrowError("Internal field 0 of ScriptMethodV8Proxy V8 object has wrong value");
551614 return;
552615 }
553− ScriptMethodV8Proxy *proxy = reinterpret_cast<ScriptMethodV8Proxy*>(arguments.This()->GetAlignedPointerFromInternalField(1));
616+ ScriptMethodV8Proxy *proxy = reinterpret_cast<ScriptMethodV8Proxy*>(data->GetAlignedPointerFromInternalField(1));
554617 proxy->call(arguments);
555618 }
556619
@@ -565,7 +628,7 @@ void ScriptMethodV8Proxy::call(const v8::FunctionCallbackInfo<v8::Value>& argume · 8 unmodified lines
565628 v8::HandleScope handleScope(_engine->getIsolate());
566629
567630 int scriptNumArgs = arguments.Length();
568− int numArgs = std::min(scriptNumArgs, _numMaxParms);
631+ int numArgs = std::min(scriptNumArgs, _numMaxParams);
569632
570633 const int scriptValueTypeId = qMetaTypeId<ScriptValue>();
571634
@@ -739,7 +802,7 @@ void ScriptMethodV8Proxy::call(const v8::FunctionCallbackInfo<v8::Value>& argume · 167 unmodified lines
739802 }
740803
741804 int scriptNumArgs = context->argumentCount();
742− int numArgs = std::min(scriptNumArgs, _numMaxParms);
805+ int numArgs = std::min(scriptNumArgs, _numMaxParams);
743806
744807 const int scriptValueTypeId = qMetaTypeId<ScriptValue>();
745808