From afbb57ae84ecbee5fab9eb6e58356b19d7995ea5 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Mon, 15 May 2017 09:56:05 +0200 Subject: Move the prototype into the internal class This saves another pointer on all Objects. Currently introduces a slight performance regression on some of the v8 benchmarks, that needs addressing. Change-Id: I87de8e1d198d2683f4e903c467ce2a60ba542243 Reviewed-by: Simon Hausmann --- src/qml/jsruntime/qv4context_p.h | 1 + src/qml/jsruntime/qv4engine.cpp | 106 ++++++++++++++++++-------------- src/qml/jsruntime/qv4engine_p.h | 2 + src/qml/jsruntime/qv4enginebase_p.h | 2 + src/qml/jsruntime/qv4errorobject.cpp | 3 +- src/qml/jsruntime/qv4errorobject_p.h | 18 +++--- src/qml/jsruntime/qv4functionobject.cpp | 17 +++-- src/qml/jsruntime/qv4functionobject_p.h | 5 +- src/qml/jsruntime/qv4internalclass.cpp | 53 +++++++++++++++- src/qml/jsruntime/qv4internalclass_p.h | 26 +++++--- src/qml/jsruntime/qv4lookup.cpp | 60 +++++++++--------- src/qml/jsruntime/qv4object.cpp | 15 +++-- src/qml/jsruntime/qv4object_p.h | 4 +- src/qml/jsruntime/qv4stringobject_p.h | 1 + src/qml/jsruntime/qv4typedarray.cpp | 1 + src/qml/memory/qv4mm_p.h | 19 +++--- 16 files changed, 215 insertions(+), 118 deletions(-) (limited to 'src') diff --git a/src/qml/jsruntime/qv4context_p.h b/src/qml/jsruntime/qv4context_p.h index c742df7b97..89ff6dc957 100644 --- a/src/qml/jsruntime/qv4context_p.h +++ b/src/qml/jsruntime/qv4context_p.h @@ -272,6 +272,7 @@ struct Q_QML_EXPORT ExecutionContext : public Managed struct Q_QML_EXPORT CallContext : public ExecutionContext { V4_MANAGED(CallContext, ExecutionContext) + V4_INTERNALCLASS(CallContext) // formals are in reverse order Identifier * const *formals() const; diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index 6b05d9a05c..daab7ad279 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -213,12 +213,12 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) classPool = new InternalClassPool; internalClasses[Class_Empty] = new (classPool) InternalClass(this); - internalClasses[Class_Object] = internalClasses[Class_Empty]->changeVTable(QV4::Object::staticVTable()); internalClasses[Class_String] = internalClasses[EngineBase::Class_Empty]->changeVTable(QV4::String::staticVTable()); internalClasses[Class_MemberData] = internalClasses[EngineBase::Class_Empty]->changeVTable(QV4::MemberData::staticVTable()); internalClasses[Class_SimpleArrayData] = internalClasses[EngineBase::Class_Empty]->changeVTable(QV4::SimpleArrayData::staticVTable()); internalClasses[Class_SparseArrayData] = internalClasses[EngineBase::Class_Empty]->changeVTable(QV4::SparseArrayData::staticVTable()); internalClasses[Class_ExecutionContext] = internalClasses[EngineBase::Class_Empty]->changeVTable(QV4::ExecutionContext::staticVTable()); + internalClasses[Class_CallContext] = internalClasses[EngineBase::Class_Empty]->changeVTable(QV4::CallContext::staticVTable()); jsStrings[String_Empty] = newIdentifier(QString()); jsStrings[String_undefined] = newIdentifier(QStringLiteral("undefined")); @@ -257,15 +257,20 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) jsStrings[String_buffer] = newIdentifier(QStringLiteral("buffer")); jsStrings[String_lastIndex] = newIdentifier(QStringLiteral("lastIndex")); - jsObjects[ObjectProto] = memoryManager->allocObject(internalClasses[Class_Object]); + InternalClass *ic = internalClasses[Class_Empty]->changeVTable(QV4::Object::staticVTable()); + jsObjects[ObjectProto] = memoryManager->allocObject(ic); + internalClasses[Class_Object] = ic->changePrototype(objectPrototype()->d()); - internalClasses[Class_ArrayObject] = internalClasses[Class_Empty]->changeVTable(QV4::ArrayObject::staticVTable()); - internalClasses[Class_ArrayObject] = internalClasses[Class_ArrayObject]->addMember(id_length(), Attr_NotConfigurable|Attr_NotEnumerable); - jsObjects[ArrayProto] = memoryManager->allocObject(internalClasses[Class_ArrayObject], objectPrototype()); + ic = newInternalClass(ArrayPrototype::staticVTable(), objectPrototype()); + Q_ASSERT(ic->prototype); + ic = ic->addMember(id_length(), Attr_NotConfigurable|Attr_NotEnumerable); + Q_ASSERT(ic->prototype); + jsObjects[ArrayProto] = memoryManager->allocObject(ic, objectPrototype()); + internalClasses[Class_ArrayObject] = ic->changePrototype(arrayPrototype()->d()); jsObjects[PropertyListProto] = memoryManager->allocObject(); - InternalClass *argsClass = internalClasses[Class_Empty]->changeVTable(QV4::ArgumentsObject::staticVTable()) - ->addMember(id_length(), Attr_NotEnumerable); + InternalClass *argsClass = newInternalClass(ArgumentsObject::staticVTable(), objectPrototype()); + argsClass = argsClass->addMember(id_length(), Attr_NotEnumerable); internalClasses[EngineBase::Class_ArgumentsObject] = argsClass->addMember(id_callee(), Attr_Data|Attr_NotEnumerable); argsClass = argsClass->addMember(id_callee(), Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable); internalClasses[EngineBase::Class_StrictArgumentsObject] = argsClass->addMember(id_caller(), Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable); @@ -274,25 +279,31 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) Q_ASSERT(globalObject->d()->vtable()); initRootContext(); - internalClasses[Class_StringObject] = internalClasses[Class_Empty]->changeVTable(QV4::StringObject::staticVTable()); - internalClasses[EngineBase::Class_StringObject] = internalClasses[Class_StringObject]->addMember(id_length(), Attr_ReadOnly); + ic = newInternalClass(QV4::StringObject::staticVTable(), objectPrototype()); + ic = ic->addMember(id_length(), Attr_ReadOnly); + jsObjects[StringProto] = memoryManager->allocObject(ic); + internalClasses[Class_StringObject] = ic->changePrototype(stringPrototype()->d()); Q_ASSERT(internalClasses[EngineBase::Class_StringObject]->find(id_length()) == Heap::StringObject::LengthPropertyIndex); - jsObjects[StringProto] = memoryManager->allocObject(internalClasses[EngineBase::Class_StringObject], objectPrototype()); + jsObjects[NumberProto] = memoryManager->allocObject(); jsObjects[BooleanProto] = memoryManager->allocObject(); jsObjects[DateProto] = memoryManager->allocObject(); uint index; - InternalClass *functionProtoClass = - internalClasses[Class_Empty]->changeVTable(QV4::FunctionPrototype::staticVTable()) - ->addMember(id_prototype(), Attr_NotEnumerable, &index); + ic = newInternalClass(QV4::FunctionPrototype::staticVTable(), objectPrototype()); + ic = ic->addMember(id_prototype(), Attr_NotEnumerable, &index); Q_ASSERT(index == Heap::FunctionObject::Index_Prototype); - jsObjects[FunctionProto] = memoryManager->allocObject(functionProtoClass, objectPrototype()); - internalClasses[EngineBase::Class_FunctionObject] = internalClasses[Class_Object]->addMember(id_prototype(), Attr_NotEnumerable|Attr_NotConfigurable, &index); + jsObjects[FunctionProto] = memoryManager->allocObject(ic, objectPrototype()); + ic = newInternalClass(FunctionObject::staticVTable(), functionPrototype()); + ic = ic->addMember(id_prototype(), Attr_NotEnumerable|Attr_NotConfigurable, &index); Q_ASSERT(index == Heap::FunctionObject::Index_Prototype); - internalClasses[EngineBase::Class_ScriptFunction] = internalClasses[EngineBase::Class_FunctionObject]->addMember(id_name(), Attr_ReadOnly, &index); + internalClasses[EngineBase::Class_FunctionObject] = ic; + ic = ic->addMember(id_name(), Attr_ReadOnly, &index); Q_ASSERT(index == Heap::ScriptFunction::Index_Name); - internalClasses[EngineBase::Class_ScriptFunction] = internalClasses[EngineBase::Class_ScriptFunction]->addMember(id_length(), Attr_ReadOnly, &index); + ic = ic->changeVTable(ScriptFunction::staticVTable()); + internalClasses[EngineBase::Class_ScriptFunction] = ic->addMember(id_length(), Attr_ReadOnly, &index); + Q_ASSERT(index == Heap::ScriptFunction::Index_Length); + internalClasses[EngineBase::Class_BuiltinFunction] = ic->changeVTable(BuiltinFunction::staticVTable()); Q_ASSERT(index == Heap::ScriptFunction::Index_Length); internalClasses[EngineBase::Class_ObjectProto] = internalClasses[Class_Object]->addMember(id_constructor(), Attr_NotEnumerable, &index); Q_ASSERT(index == Heap::FunctionObject::Index_ProtoConstructor); @@ -300,59 +311,59 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) Scope scope(this); ScopedString str(scope); internalClasses[Class_RegExp] = internalClasses[EngineBase::Class_Empty]->changeVTable(QV4::RegExp::staticVTable()); - internalClasses[EngineBase::Class_RegExpObject] = - internalClasses[Class_Empty]->changeVTable(QV4::RegExpObject::staticVTable()) - ->addMember(id_lastIndex(), Attr_NotEnumerable|Attr_NotConfigurable, &index); + ic = newInternalClass(QV4::RegExpObject::staticVTable(), objectPrototype()); + ic = ic->addMember(id_lastIndex(), Attr_NotEnumerable|Attr_NotConfigurable, &index); Q_ASSERT(index == RegExpObject::Index_LastIndex); - internalClasses[EngineBase::Class_RegExpObject] = internalClasses[EngineBase::Class_RegExpObject]->addMember((str = newIdentifier(QStringLiteral("source"))), Attr_ReadOnly, &index); + ic = ic->addMember((str = newIdentifier(QStringLiteral("source"))), Attr_ReadOnly, &index); Q_ASSERT(index == RegExpObject::Index_Source); - internalClasses[EngineBase::Class_RegExpObject] = internalClasses[EngineBase::Class_RegExpObject]->addMember((str = newIdentifier(QStringLiteral("global"))), Attr_ReadOnly, &index); + ic = ic->addMember((str = newIdentifier(QStringLiteral("global"))), Attr_ReadOnly, &index); Q_ASSERT(index == RegExpObject::Index_Global); - internalClasses[EngineBase::Class_RegExpObject] = internalClasses[EngineBase::Class_RegExpObject]->addMember((str = newIdentifier(QStringLiteral("ignoreCase"))), Attr_ReadOnly, &index); + ic = ic->addMember((str = newIdentifier(QStringLiteral("ignoreCase"))), Attr_ReadOnly, &index); Q_ASSERT(index == RegExpObject::Index_IgnoreCase); - internalClasses[EngineBase::Class_RegExpObject] = internalClasses[EngineBase::Class_RegExpObject]->addMember((str = newIdentifier(QStringLiteral("multiline"))), Attr_ReadOnly, &index); + ic = ic->addMember((str = newIdentifier(QStringLiteral("multiline"))), Attr_ReadOnly, &index); Q_ASSERT(index == RegExpObject::Index_Multiline); + jsObjects[RegExpProto] = memoryManager->allocObject(ic, objectPrototype()); + internalClasses[Class_RegExpObject] = ic->changePrototype(regExpPrototype()->d()); - jsObjects[RegExpProto] = memoryManager->allocObject(internalClasses[EngineBase::Class_RegExpObject], objectPrototype()); - internalClasses[EngineBase::Class_RegExpExecArray] = internalClasses[Class_ArrayObject]->addMember(id_index(), Attr_Data, &index); + ic = internalClasses[Class_ArrayObject]->addMember(id_index(), Attr_Data, &index); Q_ASSERT(index == RegExpObject::Index_ArrayIndex); - internalClasses[EngineBase::Class_RegExpExecArray] = internalClasses[EngineBase::Class_RegExpExecArray]->addMember(id_input(), Attr_Data, &index); + internalClasses[EngineBase::Class_RegExpExecArray] = ic->addMember(id_input(), Attr_Data, &index); Q_ASSERT(index == RegExpObject::Index_ArrayInput); - internalClasses[EngineBase::Class_ErrorObject] = - internalClasses[Class_Empty]->changeVTable(QV4::ErrorObject::staticVTable()) - ->addMember((str = newIdentifier(QStringLiteral("stack"))), Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable, &index); + ic = newInternalClass(ErrorObject::staticVTable(), 0); + ic = ic->addMember((str = newIdentifier(QStringLiteral("stack"))), Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable, &index); Q_ASSERT(index == ErrorObject::Index_Stack); - internalClasses[EngineBase::Class_ErrorObject] = internalClasses[EngineBase::Class_ErrorObject]->addMember((str = newIdentifier(QStringLiteral("fileName"))), Attr_Data|Attr_NotEnumerable, &index); + ic = ic->addMember((str = newIdentifier(QStringLiteral("fileName"))), Attr_Data|Attr_NotEnumerable, &index); Q_ASSERT(index == ErrorObject::Index_FileName); - internalClasses[EngineBase::Class_ErrorObject] = internalClasses[EngineBase::Class_ErrorObject]->addMember((str = newIdentifier(QStringLiteral("lineNumber"))), Attr_Data|Attr_NotEnumerable, &index); + ic = ic->addMember((str = newIdentifier(QStringLiteral("lineNumber"))), Attr_Data|Attr_NotEnumerable, &index); + internalClasses[EngineBase::Class_ErrorObject] = ic; Q_ASSERT(index == ErrorObject::Index_LineNumber); - internalClasses[EngineBase::Class_ErrorObjectWithMessage] = internalClasses[EngineBase::Class_ErrorObject]->addMember((str = newIdentifier(QStringLiteral("message"))), Attr_Data|Attr_NotEnumerable, &index); + internalClasses[EngineBase::Class_ErrorObjectWithMessage] = ic->addMember((str = newIdentifier(QStringLiteral("message"))), Attr_Data|Attr_NotEnumerable, &index); Q_ASSERT(index == ErrorObject::Index_Message); - internalClasses[EngineBase::Class_ErrorProto] = - internalClasses[Class_Empty]->changeVTable(QV4::ErrorPrototype::staticVTable()) - ->addMember(id_constructor(), Attr_Data|Attr_NotEnumerable, &index); + ic = newInternalClass(ErrorObject::staticVTable(), objectPrototype()); + ic = ic->addMember(id_constructor(), Attr_Data|Attr_NotEnumerable, &index); Q_ASSERT(index == ErrorPrototype::Index_Constructor); - internalClasses[EngineBase::Class_ErrorProto] = internalClasses[EngineBase::Class_ErrorProto]->addMember((str = newIdentifier(QStringLiteral("message"))), Attr_Data|Attr_NotEnumerable, &index); + ic = ic->addMember((str = newIdentifier(QStringLiteral("message"))), Attr_Data|Attr_NotEnumerable, &index); Q_ASSERT(index == ErrorPrototype::Index_Message); - internalClasses[EngineBase::Class_ErrorProto] = internalClasses[EngineBase::Class_ErrorProto]->addMember(id_name(), Attr_Data|Attr_NotEnumerable, &index); + internalClasses[EngineBase::Class_ErrorProto] = ic->addMember(id_name(), Attr_Data|Attr_NotEnumerable, &index); Q_ASSERT(index == ErrorPrototype::Index_Name); jsObjects[GetStack_Function] = BuiltinFunction::create(rootContext(), str = newIdentifier(QStringLiteral("stack")), ErrorObject::method_get_stack); getStackFunction()->defineReadonlyProperty(id_length(), Primitive::fromInt32(0)); jsObjects[ErrorProto] = memoryManager->allocObject(internalClasses[EngineBase::Class_ErrorProto], objectPrototype()); - jsObjects[EvalErrorProto] = memoryManager->allocObject(internalClasses[EngineBase::Class_ErrorProto], errorPrototype()); - jsObjects[RangeErrorProto] = memoryManager->allocObject(internalClasses[EngineBase::Class_ErrorProto], errorPrototype()); - jsObjects[ReferenceErrorProto] = memoryManager->allocObject(internalClasses[EngineBase::Class_ErrorProto], errorPrototype()); - jsObjects[SyntaxErrorProto] = memoryManager->allocObject(internalClasses[EngineBase::Class_ErrorProto], errorPrototype()); - jsObjects[TypeErrorProto] = memoryManager->allocObject(internalClasses[EngineBase::Class_ErrorProto], errorPrototype()); - jsObjects[URIErrorProto] = memoryManager->allocObject(internalClasses[EngineBase::Class_ErrorProto], errorPrototype()); + jsObjects[EvalErrorProto] = memoryManager->allocObject(internalClasses[EngineBase::Class_ErrorProto]->changePrototype(errorPrototype()->d()), errorPrototype()); + jsObjects[RangeErrorProto] = memoryManager->allocObject(internalClasses[EngineBase::Class_ErrorProto]->changePrototype(errorPrototype()->d()), errorPrototype()); + jsObjects[ReferenceErrorProto] = memoryManager->allocObject(internalClasses[EngineBase::Class_ErrorProto]->changePrototype(errorPrototype()->d()), errorPrototype()); + jsObjects[SyntaxErrorProto] = memoryManager->allocObject(internalClasses[EngineBase::Class_ErrorProto]->changePrototype(errorPrototype()->d()), errorPrototype()); + jsObjects[TypeErrorProto] = memoryManager->allocObject(internalClasses[EngineBase::Class_ErrorProto]->changePrototype(errorPrototype()->d()), errorPrototype()); + jsObjects[URIErrorProto] = memoryManager->allocObject(internalClasses[EngineBase::Class_ErrorProto]->changePrototype(errorPrototype()->d()), errorPrototype()); jsObjects[VariantProto] = memoryManager->allocObject(); Q_ASSERT(variantPrototype()->prototype() == objectPrototype()->d()); - jsObjects[SequenceProto] = ScopedValue(scope, memoryManager->allocObject()); + ic = newInternalClass(SequencePrototype::staticVTable(), SequencePrototype::defaultPrototype(this)); + jsObjects[SequenceProto] = ScopedValue(scope, memoryManager->allocObject(ic, SequencePrototype::defaultPrototype(this))); ExecutionContext *global = rootContext(); jsObjects[Object_Ctor] = memoryManager->allocObject(global); @@ -538,6 +549,11 @@ ExecutionContext *ExecutionEngine::pushGlobalContext() return currentContext; } +InternalClass *ExecutionEngine::newInternalClass(const VTable *vtable, Object *prototype) +{ + return internalClasses[EngineBase::Class_Empty]->changeVTable(vtable)->changePrototype(prototype ? prototype->d() : 0); +} + Heap::Object *ExecutionEngine::newObject() { return memoryManager->allocObject(); diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h index 1d07196c28..a569b8ddf9 100644 --- a/src/qml/jsruntime/qv4engine_p.h +++ b/src/qml/jsruntime/qv4engine_p.h @@ -366,6 +366,8 @@ public: void popContext(); ExecutionContext *parentContext(ExecutionContext *context) const; + InternalClass *newInternalClass(const VTable *vtable, Object *prototype); + Heap::Object *newObject(); Heap::Object *newObject(InternalClass *internalClass, Object *prototype); diff --git a/src/qml/jsruntime/qv4enginebase_p.h b/src/qml/jsruntime/qv4enginebase_p.h index e124adb810..06c346b3c0 100644 --- a/src/qml/jsruntime/qv4enginebase_p.h +++ b/src/qml/jsruntime/qv4enginebase_p.h @@ -88,11 +88,13 @@ struct EngineBase { Class_SimpleArrayData, Class_SparseArrayData, Class_ExecutionContext, + Class_CallContext, Class_Object, Class_ArrayObject, Class_FunctionObject, Class_StringObject, Class_ScriptFunction, + Class_BuiltinFunction, Class_ObjectProto, Class_RegExp, Class_RegExpObject, diff --git a/src/qml/jsruntime/qv4errorobject.cpp b/src/qml/jsruntime/qv4errorobject.cpp index 65507e2251..6811438915 100644 --- a/src/qml/jsruntime/qv4errorobject.cpp +++ b/src/qml/jsruntime/qv4errorobject.cpp @@ -328,8 +328,7 @@ void ErrorPrototype::init(ExecutionEngine *engine, Object *ctor, Object *obj, He *obj->propertyData(Index_Constructor) = ctor; *obj->propertyData(Index_Message) = engine->id_empty(); *obj->propertyData(Index_Name) = engine->newString(QString::fromLatin1(ErrorObject::className(t))); - if (t == Heap::ErrorObject::Error) - obj->defineDefaultProperty(engine->id_toString(), method_toString, 0); + obj->defineDefaultProperty(engine->id_toString(), method_toString, 0); } void ErrorPrototype::method_toString(const BuiltinFunction *, Scope &scope, CallData *callData) diff --git a/src/qml/jsruntime/qv4errorobject_p.h b/src/qml/jsruntime/qv4errorobject_p.h index 34e4b4a682..12531c9309 100644 --- a/src/qml/jsruntime/qv4errorobject_p.h +++ b/src/qml/jsruntime/qv4errorobject_p.h @@ -326,25 +326,25 @@ inline SyntaxErrorObject *ErrorObject::asSyntaxError() template Heap::Object *ErrorObject::create(ExecutionEngine *e, const Value &message) { - return e->memoryManager->allocObject( - e->internalClasses[message.isUndefined() ? EngineBase::Class_ErrorObject : EngineBase::Class_ErrorObjectWithMessage], - T::defaultPrototype(e), message); + InternalClass *ic = e->internalClasses[message.isUndefined() ? EngineBase::Class_ErrorObject : EngineBase::Class_ErrorObjectWithMessage]; + ic = ic->changePrototype(T::defaultPrototype(e)->d()); + return e->memoryManager->allocObject(ic, T::defaultPrototype(e), message); } template Heap::Object *ErrorObject::create(ExecutionEngine *e, const QString &message) { Scope scope(e); ScopedValue v(scope, message.isEmpty() ? Encode::undefined() : e->newString(message)->asReturnedValue()); - return e->memoryManager->allocObject( - e->internalClasses[v->isUndefined() ? EngineBase::Class_ErrorObject : EngineBase::Class_ErrorObjectWithMessage], - T::defaultPrototype(e), v); + InternalClass *ic = e->internalClasses[v->isUndefined() ? EngineBase::Class_ErrorObject : EngineBase::Class_ErrorObjectWithMessage]; + ic = ic->changePrototype(T::defaultPrototype(e)->d()); + return e->memoryManager->allocObject(ic, T::defaultPrototype(e), v); } template Heap::Object *ErrorObject::create(ExecutionEngine *e, const QString &message, const QString &filename, int line, int column) { Scope scope(e); ScopedValue v(scope, message.isEmpty() ? Encode::undefined() : e->newString(message)->asReturnedValue()); - return e->memoryManager->allocObject( - e->internalClasses[v->isUndefined() ? EngineBase::Class_ErrorObject : EngineBase::Class_ErrorObjectWithMessage], - T::defaultPrototype(e), v, filename, line, column); + InternalClass *ic = e->internalClasses[v->isUndefined() ? EngineBase::Class_ErrorObject : EngineBase::Class_ErrorObjectWithMessage]; + ic = ic->changePrototype(T::defaultPrototype(e)->d()); + return e->memoryManager->allocObject(ic, T::defaultPrototype(e), v, filename, line, column); } diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp index 86362fa0cb..4be14c09ba 100644 --- a/src/qml/jsruntime/qv4functionobject.cpp +++ b/src/qml/jsruntime/qv4functionobject.cpp @@ -375,8 +375,8 @@ void ScriptFunction::construct(const Managed *that, Scope &scope, CallData *call Scoped f(scope, static_cast(that)); - InternalClass *ic = v4->internalClasses[EngineBase::Class_Object]; - ScopedObject proto(scope, f->protoForConstructor()); + InternalClass *ic = f->classForConstructor(); + ScopedObject proto(scope, ic->prototype); ScopedObject obj(scope, v4->newObject(ic, proto)); callData->thisObject = obj.asReturnedValue(); @@ -444,12 +444,19 @@ void Heap::ScriptFunction::init(QV4::ExecutionContext *scope, Function *function } } -Heap::Object *ScriptFunction::protoForConstructor() const +InternalClass *ScriptFunction::classForConstructor() const { const Object *o = d()->protoProperty(); + InternalClass *ic = d()->cachedClassForConstructor; + if (ic && ic->prototype == o->d()) + return ic; + + ic = engine()->internalClasses[EngineBase::Class_Object]; if (o) - return o->d(); - return engine()->objectPrototype()->d(); + ic = ic->changePrototype(o->d()); + d()->cachedClassForConstructor = ic; + + return ic; } diff --git a/src/qml/jsruntime/qv4functionobject_p.h b/src/qml/jsruntime/qv4functionobject_p.h index bfaa1ae056..354f6b2e3f 100644 --- a/src/qml/jsruntime/qv4functionobject_p.h +++ b/src/qml/jsruntime/qv4functionobject_p.h @@ -117,6 +117,8 @@ struct ScriptFunction : FunctionObject { Index_Length }; void init(QV4::ExecutionContext *scope, Function *function); + + QV4::InternalClass *cachedClassForConstructor; }; struct BoundFunction : FunctionObject { @@ -199,6 +201,7 @@ struct Q_QML_EXPORT OldBuiltinFunction : FunctionObject { struct Q_QML_EXPORT BuiltinFunction : FunctionObject { V4_OBJECT2(BuiltinFunction, FunctionObject) + V4_INTERNALCLASS(BuiltinFunction) static Heap::OldBuiltinFunction *create(ExecutionContext *scope, String *name, ReturnedValue (*code)(CallContext *)) { @@ -241,7 +244,7 @@ struct ScriptFunction : FunctionObject { static void construct(const Managed *, Scope &scope, CallData *callData); static void call(const Managed *that, Scope &scope, CallData *callData); - Heap::Object *protoForConstructor() const; + InternalClass *classForConstructor() const; }; diff --git a/src/qml/jsruntime/qv4internalclass.cpp b/src/qml/jsruntime/qv4internalclass.cpp index 9a4087485f..600198567a 100644 --- a/src/qml/jsruntime/qv4internalclass.cpp +++ b/src/qml/jsruntime/qv4internalclass.cpp @@ -106,6 +106,7 @@ void PropertyHash::addEntry(const PropertyHash::Entry &entry, int classSize) InternalClass::InternalClass(ExecutionEngine *engine) : engine(engine) , vtable(0) + , prototype(0) , m_sealed(0) , m_frozen(0) , size(0) @@ -118,6 +119,7 @@ InternalClass::InternalClass(const QV4::InternalClass &other) : QQmlJS::Managed() , engine(other.engine) , vtable(other.vtable) + , prototype(other.prototype) , propertyTable(other.propertyTable) , nameMap(other.nameMap) , propertyData(other.propertyData) @@ -223,6 +225,7 @@ InternalClass *InternalClass::changeMember(Identifier *identifier, PropertyAttri // create a new class and add it to the tree InternalClass *newClass = engine->internalClasses[EngineBase::Class_Empty]->changeVTable(vtable); + newClass = newClass->changePrototype(prototype); for (uint i = 0; i < size; ++i) { if (i == idx) { newClass = newClass->addMember(nameMap.at(i), data); @@ -236,6 +239,35 @@ InternalClass *InternalClass::changeMember(Identifier *identifier, PropertyAttri return newClass; } +InternalClass *InternalClass::changePrototypeImpl(Heap::Object *proto) +{ + Q_ASSERT(prototype != proto); + + Transition temp = { { nullptr }, 0, Transition::PrototypeChange }; + temp.prototype = proto; + + Transition &t = lookupOrInsertTransition(temp); + if (t.lookup) + return t.lookup; + + // create a new class and add it to the tree + InternalClass *newClass; + if (!size && !prototype) { + newClass = engine->newClass(*this); + newClass->prototype = proto; + } else { + newClass = engine->internalClasses[EngineBase::Class_Empty]->changeVTable(vtable); + newClass = newClass->changePrototype(proto); + for (uint i = 0; i < size; ++i) { + if (!propertyData.at(i).isEmpty()) + newClass = newClass->addMember(nameMap.at(i), propertyData.at(i)); + } + } + + t.lookup = newClass; + return newClass; +} + InternalClass *InternalClass::changeVTableImpl(const VTable *vt) { Q_ASSERT(vtable != vt); @@ -366,6 +398,7 @@ void InternalClass::removeMember(Object *object, Identifier *id) } else { // create a new class and add it to the tree InternalClass *newClass = oldClass->engine->internalClasses[EngineBase::Class_Empty]->changeVTable(oldClass->vtable); + newClass = newClass->changePrototype(oldClass->prototype); for (uint i = 0; i < oldClass->size; ++i) { if (i == propIdx) continue; @@ -411,6 +444,7 @@ InternalClass *InternalClass::sealed() return m_sealed; m_sealed = engine->internalClasses[EngineBase::Class_Empty]->changeVTable(vtable); + m_sealed = m_sealed->changePrototype(prototype); for (uint i = 0; i < size; ++i) { PropertyAttributes attrs = propertyData.at(i); if (attrs.isEmpty()) @@ -440,6 +474,7 @@ InternalClass *InternalClass::frozen() InternalClass *InternalClass::propertiesFrozen() const { InternalClass *frozen = engine->internalClasses[EngineBase::Class_Empty]->changeVTable(vtable); + frozen = frozen->changePrototype(prototype); for (uint i = 0; i < size; ++i) { PropertyAttributes attrs = propertyData.at(i); if (attrs.isEmpty()) @@ -480,9 +515,25 @@ void InternalClass::destroy() } } +void InternalClass::mark(ExecutionEngine *e) +{ + if (m_sealed) + m_sealed->mark(e); + if (m_frozen) + m_frozen->mark(e); + + for (size_t i = 0; i < transitions.size(); ++i) { + Q_ASSERT(transitions.at(i).lookup); + transitions.at(i).lookup->mark(e); + } + if (prototype) + prototype->mark(engine); +} + void InternalClassPool::markObjects(ExecutionEngine *engine) { - Q_UNUSED(engine); + InternalClass *ic = engine->internalClasses[EngineBase::Class_Empty]; + ic->mark(engine); } QT_END_NAMESPACE diff --git a/src/qml/jsruntime/qv4internalclass_p.h b/src/qml/jsruntime/qv4internalclass_p.h index 3c4e0838d9..031f66793b 100644 --- a/src/qml/jsruntime/qv4internalclass_p.h +++ b/src/qml/jsruntime/qv4internalclass_p.h @@ -223,6 +223,7 @@ struct InternalClassTransition union { Identifier *id; const VTable *vtable; + Heap::Object *prototype; }; InternalClass *lookup; int flags; @@ -230,6 +231,7 @@ struct InternalClassTransition // range 0-0xff is reserved for attribute changes NotExtensible = 0x100, VTableChange = 0x200, + PrototypeChange = 0x201 }; bool operator==(const InternalClassTransition &other) const @@ -242,6 +244,7 @@ struct InternalClassTransition struct InternalClass : public QQmlJS::Managed { ExecutionEngine *engine; const VTable *vtable; + Heap::Object *prototype; PropertyHash propertyTable; // id to valueIndex SharedInternalClassData nameMap; @@ -257,30 +260,37 @@ struct InternalClass : public QQmlJS::Managed { uint size; bool extensible; - InternalClass *nonExtensible(); - InternalClass *changeVTable(const VTable *vt) { + Q_REQUIRED_RESULT InternalClass *nonExtensible(); + Q_REQUIRED_RESULT InternalClass *changeVTable(const VTable *vt) { if (vtable == vt) return this; return changeVTableImpl(vt); } + Q_REQUIRED_RESULT InternalClass *changePrototype(Heap::Object *proto) { + if (prototype == proto) + return this; + return changePrototypeImpl(proto); + } static void addMember(Object *object, String *string, PropertyAttributes data, uint *index); - InternalClass *addMember(String *string, PropertyAttributes data, uint *index = 0); - InternalClass *addMember(Identifier *identifier, PropertyAttributes data, uint *index = 0); - InternalClass *changeMember(Identifier *identifier, PropertyAttributes data, uint *index = 0); + Q_REQUIRED_RESULT InternalClass *addMember(String *string, PropertyAttributes data, uint *index = 0); + Q_REQUIRED_RESULT InternalClass *addMember(Identifier *identifier, PropertyAttributes data, uint *index = 0); + Q_REQUIRED_RESULT InternalClass *changeMember(Identifier *identifier, PropertyAttributes data, uint *index = 0); static void changeMember(Object *object, String *string, PropertyAttributes data, uint *index = 0); static void removeMember(Object *object, Identifier *id); uint find(const String *string); uint find(const Identifier *id); - InternalClass *sealed(); - InternalClass *frozen(); - InternalClass *propertiesFrozen() const; + Q_REQUIRED_RESULT InternalClass *sealed(); + Q_REQUIRED_RESULT InternalClass *frozen(); + Q_REQUIRED_RESULT InternalClass *propertiesFrozen() const; void destroy(); + void mark(ExecutionEngine *e); private: Q_QML_EXPORT InternalClass *changeVTableImpl(const VTable *vt); + Q_QML_EXPORT InternalClass *changePrototypeImpl(Heap::Object *proto); InternalClass *addMemberImpl(Identifier *identifier, PropertyAttributes data, uint *index); friend struct ExecutionEngine; InternalClass(ExecutionEngine *engine); diff --git a/src/qml/jsruntime/qv4lookup.cpp b/src/qml/jsruntime/qv4lookup.cpp index f8ac0cb650..25fa670115 100644 --- a/src/qml/jsruntime/qv4lookup.cpp +++ b/src/qml/jsruntime/qv4lookup.cpp @@ -63,7 +63,7 @@ ReturnedValue Lookup::lookup(const Value &thisObject, Object *o, PropertyAttribu return !attrs->isAccessor() ? v->asReturnedValue() : Object::getValue(thisObject, *v, *attrs); } - obj = obj->prototype; + obj = obj->prototype(); ++i; } level = Size; @@ -76,7 +76,7 @@ ReturnedValue Lookup::lookup(const Value &thisObject, Object *o, PropertyAttribu return !attrs->isAccessor() ? v->asReturnedValue() : Object::getValue(thisObject, *v, *attrs); } - obj = obj->prototype; + obj = obj->prototype(); } return Primitive::emptyValue().asReturnedValue(); } @@ -98,7 +98,7 @@ ReturnedValue Lookup::lookup(const Object *thisObject, PropertyAttributes *attrs return !attrs->isAccessor() ? v->asReturnedValue() : thisObject->getValue(*v, *attrs); } - obj = obj->prototype; + obj = obj->prototype(); ++i; } level = Size; @@ -111,7 +111,7 @@ ReturnedValue Lookup::lookup(const Object *thisObject, PropertyAttributes *attrs return !attrs->isAccessor() ? v->asReturnedValue() : thisObject->getValue(*v, *attrs); } - obj = obj->prototype; + obj = obj->prototype(); } return Primitive::emptyValue().asReturnedValue(); } @@ -402,8 +402,8 @@ ReturnedValue Lookup::getter1(Lookup *l, ExecutionEngine *engine, const Value &o // the internal class won't match Heap::Object *o = static_cast(object.heapObject()); if (o) { - if (l->classList[0] == o->internalClass && l->classList[1] == o->prototype->internalClass) - return o->prototype->propertyData(l->index)->asReturnedValue(); + if (l->classList[0] == o->internalClass && l->classList[1] == o->prototype()->internalClass) + return o->prototype()->propertyData(l->index)->asReturnedValue(); } return getterTwoClasses(l, engine, object); } @@ -415,9 +415,9 @@ ReturnedValue Lookup::getter2(Lookup *l, ExecutionEngine *engine, const Value &o Heap::Object *o = static_cast(object.heapObject()); if (o) { if (l->classList[0] == o->internalClass) { - Heap::Object *p = o->prototype; + Heap::Object *p = o->prototype(); if (l->classList[1] == p->internalClass) { - p = p->prototype; + p = p->prototype(); if (l->classList[2] == p->internalClass) return p->propertyData(l->index)->asReturnedValue(); } @@ -480,8 +480,8 @@ ReturnedValue Lookup::getter0Inlinegetter1(Lookup *l, ExecutionEngine *engine, c if (o) { if (l->classList[0] == o->internalClass) return o->inlinePropertyData(l->index)->asReturnedValue(); - if (l->classList[2] == o->internalClass && l->classList[3] == o->prototype->internalClass) - return o->prototype->propertyData(l->index2)->asReturnedValue(); + if (l->classList[2] == o->internalClass && l->classList[3] == o->prototype()->internalClass) + return o->prototype()->propertyData(l->index2)->asReturnedValue(); } l->getter = getterFallback; return getterFallback(l, engine, object); @@ -495,8 +495,8 @@ ReturnedValue Lookup::getter0MemberDatagetter1(Lookup *l, ExecutionEngine *engin if (o) { if (l->classList[0] == o->internalClass) return o->memberData->data[l->index].asReturnedValue(); - if (l->classList[2] == o->internalClass && l->classList[3] == o->prototype->internalClass) - return o->prototype->propertyData(l->index2)->asReturnedValue(); + if (l->classList[2] == o->internalClass && l->classList[3] == o->prototype()->internalClass) + return o->prototype()->propertyData(l->index2)->asReturnedValue(); } l->getter = getterFallback; return getterFallback(l, engine, object); @@ -509,11 +509,11 @@ ReturnedValue Lookup::getter1getter1(Lookup *l, ExecutionEngine *engine, const V Heap::Object *o = static_cast(object.heapObject()); if (o) { if (l->classList[0] == o->internalClass && - l->classList[1] == o->prototype->internalClass) - return o->prototype->propertyData(l->index)->asReturnedValue(); + l->classList[1] == o->prototype()->internalClass) + return o->prototype()->propertyData(l->index)->asReturnedValue(); if (l->classList[2] == o->internalClass && - l->classList[3] == o->prototype->internalClass) - return o->prototype->propertyData(l->index2)->asReturnedValue(); + l->classList[3] == o->prototype()->internalClass) + return o->prototype()->propertyData(l->index2)->asReturnedValue(); return getterFallback(l, engine, object); } l->getter = getterFallback; @@ -550,9 +550,9 @@ ReturnedValue Lookup::getterAccessor1(Lookup *l, ExecutionEngine *engine, const Heap::Object *o = static_cast(object.heapObject()); if (o) { if (l->classList[0] == o->internalClass && - l->classList[1] == o->prototype->internalClass) { + l->classList[1] == o->prototype()->internalClass) { Scope scope(o->internalClass->engine); - ScopedFunctionObject getter(scope, o->prototype->propertyData(l->index + Object::GetterOffset)); + ScopedFunctionObject getter(scope, o->prototype()->propertyData(l->index + Object::GetterOffset)); if (!getter) return Encode::undefined(); @@ -573,9 +573,9 @@ ReturnedValue Lookup::getterAccessor2(Lookup *l, ExecutionEngine *engine, const Heap::Object *o = static_cast(object.heapObject()); if (o) { if (l->classList[0] == o->internalClass) { - o = o->prototype; + o = o->prototype(); if (l->classList[1] == o->internalClass) { - o = o->prototype; + o = o->prototype(); if (l->classList[2] == o->internalClass) { Scope scope(o->internalClass->engine); ScopedFunctionObject getter(scope, o->propertyData(l->index + Object::GetterOffset)); @@ -621,8 +621,8 @@ ReturnedValue Lookup::primitiveGetter1(Lookup *l, ExecutionEngine *engine, const if (object.type() == l->type) { Heap::Object *o = l->proto; if (l->classList[0] == o->internalClass && - l->classList[1] == o->prototype->internalClass) - return o->prototype->propertyData(l->index)->asReturnedValue(); + l->classList[1] == o->prototype()->internalClass) + return o->prototype()->propertyData(l->index)->asReturnedValue(); } l->getter = getterGeneric; return getterGeneric(l, engine, object); @@ -653,9 +653,9 @@ ReturnedValue Lookup::primitiveGetterAccessor1(Lookup *l, ExecutionEngine *engin if (object.type() == l->type) { Heap::Object *o = l->proto; if (l->classList[0] == o->internalClass && - l->classList[1] == o->prototype->internalClass) { + l->classList[1] == o->prototype()->internalClass) { Scope scope(o->internalClass->engine); - ScopedFunctionObject getter(scope, o->prototype->propertyData(l->index + Object::GetterOffset)); + ScopedFunctionObject getter(scope, o->prototype()->propertyData(l->index + Object::GetterOffset)); if (!getter) return Encode::undefined(); @@ -758,11 +758,11 @@ ReturnedValue Lookup::globalGetter2(Lookup *l, ExecutionEngine *engine) { Heap::Object *o = engine->globalObject->d(); if (l->classList[0] == o->internalClass) { - o = o->prototype; + o = o->prototype(); if (l->classList[1] == o->internalClass) { - o = o->prototype; + o = o->prototype(); if (l->classList[2] == o->internalClass) { - return o->prototype->propertyData(l->index)->asReturnedValue(); + return o->prototype()->propertyData(l->index)->asReturnedValue(); } } } @@ -811,9 +811,9 @@ ReturnedValue Lookup::globalGetterAccessor2(Lookup *l, ExecutionEngine *engine) { Heap::Object *o = engine->globalObject->d(); if (l->classList[0] == o->internalClass) { - o = o->prototype; + o = o->prototype(); if (l->classList[1] == o->internalClass) { - o = o->prototype; + o = o->prototype(); if (l->classList[2] == o->internalClass) { Scope scope(o->internalClass->engine); ScopedFunctionObject getter(scope, o->propertyData(l->index + Object::GetterOffset)); @@ -934,7 +934,7 @@ void Lookup::setterInsert2(Lookup *l, ExecutionEngine *engine, Value &object, co if (o && o->internalClass() == l->classList[0]) { Heap::Object *p = o->prototype(); if (p && p->internalClass == l->classList[1]) { - p = p->prototype; + p = p->prototype(); if (p && p->internalClass == l->classList[2]) { o->setInternalClass(l->classList[3]); *o->propertyData(l->index) = value; diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp index 838ae96c59..4abe508e10 100644 --- a/src/qml/jsruntime/qv4object.cpp +++ b/src/qml/jsruntime/qv4object.cpp @@ -88,13 +88,14 @@ void Object::setProperty(uint index, const Property *p) bool Object::setPrototype(Object *proto) { - Heap::Object *pp = proto ? proto->d() : 0; + Heap::Object *p = proto ? proto->d() : 0; + Heap::Object *pp = p; while (pp) { if (pp == d()) return false; - pp = pp->prototype; + pp = pp->prototype(); } - d()->prototype = proto ? proto->d() : 0; + setInternalClass(internalClass()->changePrototype(p)); return true; } @@ -264,8 +265,6 @@ void Object::markObjects(Heap::Base *that, ExecutionEngine *e) o->memberData->mark(e); if (o->arrayData) o->arrayData->mark(e); - if (o->prototype) - o->prototype->mark(e); uint nInline = o->vtable()->nInlineProperties; Value *v = reinterpret_cast(o) + o->vtable()->inlinePropertyOffset; const Value *end = v + nInline; @@ -345,7 +344,7 @@ Value *Object::getValueOrSetter(String *name, PropertyAttributes *attrs) return o->propertyData(attrs->isAccessor() ? idx + SetterOffset : idx); } - o = o->prototype; + o = o->prototype(); } *attrs = Attr_Invalid; return 0; @@ -368,7 +367,7 @@ Value *Object::getValueOrSetter(uint index, PropertyAttributes *attrs) return reinterpret_cast(0x1); } } - o = o->prototype; + o = o->prototype(); } *attrs = Attr_Invalid; return 0; @@ -1204,7 +1203,7 @@ ReturnedValue Object::instanceOf(const Object *typeObject, const Value &var) // 15.3.5.3, 4 while (v) { // 15.3.5.3, 4, a - v = v->prototype; + v = v->prototype(); // 15.3.5.3, 4, b if (!v) diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h index 951659a4bc..cf04a84175 100644 --- a/src/qml/jsruntime/qv4object_p.h +++ b/src/qml/jsruntime/qv4object_p.h @@ -95,7 +95,7 @@ struct Object : Base { return memberData->data + index; } - Pointer prototype; + Heap::Object *prototype() const { return internalClass->prototype; } Pointer memberData; Pointer arrayData; }; @@ -215,7 +215,7 @@ struct Q_QML_EXPORT Object: Managed { void setProperty(uint index, const Property *p); const ObjectVTable *vtable() const { return reinterpret_cast(d()->vtable()); } - Heap::Object *prototype() const { return d()->prototype; } + Heap::Object *prototype() const { return d()->prototype(); } bool setPrototype(Object *proto); void getOwnProperty(String *name, PropertyAttributes *attrs, Property *p = 0); diff --git a/src/qml/jsruntime/qv4stringobject_p.h b/src/qml/jsruntime/qv4stringobject_p.h index b8fb80546f..2e64364f9f 100644 --- a/src/qml/jsruntime/qv4stringobject_p.h +++ b/src/qml/jsruntime/qv4stringobject_p.h @@ -109,6 +109,7 @@ struct StringCtor: FunctionObject struct StringPrototype: StringObject { + V4_PROTOTYPE(objectPrototype) void init(ExecutionEngine *engine, Object *ctor); static void method_toString(const BuiltinFunction *, Scope &scope, CallData *callData); diff --git a/src/qml/jsruntime/qv4typedarray.cpp b/src/qml/jsruntime/qv4typedarray.cpp index bb28a7683c..80655aded6 100644 --- a/src/qml/jsruntime/qv4typedarray.cpp +++ b/src/qml/jsruntime/qv4typedarray.cpp @@ -373,6 +373,7 @@ void Heap::TypedArray::init(Type t) Heap::TypedArray *TypedArray::create(ExecutionEngine *e, Heap::TypedArray::Type t) { QV4::InternalClass *ic = e->internalClasses[EngineBase::Class_Empty]->changeVTable(staticVTable()); + ic = ic->changePrototype(e->typedArrayPrototype[t].d()); return e->memoryManager->allocObject(ic, e->typedArrayPrototype + t, t); } diff --git a/src/qml/memory/qv4mm_p.h b/src/qml/memory/qv4mm_p.h index 8f12fa7cbd..69d3eeb93c 100644 --- a/src/qml/memory/qv4mm_p.h +++ b/src/qml/memory/qv4mm_p.h @@ -247,11 +247,11 @@ public: { InternalClass *ic = ObjectType::defaultInternalClass(engine); ic = ic->changeVTable(ObjectType::staticVTable()); + ic = ic->changePrototype(ObjectType::defaultPrototype(engine)->d()); Heap::Object *o = allocObjectWithMemberData(ObjectType::staticVTable(), ic->size); - Object *prototype = ObjectType::defaultPrototype(engine); o->internalClass = ic; Q_ASSERT(o->internalClass && o->internalClass->vtable); - o->prototype = prototype->d(); + Q_ASSERT(o->internalClass->prototype == ObjectType::defaultPrototype(engine)->d()); return static_cast(o); } @@ -279,7 +279,8 @@ public: { Scope scope(engine); Scoped t(scope, allocateObject(ic)); - t->d_unchecked()->prototype = prototype->d(); + Q_ASSERT(t->internalClass()->prototype == (prototype ? prototype->d() : 0)); + Q_UNUSED(prototype); t->d_unchecked()->init(); return t->d(); } @@ -289,7 +290,8 @@ public: { Scope scope(engine); Scoped t(scope, allocateObject(ic)); - t->d_unchecked()->prototype = prototype->d(); + Q_ASSERT(t->internalClass()->prototype == (prototype ? prototype->d() : 0)); + Q_UNUSED(prototype); t->d_unchecked()->init(arg1); return t->d(); } @@ -299,7 +301,8 @@ public: { Scope scope(engine); Scoped t(scope, allocateObject(ic)); - t->d_unchecked()->prototype = prototype->d(); + Q_ASSERT(t->internalClass()->prototype == (prototype ? prototype->d() : 0)); + Q_UNUSED(prototype); t->d_unchecked()->init(arg1, arg2); return t->d(); } @@ -309,7 +312,8 @@ public: { Scope scope(engine); Scoped t(scope, allocateObject(ic)); - t->d_unchecked()->prototype = prototype->d(); + Q_ASSERT(t->internalClass()->prototype == (prototype ? prototype->d() : 0)); + Q_UNUSED(prototype); t->d_unchecked()->init(arg1, arg2, arg3); return t->d(); } @@ -319,7 +323,8 @@ public: { Scope scope(engine); Scoped t(scope, allocateObject(ic)); - t->d_unchecked()->prototype = prototype->d(); + Q_ASSERT(t->internalClass()->prototype == (prototype ? prototype->d() : 0)); + Q_UNUSED(prototype); t->d_unchecked()->init(arg1, arg2, arg3, arg4); return t->d(); } -- cgit v1.2.3