Showing the changes to libraries/script-engine/src/v8/ScriptObjectV8Proxy.cpp (1 of 29 files). Show all
Unified · Split
| @@ -24,12 +24,7 @@ · 23 unmodified lines | ||
| 24 | 24 | #include "ScriptValueV8Wrapper.h" |
| 25 | 25 | #include "ScriptEngineLoggingV8.h" |
| 26 | 26 | |
| 27 | −//V8TODO: is this needed for anything? It could cause trouble with multithreading if V8ScriptContext is v8::Persistent | |
| 28 | −//Q_DECLARE_METATYPE(V8ScriptContext*) | |
| 29 | − | |
| 30 | 27 | Q_DECLARE_METATYPE(ScriptValue) |
| 31 | −//V8TODO: default constructor would be needed | |
| 32 | −//Q_DECLARE_METATYPE(V8ScriptValue) | |
| 33 | 28 | |
| 34 | 29 | Q_DECLARE_METATYPE(QSharedPointer<ScriptObjectV8Proxy>) |
| 35 | 30 | Q_DECLARE_METATYPE(QSharedPointer<ScriptVariantV8Proxy>) |
| @@ -76,7 +71,6 @@ private: // storage · 40 unmodified lines | ||
| 76 | 71 | |
| 77 | 72 | ScriptObjectV8Proxy::ScriptObjectV8Proxy(ScriptEngineV8* engine, QObject* object, bool ownsObject, const ScriptEngine::QObjectWrapOptions& options) : |
| 78 | 73 | _engine(engine), _wrapOptions(options), _ownsObject(ownsObject), _object(object) { |
| 79 | − //_v8ObjectTemplate(engine->getIsolate(), v8::ObjectTemplate::New(engine->getIsolate()) | |
| 80 | 74 | Q_ASSERT(_engine != nullptr); |
| 81 | 75 | investigate(); |
| 82 | 76 | } |
| @@ -90,11 +84,9 @@ V8ScriptValue ScriptObjectV8Proxy::newQObject(ScriptEngineV8* engine, QObject* o · 7 unmodified lines | ||
| 90 | 84 | ScriptEngineV8::ObjectWrapperMap::const_iterator lookup = engine->_qobjectWrapperMap.find(object); |
| 91 | 85 | if (lookup != engine->_qobjectWrapperMap.end()) { |
| 92 | 86 | QSharedPointer<ScriptObjectV8Proxy> proxy = lookup.value().lock(); |
| 93 | − // V8TODO: is conversion to QVariant and back needed? | |
| 94 | 87 | if (proxy) { |
| 95 | 88 | return V8ScriptValue(engine, proxy.get()->toV8Value()); |
| 96 | 89 | } |
| 97 | − //if (proxy) return engine->newObject(proxy.get(), engine->newVariant(QVariant::fromValue(proxy)));; | |
| 98 | 90 | } |
| 99 | 91 | } |
| 100 | 92 | |
| @@ -125,12 +117,10 @@ V8ScriptValue ScriptObjectV8Proxy::newQObject(ScriptEngineV8* engine, QObject* o · 24 unmodified lines | ||
| 125 | 117 | ScriptEngineV8::ObjectWrapperMap::const_iterator lookup = engine->_qobjectWrapperMap.find(object); |
| 126 | 118 | if (lookup != engine->_qobjectWrapperMap.end()) { |
| 127 | 119 | QSharedPointer<ScriptObjectV8Proxy> proxy = lookup.value().lock(); |
| 128 | − //if (proxy) return qengine->newObject(proxy.get(), qengine->newVariant(QVariant::fromValue(proxy)));; | |
| 129 | 120 | if (proxy) { |
| 130 | 121 | return V8ScriptValue(engine, proxy.get()->toV8Value()); |
| 131 | 122 | } |
| 132 | 123 | } |
| 133 | − // V8TODO add a V8 callback that removes pointer for the script engine owned ob from the map so that it gets deleted | |
| 134 | 124 | // register the wrapper with the engine and make sure it cleans itself up |
| 135 | 125 | engine->_qobjectWrapperMap.insert(object, proxy); |
| 136 | 126 | engine->_qobjectWrapperMapV8.insert(object, proxy); |
| @@ -146,13 +136,10 @@ V8ScriptValue ScriptObjectV8Proxy::newQObject(ScriptEngineV8* engine, QObject* o · 9 unmodified lines | ||
| 146 | 136 | if (lookupV8 != enginePtr->_qobjectWrapperMapV8.end()) { |
| 147 | 137 | enginePtr->_qobjectWrapperMapV8.erase(lookupV8); |
| 148 | 138 | } |
| 149 | − //qDebug() << "ScriptObjectV8Proxy::newQObject object deleted, object count: " << enginePtr->_qobjectWrapperMapV8.size(); | |
| 150 | 139 | }); |
| 151 | − //qDebug() << "ScriptObjectV8Proxy::newQObject object count: " << engine->_qobjectWrapperMapV8.size(); | |
| 152 | 140 | } |
| 153 | 141 | |
| 154 | 142 | return V8ScriptValue(engine, proxy.get()->toV8Value()); |
| 155 | − //return qengine->newObject(proxy.get(), qengine->newVariant(QVariant::fromValue(proxy))); | |
| 156 | 143 | } |
| 157 | 144 | |
| 158 | 145 | ScriptObjectV8Proxy* ScriptObjectV8Proxy::unwrapProxy(const V8ScriptValue& val) { |
| @@ -162,20 +149,17 @@ ScriptObjectV8Proxy* ScriptObjectV8Proxy::unwrapProxy(const V8ScriptValue& val) · 3 unmodified lines | ||
| 162 | 149 | v8::HandleScope handleScope(isolate); |
| 163 | 150 | v8::Local<v8::Context> context = val.constGetContext(); |
| 164 | 151 | v8::Context::Scope contextScope(context); |
| 165 | − //V8TODO This shouldn't cause problems but I'm not sure if it's ok | |
| 166 | − //v8::HandleScope handleScope(const_cast<v8::Isolate*>(val.constGetIsolate())); | |
| 167 | 152 | auto v8Value = val.constGet(); |
| 168 | 153 | Q_ASSERT(!v8Value.IsEmpty()); |
| 154 | + | |
| 169 | 155 | if (v8Value->IsNullOrUndefined()) { |
| 170 | 156 | return nullptr; |
| 171 | 157 | } |
| 172 | 158 | if (!v8Value->IsObject()) { |
| 173 | − //qCDebug(scriptengine_v8) << "Cannot unwrap proxy - value is not an object"; | |
| 174 | 159 | return nullptr; |
| 175 | 160 | } |
| 176 | 161 | v8::Local<v8::Object> v8Object = v8::Local<v8::Object>::Cast(v8Value); |
| 177 | 162 | if (v8Object->InternalFieldCount() != 3) { |
| 178 | − //qCDebug(scriptengine_v8) << "Cannot unwrap proxy - wrong number of internal fields"; | |
| 179 | 163 | return nullptr; |
| 180 | 164 | } |
| 181 | 165 | if (v8Object->GetAlignedPointerFromInternalField(0) != internalPointsToQObjectProxy) { |
| @@ -189,20 +173,16 @@ ScriptObjectV8Proxy* ScriptObjectV8Proxy::unwrapProxy(v8::Isolate* isolate, v8:: · 7 unmodified lines | ||
| 189 | 173 | v8::Locker locker(isolate); |
| 190 | 174 | v8::Isolate::Scope isolateScope(isolate); |
| 191 | 175 | v8::HandleScope handleScope(isolate); |
| 192 | − //V8TODO: shouldn't there be context scope here? | |
| 193 | − //v8::Local<v8::Context> context = val.constGetContext(); | |
| 194 | − //v8::Context::Scope contextScope(context); | |
| 176 | + //V8TODO: should there be context scope here? | |
| 177 | + | |
| 195 | 178 | if (value->IsNullOrUndefined()) { |
| 196 | − //qCDebug(scriptengine_v8) << "Cannot unwrap proxy - value is not an object"; | |
| 197 | 179 | return nullptr; |
| 198 | 180 | } |
| 199 | 181 | if (!value->IsObject()) { |
| 200 | − //qCDebug(scriptengine_v8) << "Cannot unwrap proxy - value is not an object"; | |
| 201 | 182 | return nullptr; |
| 202 | 183 | } |
| 203 | 184 | v8::Local<v8::Object> v8Object = v8::Local<v8::Object>::Cast(value); |
| 204 | 185 | if (v8Object->InternalFieldCount() != 3) { |
| 205 | − //qCDebug(scriptengine_v8) << "Cannot unwrap proxy - wrong number of internal fields"; | |
| 206 | 186 | return nullptr; |
| 207 | 187 | } |
| 208 | 188 | if (v8Object->GetAlignedPointerFromInternalField(0) != internalPointsToQObjectProxy) { |
| @@ -257,13 +237,8 @@ void ScriptObjectV8Proxy::investigate() { · 48 unmodified lines | ||
| 257 | 237 | |
| 258 | 238 | const QMetaObject* metaObject = qobject->metaObject(); |
| 259 | 239 | |
| 260 | − //auto objectTemplate = _v8ObjectTemplate.Get(_engine->getIsolate()); | |
| 261 | 240 | auto objectTemplate = _engine->getObjectProxyTemplate(); |
| 262 | − /*auto objectTemplate = v8::ObjectTemplate::New(_engine->getIsolate()); | |
| 263 | − objectTemplate->SetInternalFieldCount(3); | |
| 264 | − objectTemplate->SetHandler(v8::NamedPropertyHandlerConfiguration(v8Get, v8Set, nullptr, nullptr, v8GetPropertyNames));*/ | |
| 265 | 241 | |
| 266 | − //qCDebug(scriptengine_v8) << "Investigate: " << metaObject->className(); | |
| 267 | 242 | if (QString("ConsoleScriptingInterface") == metaObject->className()) { |
| 268 | 243 | printf("ConsoleScriptingInterface"); |
| 269 | 244 | } |
| @@ -274,7 +249,6 @@ void ScriptObjectV8Proxy::investigate() { · 4 unmodified lines | ||
| 274 | 249 | QMetaProperty prop = metaObject->property(idx); |
| 275 | 250 | if (!prop.isScriptable()) continue; |
| 276 | 251 | |
| 277 | − //qCDebug(scriptengine_v8) << "Investigate: " << metaObject->className() << " Property: " << prop.name(); | |
| 278 | 252 | // always exclude child objects (at least until we decide otherwise) |
| 279 | 253 | int metaTypeId = prop.userType(); |
| 280 | 254 | if (metaTypeId != QMetaType::UnknownType) { |
| @@ -284,7 +258,6 @@ void ScriptObjectV8Proxy::investigate() { · 3 unmodified lines | ||
| 284 | 258 | } |
| 285 | 259 | } |
| 286 | 260 | |
| 287 | − //auto v8Name = v8::String::NewFromUtf8(_engine->getIsolate(), prop.name()).ToLocalChecked(); | |
| 288 | 261 | PropertyDef& propDef = _props.insert(idx, PropertyDef(prop.name(), idx)).value(); |
| 289 | 262 | _propNameMap.insert(prop.name(), &propDef); |
| 290 | 263 | propDef.flags = ScriptValue::Undeletable | ScriptValue::PropertyGetter | ScriptValue::PropertySetter | |
| @@ -298,7 +271,6 @@ void ScriptObjectV8Proxy::investigate() { · 7 unmodified lines | ||
| 298 | 271 | QHash<QString, int> methodNames; |
| 299 | 272 | for (int idx = startIdx; idx < num; ++idx) { |
| 300 | 273 | QMetaMethod method = metaObject->method(idx); |
| 301 | − //qCDebug(scriptengine_v8) << "Investigate: " << metaObject->className() << " Method: " << method.name(); | |
| 302 | 274 | |
| 303 | 275 | // perhaps keep this comment? Calls (like AudioScriptingInterface::playSound) seem to expect non-public methods to be script-accessible |
| 304 | 276 | /* if (method.access() != QMetaMethod::Public) continue;*/ |
| @@ -333,9 +305,6 @@ void ScriptObjectV8Proxy::investigate() { · 28 unmodified lines | ||
| 333 | 305 | signalDef.name = szName; |
| 334 | 306 | signalDef.signal = method; |
| 335 | 307 | _signalNameMap.insert(szName, &signalDef); |
| 336 | − //qCDebug(scriptengine_v8) << "Utf8Value 1: " << QString(*v8::String::Utf8Value(const_cast<v8::Isolate*>(_engine->getIsolate()), nameString)); | |
| 337 | − //qCDebug(scriptengine_v8) << "Utf8Value 2: " << QString(*v8::String::Utf8Value(const_cast<v8::Isolate*>(_engine->getIsolate()), name.constGet())); | |
| 338 | − //qCDebug(scriptengine_v8) << "toQString: " << name.toQString(); | |
| 339 | 308 | methodNames.insert(szName, idx); |
| 340 | 309 | } else { |
| 341 | 310 | int originalMethodId = nameLookup.value(); |
| @@ -376,10 +345,6 @@ void ScriptObjectV8Proxy::investigate() { · 34 unmodified lines | ||
| 376 | 345 | } |
| 377 | 346 | |
| 378 | 347 | v8::Local<v8::Object> v8Object = objectTemplate->NewInstance(_engine->getContext()).ToLocalChecked(); |
| 379 | − /*if (QString(metaObject->className()) == QString("TestQObject")) { | |
| 380 | − //qDebug() << "TestQObject investigate: _methods.size: " << _methods.size(); | |
| 381 | − return; | |
| 382 | − }*/ | |
| 383 | 348 | |
| 384 | 349 | v8Object->SetAlignedPointerInInternalField(0, const_cast<void*>(internalPointsToQObjectProxy)); |
| 385 | 350 | v8Object->SetAlignedPointerInInternalField(1, reinterpret_cast<void*>(this)); |
| @@ -406,9 +371,6 @@ void ScriptObjectV8Proxy::investigate() { · 20 unmodified lines | ||
| 406 | 371 | } |
| 407 | 372 | |
| 408 | 373 | void ScriptObjectV8Proxy::weakHandleCallback(const v8::WeakCallbackInfo<ScriptObjectV8Proxy>& info) { |
| 409 | − //V8TODO: does the object need to be moved to script engine thread? | |
| 410 | − //V8TODO: why does this never get called? | |
| 411 | − //qDebug(scriptengine_v8) << "ScriptObjectV8Proxy::weakHandleCallback"; | |
| 412 | 374 | auto proxy = info.GetParameter(); |
| 413 | 375 | proxy->_v8Object.Reset(); |
| 414 | 376 | info.GetParameter()->_object->deleteLater(); |
| @@ -423,41 +385,24 @@ QString ScriptObjectV8Proxy::name() const { · 8 unmodified lines | ||
| 423 | 385 | return _object->metaObject()->className(); |
| 424 | 386 | } |
| 425 | 387 | |
| 426 | −// V8TODO: check if it would be more optimal to use V8ScriptString& name or QString name | |
| 427 | 388 | ScriptObjectV8Proxy::QueryFlags ScriptObjectV8Proxy::queryProperty(const V8ScriptValue& object, const V8ScriptString& name, QueryFlags flags, uint* id) { |
| 428 | 389 | auto isolate = _engine->getIsolate(); |
| 429 | 390 | v8::Locker locker(isolate); |
| 430 | 391 | v8::Isolate::Scope isolateScope(isolate); |
| 431 | 392 | v8::HandleScope handleScope(isolate); |
| 432 | − // V8TODO: this might be inefficient when there's large number of properties | |
| 433 | 393 | v8::Local<v8::Context> context = _engine->getContext(); |
| 434 | 394 | v8::Context::Scope contextScope(context); |
| 435 | 395 | QString nameStr(*v8::String::Utf8Value(isolate, name.constGet())); |
| 436 | 396 | |
| 437 | 397 | // check for methods |
| 438 | − /*for (MethodDefMap::const_iterator trans = _methods.cbegin(); trans != _methods.cend(); ++trans) { | |
| 439 | − v8::String::Utf8Value methodNameStr(isolate, trans.value().name.constGet()); | |
| 440 | − //qCDebug(scriptengine_v8) << "queryProperty : " << *nameStr << " method: " << *methodNameStr; | |
| 441 | − if (!(trans.value().name == name)) continue; | |
| 442 | − *id = trans.key() | METHOD_TYPE; | |
| 443 | − return flags & (HandlesReadAccess | HandlesWriteAccess); | |
| 444 | − }*/ | |
| 445 | 398 | MethodNameMap::const_iterator method = _methodNameMap.find(nameStr); |
| 446 | 399 | if (method != _methodNameMap.cend()) { |
| 447 | − //v8::String::Utf8Value methodNameStr(isolate, trans.value().name.constGet()); | |
| 448 | − //qCDebug(scriptengine_v8) << "queryProperty : " << *nameStr << " method: " << *methodNameStr; | |
| 449 | 400 | const MethodDef* methodDef = method.value(); |
| 450 | 401 | *id = methodDef->_id | METHOD_TYPE; |
| 451 | 402 | return flags & (HandlesReadAccess | HandlesWriteAccess); |
| 452 | 403 | } |
| 453 | 404 | |
| 454 | 405 | // check for properties |
| 455 | − /*for (PropertyDefMap::const_iterator trans = _props.cbegin(); trans != _props.cend(); ++trans) { | |
| 456 | − const PropertyDef& propDef = trans.value(); | |
| 457 | − if (!(propDef.name == name)) continue; | |
| 458 | − *id = trans.key() | PROPERTY_TYPE; | |
| 459 | − return flags & (HandlesReadAccess | HandlesWriteAccess); | |
| 460 | − }*/ | |
| 461 | 406 | PropertyNameMap::const_iterator prop = _propNameMap.find(nameStr); |
| 462 | 407 | if (prop != _propNameMap.cend()) { |
| 463 | 408 | const PropertyDef* propDef = prop.value(); |
| @@ -505,9 +450,7 @@ ScriptValue::PropertyFlags ScriptObjectV8Proxy::propertyFlags(const V8ScriptValu · 41 unmodified lines | ||
| 505 | 450 | |
| 506 | 451 | void ScriptObjectV8Proxy::v8Get(v8::Local<v8::Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) { |
| 507 | 452 | v8::HandleScope handleScope(info.GetIsolate()); |
| 508 | − //V8TODO: should there be a context scope here? | |
| 509 | 453 | v8::String::Utf8Value utf8Value(info.GetIsolate(), name); |
| 510 | − //qCDebug(scriptengine_v8) << "Get: " << *utf8Value; | |
| 511 | 454 | v8::Local<v8::Value> objectV8 = info.This(); |
| 512 | 455 | ScriptObjectV8Proxy *proxy = ScriptObjectV8Proxy::unwrapProxy(info.GetIsolate(), objectV8); |
| 513 | 456 | if (!proxy) { |
| @@ -521,17 +464,7 @@ void ScriptObjectV8Proxy::v8Get(v8::Local<v8::Name> name, const v8::PropertyCall · 7 unmodified lines | ||
| 521 | 464 | Q_ASSERT(false); |
| 522 | 465 | } |
| 523 | 466 | v8::Local<v8::String> v8NameString; |
| 524 | − /*if (name->IsString()) { | |
| 525 | − v8NameString = v8::Local<v8::String>::Cast(name); | |
| 526 | − } else { | |
| 527 | − if (!name->ToString(info.GetIsolate()->GetCurrentContext()).ToLocal(&v8NameString)) { | |
| 528 | − Q_ASSERT(false); | |
| 529 | − } | |
| 530 | − } | |
| 531 | 467 | |
| 532 | − if (name->IsSymbol()) { | |
| 533 | − qCDebug(scriptengine_v8) << "ScriptObjectV8Proxy::v8Set: symbol: " + nameString.toQString(); | |
| 534 | − }*/ | |
| 535 | 468 | if (name->IsString()) { |
| 536 | 469 | V8ScriptString nameString(proxy->_engine, v8::Local<v8::String>::Cast(name)); |
| 537 | 470 | uint id; |
| @@ -553,9 +486,7 @@ void ScriptObjectV8Proxy::v8Get(v8::Local<v8::Name> name, const v8::PropertyCall · 15 unmodified lines | ||
| 553 | 486 | |
| 554 | 487 | void ScriptObjectV8Proxy::v8Set(v8::Local<v8::Name> name, v8::Local<v8::Value> value, const v8::PropertyCallbackInfo<v8::Value>& info) { |
| 555 | 488 | v8::HandleScope handleScope(info.GetIsolate()); |
| 556 | − //V8TODO: should there be a context scope here? | |
| 557 | 489 | v8::String::Utf8Value utf8Value(info.GetIsolate(), name); |
| 558 | − //qCDebug(scriptengine_v8) << "Set: " << *utf8Value; | |
| 559 | 490 | v8::Local<v8::Value> objectV8 = info.This(); |
| 560 | 491 | ScriptObjectV8Proxy *proxy = ScriptObjectV8Proxy::unwrapProxy(info.GetIsolate(), objectV8); |
| 561 | 492 | if (!proxy) { |
| @@ -568,18 +499,7 @@ void ScriptObjectV8Proxy::v8Set(v8::Local<v8::Name> name, v8::Local<v8::Value> v · 6 unmodified lines | ||
| 568 | 499 | qCDebug(scriptengine_v8) << notStringMessage; |
| 569 | 500 | Q_ASSERT(false); |
| 570 | 501 | } |
| 571 | − /*v8::Local<v8::String> v8NameString; | |
| 572 | − if (name->IsString()) { | |
| 573 | − v8NameString = v8::Local<v8::String>::Cast(name); | |
| 574 | − } else { | |
| 575 | − if (!name->ToString(info.GetIsolate()->GetCurrentContext()).ToLocal(&v8NameString)) { | |
| 576 | − Q_ASSERT(false); | |
| 577 | − } | |
| 578 | − } | |
| 579 | − if (name->IsSymbol()) { | |
| 580 | − qCDebug(scriptengine_v8) << "ScriptObjectV8Proxy::v8Set: symbol: " + nameString.toQString(); | |
| 581 | − }*/ | |
| 582 | − //V8ScriptString nameString(info.GetIsolate(), name->ToString(proxy->_engine->getContext()).ToLocalChecked()); | |
| 502 | + | |
| 583 | 503 | if (name->IsString()) { |
| 584 | 504 | V8ScriptString nameString(proxy->_engine, v8::Local<v8::String>::Cast(name)); |
| 585 | 505 | uint id; |
| @@ -590,7 +510,7 @@ void ScriptObjectV8Proxy::v8Set(v8::Local<v8::Name> name, v8::Local<v8::Value> v · 4 unmodified lines | ||
| 590 | 510 | return; |
| 591 | 511 | } |
| 592 | 512 | } |
| 593 | − // V8TODO: Should it be v8::Object or v8::Local<v8::Object>? | |
| 513 | + | |
| 594 | 514 | if (info.This()->GetInternalField(2).As<v8::Object>()->Set(proxy->_engine->getContext(), name, value).FromMaybe(false)) { |
| 595 | 515 | info.GetReturnValue().Set(value); |
| 596 | 516 | } else { |
| @@ -599,7 +519,6 @@ void ScriptObjectV8Proxy::v8Set(v8::Local<v8::Name> name, v8::Local<v8::Value> v · 2 unmodified lines | ||
| 599 | 519 | } |
| 600 | 520 | |
| 601 | 521 | void ScriptObjectV8Proxy::v8GetPropertyNames(const v8::PropertyCallbackInfo<v8::Array>& info) { |
| 602 | − //qCDebug(scriptengine_v8) << "ScriptObjectV8Proxy::v8GetPropertyNames called"; | |
| 603 | 522 | v8::HandleScope handleScope(info.GetIsolate()); |
| 604 | 523 | auto context = info.GetIsolate()->GetCurrentContext(); |
| 605 | 524 | v8::Context::Scope contextScope(context); |
| @@ -610,7 +529,6 @@ void ScriptObjectV8Proxy::v8GetPropertyNames(const v8::PropertyCallbackInfo<v8:: · 4 unmodified lines | ||
| 610 | 529 | return; |
| 611 | 530 | } |
| 612 | 531 | V8ScriptValue object(proxy->_engine, objectV8); |
| 613 | − //uint id; | |
| 614 | 532 | v8::Local<v8::Array> properties = proxy->getPropertyNames(); |
| 615 | 533 | v8::Local<v8::Array> objectProperties; |
| 616 | 534 | uint32_t propertiesLength = properties->Length(); |
| @@ -695,7 +613,6 @@ V8ScriptValue ScriptObjectV8Proxy::property(const V8ScriptValue& object, const V · 78 unmodified lines | ||
| 695 | 613 | qCDebug(scriptengine_v8) << "Method with QMetaType::UnknownType " << metaObject->className() << " " << (*iter).name(); |
| 696 | 614 | } |
| 697 | 615 | } //V8TODO: is new method created during every call? It needs to be cached instead |
| 698 | − //bool isMethodDefined = false; | |
| 699 | 616 | v8::Local<v8::Value> property; |
| 700 | 617 | if(_v8Object.Get(isolate)->GetInternalField(2).As<v8::Object>()->Get(_engine->getContext(), name.constGet()).ToLocal(&property)) { |
| 701 | 618 | if (!property->IsUndefined()) { |
| @@ -725,7 +642,6 @@ V8ScriptValue ScriptObjectV8Proxy::property(const V8ScriptValue& object, const V · 23 unmodified lines | ||
| 725 | 642 | // It's not necessarily new, newQObject looks for it first in object wrapper map |
| 726 | 643 | // V8TODO: won't ScriptEngine::ScriptOwnership cause trouble here? |
| 727 | 644 | return ScriptObjectV8Proxy::newQObject(_engine, proxy, ScriptEngine::ScriptOwnership, options); |
| 728 | − //return _engine->newQObject(proxy, ScriptEngine::ScriptOwnership, options); | |
| 729 | 645 | } |
| 730 | 646 | } |
| 731 | 647 | return V8ScriptValue(_engine, v8::Null(isolate)); |
| @@ -777,8 +693,6 @@ ScriptVariantV8Proxy::ScriptVariantV8Proxy(ScriptEngineV8* engine, const QVarian · 45 unmodified lines | ||
| 777 | 693 | v8::HandleScope handleScope(isolate); |
| 778 | 694 | v8::Context::Scope contextScope(engine->getContext()); |
| 779 | 695 | auto variantDataTemplate = _engine->getVariantDataTemplate(); |
| 780 | − //auto variantDataTemplate = v8::ObjectTemplate::New(isolate); | |
| 781 | − //variantDataTemplate->SetInternalFieldCount(2); | |
| 782 | 696 | auto variantData = variantDataTemplate->NewInstance(engine->getContext()).ToLocalChecked(); |
| 783 | 697 | variantData->SetAlignedPointerInInternalField(0, const_cast<void*>(internalPointsToQVariantInProxy)); |
| 784 | 698 | // 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() { · 8 unmodified lines | ||
| 793 | 707 | v8::Isolate::Scope isolateScope(isolate); |
| 794 | 708 | v8::HandleScope handleScope(isolate); |
| 795 | 709 | // V8TODO: Add similar deletion handling as for object proxy |
| 796 | − //_v8ObjectTemplate.Reset(); | |
| 797 | 710 | _v8Object.Reset(); |
| 798 | 711 | } |
| 799 | 712 | |
| @@ -814,9 +727,6 @@ V8ScriptValue ScriptVariantV8Proxy::newVariant(ScriptEngineV8* engine, const QVa · 14 unmodified lines | ||
| 814 | 727 | auto proxy = new ScriptVariantV8Proxy(engine, variant, proto, protoProxy); |
| 815 | 728 | |
| 816 | 729 | auto variantProxyTemplate = engine->getVariantProxyTemplate(); |
| 817 | − //auto variantProxyTemplate = v8::ObjectTemplate::New(isolate); | |
| 818 | − //variantProxyTemplate->SetInternalFieldCount(2); | |
| 819 | − //variantProxyTemplate->SetHandler(v8::NamedPropertyHandlerConfiguration(v8Get, v8Set, nullptr, nullptr, v8GetPropertyNames)); | |
| 820 | 730 | auto variantProxy = variantProxyTemplate->NewInstance(engine->getContext()).ToLocalChecked(); |
| 821 | 731 | variantProxy->SetAlignedPointerInInternalField(0, const_cast<void*>(internalPointsToQVariantProxy)); |
| 822 | 732 | variantProxy->SetAlignedPointerInInternalField(1, reinterpret_cast<void*>(proxy)); |
| @@ -905,13 +815,6 @@ void ScriptVariantV8Proxy::v8Get(v8::Local<v8::Name> name, const v8::PropertyCal · 82 unmodified lines | ||
| 905 | 815 | } |
| 906 | 816 | |
| 907 | 817 | qCDebug(scriptengine_v8) << "Value not found: " << *utf8Name; |
| 908 | − // V8TODO: this is done differently for variant proxy - use internal field of _v8Object instead? | |
| 909 | − /*v8::Local<v8::Value> property; | |
| 910 | − if(info.This()->GetInternalField(2).As<v8::Object>()->Get(proxy->_engine->getContext(), name).ToLocal(&property)) { | |
| 911 | − info.GetReturnValue().Set(property); | |
| 912 | − } else { | |
| 913 | − qCDebug(scriptengine_v8) << "Value not found: " << *utf8Value; | |
| 914 | − }*/ | |
| 915 | 818 | } |
| 916 | 819 | |
| 917 | 820 | 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> · 23 unmodified lines | ||
| 941 | 844 | return; |
| 942 | 845 | } |
| 943 | 846 | } |
| 944 | − // V8TODO: this is done differently for variant proxy - use internal field of _v8Object instead? | |
| 945 | − /*if (info.This()->GetInternalField(2).As<v8::Object>()->Set(proxy->_engine->getContext(), name, value).FromMaybe(false)) { | |
| 946 | − info.GetReturnValue().Set(value); | |
| 947 | − } else { | |
| 948 | − qCDebug(scriptengine_v8) << "Set failed: " << *utf8Name; | |
| 949 | − }*/ | |
| 950 | 847 | qCDebug(scriptengine_v8) << "Set failed: " << *utf8Name; |
| 951 | 848 | } |
| 952 | 849 | |
| 953 | 850 | void ScriptVariantV8Proxy::v8GetPropertyNames(const v8::PropertyCallbackInfo<v8::Array>& info) { |
| 954 | 851 | //V8TODO: Only methods from the prototype should be listed. |
| 955 | − //qCDebug(scriptengine_v8) << "ScriptObjectV8Proxy::v8GetPropertyNames called"; | |
| 956 | 852 | v8::HandleScope handleScope(info.GetIsolate()); |
| 957 | 853 | auto context = info.GetIsolate()->GetCurrentContext(); |
| 958 | 854 | v8::Context::Scope contextScope(context); |
| @@ -965,15 +861,6 @@ void ScriptVariantV8Proxy::v8GetPropertyNames(const v8::PropertyCallbackInfo<v8: · 6 unmodified lines | ||
| 965 | 861 | V8ScriptValue object(proxy->_engine, objectV8); |
| 966 | 862 | v8::Local<v8::Array> properties = proxy->_proto->getPropertyNames(); |
| 967 | 863 | v8::Local<v8::Array> objectProperties; |
| 968 | − // V8TODO: this is done differently for variant proxy - use internal field of _v8Object instead? | |
| 969 | − /*uint32_t propertiesLength = properties->Length(); | |
| 970 | − if (info.This()->GetInternalField(2).As<v8::Object>()->GetPropertyNames(context).ToLocal(&objectProperties)) { | |
| 971 | − for (uint32_t n = 0; n < objectProperties->Length(); n++) { | |
| 972 | − if(!properties->Set(context, propertiesLength+n, objectProperties->Get(context, n).ToLocalChecked()).FromMaybe(false)) { | |
| 973 | − qCDebug(scriptengine_v8) << "ScriptObjectV8Proxy::v8GetPropertyNames: Cannot add member name"; | |
| 974 | − } | |
| 975 | − } | |
| 976 | − }*/ | |
| 977 | 864 | info.GetReturnValue().Set(properties); |
| 978 | 865 | } |
| 979 | 866 | |
| @@ -996,7 +883,6 @@ ScriptMethodV8Proxy::ScriptMethodV8Proxy(ScriptEngineV8* engine, QObject* object · 16 unmodified lines | ||
| 996 | 883 | } |
| 997 | 884 | |
| 998 | 885 | ScriptMethodV8Proxy::~ScriptMethodV8Proxy() { |
| 999 | − //qCDebug(scriptengine_v8) << "ScriptMethodV8Proxy destroyed"; | |
| 1000 | 886 | auto isolate = _engine->getIsolate(); |
| 1001 | 887 | v8::Locker locker(isolate); |
| 1002 | 888 | v8::Isolate::Scope isolateScope(isolate); |
| @@ -1005,7 +891,6 @@ ScriptMethodV8Proxy::~ScriptMethodV8Proxy() { · 2 unmodified lines | ||
| 1005 | 891 | } |
| 1006 | 892 | |
| 1007 | 893 | void ScriptMethodV8Proxy::weakHandleCallback(const v8::WeakCallbackInfo<ScriptMethodV8Proxy>& info) { |
| 1008 | − //qDebug(scriptengine_v8) << "ScriptMethodV8Proxy::weakHandleCallback"; | |
| 1009 | 894 | auto proxy = info.GetParameter(); |
| 1010 | 895 | proxy->_objectLifetime.Reset(); |
| 1011 | 896 | info.GetParameter()->deleteLater(); |
| @@ -1019,12 +904,8 @@ V8ScriptValue ScriptMethodV8Proxy::newMethod(ScriptEngineV8* engine, QObject* ob · 7 unmodified lines | ||
| 1019 | 904 | v8::HandleScope handleScope(isolate); |
| 1020 | 905 | v8::Context::Scope contextScope(engine->getContext()); |
| 1021 | 906 | auto methodDataTemplate = engine->getMethodDataTemplate(); |
| 1022 | − //auto methodDataTemplate = v8::ObjectTemplate::New(isolate); | |
| 1023 | − //methodDataTemplate->SetInternalFieldCount(2); | |
| 1024 | 907 | auto methodData = methodDataTemplate->NewInstance(engine->getContext()).ToLocalChecked(); |
| 1025 | 908 | methodData->SetAlignedPointerInInternalField(0, const_cast<void*>(internalPointsToMethodProxy)); |
| 1026 | − // V8TODO it needs to be deleted somehow on object destruction | |
| 1027 | − // weak persistent callback would do this | |
| 1028 | 909 | methodData->SetAlignedPointerInInternalField(1, reinterpret_cast<void*>(new ScriptMethodV8Proxy(engine, object, lifetime, metas, numMaxParams))); |
| 1029 | 910 | auto v8Function = v8::Function::New(engine->getContext(), callback, methodData, numMaxParams).ToLocalChecked(); |
| 1030 | 911 | return V8ScriptValue(engine, v8Function); |
| @@ -1042,31 +923,16 @@ QString ScriptMethodV8Proxy::fullName() const { · 11 unmodified lines | ||
| 1042 | 923 | return QString("%1::%2").arg(_object->metaObject()->className(), firstMethod.name()); |
| 1043 | 924 | } |
| 1044 | 925 | |
| 1045 | −// V8TODO | |
| 1046 | −/*bool ScriptMethodV8Proxy::supportsExtension(Extension extension) const { | |
| 1047 | − switch (extension) { | |
| 1048 | − case Callable: | |
| 1049 | − return true; | |
| 1050 | − default: | |
| 1051 | − return false; | |
| 1052 | − } | |
| 1053 | −}*/ | |
| 1054 | − | |
| 1055 | 926 | void ScriptMethodV8Proxy::callback(const v8::FunctionCallbackInfo<v8::Value>& arguments) { |
| 1056 | 927 | v8::Locker locker(arguments.GetIsolate()); |
| 1057 | 928 | v8::Isolate::Scope isolateScope(arguments.GetIsolate()); |
| 1058 | 929 | v8::HandleScope handleScope(arguments.GetIsolate()); |
| 1059 | − //Q_ASSERT(!arguments.GetIsolate()->GetCurrentContext().IsEmpty()); | |
| 1060 | 930 | v8::Context::Scope contextScope(arguments.GetIsolate()->GetCurrentContext()); |
| 1061 | 931 | if (!arguments.Data()->IsObject()) { |
| 1062 | 932 | arguments.GetIsolate()->ThrowError("Method value is not an object"); |
| 1063 | 933 | return; |
| 1064 | 934 | } |
| 1065 | 935 | v8::Local<v8::Object> data = v8::Local<v8::Object>::Cast(arguments.Data()); |
| 1066 | − /*if (!arguments.Data()->IsCallable()) { | |
| 1067 | − arguments.GetIsolate()->ThrowError("Method value is not callable"); | |
| 1068 | − return; | |
| 1069 | − }*/ | |
| 1070 | 936 | if (data->InternalFieldCount() != 2) { |
| 1071 | 937 | arguments.GetIsolate()->ThrowError("Incorrect number of internal fields during method call"); |
| 1072 | 938 | return; |
| @@ -1092,8 +958,6 @@ void ScriptMethodV8Proxy::call(const v8::FunctionCallbackInfo<v8::Value>& argume · 19 unmodified lines | ||
| 1092 | 958 | return; |
| 1093 | 959 | } |
| 1094 | 960 | |
| 1095 | − //v8::HandleScope handleScope(_engine->getIsolate()); | |
| 1096 | − | |
| 1097 | 961 | int scriptNumArgs = arguments.Length(); |
| 1098 | 962 | int numArgs = std::min(scriptNumArgs, _numMaxParams); |
| 1099 | 963 | |
| @@ -1113,7 +977,6 @@ void ScriptMethodV8Proxy::call(const v8::FunctionCallbackInfo<v8::Value>& argume · 13 unmodified lines | ||
| 1113 | 977 | int bestMeta = 0; |
| 1114 | 978 | int bestConversionPenaltyScore = 0; |
| 1115 | 979 | |
| 1116 | − | |
| 1117 | 980 | for (int i = 0; i < num_metas; i++) { |
| 1118 | 981 | const QMetaMethod& meta = _metas[i]; |
| 1119 | 982 | int methodNumArgs = meta.parameterCount(); |
| @@ -1208,16 +1071,6 @@ void ScriptMethodV8Proxy::call(const v8::FunctionCallbackInfo<v8::Value>& argume · 88 unmodified lines | ||
| 1208 | 1071 | return; |
| 1209 | 1072 | } else if (returnTypeId == scriptValueTypeId) { |
| 1210 | 1073 | ScriptValue result; |
| 1211 | − /*if (_metas.front().name() == "createGarbageCollectorDebuggingObject") { | |
| 1212 | − //qDebug() << "createGarbageCollectorDebuggingObject"; | |
| 1213 | − return; | |
| 1214 | − }*/ | |
| 1215 | − /*const char* typeName = meta.typeName(); | |
| 1216 | − QVariant qRetVal(returnTypeId, static_cast<void*>(NULL)); | |
| 1217 | − QGenericReturnArgument sRetVal(typeName, const_cast<void*>(qRetVal.constData())); | |
| 1218 | − bool success = meta.invoke(qobject, Qt::DirectConnection, sRetVal, qGenArgs[0], | |
| 1219 | − qGenArgs[1], qGenArgs[2], qGenArgs[3], qGenArgs[4], qGenArgs[5], qGenArgs[6], | |
| 1220 | − qGenArgs[7], qGenArgs[8], qGenArgs[9]);*/ | |
| 1221 | 1074 | bool success = meta.invoke(qobject, Qt::DirectConnection, Q_RETURN_ARG(ScriptValue, result), qGenArgs[0], |
| 1222 | 1075 | qGenArgs[1], qGenArgs[2], qGenArgs[3], qGenArgs[4], qGenArgs[5], qGenArgs[6], |
| 1223 | 1076 | qGenArgs[7], qGenArgs[8], qGenArgs[9]); |
| @@ -1226,7 +1079,6 @@ void ScriptMethodV8Proxy::call(const v8::FunctionCallbackInfo<v8::Value>& argume · 2 unmodified lines | ||
| 1226 | 1079 | return; |
| 1227 | 1080 | } |
| 1228 | 1081 | V8ScriptValue v8Result = ScriptValueV8Wrapper::fullUnwrap(_engine, result); |
| 1229 | − //V8ScriptValue v8Result = _engine->castVariantToValue(qRetVal); | |
| 1230 | 1082 | arguments.GetReturnValue().Set(v8Result.get()); |
| 1231 | 1083 | return; |
| 1232 | 1084 | } else { |
| @@ -1271,8 +1123,6 @@ void ScriptMethodV8Proxy::call(const v8::FunctionCallbackInfo<v8::Value>& argume · 38 unmodified lines | ||
| 1271 | 1123 | .arg(fullName()).arg(arg+1).arg(argTypeName, methodTypeName); |
| 1272 | 1124 | qCDebug(scriptengine_v8) << errorMessage << "\n Backtrace:" << _engine->currentContext()->backtrace(); |
| 1273 | 1125 | isolate->ThrowError(v8::String::NewFromUtf8(isolate, errorMessage.toStdString().c_str()).ToLocalChecked()); |
| 1274 | − //context->throwError(V8ScriptContext::TypeError, QString("Native call of %1 failed: Cannot convert parameter %2 from %3 to %4") | |
| 1275 | − // .arg(fullName()).arg(arg+1).arg(argTypeName, methodTypeName)); | |
| 1276 | 1126 | return; |
| 1277 | 1127 | } |
| 1278 | 1128 | } |
| @@ -1280,179 +1130,10 @@ void ScriptMethodV8Proxy::call(const v8::FunctionCallbackInfo<v8::Value>& argume · 1 unmodified line | ||
| 1280 | 1130 | QString errorMessage = QString("Native call of %1 failed: could not locate an overload with the requested arguments").arg(fullName()); |
| 1281 | 1131 | qCDebug(scriptengine_v8) << errorMessage; |
| 1282 | 1132 | isolate->ThrowError(v8::String::NewFromUtf8(isolate, errorMessage.toStdString().c_str()).ToLocalChecked()); |
| 1283 | − // V8TODO: it happens sometimes for some reason | |
| 1284 | 1133 | Q_ASSERT(false); // really shouldn't have gotten here -- it didn't work before and it's working now? |
| 1285 | 1134 | return; |
| 1286 | 1135 | } |
| 1287 | 1136 | |
| 1288 | −//V8TODO: was this used anywhere? | |
| 1289 | −/*QVariant ScriptMethodV8Proxy::extension(Extension extension, const QVariant& argument) { | |
| 1290 | − if (extension != Callable) return QVariant(); | |
| 1291 | − V8ScriptContext* context = qvariant_cast<V8ScriptContext*>(argument); | |
| 1292 | − | |
| 1293 | − QObject* qobject = _object; | |
| 1294 | − if (!qobject) { | |
| 1295 | − context->throwError(V8ScriptContext::ReferenceError, "Referencing deleted native object"); | |
| 1296 | − return QVariant(); | |
| 1297 | − } | |
| 1298 | − | |
| 1299 | − int scriptNumArgs = context->argumentCount(); | |
| 1300 | − int numArgs = std::min(scriptNumArgs, _numMaxParams); | |
| 1301 | − | |
| 1302 | − const int scriptValueTypeId = qMetaTypeId<ScriptValue>(); | |
| 1303 | − | |
| 1304 | − int parameterConversionFailureId = 0; | |
| 1305 | − int parameterConversionFailureCount = 0; | |
| 1306 | − | |
| 1307 | − int num_metas = _metas.size(); | |
| 1308 | − QVector< QList<ScriptValue> > qScriptArgLists; | |
| 1309 | − QVector< QVector <QGenericArgument> > qGenArgsVectors; | |
| 1310 | − QVector< QList<QVariant> > qVarArgLists; | |
| 1311 | − qScriptArgLists.resize(num_metas); | |
| 1312 | − qGenArgsVectors.resize(num_metas); | |
| 1313 | − qVarArgLists.resize(num_metas); | |
| 1314 | − bool isValidMetaSelected = false; | |
| 1315 | − int bestMeta = 0; | |
| 1316 | − int bestConversionPenaltyScore = 0; | |
| 1317 | − | |
| 1318 | − for (int i = 0; i < num_metas; i++) { | |
| 1319 | − const QMetaMethod& meta = _metas[i]; | |
| 1320 | − int methodNumArgs = meta.parameterCount(); | |
| 1321 | − if (methodNumArgs != numArgs) { | |
| 1322 | − continue; | |
| 1323 | − } | |
| 1324 | − | |
| 1325 | − qGenArgsVectors[i].resize(10); | |
| 1326 | − int conversionPenaltyScore = 0; | |
| 1327 | − int conversionFailures = 0; | |
| 1328 | − | |
| 1329 | − for (int arg = 0; arg < numArgs; ++arg) { | |
| 1330 | − int methodArgTypeId = meta.parameterType(arg); | |
| 1331 | − Q_ASSERT(methodArgTypeId != QMetaType::UnknownType); | |
| 1332 | − V8ScriptValue argVal = context->argument(arg); | |
| 1333 | − if (methodArgTypeId == scriptValueTypeId) { | |
| 1334 | − qScriptArgLists[i].append(ScriptValue(new ScriptValueV8Wrapper(_engine, argVal))); | |
| 1335 | − qGenArgsVectors[i][arg] = Q_ARG(ScriptValue, qScriptArgLists[i].back()); | |
| 1336 | − } else if (methodArgTypeId == QMetaType::QVariant) { | |
| 1337 | − qVarArgLists[i].append(argVal.toVariant()); | |
| 1338 | − qGenArgsVectors[i][arg] = Q_ARG(QVariant, qVarArgLists[i].back()); | |
| 1339 | − } else { | |
| 1340 | − QVariant varArgVal; | |
| 1341 | − if (!_engine->castValueToVariant(argVal, varArgVal, methodArgTypeId)) { | |
| 1342 | − conversionFailures++; | |
| 1343 | − } else { | |
| 1344 | − qVarArgLists[i].append(varArgVal); | |
| 1345 | − const QVariant& converted = qVarArgLists[i].back(); | |
| 1346 | − conversionPenaltyScore = _engine->computeCastPenalty(argVal, methodArgTypeId); | |
| 1347 | − | |
| 1348 | − // a lot of type conversion assistance thanks to https://stackoverflow.com/questions/28457819/qt-invoke-method-with-qvariant | |
| 1349 | − // A const_cast is needed because calling data() would detach the QVariant. | |
| 1350 | − qGenArgsVectors[i][arg] = | |
| 1351 | − QGenericArgument(QMetaType::typeName(converted.userType()), const_cast<void*>(converted.constData())); | |
| 1352 | − } | |
| 1353 | − } | |
| 1354 | − } | |
| 1355 | − if (conversionFailures) { | |
| 1356 | − if (conversionFailures < parameterConversionFailureCount || !parameterConversionFailureCount) { | |
| 1357 | − parameterConversionFailureCount = conversionFailures; | |
| 1358 | − parameterConversionFailureId = meta.methodIndex(); | |
| 1359 | − } | |
| 1360 | − continue; | |
| 1361 | − } | |
| 1362 | − | |
| 1363 | − if (!isValidMetaSelected) { | |
| 1364 | − isValidMetaSelected = true; | |
| 1365 | − bestMeta = i; | |
| 1366 | − bestConversionPenaltyScore = conversionPenaltyScore; | |
| 1367 | − } | |
| 1368 | − if (isValidMetaSelected && bestConversionPenaltyScore > conversionPenaltyScore) { | |
| 1369 | − bestMeta = i; | |
| 1370 | − bestConversionPenaltyScore = conversionPenaltyScore; | |
| 1371 | − } | |
| 1372 | − } | |
| 1373 | − | |
| 1374 | − if (isValidMetaSelected) { | |
| 1375 | − ScriptContextV8Wrapper ourContext(_engine, context); | |
| 1376 | − ScriptContextGuard guard(&ourContext); | |
| 1377 | − const QMetaMethod& meta = _metas[bestMeta]; | |
| 1378 | − int returnTypeId = meta.returnType(); | |
| 1379 | − QVector <QGenericArgument> &qGenArgs = qGenArgsVectors[bestMeta]; | |
| 1380 | − | |
| 1381 | − // The Qt MOC engine will automatically call qRegisterMetaType on invokable parameters and properties, but there's | |
| 1382 | − // nothing in there for return values so these need to be explicitly runtime-registered! | |
| 1383 | − Q_ASSERT(returnTypeId != QMetaType::UnknownType); | |
| 1384 | − if (returnTypeId == QMetaType::UnknownType) { | |
| 1385 | − _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()); | |
| 1386 | − return QVariant(); | |
| 1387 | − } else if (returnTypeId == QMetaType::Void) { | |
| 1388 | − bool success = meta.invoke(qobject, Qt::DirectConnection, qGenArgs[0], qGenArgs[1], qGenArgs[2], qGenArgs[3], | |
| 1389 | − qGenArgs[4], qGenArgs[5], qGenArgs[6], qGenArgs[7], qGenArgs[8], qGenArgs[9]); | |
| 1390 | − if (!success) { | |
| 1391 | − _engine->getIsolate()->ThrowError(v8::String::NewFromUtf8(_engine->getIsolate(), QString("Unexpected: Native call of %1 failed").arg(fullName()).toStdString().c_str()).ToLocalChecked()); | |
| 1392 | − } | |
| 1393 | − return QVariant(); | |
| 1394 | − } else if (returnTypeId == scriptValueTypeId) { | |
| 1395 | − ScriptValue result; | |
| 1396 | − bool success = meta.invoke(qobject, Qt::DirectConnection, Q_RETURN_ARG(ScriptValue, result), qGenArgs[0], | |
| 1397 | − qGenArgs[1], qGenArgs[2], qGenArgs[3], qGenArgs[4], qGenArgs[5], qGenArgs[6], | |
| 1398 | − qGenArgs[7], qGenArgs[8], qGenArgs[9]); | |
| 1399 | − if (!success) { | |
| 1400 | − _engine->getIsolate()->ThrowError(v8::String::NewFromUtf8(_engine->getIsolate(), QString("Unexpected: Native call of %1 failed").arg(fullName()).toStdString().c_str()).ToLocalChecked()); | |
| 1401 | − return QVariant(); | |
| 1402 | − } | |
| 1403 | − V8ScriptValue qResult = ScriptValueV8Wrapper::fullUnwrap(_engine, result); | |
| 1404 | − return QVariant::fromValue(qResult); | |
| 1405 | − } else { | |
| 1406 | − // a lot of type conversion assistance thanks to https://stackoverflow.com/questions/28457819/qt-invoke-method-with-qvariant | |
| 1407 | − const char* typeName = meta.typeName(); | |
| 1408 | − QVariant qRetVal(returnTypeId, static_cast<void*>(NULL)); | |
| 1409 | − QGenericReturnArgument sRetVal(typeName, const_cast<void*>(qRetVal.constData())); | |
| 1410 | − | |
| 1411 | − bool success = | |
| 1412 | − meta.invoke(qobject, Qt::DirectConnection, sRetVal, qGenArgs[0], qGenArgs[1], qGenArgs[2], qGenArgs[3], | |
| 1413 | − qGenArgs[4], qGenArgs[5], qGenArgs[6], qGenArgs[7], qGenArgs[8], qGenArgs[9]); | |
| 1414 | − if (!success) { | |
| 1415 | − _engine->getIsolate()->ThrowError(v8::String::NewFromUtf8(_engine->getIsolate(), QString("Unexpected: Native call of %1 failed").arg(fullName()).toStdString().c_str()).ToLocalChecked()); | |
| 1416 | − return QVariant(); | |
| 1417 | − } | |
| 1418 | − V8ScriptValue qResult = _engine->castVariantToValue(qRetVal); | |
| 1419 | − return QVariant::fromValue(qResult); | |
| 1420 | − } | |
| 1421 | − } | |
| 1422 | − | |
| 1423 | − // we failed to convert the call to C++, try to create a somewhat sane error message | |
| 1424 | − if (parameterConversionFailureCount == 0) { | |
| 1425 | − _engine->getIsolate()->ThrowError(v8::String::NewFromUtf8(_engine->getIsolate(), QString("Native call of %1 failed: unexpected parameter count").arg(fullName()).toStdString().c_str()).ToLocalChecked()); | |
| 1426 | − return QVariant(); | |
| 1427 | − } | |
| 1428 | − | |
| 1429 | − const QMetaMethod& meta = _object->metaObject()->method(parameterConversionFailureId); | |
| 1430 | − int methodNumArgs = meta.parameterCount(); | |
| 1431 | − Q_ASSERT(methodNumArgs == numArgs); | |
| 1432 | − | |
| 1433 | − for (int arg = 0; arg < numArgs; ++arg) { | |
| 1434 | − int methodArgTypeId = meta.parameterType(arg); | |
| 1435 | − Q_ASSERT(methodArgTypeId != QMetaType::UnknownType); | |
| 1436 | − V8ScriptValue argVal = context->argument(arg); | |
| 1437 | − if (methodArgTypeId != scriptValueTypeId && methodArgTypeId != QMetaType::QVariant) { | |
| 1438 | − QVariant varArgVal; | |
| 1439 | − if (!_engine->castValueToVariant(argVal, varArgVal, methodArgTypeId)) { | |
| 1440 | − QByteArray methodTypeName = QMetaType(methodArgTypeId).name(); | |
| 1441 | − QByteArray argTypeName = _engine->valueType(argVal).toLatin1(); | |
| 1442 | − _engine->getIsolate()->ThrowError(v8::String::NewFromUtf8(_engine->getIsolate(), QString("Native call of %1 failed: Cannot convert parameter %2 from %3 to %4") | |
| 1443 | − .arg(fullName()).arg(arg+1).arg(argTypeName, methodTypeName).toStdString().c_str()).ToLocalChecked()); | |
| 1444 | − context->throwError(V8ScriptContext::TypeError, QString("Native call of %1 failed: Cannot convert parameter %2 from %3 to %4") | |
| 1445 | − .arg(fullName()).arg(arg+1).arg(argTypeName, methodTypeName)); | |
| 1446 | − return QVariant(); | |
| 1447 | − } | |
| 1448 | − } | |
| 1449 | − } | |
| 1450 | − | |
| 1451 | − context->throwError(QString("Native call of %1 failed: could not locate an overload with the requested arguments").arg(fullName())); | |
| 1452 | − Q_ASSERT(false); // really shouldn't have gotten here -- it didn't work before and it's working now? | |
| 1453 | − return QVariant(); | |
| 1454 | −}*/ | |
| 1455 | − | |
| 1456 | 1137 | ScriptSignalV8Proxy::ScriptSignalV8Proxy(ScriptEngineV8* engine, QObject* object, V8ScriptValue lifetime, const QMetaMethod& meta) : |
| 1457 | 1138 | _engine(engine), _object(object), _meta(meta), _metaCallId(discoverMetaCallIdx()) { |
| 1458 | 1139 | auto isolate = _engine->getIsolate(); |
| @@ -1475,7 +1156,6 @@ ScriptSignalV8Proxy::~ScriptSignalV8Proxy() { · 16 unmodified lines | ||
| 1475 | 1156 | } |
| 1476 | 1157 | |
| 1477 | 1158 | void ScriptSignalV8Proxy::weakHandleCallback(const v8::WeakCallbackInfo<ScriptSignalV8Proxy>& info) { |
| 1478 | − //qDebug(scriptengine_v8) << "ScriptSignalV8Proxy::weakHandleCallback"; | |
| 1479 | 1159 | auto proxy = info.GetParameter(); |
| 1480 | 1160 | proxy->_objectLifetime.Reset(); |
| 1481 | 1161 | proxy->deleteLater(); |
| @@ -1512,17 +1192,6 @@ int ScriptSignalV8Proxy::qt_metacall(QMetaObject::Call call, int id, void** argu · 30 unmodified lines | ||
| 1512 | 1192 | v8::Locker locker(isolate); |
| 1513 | 1193 | v8::Isolate::Scope isolateScope(isolate); |
| 1514 | 1194 | |
| 1515 | − //V8ScriptValueList args(isolate, v8::Null(isolate)); | |
| 1516 | − // Moved to inside of the lock - could it cause crashes if left here? | |
| 1517 | − /*v8::Local<v8::Value> args[Q_METAMETHOD_INVOKE_MAX_ARGS]; | |
| 1518 | − int numArgs = _meta.parameterCount(); | |
| 1519 | − for (int arg = 0; arg < numArgs; ++arg) { | |
| 1520 | − int methodArgTypeId = _meta.parameterType(arg); | |
| 1521 | − Q_ASSERT(methodArgTypeId != QMetaType::UnknownType); | |
| 1522 | − QVariant argValue(methodArgTypeId, arguments[arg+1]); | |
| 1523 | − args[arg] = _engine->castVariantToValue(argValue).get(); | |
| 1524 | − }*/ | |
| 1525 | − | |
| 1526 | 1195 | QList<Connection> connections; |
| 1527 | 1196 | withReadLock([&]{ |
| 1528 | 1197 | connections = _connections; |
| @@ -1530,9 +1199,7 @@ int ScriptSignalV8Proxy::qt_metacall(QMetaObject::Call call, int id, void** argu · 1 unmodified line | ||
| 1530 | 1199 | |
| 1531 | 1200 | // V8TODO: this may cause deadlocks on connect/disconnect, so the connect/disconnect procedure needs to be reworked. |
| 1532 | 1201 | // It should probably add events to a separate list that would be processed before and after all the events for the signal. |
| 1533 | − //withReadLock([&]{ | |
| 1534 | 1202 | { |
| 1535 | − // V8TODO: check all other lambda functions to make sure they have handle scope - could they cause crashes otherwise? | |
| 1536 | 1203 | v8::HandleScope handleScope(isolate); |
| 1537 | 1204 | // V8TODO: should we use function creation context, or context in which connect happened? |
| 1538 | 1205 | auto context = _engine->getContext(); |
| @@ -1545,23 +1212,9 @@ int ScriptSignalV8Proxy::qt_metacall(QMetaObject::Call call, int id, void** argu · 6 unmodified lines | ||
| 1545 | 1212 | QVariant argValue(methodArgTypeId, arguments[arg + 1]); |
| 1546 | 1213 | args[arg] = _engine->castVariantToValue(argValue).get(); |
| 1547 | 1214 | } |
| 1548 | − //for (ConnectionList::iterator iter = _connections.begin(); iter != _connections.end(); ++iter) { | |
| 1549 | 1215 | for (ConnectionList::iterator iter = connections.begin(); iter != connections.end(); ++iter) { |
| 1550 | 1216 | Connection& conn = *iter; |
| 1551 | 1217 | { |
| 1552 | − /*if (!conn.callback.get()->IsFunction()) { | |
| 1553 | − auto stringV8 = conn.callback.get()->ToDetailString(context).ToLocalChecked(); | |
| 1554 | − QString error = *v8::String::Utf8Value(_engine->getIsolate(), stringV8); | |
| 1555 | − qCDebug(scriptengine_v8) << error; | |
| 1556 | − Q_ASSERT(false); | |
| 1557 | − } | |
| 1558 | − v8::Local<v8::Function> callback = v8::Local<v8::Function>::Cast(conn.callback.get()); | |
| 1559 | − auto functionContext = callback->CreationContext(); | |
| 1560 | − v8::Context::Scope functionContextScope(functionContext); | |
| 1561 | − _engine->pushContext(functionContext);*/ | |
| 1562 | − /*auto functionContext = _v8Context.Get(_engine->getIsolate()); | |
| 1563 | − _engine->pushContext(functionContext); | |
| 1564 | − v8::Context::Scope functionContextScope(functionContext);*/ | |
| 1565 | 1218 | auto functionContext = context; |
| 1566 | 1219 | |
| 1567 | 1220 | Q_ASSERT(!conn.callback.get().IsEmpty()); |
| @@ -1595,11 +1248,9 @@ int ScriptSignalV8Proxy::qt_metacall(QMetaObject::Call call, int id, void** argu · 27 unmodified lines | ||
| 1595 | 1248 | |
| 1596 | 1249 | _engine->setUncaughtException(tryCatch, "Error in signal proxy"); |
| 1597 | 1250 | } |
| 1598 | − //_engine->popContext(); | |
| 1599 | 1251 | } |
| 1600 | 1252 | } |
| 1601 | 1253 | } |
| 1602 | − //}); | |
| 1603 | 1254 | |
| 1604 | 1255 | #ifdef SCRIPT_EVENT_PERFORMANCE_STATISTICS |
| 1605 | 1256 | _totalCallTime_s += callTimer.elapsed() / 1000.0f; |
| @@ -1630,10 +1281,6 @@ ScriptSignalV8Proxy::ConnectionList::iterator ScriptSignalV8Proxy::findConnectio · 24 unmodified lines | ||
| 1630 | 1281 | return iterOut; |
| 1631 | 1282 | } |
| 1632 | 1283 | |
| 1633 | −/*void ScriptSignalV8Proxy::connect(ScriptValue arg0) { | |
| 1634 | − connect(arg0, ScriptValue(_engine->getIsolate(), v8::Undefined(_engine->getIsolate()))); | |
| 1635 | −}*/ | |
| 1636 | − | |
| 1637 | 1284 | void ScriptSignalV8Proxy::connect(ScriptValue arg0, ScriptValue arg1) { |
| 1638 | 1285 | v8::Isolate *isolate = _engine->getIsolate(); |
| 1639 | 1286 | v8::Locker locker(isolate); |
| @@ -1646,8 +1293,6 @@ void ScriptSignalV8Proxy::connect(ScriptValue arg0, ScriptValue arg1) { · 6 unmodified lines | ||
| 1646 | 1293 | return; |
| 1647 | 1294 | } |
| 1648 | 1295 | |
| 1649 | − //v8::HandleScope handleScope(isolate); | |
| 1650 | − | |
| 1651 | 1296 | // untangle the arguments |
| 1652 | 1297 | V8ScriptValue callback(_engine, v8::Null(isolate)); |
| 1653 | 1298 | V8ScriptValue callbackThis(_engine, v8::Null(isolate)); |
| @@ -1697,15 +1342,12 @@ void ScriptSignalV8Proxy::connect(ScriptValue arg0, ScriptValue arg1) { · 43 unmodified lines | ||
| 1697 | 1342 | ScriptSignalV8Proxy* thisProxy = dynamic_cast<ScriptSignalV8Proxy*>(ScriptObjectV8Proxy::unwrapProxy(v8ThisObject)->toQObject()); |
| 1698 | 1343 | Q_ASSERT(thisProxy); |
| 1699 | 1344 | qCDebug(scriptengine_v8) << "ScriptSignalV8Proxy::connect: " << thisProxy->fullName() << " fullName: " << fullName(); |
| 1700 | − //Q_ASSERT(destFunction->InternalFieldCount() == 4); | |
| 1701 | − //Q_ASSERT(destData.get()->IsArray()); | |
| 1702 | − //v8::Local<v8::Value> destData = destFunction->GetInternalField(3); | |
| 1703 | 1345 | if (!destFunction->Get(destFunctionContext, destDataName).ToLocal(&destData)) { |
| 1704 | 1346 | Q_ASSERT(false); |
| 1705 | 1347 | } |
| 1706 | 1348 | if (destData->IsArray()) { |
| 1707 | 1349 | v8::Local<v8::Array> destArray = v8::Local<v8::Array>::Cast(destData); |
| 1708 | − int length = destArray->Length();//destData.property("length").toInteger(); | |
| 1350 | + int length = destArray->Length(); | |
| 1709 | 1351 | // V8TODO: Maybe copying array is unnecessary? |
| 1710 | 1352 | v8::Local<v8::Array> newArray = v8::Array::New(isolate, length + 1); |
| 1711 | 1353 | bool foundIt = false; |
| @@ -1726,7 +1368,6 @@ void ScriptSignalV8Proxy::connect(ScriptValue arg0, ScriptValue arg1) { · 14 unmodified lines | ||
| 1726 | 1368 | } |
| 1727 | 1369 | } |
| 1728 | 1370 | if (!newArray->Set(destFunctionContext, length, v8ThisObject.get()).FromMaybe(false)) { |
| 1729 | − //if (!newArray->Set(destFunctionContext, length, v8ThisObject.get()).FromMaybe(false)) { | |
| 1730 | 1371 | Q_ASSERT(false); |
| 1731 | 1372 | } |
| 1732 | 1373 | if (!destFunction->Set(destFunctionContext, destDataName, newArray).FromMaybe(false)) { |
| @@ -1741,16 +1382,9 @@ void ScriptSignalV8Proxy::connect(ScriptValue arg0, ScriptValue arg1) { · 8 unmodified lines | ||
| 1741 | 1382 | Q_ASSERT(false); |
| 1742 | 1383 | } |
| 1743 | 1384 | } |
| 1744 | − /*{ | |
| 1745 | − V8ScriptValueList args; | |
| 1746 | − args << thisObject(); | |
| 1747 | − destData.property("push").call(destData, args); | |
| 1748 | − }*/ | |
| 1749 | 1385 | |
| 1750 | 1386 | // add this to our internal list of connections |
| 1751 | 1387 | Connection newConnection(callbackThis, callback); |
| 1752 | − //newConn.callback = callback; | |
| 1753 | − //newConn.thisValue = callbackThis; | |
| 1754 | 1388 | |
| 1755 | 1389 | withWriteLock([&]{ |
| 1756 | 1390 | _connections.append(newConnection); |
| @@ -1764,10 +1398,6 @@ void ScriptSignalV8Proxy::connect(ScriptValue arg0, ScriptValue arg1) { · 7 unmodified lines | ||
| 1764 | 1398 | } |
| 1765 | 1399 | } |
| 1766 | 1400 | |
| 1767 | −/*void ScriptSignalV8Proxy::disconnect(ScriptValue arg0) { | |
| 1768 | − disconnect(arg0, V8ScriptValue(_engine->getIsolate(), v8::Undefined(_engine->getIsolate()))); | |
| 1769 | −}*/ | |
| 1770 | − | |
| 1771 | 1401 | void ScriptSignalV8Proxy::disconnect(ScriptValue arg0, ScriptValue arg1) { |
| 1772 | 1402 | QObject* qobject = _object; |
| 1773 | 1403 | v8::Isolate *isolate = _engine->getIsolate(); |
| @@ -1832,18 +1462,15 @@ void ScriptSignalV8Proxy::disconnect(ScriptValue arg0, ScriptValue arg1) { · 58 unmodified lines | ||
| 1832 | 1462 | ScriptSignalV8Proxy* thisProxy = dynamic_cast<ScriptSignalV8Proxy*>(ScriptObjectV8Proxy::unwrapProxy(v8ThisObject)->toQObject()); |
| 1833 | 1463 | Q_ASSERT(thisProxy); |
| 1834 | 1464 | qCDebug(scriptengine_v8) << "ScriptSignalV8Proxy::disconnect: " << thisProxy->fullName() << " fullName: " << fullName(); |
| 1835 | − //V8ScriptValue destData = callback.data(); | |
| 1836 | − //Q_ASSERT(destData->IsArray()); | |
| 1837 | 1465 | if (!destFunction->Get(destFunctionContext, destDataName).ToLocal(&destData)) { |
| 1838 | 1466 | Q_ASSERT(false); |
| 1839 | 1467 | } |
| 1840 | 1468 | if (destData->IsArray()) { |
| 1841 | 1469 | v8::Local<v8::Array> destArray = v8::Local<v8::Array>::Cast(destData); |
| 1842 | − int length = destArray->Length();//destData.property("length").toInteger(); | |
| 1470 | + int length = destArray->Length(); | |
| 1843 | 1471 | v8::Local<v8::Array> newArray = v8::Array::New(isolate, length - 1); |
| 1844 | 1472 | bool foundIt = false; |
| 1845 | 1473 | int newIndex = 0; |
| 1846 | − //for (int idx = 0; idx < length && !foundIt; ++idx) { | |
| 1847 | 1474 | for (int idx = 0; idx < length; ++idx) { |
| 1848 | 1475 | v8::Local<v8::Value> entry = destArray->Get(destFunctionContext, idx).ToLocalChecked(); |
| 1849 | 1476 | // For debugging: |
| @@ -1863,9 +1490,6 @@ void ScriptSignalV8Proxy::disconnect(ScriptValue arg0, ScriptValue arg1) { · 13 unmodified lines | ||
| 1863 | 1490 | //V8TODO: compare proxies instead? |
| 1864 | 1491 | foundIt = true; |
| 1865 | 1492 | qCDebug(scriptengine_v8) << "ScriptSignalV8Proxy::disconnect foundIt"; |
| 1866 | − //V8ScriptValueList args; | |
| 1867 | − //args << idx << 1; | |
| 1868 | − //destData.property("splice").call(destData, args); | |
| 1869 | 1493 | } else { |
| 1870 | 1494 | if (!newArray->Set(destFunctionContext, newIndex, entry).FromMaybe(false)) { |
| 1871 | 1495 | Q_ASSERT(false); |