V4: Do not update proto usage before engine is fully initialized

Updating the prototype usage is very expensive. We only need to do it
once there are lookups. Before the engine is fully initialized there are
no lookups.

Change-Id: Ic919a1f8955718d417e7747ea72e009d443c42fd
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
This commit is contained in:
Ulf Hermann 2022-08-29 19:11:42 +02:00
parent d183606126
commit 4c3098ab10
4 changed files with 48 additions and 2 deletions

View File

@ -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<QString> &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)

View File

@ -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;

View File

@ -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<Heap::Object *>(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<Heap::Object *>(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<Heap::Object *>(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<Heap::Object *>(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 *>(object.managed());
if (o && o->internalClass()->protoId == l->insertionLookup.protoId) {
o->setInternalClass(l->insertionLookup.newClass);

View File

@ -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]);