diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index c94b24b263..4e8b29e33d 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -867,6 +867,7 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine) QV4::QObjectWrapper::initializeBindings(this); m_delayedCallQueue.init(this); + isInitialized = true; } ExecutionEngine::~ExecutionEngine() @@ -2182,8 +2183,11 @@ const QSet &ExecutionEngine::illegalNames() const void ExecutionEngine::setQmlEngine(QQmlEngine *engine) { + // Second stage of initialization. We're updating some more prototypes here. + isInitialized = false; m_qmlEngine = engine; initQmlGlobalObject(); + isInitialized = true; } static void freeze_recursive(QV4::ExecutionEngine *v4, QV4::Object *object) diff --git a/src/qml/jsruntime/qv4enginebase_p.h b/src/qml/jsruntime/qv4enginebase_p.h index dc69529860..dd85f17717 100644 --- a/src/qml/jsruntime/qv4enginebase_p.h +++ b/src/qml/jsruntime/qv4enginebase_p.h @@ -44,7 +44,8 @@ struct Q_QML_EXPORT EngineBase { #endif quint8 isExecutingInRegExpJIT = false; - quint8 padding[3]; + quint8 isInitialized = false; + quint8 padding[2]; MemoryManager *memoryManager = nullptr; qint32 callDepth = 0; diff --git a/src/qml/jsruntime/qv4lookup.cpp b/src/qml/jsruntime/qv4lookup.cpp index ddd6f0174d..4e41fd60ce 100644 --- a/src/qml/jsruntime/qv4lookup.cpp +++ b/src/qml/jsruntime/qv4lookup.cpp @@ -38,6 +38,9 @@ ReturnedValue Lookup::resolveGetter(ExecutionEngine *engine, const Object *objec ReturnedValue Lookup::resolvePrimitiveGetter(ExecutionEngine *engine, const Value &object) { + // Otherwise we cannot trust the protoIds + Q_ASSERT(engine->isInitialized); + primitiveLookup.type = object.type(); switch (primitiveLookup.type) { case Value::Undefined_Type: @@ -83,6 +86,9 @@ ReturnedValue Lookup::resolvePrimitiveGetter(ExecutionEngine *engine, const Valu ReturnedValue Lookup::resolveGlobalGetter(ExecutionEngine *engine) { + // Otherwise we cannot trust the protoIds + Q_ASSERT(engine->isInitialized); + Object *o = engine->globalObject; PropertyKey name = engine->identifierTable->asPropertyKey(engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]); protoLookup.protoId = o->internalClass()->protoId; @@ -220,6 +226,9 @@ ReturnedValue Lookup::getter0Inline(Lookup *l, ExecutionEngine *engine, const Va ReturnedValue Lookup::getterProto(Lookup *l, ExecutionEngine *engine, const Value &object) { + // Otherwise we cannot trust the protoIds + Q_ASSERT(engine->isInitialized); + // we can safely cast to a QV4::Object here. If object is actually a string, // the internal class won't match Heap::Object *o = static_cast(object.heapObject()); @@ -277,6 +286,9 @@ ReturnedValue Lookup::getter0MemberDatagetter0MemberData(Lookup *l, ExecutionEng ReturnedValue Lookup::getterProtoTwoClasses(Lookup *l, ExecutionEngine *engine, const Value &object) { + // Otherwise we cannot trust the protoIds + Q_ASSERT(engine->isInitialized); + // we can safely cast to a QV4::Object here. If object is actually a string, // the internal class won't match Heap::Object *o = static_cast(object.heapObject()); @@ -312,6 +324,9 @@ ReturnedValue Lookup::getterAccessor(Lookup *l, ExecutionEngine *engine, const V ReturnedValue Lookup::getterProtoAccessor(Lookup *l, ExecutionEngine *engine, const Value &object) { + // Otherwise we cannot trust the protoIds + Q_ASSERT(engine->isInitialized); + // we can safely cast to a QV4::Object here. If object is actually a string, // the internal class won't match Heap::Object *o = static_cast(object.heapObject()); @@ -328,6 +343,9 @@ ReturnedValue Lookup::getterProtoAccessor(Lookup *l, ExecutionEngine *engine, co ReturnedValue Lookup::getterProtoAccessorTwoClasses(Lookup *l, ExecutionEngine *engine, const Value &object) { + // Otherwise we cannot trust the protoIds + Q_ASSERT(engine->isInitialized); + // we can safely cast to a QV4::Object here. If object is actually a string, // the internal class won't match Heap::Object *o = static_cast(object.heapObject()); @@ -381,6 +399,9 @@ ReturnedValue Lookup::getterQObject(Lookup *lookup, ExecutionEngine *engine, con ReturnedValue Lookup::primitiveGetterProto(Lookup *l, ExecutionEngine *engine, const Value &object) { + // Otherwise we cannot trust the protoIds + Q_ASSERT(engine->isInitialized); + if (object.type() == l->primitiveLookup.type && !object.isObject()) { Heap::Object *o = l->primitiveLookup.proto; if (l->primitiveLookup.protoId == o->internalClass->protoId) @@ -392,6 +413,9 @@ ReturnedValue Lookup::primitiveGetterProto(Lookup *l, ExecutionEngine *engine, c ReturnedValue Lookup::primitiveGetterAccessor(Lookup *l, ExecutionEngine *engine, const Value &object) { + // Otherwise we cannot trust the protoIds + Q_ASSERT(engine->isInitialized); + if (object.type() == l->primitiveLookup.type && !object.isObject()) { Heap::Object *o = l->primitiveLookup.proto; if (l->primitiveLookup.protoId == o->internalClass->protoId) { @@ -423,6 +447,9 @@ ReturnedValue Lookup::globalGetterGeneric(Lookup *l, ExecutionEngine *engine) ReturnedValue Lookup::globalGetterProto(Lookup *l, ExecutionEngine *engine) { + // Otherwise we cannot trust the protoIds + Q_ASSERT(engine->isInitialized); + Heap::Object *o = engine->globalObject->d(); if (l->protoLookup.protoId == o->internalClass->protoId) return l->protoLookup.data->asReturnedValue(); @@ -432,6 +459,9 @@ ReturnedValue Lookup::globalGetterProto(Lookup *l, ExecutionEngine *engine) ReturnedValue Lookup::globalGetterProtoAccessor(Lookup *l, ExecutionEngine *engine) { + // Otherwise we cannot trust the protoIds + Q_ASSERT(engine->isInitialized); + Heap::Object *o = engine->globalObject->d(); if (l->protoLookup.protoId == o->internalClass->protoId) { const Value *getter = l->protoLookup.data; @@ -551,6 +581,9 @@ bool Lookup::setter0setter0(Lookup *l, ExecutionEngine *engine, Value &object, c bool Lookup::setterInsert(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value) { + // Otherwise we cannot trust the protoIds + Q_ASSERT(engine->isInitialized); + Object *o = static_cast(object.managed()); if (o && o->internalClass()->protoId == l->insertionLookup.protoId) { o->setInternalClass(l->insertionLookup.newClass); diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp index aec04b167d..ef4a40f4f3 100644 --- a/src/qml/jsruntime/qv4object.cpp +++ b/src/qml/jsruntime/qv4object.cpp @@ -68,7 +68,9 @@ void Object::setInternalClass(Heap::InternalClass *ic) } } - if (ic->isUsedAsProto()) + // Before the engine is done initializing, we cannot have any lookups. + // Therefore, there is no point in updating the proto IDs. + if (ic->engine->isInitialized && ic->isUsedAsProto()) ic->updateProtoUsage(p); } @@ -734,6 +736,9 @@ ReturnedValue Object::virtualInstanceOf(const Object *typeObject, const Value &v ReturnedValue Object::virtualResolveLookupGetter(const Object *object, ExecutionEngine *engine, Lookup *lookup) { + // Otherwise we cannot trust the protoIds + Q_ASSERT(engine->isInitialized); + Heap::Object *obj = object->d(); PropertyKey name = engine->identifierTable->asPropertyKey(engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[lookup->nameIndex]); if (name.isArrayIndex()) { @@ -769,6 +774,9 @@ ReturnedValue Object::virtualResolveLookupGetter(const Object *object, Execution bool Object::virtualResolveLookupSetter(Object *object, ExecutionEngine *engine, Lookup *lookup, const Value &value) { + // Otherwise we cannot trust the protoIds + Q_ASSERT(engine->isInitialized); + Scope scope(engine); ScopedString name(scope, scope.engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[lookup->nameIndex]);