From 6002b48c3c5edc509c269c801fc8a088d5065ce8 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Fri, 5 Jan 2018 15:30:23 +0100 Subject: garbage collect InternalClass Internal classes are now allocated and collected through the GC. As they are important to the deletion of other objects (because of the vtable pointer living inside the internal class), they need to get destroyed after regular objects have been sweeped. Achieve this by using a separate block allocator for internal class objects. Our lookups do often contain pointers to internal classes, so those need to be marked as well, so we don't accidentally collect them. Change-Id: I4762b054361c70c31f79f920f669ea0e8551601f Reviewed-by: Simon Hausmann --- .../qmldbg_debugger/qv4datacollector.cpp | 2 +- .../qqmlnativedebugservice.cpp | 2 +- src/qml/compiler/qv4compileddata.cpp | 36 +++- src/qml/compiler/qv4compileddata_p.h | 5 +- src/qml/jsruntime/qv4engine.cpp | 67 +++--- src/qml/jsruntime/qv4engine_p.h | 8 +- src/qml/jsruntime/qv4enginebase_p.h | 4 +- src/qml/jsruntime/qv4errorobject_p.h | 16 +- src/qml/jsruntime/qv4function.cpp | 10 +- src/qml/jsruntime/qv4function_p.h | 2 +- src/qml/jsruntime/qv4functionobject.cpp | 17 +- src/qml/jsruntime/qv4functionobject_p.h | 10 +- src/qml/jsruntime/qv4global_p.h | 1 + src/qml/jsruntime/qv4internalclass.cpp | 226 ++++++++++++--------- src/qml/jsruntime/qv4internalclass_p.h | 64 +++--- src/qml/jsruntime/qv4lookup.cpp | 52 ++++- src/qml/jsruntime/qv4lookup_p.h | 10 +- src/qml/jsruntime/qv4managed.cpp | 5 + src/qml/jsruntime/qv4managed_p.h | 37 +++- src/qml/jsruntime/qv4object.cpp | 17 +- src/qml/jsruntime/qv4object_p.h | 2 +- src/qml/jsruntime/qv4runtime.cpp | 10 +- src/qml/jsruntime/qv4string.cpp | 1 + src/qml/jsruntime/qv4typedarray.cpp | 6 +- src/qml/memory/qv4heap_p.h | 5 +- src/qml/memory/qv4mm.cpp | 15 +- src/qml/memory/qv4mm_p.h | 54 +++-- src/qml/qml/v8/qv8engine.cpp | 2 +- 28 files changed, 431 insertions(+), 255 deletions(-) (limited to 'src') diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp index c86f3d1803..25ae29d8d9 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp @@ -269,7 +269,7 @@ bool QV4DataCollector::collectScope(QJsonObject *dict, int frameNr, int scopeNr) Refs collectedRefs; QV4::ScopedValue v(scope); - QV4::InternalClass *ic = ctxt->internalClass(); + QV4::Heap::InternalClass *ic = ctxt->internalClass(); for (uint i = 0; i < ic->size; ++i) { QString name = ic->nameMap[i]->string; names.append(name); diff --git a/src/plugins/qmltooling/qmldbg_nativedebugger/qqmlnativedebugservice.cpp b/src/plugins/qmltooling/qmldbg_nativedebugger/qqmlnativedebugservice.cpp index e17fe92983..6db82e9f52 100644 --- a/src/plugins/qmltooling/qmldbg_nativedebugger/qqmlnativedebugservice.cpp +++ b/src/plugins/qmltooling/qmldbg_nativedebugger/qqmlnativedebugservice.cpp @@ -491,7 +491,7 @@ void NativeDebugger::handleVariables(QJsonObject *response, const QJsonObject &a collector.collect(&output, QString(), QStringLiteral("this"), thisObject); QV4::Scoped callContext(scope, frame->callContext()); if (callContext) { - QV4::InternalClass *ic = callContext->internalClass(); + QV4::Heap::InternalClass *ic = callContext->internalClass(); QV4::ScopedValue v(scope); for (uint i = 0; i < ic->size; ++i) { QString name = ic->nameMap[i]->string; diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp index a149d84646..005263e582 100644 --- a/src/qml/compiler/qv4compileddata.cpp +++ b/src/qml/compiler/qv4compileddata.cpp @@ -96,8 +96,9 @@ static QString cacheFilePath(const QUrl &url) #endif CompilationUnit::CompilationUnit(const Unit *unitData) - : data(unitData) -{} +{ + data = unitData; +} #ifndef V4_BOOTSTRAP CompilationUnit::~CompilationUnit() @@ -157,15 +158,15 @@ QV4::Function *CompilationUnit::linkToEngine(ExecutionEngine *engine) } if (data->jsClassTableSize) { - runtimeClasses = (QV4::InternalClass**)malloc(data->jsClassTableSize * sizeof(QV4::InternalClass*)); + runtimeClasses = (QV4::Heap::InternalClass **)malloc(data->jsClassTableSize * sizeof(QV4::Heap::InternalClass *)); + // memset the regexps to 0 in case a GC run happens while we're within the loop below + memset(runtimeClasses, 0, data->jsClassTableSize * sizeof(QV4::Heap::InternalClass *)); for (uint i = 0; i < data->jsClassTableSize; ++i) { int memberCount = 0; const CompiledData::JSClassMember *member = data->jsClassAt(i, &memberCount); - QV4::InternalClass *klass = engine->internalClasses(QV4::ExecutionEngine::Class_Object); + runtimeClasses[i] = engine->internalClasses(QV4::ExecutionEngine::Class_Object); for (int j = 0; j < memberCount; ++j, ++member) - klass = klass->addMember(engine->identifierTable->identifier(runtimeStrings[member->nameOffset]), member->isAccessor ? QV4::Attr_Accessor : QV4::Attr_Data); - - runtimeClasses[i] = klass; + runtimeClasses[i] = runtimeClasses[i]->addMember(engine->identifierTable->identifier(runtimeStrings[member->nameOffset]), member->isAccessor ? QV4::Attr_Accessor : QV4::Attr_Data); } } @@ -244,13 +245,28 @@ void CompilationUnit::unlink() void CompilationUnit::markObjects(QV4::MarkStack *markStack) { - for (uint i = 0; i < data->stringTableSize; ++i) - if (runtimeStrings[i]) - runtimeStrings[i]->mark(markStack); + if (runtimeStrings) { + for (uint i = 0; i < data->stringTableSize; ++i) + if (runtimeStrings[i]) + runtimeStrings[i]->mark(markStack); + } if (runtimeRegularExpressions) { for (uint i = 0; i < data->regexpTableSize; ++i) runtimeRegularExpressions[i].mark(markStack); } + if (runtimeClasses) { + for (uint i = 0; i < data->jsClassTableSize; ++i) + if (runtimeClasses[i]) + runtimeClasses[i]->mark(markStack); + } + for (QV4::Function *f : qAsConst(runtimeFunctions)) + if (f && f->internalClass) + f->internalClass->mark(markStack); + + if (runtimeLookups) { + for (uint i = 0; i < data->lookupTableSize; ++i) + runtimeLookups[i].markObjects(markStack); + } } IdentifierHash CompilationUnit::namedObjectsPerComponent(int componentObjectIndex) diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h index 1df9d6794f..66707456cd 100644 --- a/src/qml/compiler/qv4compileddata_p.h +++ b/src/qml/compiler/qv4compileddata_p.h @@ -881,6 +881,8 @@ struct Q_QML_PRIVATE_EXPORT CompilationUnitBase QV4::Heap::String **runtimeStrings = nullptr; // Array const Value* constants = nullptr; QV4::Value *runtimeRegularExpressions = nullptr; + const Unit *data = nullptr; + QV4::Heap::InternalClass **runtimeClasses = nullptr; }; Q_STATIC_ASSERT(std::is_standard_layout::value); @@ -915,8 +917,6 @@ public: return refCount.load(); } - const Unit *data = nullptr; - // Called only when building QML, when we build the header for JS first and append QML data QV4::CompiledData::Unit *createUnitData(QmlIR::Document *irDocument); @@ -943,7 +943,6 @@ public: } QV4::Lookup *runtimeLookups = nullptr; - QV4::InternalClass **runtimeClasses = nullptr; QVector runtimeFunctions; mutable QQmlNullableValue m_url; mutable QQmlNullableValue m_finalUrl; diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index 69ac329c4e..7964a97cc4 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -199,7 +199,10 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine) identifierTable = new IdentifierTable(this); - classes[Class_Empty] = new InternalClass(this); + memset(classes, 0, sizeof(classes)); + classes[Class_Empty] = memoryManager->allocIC(); + classes[Class_Empty]->init(this); + classes[Class_String] = classes[Class_Empty]->changeVTable(QV4::String::staticVTable()); classes[Class_MemberData] = classes[Class_Empty]->changeVTable(QV4::MemberData::staticVTable()); classes[Class_SimpleArrayData] = classes[Class_Empty]->changeVTable(QV4::SimpleArrayData::staticVTable()); @@ -246,20 +249,23 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine) jsStrings[String_buffer] = newIdentifier(QStringLiteral("buffer")); jsStrings[String_lastIndex] = newIdentifier(QStringLiteral("lastIndex")); - InternalClass *ic = classes[Class_Empty]->changeVTable(QV4::Object::staticVTable()); - jsObjects[ObjectProto] = memoryManager->allocObject(ic); + Scope scope(this); + Scoped ic(scope); + ic = classes[Class_Empty]->changeVTable(QV4::Object::staticVTable()); + jsObjects[ObjectProto] = memoryManager->allocObject(ic->d()); classes[Class_Object] = ic->changePrototype(objectPrototype()->d()); classes[EngineBase::Class_QmlContextWrapper] = classes[Class_Object]->changeVTable(QV4::QQmlContextWrapper::staticVTable()); ic = newInternalClass(ArrayPrototype::staticVTable(), objectPrototype()); - Q_ASSERT(ic->prototype); + Q_ASSERT(ic->d()->prototype); ic = ic->addMember(id_length(), Attr_NotConfigurable|Attr_NotEnumerable); - Q_ASSERT(ic->prototype); - jsObjects[ArrayProto] = memoryManager->allocObject(ic); + Q_ASSERT(ic->d()->prototype); + jsObjects[ArrayProto] = memoryManager->allocObject(ic->d()); classes[Class_ArrayObject] = ic->changePrototype(arrayPrototype()->d()); jsObjects[PropertyListProto] = memoryManager->allocate(); - InternalClass *argsClass = newInternalClass(ArgumentsObject::staticVTable(), objectPrototype()); + Scoped argsClass(scope); + argsClass = newInternalClass(ArgumentsObject::staticVTable(), objectPrototype()); argsClass = argsClass->addMember(id_length(), Attr_NotEnumerable); classes[Class_ArgumentsObject] = argsClass->addMember(id_callee(), Attr_Data|Attr_NotEnumerable); argsClass = newInternalClass(StrictArgumentsObject::staticVTable(), objectPrototype()); @@ -273,7 +279,7 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine) ic = newInternalClass(QV4::StringObject::staticVTable(), objectPrototype()); ic = ic->addMember(id_length(), Attr_ReadOnly); - jsObjects[StringProto] = memoryManager->allocObject(ic); + jsObjects[StringProto] = memoryManager->allocObject(ic->d()); classes[Class_StringObject] = ic->changePrototype(stringPrototype()->d()); Q_ASSERT(classes[Class_StringObject]->find(id_length()) == Heap::StringObject::LengthPropertyIndex); @@ -285,11 +291,11 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine) 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(ic); + jsObjects[FunctionProto] = memoryManager->allocObject(ic->d()); ic = newInternalClass(FunctionObject::staticVTable(), functionPrototype()); ic = ic->addMember(id_prototype(), Attr_NotEnumerable|Attr_NotConfigurable, &index); Q_ASSERT(index == Heap::FunctionObject::Index_Prototype); - classes[Class_FunctionObject] = ic; + classes[Class_FunctionObject] = ic->d(); ic = ic->addMember(id_name(), Attr_ReadOnly, &index); Q_ASSERT(index == Heap::ScriptFunction::Index_Name); ic = ic->changeVTable(ScriptFunction::staticVTable()); @@ -298,7 +304,6 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine) classes[Class_ObjectProto] = classes[Class_Object]->addMember(id_constructor(), Attr_NotEnumerable, &index); Q_ASSERT(index == Heap::FunctionObject::Index_ProtoConstructor); - Scope scope(this); ScopedString str(scope); classes[Class_RegExp] = classes[Class_Empty]->changeVTable(QV4::RegExp::staticVTable()); ic = newInternalClass(QV4::RegExpObject::staticVTable(), objectPrototype()); @@ -312,7 +317,7 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine) Q_ASSERT(index == RegExpObject::Index_IgnoreCase); ic = ic->addMember((str = newIdentifier(QStringLiteral("multiline"))), Attr_ReadOnly, &index); Q_ASSERT(index == RegExpObject::Index_Multiline); - jsObjects[RegExpProto] = memoryManager->allocObject(ic); + jsObjects[RegExpProto] = memoryManager->allocObject(ic->d()); classes[Class_RegExpObject] = ic->changePrototype(regExpPrototype()->d()); ic = classes[Class_ArrayObject]->addMember(id_index(), Attr_Data, &index); @@ -326,7 +331,7 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine) ic = ic->addMember((str = newIdentifier(QStringLiteral("fileName"))), Attr_Data|Attr_NotEnumerable, &index); Q_ASSERT(index == ErrorObject::Index_FileName); ic = ic->addMember((str = newIdentifier(QStringLiteral("lineNumber"))), Attr_Data|Attr_NotEnumerable, &index); - classes[Class_ErrorObject] = ic; + classes[Class_ErrorObject] = ic->d(); Q_ASSERT(index == ErrorObject::Index_LineNumber); classes[Class_ErrorObjectWithMessage] = ic->addMember((str = newIdentifier(QStringLiteral("message"))), Attr_Data|Attr_NotEnumerable, &index); Q_ASSERT(index == ErrorObject::Index_Message); @@ -342,19 +347,20 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine) getStackFunction()->defineReadonlyProperty(id_length(), Primitive::fromInt32(0)); jsObjects[ErrorProto] = memoryManager->allocObject(classes[Class_ErrorProto]); - jsObjects[EvalErrorProto] = memoryManager->allocObject(classes[Class_ErrorProto]->changePrototype(errorPrototype()->d())); - jsObjects[RangeErrorProto] = memoryManager->allocObject(classes[Class_ErrorProto]->changePrototype(errorPrototype()->d())); - jsObjects[ReferenceErrorProto] = memoryManager->allocObject(classes[Class_ErrorProto]->changePrototype(errorPrototype()->d())); - jsObjects[SyntaxErrorProto] = memoryManager->allocObject(classes[Class_ErrorProto]->changePrototype(errorPrototype()->d())); - jsObjects[TypeErrorProto] = memoryManager->allocObject(classes[Class_ErrorProto]->changePrototype(errorPrototype()->d())); - jsObjects[URIErrorProto] = memoryManager->allocObject(classes[Class_ErrorProto]->changePrototype(errorPrototype()->d())); + ic = classes[Class_ErrorProto]->changePrototype(errorPrototype()->d()); + jsObjects[EvalErrorProto] = memoryManager->allocObject(ic->d()); + jsObjects[RangeErrorProto] = memoryManager->allocObject(ic->d()); + jsObjects[ReferenceErrorProto] = memoryManager->allocObject(ic->d()); + jsObjects[SyntaxErrorProto] = memoryManager->allocObject(ic->d()); + jsObjects[TypeErrorProto] = memoryManager->allocObject(ic->d()); + jsObjects[URIErrorProto] = memoryManager->allocObject(ic->d()); jsObjects[VariantProto] = memoryManager->allocate(); Q_ASSERT(variantPrototype()->prototype() == objectPrototype()->d()); #if QT_CONFIG(qml_sequence_object) ic = newInternalClass(SequencePrototype::staticVTable(), SequencePrototype::defaultPrototype(this)); - jsObjects[SequenceProto] = ScopedValue(scope, memoryManager->allocObject(ic)); + jsObjects[SequenceProto] = ScopedValue(scope, memoryManager->allocObject(ic->d())); #endif ExecutionContext *global = rootContext(); @@ -496,7 +502,6 @@ ExecutionEngine::~ExecutionEngine() while (!compilationUnits.isEmpty()) (*compilationUnits.begin())->unlink(); - internalClasses(Class_Empty)->destroyAll(); delete bumperPointerAllocator; delete regExpCache; delete regExpAllocator; @@ -532,14 +537,18 @@ void ExecutionEngine::initRootContext() jsObjects[IntegerNull] = Encode((int)0); } -InternalClass *ExecutionEngine::newClass(InternalClass *other) +Heap::InternalClass *ExecutionEngine::newClass(Heap::InternalClass *other) { - return new InternalClass(other); + Heap::InternalClass *ic = memoryManager->allocIC(); + ic->init(other); + return ic; } -InternalClass *ExecutionEngine::newInternalClass(const VTable *vtable, Object *prototype) +Heap::InternalClass *ExecutionEngine::newInternalClass(const VTable *vtable, Object *prototype) { - return internalClasses(Class_Empty)->changeVTable(vtable)->changePrototype(prototype ? prototype->d() : nullptr); + Scope scope(this); + Scoped ic(scope, internalClasses(Class_Empty)->changeVTable(vtable)); + return ic->changePrototype(prototype ? prototype->d() : nullptr); } Heap::Object *ExecutionEngine::newObject() @@ -547,7 +556,7 @@ Heap::Object *ExecutionEngine::newObject() return memoryManager->allocate(); } -Heap::Object *ExecutionEngine::newObject(InternalClass *internalClass) +Heap::Object *ExecutionEngine::newObject(Heap::InternalClass *internalClass) { return memoryManager->allocObject(internalClass); } @@ -624,7 +633,7 @@ Heap::ArrayObject *ExecutionEngine::newArrayObject(const QStringList &list) return memoryManager->allocate(list); } -Heap::ArrayObject *ExecutionEngine::newArrayObject(InternalClass *internalClass) +Heap::ArrayObject *ExecutionEngine::newArrayObject(Heap::InternalClass *internalClass) { return memoryManager->allocObject(internalClass); } @@ -916,7 +925,9 @@ void ExecutionEngine::markObjects(MarkStack *markStack) setter->mark(markStack); } - InternalClass::markObjects(internalClasses(Class_Empty), markStack); + for (int i = 0; i < NClasses; ++i) + if (classes[i]) + classes[i]->mark(markStack); markStack->drain(); for (auto compilationUnit: compilationUnits) { diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h index c1ee5ee926..737f377730 100644 --- a/src/qml/jsruntime/qv4engine_p.h +++ b/src/qml/jsruntime/qv4engine_p.h @@ -400,10 +400,10 @@ public: int newInternalClassId() { return ++internalClassIdCount; } - InternalClass *newInternalClass(const VTable *vtable, Object *prototype); + Heap::InternalClass *newInternalClass(const VTable *vtable, Object *prototype); Heap::Object *newObject(); - Heap::Object *newObject(InternalClass *internalClass); + Heap::Object *newObject(Heap::InternalClass *internalClass); Heap::String *newString(const QString &s = QString()); Heap::String *newIdentifier(const QString &text); @@ -415,7 +415,7 @@ public: Heap::ArrayObject *newArrayObject(int count = 0); Heap::ArrayObject *newArrayObject(const Value *values, int length); Heap::ArrayObject *newArrayObject(const QStringList &list); - Heap::ArrayObject *newArrayObject(InternalClass *ic); + Heap::ArrayObject *newArrayObject(Heap::InternalClass *ic); Heap::ArrayBuffer *newArrayBuffer(const QByteArray &array); Heap::ArrayBuffer *newArrayBuffer(size_t length); @@ -455,7 +455,7 @@ public: void initRootContext(); - InternalClass *newClass(InternalClass *other); + Heap::InternalClass *newClass(Heap::InternalClass *other); StackTrace exceptionStackTrace; diff --git a/src/qml/jsruntime/qv4enginebase_p.h b/src/qml/jsruntime/qv4enginebase_p.h index 35ae0d09d2..b7f6b8d3cd 100644 --- a/src/qml/jsruntime/qv4enginebase_p.h +++ b/src/qml/jsruntime/qv4enginebase_p.h @@ -115,8 +115,8 @@ struct Q_QML_EXPORT EngineBase { Class_QmlContextWrapper, NClasses }; - InternalClass *classes[NClasses]; - InternalClass *internalClasses(InternalClassType icType) { return classes[icType]; } + Heap::InternalClass *classes[NClasses]; + Heap::InternalClass *internalClasses(InternalClassType icType) { return classes[icType]; } }; #if defined(Q_CC_MSVC) || defined(Q_CC_GNU) #pragma pack(pop) diff --git a/src/qml/jsruntime/qv4errorobject_p.h b/src/qml/jsruntime/qv4errorobject_p.h index 7fb4a71a29..44b88f0d31 100644 --- a/src/qml/jsruntime/qv4errorobject_p.h +++ b/src/qml/jsruntime/qv4errorobject_p.h @@ -329,27 +329,25 @@ inline SyntaxErrorObject *ErrorObject::asSyntaxError() template Heap::Object *ErrorObject::create(ExecutionEngine *e, const Value &message) { EngineBase::InternalClassType klass = message.isUndefined() ? EngineBase::Class_ErrorObject : EngineBase::Class_ErrorObjectWithMessage; - InternalClass *ic = e->internalClasses(klass); - ic = ic->changePrototype(T::defaultPrototype(e)->d()); - return e->memoryManager->allocObject(ic, message); + Scope scope(e); + Scoped ic(scope, e->internalClasses(klass)->changePrototype(T::defaultPrototype(e)->d())); + return e->memoryManager->allocObject(ic->d(), 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()); EngineBase::InternalClassType klass = v->isUndefined() ? EngineBase::Class_ErrorObject : EngineBase::Class_ErrorObjectWithMessage; - InternalClass *ic = e->internalClasses(klass); - ic = ic->changePrototype(T::defaultPrototype(e)->d()); - return e->memoryManager->allocObject(ic, v); + Scoped ic(scope, e->internalClasses(klass)->changePrototype(T::defaultPrototype(e)->d())); + return e->memoryManager->allocObject(ic->d(), 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()); EngineBase::InternalClassType klass = v->isUndefined() ? EngineBase::Class_ErrorObject : EngineBase::Class_ErrorObjectWithMessage; - InternalClass *ic = e->internalClasses(klass); - ic = ic->changePrototype(T::defaultPrototype(e)->d()); - return e->memoryManager->allocObject(ic, v, filename, line, column); + Scoped ic(scope, e->internalClasses(klass)->changePrototype(T::defaultPrototype(e)->d())); + return e->memoryManager->allocObject(ic->d(), v, filename, line, column); } diff --git a/src/qml/jsruntime/qv4function.cpp b/src/qml/jsruntime/qv4function.cpp index a2eaa3c2b2..493147e99b 100644 --- a/src/qml/jsruntime/qv4function.cpp +++ b/src/qml/jsruntime/qv4function.cpp @@ -61,18 +61,18 @@ Function::Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit, , codeRef(nullptr) , hasQmlDependencies(function->hasQmlDependencies()) { - Q_UNUSED(engine); - - internalClass = engine->internalClasses(EngineBase::Class_CallContext); + Scope scope(engine); + Scoped ic(scope, engine->internalClasses(EngineBase::Class_CallContext)); // first locals const quint32_le *localsIndices = compiledFunction->localsTable(); for (quint32 i = 0; i < compiledFunction->nLocals; ++i) - internalClass = internalClass->addMember(engine->identifierTable->identifier(compilationUnit->runtimeStrings[localsIndices[i]]), Attr_NotConfigurable); + ic = ic->addMember(engine->identifierTable->identifier(compilationUnit->runtimeStrings[localsIndices[i]]), Attr_NotConfigurable); const quint32_le *formalsIndices = compiledFunction->formalsTable(); for (quint32 i = 0; i < compiledFunction->nFormals; ++i) - internalClass = internalClass->addMember(engine->identifierTable->identifier(compilationUnit->runtimeStrings[formalsIndices[i]]), Attr_NotConfigurable); + ic = ic->addMember(engine->identifierTable->identifier(compilationUnit->runtimeStrings[formalsIndices[i]]), Attr_NotConfigurable); + internalClass = ic->d(); nFormals = compiledFunction->nFormals; } diff --git a/src/qml/jsruntime/qv4function_p.h b/src/qml/jsruntime/qv4function_p.h index 59a94e5dde..c8dbcec51d 100644 --- a/src/qml/jsruntime/qv4function_p.h +++ b/src/qml/jsruntime/qv4function_p.h @@ -81,7 +81,7 @@ struct Q_QML_EXPORT Function { JSC::MacroAssemblerCodeRef *codeRef; // first nArguments names in internalClass are the actual arguments - InternalClass *internalClass; + Heap::InternalClass *internalClass; uint nFormals; int interpreterCallCount = 0; bool hasQmlDependencies; diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp index 7cee808812..bc28dd2f6c 100644 --- a/src/qml/jsruntime/qv4functionobject.cpp +++ b/src/qml/jsruntime/qv4functionobject.cpp @@ -371,8 +371,7 @@ ReturnedValue ScriptFunction::callAsConstructor(const FunctionObject *fo, const const ScriptFunction *f = static_cast(fo); Scope scope(v4); - InternalClass *ic = f->classForConstructor(); - ScopedValue thisObject(scope, v4->memoryManager->allocObject(ic)); + ScopedValue thisObject(scope, v4->memoryManager->allocObject(f->classForConstructor())); ReturnedValue result = Moth::VME::exec(fo, thisObject, argv, argc); @@ -415,19 +414,19 @@ void Heap::ScriptFunction::init(QV4::ExecutionContext *scope, Function *function } } -InternalClass *ScriptFunction::classForConstructor() const +Heap::InternalClass *ScriptFunction::classForConstructor() const { const Object *o = d()->protoProperty(); - InternalClass *ic = d()->cachedClassForConstructor; - if (ic && ic->prototype == o->d()) - return ic; + if (d()->cachedClassForConstructor && d()->cachedClassForConstructor->prototype == o->d()) + return d()->cachedClassForConstructor; - ic = engine()->internalClasses(EngineBase::Class_Object); + Scope scope(engine()); + Scoped ic(scope, engine()->internalClasses(EngineBase::Class_Object)); if (o) ic = ic->changePrototype(o->d()); - d()->cachedClassForConstructor = ic; + d()->cachedClassForConstructor.set(scope.engine, ic->d()); - return ic; + return ic->d(); } DEFINE_OBJECT_VTABLE(IndexedBuiltinFunction); diff --git a/src/qml/jsruntime/qv4functionobject_p.h b/src/qml/jsruntime/qv4functionobject_p.h index 08fe02a462..0bc37def24 100644 --- a/src/qml/jsruntime/qv4functionobject_p.h +++ b/src/qml/jsruntime/qv4functionobject_p.h @@ -109,14 +109,16 @@ struct IndexedBuiltinFunction : FunctionObject { uint index; }; -struct ScriptFunction : FunctionObject { +#define ScriptFunctionMembers(class, Member) \ + Member(class, Pointer, InternalClass *, cachedClassForConstructor) + +DECLARE_HEAP_OBJECT(ScriptFunction, FunctionObject) { + DECLARE_MARKOBJECTS(ScriptFunction) enum { Index_Name = FunctionObject::Index_Prototype + 1, Index_Length }; void init(QV4::ExecutionContext *scope, Function *function); - - QV4::InternalClass *cachedClassForConstructor; }; #define BoundFunctionMembers(class, Member) \ @@ -225,7 +227,7 @@ struct ScriptFunction : FunctionObject { static ReturnedValue callAsConstructor(const FunctionObject *, const Value *argv, int argc); static ReturnedValue call(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc); - InternalClass *classForConstructor() const; + Heap::InternalClass *classForConstructor() const; }; diff --git a/src/qml/jsruntime/qv4global_p.h b/src/qml/jsruntime/qv4global_p.h index 41015be24a..9cc63a98c5 100644 --- a/src/qml/jsruntime/qv4global_p.h +++ b/src/qml/jsruntime/qv4global_p.h @@ -168,6 +168,7 @@ namespace Heap { struct CallContext; struct QmlContext; struct ScriptFunction; + struct InternalClass; struct BooleanObject; struct NumberObject; diff --git a/src/qml/jsruntime/qv4internalclass.cpp b/src/qml/jsruntime/qv4internalclass.cpp index 7aa2fb4cca..b42afcf027 100644 --- a/src/qml/jsruntime/qv4internalclass.cpp +++ b/src/qml/jsruntime/qv4internalclass.cpp @@ -47,7 +47,7 @@ QT_BEGIN_NAMESPACE -using namespace QV4; +namespace QV4 { static const uchar prime_deltas[] = { 0, 0, 1, 3, 1, 5, 3, 3, 1, 9, 7, 5, 3, 9, 25, 3, @@ -126,40 +126,74 @@ void PropertyHash::detach(bool grow, int classSize) d = dd; } +namespace Heap { -InternalClass::InternalClass(ExecutionEngine *engine) - : engine(engine) - , vtable(nullptr) - , prototype(nullptr) - , parent(nullptr) - , size(0) - , extensible(true) - , isSealed(false) - , isFrozen(false) +void InternalClass::init(ExecutionEngine *engine) { + Base::init(); + new (&propertyTable) PropertyHash(); + new (&nameMap) SharedInternalClassData(); + new (&propertyData) SharedInternalClassData(); + new (&transitions) std::vector(); + + this->engine = engine; + vtable = QV4::InternalClass::staticVTable(); +// prototype = nullptr; +// parent = nullptr; +// size = 0; + extensible = true; + isFrozen = false; + isSealed = false; + isUsedAsProto = false; id = engine->newInternalClassId(); + + // Also internal classes need an internal class pointer. Simply make it point to itself + internalClass.set(engine, this); } -InternalClass::InternalClass(QV4::InternalClass *other) - : engine(other->engine) - , vtable(other->vtable) - , prototype(other->prototype) - , parent(other) - , propertyTable(other->propertyTable) - , nameMap(other->nameMap) - , propertyData(other->propertyData) - , size(other->size) - , extensible(other->extensible) - , isSealed(other->isSealed) - , isFrozen(other->isFrozen) - , isUsedAsProto(other->isUsedAsProto) +void InternalClass::init(Heap::InternalClass *other) { - Q_ASSERT(!isFrozen); + Base::init(); + Q_ASSERT(!other->isFrozen); + new (&propertyTable) PropertyHash(other->propertyTable); + new (&nameMap) SharedInternalClassData(other->nameMap); + new (&propertyData) SharedInternalClassData(other->propertyData); + new (&transitions) std::vector(); + + engine = other->engine; + vtable = other->vtable; + prototype = other->prototype; + parent = other; + size = other->size; + extensible = other->extensible; + isSealed = other->isSealed; + isFrozen = other->isFrozen; + isUsedAsProto = other->isUsedAsProto; id = engine->newInternalClassId(); + + internalClass.set(engine, other->internalClass); } -static void insertHoleIntoPropertyData(Object *object, int idx) +void InternalClass::destroy() +{ +#ifndef QT_NO_DEBUG + for (const auto &t : transitions) { + Q_ASSERT(!t.lookup || !t.lookup->isMarked()); + } +#endif + if (parent && parent->engine && parent->isMarked()) + parent->removeChildEntry(this); + + propertyTable.~PropertyHash(); + nameMap.~SharedInternalClassData(); + propertyData.~SharedInternalClassData(); + transitions.~vector(); + engine = nullptr; + Base::destroy(); +} + +static void insertHoleIntoPropertyData(QV4::Object *object, int idx) { Heap::Object *o = object->d(); ExecutionEngine *v4 = o->internalClass->engine; @@ -168,7 +202,7 @@ static void insertHoleIntoPropertyData(Object *object, int idx) o->setProperty(v4, i, *o->propertyData(i - 1)); } -static void removeFromPropertyData(Object *object, int idx, bool accessor = false) +static void removeFromPropertyData(QV4::Object *object, int idx, bool accessor = false) { Heap::Object *o = object->d(); ExecutionEngine *v4 = o->internalClass->engine; @@ -180,20 +214,22 @@ static void removeFromPropertyData(Object *object, int idx, bool accessor = fals o->setProperty(v4, size + 1, Primitive::undefinedValue()); } -void InternalClass::changeMember(Object *object, String *string, PropertyAttributes data, uint *index) +void InternalClass::changeMember(QV4::Object *object, QV4::String *string, PropertyAttributes data, uint *index) { uint idx; - InternalClass *oldClass = object->internalClass(); - InternalClass *newClass = oldClass->changeMember(string->identifier(), data, &idx); + Heap::InternalClass *oldClass = object->internalClass(); + Heap::InternalClass *newClass = oldClass->changeMember(string->identifier(), data, &idx); if (index) *index = idx; + uint oldSize = oldClass->size; object->setInternalClass(newClass); - if (newClass->size > oldClass->size) { - Q_ASSERT(newClass->size == oldClass->size + 1); + // don't use oldClass anymore, it could be GC'ed + if (newClass->size > oldSize) { + Q_ASSERT(newClass->size == oldSize + 1); insertHoleIntoPropertyData(object, idx); - } else if (newClass->size < oldClass->size) { - Q_ASSERT(newClass->size == oldClass->size - 1); + } else if (newClass->size < oldSize) { + Q_ASSERT(newClass->size == oldSize - 1); removeFromPropertyData(object, idx + 1); } } @@ -218,7 +254,7 @@ static void addDummyEntry(InternalClass *newClass, PropertyHash::Entry e) ++newClass->size; } -InternalClass *InternalClass::changeMember(Identifier *identifier, PropertyAttributes data, uint *index) +Heap::InternalClass *InternalClass::changeMember(Identifier *identifier, PropertyAttributes data, uint *index) { data.resolve(); uint idx = find(identifier); @@ -228,7 +264,7 @@ InternalClass *InternalClass::changeMember(Identifier *identifier, PropertyAttri *index = idx; if (data == propertyData.at(idx)) - return this; + return static_cast(this); Transition temp = { { identifier }, nullptr, (int)data.flags() }; Transition &t = lookupOrInsertTransition(temp); @@ -236,7 +272,7 @@ InternalClass *InternalClass::changeMember(Identifier *identifier, PropertyAttri return t.lookup; // create a new class and add it to the tree - InternalClass *newClass = engine->newClass(this); + Heap::InternalClass *newClass = engine->newClass(this); if (data.isAccessor() != propertyData.at(idx).isAccessor()) { // this changes the layout of the class, so we need to rebuild the data newClass->propertyTable = PropertyHash(); @@ -271,8 +307,10 @@ InternalClass *InternalClass::changeMember(Identifier *identifier, PropertyAttri return newClass; } -InternalClass *InternalClass::changePrototypeImpl(Heap::Object *proto) +Heap::InternalClass *InternalClass::changePrototypeImpl(Heap::Object *proto) { + Scope scope(engine); + ScopedValue protectThis(scope, this); if (proto) proto->setUsedAsProto(); Q_ASSERT(prototype != proto); @@ -286,7 +324,7 @@ InternalClass *InternalClass::changePrototypeImpl(Heap::Object *proto) return t.lookup; // create a new class and add it to the tree - InternalClass *newClass = engine->newClass(this); + Heap::InternalClass *newClass = engine->newClass(this); newClass->prototype = proto; t.lookup = newClass; @@ -294,7 +332,7 @@ InternalClass *InternalClass::changePrototypeImpl(Heap::Object *proto) return newClass; } -InternalClass *InternalClass::changeVTableImpl(const VTable *vt) +Heap::InternalClass *InternalClass::changeVTableImpl(const VTable *vt) { Q_ASSERT(vtable != vt); @@ -306,7 +344,7 @@ InternalClass *InternalClass::changeVTableImpl(const VTable *vt) return t.lookup; // create a new class and add it to the tree - InternalClass *newClass = engine->newClass(this); + Heap::InternalClass *newClass = engine->newClass(this); newClass->vtable = vt; t.lookup = newClass; @@ -315,7 +353,7 @@ InternalClass *InternalClass::changeVTableImpl(const VTable *vt) return newClass; } -InternalClass *InternalClass::nonExtensible() +Heap::InternalClass *InternalClass::nonExtensible() { if (!extensible) return this; @@ -325,7 +363,7 @@ InternalClass *InternalClass::nonExtensible() if (t.lookup) return t.lookup; - InternalClass *newClass = engine->newClass(this); + Heap::InternalClass *newClass = engine->newClass(this); newClass->extensible = false; t.lookup = newClass; @@ -333,7 +371,7 @@ InternalClass *InternalClass::nonExtensible() return newClass; } -void InternalClass::addMember(Object *object, String *string, PropertyAttributes data, uint *index) +void InternalClass::addMember(QV4::Object *object, QV4::String *string, PropertyAttributes data, uint *index) { data.resolve(); object->internalClass()->engine->identifierTable->identifier(string); @@ -343,20 +381,20 @@ void InternalClass::addMember(Object *object, String *string, PropertyAttributes } uint idx; - InternalClass *newClass = object->internalClass()->addMemberImpl(string->identifier(), data, &idx); + Heap::InternalClass *newClass = object->internalClass()->addMemberImpl(string->identifier(), data, &idx); if (index) *index = idx; object->setInternalClass(newClass); } -InternalClass *InternalClass::addMember(String *string, PropertyAttributes data, uint *index) +Heap::InternalClass *InternalClass::addMember(QV4::String *string, PropertyAttributes data, uint *index) { engine->identifierTable->identifier(string); return addMember(string->identifier(), data, index); } -InternalClass *InternalClass::addMember(Identifier *identifier, PropertyAttributes data, uint *index) +Heap::InternalClass *InternalClass::addMember(Identifier *identifier, PropertyAttributes data, uint *index) { data.resolve(); @@ -366,7 +404,7 @@ InternalClass *InternalClass::addMember(Identifier *identifier, PropertyAttribut return addMemberImpl(identifier, data, index); } -InternalClass *InternalClass::addMemberImpl(Identifier *identifier, PropertyAttributes data, uint *index) +Heap::InternalClass *InternalClass::addMemberImpl(Identifier *identifier, PropertyAttributes data, uint *index) { Transition temp = { { identifier }, nullptr, (int)data.flags() }; Transition &t = lookupOrInsertTransition(temp); @@ -378,7 +416,7 @@ InternalClass *InternalClass::addMemberImpl(Identifier *identifier, PropertyAttr return t.lookup; // create a new class and add it to the tree - InternalClass *newClass = engine->newClass(this); + Heap::InternalClass *newClass = engine->newClass(this); PropertyHash::Entry e = { identifier, newClass->size }; newClass->propertyTable.addEntry(e, newClass->size); @@ -393,9 +431,22 @@ InternalClass *InternalClass::addMemberImpl(Identifier *identifier, PropertyAttr return newClass; } -void InternalClass::removeMember(Object *object, Identifier *id) +void InternalClass::removeChildEntry(InternalClass *child) +{ + Q_ASSERT(engine); + for (auto &t : transitions) { + if (t.lookup == child) { + t.lookup = nullptr; + return; + } + } + Q_UNREACHABLE(); + +} + +void InternalClass::removeMember(QV4::Object *object, Identifier *id) { - InternalClass *oldClass = object->internalClass(); + Heap::InternalClass *oldClass = object->internalClass(); Q_ASSERT(oldClass->propertyTable.lookup(id) < oldClass->size); Transition temp = { { id }, nullptr, Transition::RemoveMember }; @@ -403,7 +454,7 @@ void InternalClass::removeMember(Object *object, Identifier *id) if (!t.lookup) { // create a new class and add it to the tree - InternalClass *newClass = oldClass->engine->newClass(oldClass); + Heap::InternalClass *newClass = oldClass->engine->newClass(oldClass); // simply make the entry inaccessible int idx = newClass->propertyTable.removeIdentifier(id, oldClass->size); newClass->nameMap.set(idx, nullptr); @@ -417,7 +468,7 @@ void InternalClass::removeMember(Object *object, Identifier *id) Q_ASSERT(object->internalClass()->size == oldClass->size); } -uint InternalClass::find(const String *string) +uint InternalClass::find(const QV4::String *string) { engine->identifierTable->identifier(string); const Identifier *id = string->d()->identifier; @@ -429,7 +480,7 @@ uint InternalClass::find(const String *string) return UINT_MAX; } -InternalClass *InternalClass::sealed() +Heap::InternalClass *InternalClass::sealed() { if (isSealed) return this; @@ -458,7 +509,7 @@ InternalClass *InternalClass::sealed() return t.lookup; } - InternalClass *s = engine->newClass(this); + Heap::InternalClass *s = engine->newClass(this); for (uint i = 0; i < size; ++i) { PropertyAttributes attrs = propertyData.at(i); @@ -474,7 +525,7 @@ InternalClass *InternalClass::sealed() return s; } -InternalClass *InternalClass::frozen() +Heap::InternalClass *InternalClass::frozen() { if (isFrozen) return this; @@ -504,7 +555,7 @@ InternalClass *InternalClass::frozen() return t.lookup; } - InternalClass *f = engine->newClass(this); + Heap::InternalClass *f = engine->newClass(this); for (uint i = 0; i < size; ++i) { PropertyAttributes attrs = propertyData.at(i); @@ -523,9 +574,10 @@ InternalClass *InternalClass::frozen() return f; } -InternalClass *InternalClass::propertiesFrozen() const +Heap::InternalClass *InternalClass::propertiesFrozen() const { - InternalClass *frozen = engine->internalClasses(EngineBase::Class_Empty)->changeVTable(vtable); + Scope scope(engine); + Scoped frozen(scope, engine->internalClasses(EngineBase::Class_Empty)->changeVTable(vtable)); frozen = frozen->changePrototype(prototype); for (uint i = 0; i < size; ++i) { PropertyAttributes attrs = propertyData.at(i); @@ -535,10 +587,10 @@ InternalClass *InternalClass::propertiesFrozen() const attrs.setConfigurable(false); frozen = frozen->addMember(nameMap.at(i), attrs); } - return frozen; + return frozen->d(); } -InternalClass *InternalClass::asProtoClass() +Heap::InternalClass *InternalClass::asProtoClass() { if (isUsedAsProto) return this; @@ -548,7 +600,7 @@ InternalClass *InternalClass::asProtoClass() if (t.lookup) return t.lookup; - InternalClass *newClass = engine->newClass(this); + Heap::InternalClass *newClass = engine->newClass(this); newClass->isUsedAsProto = true; t.lookup = newClass; @@ -556,34 +608,13 @@ InternalClass *InternalClass::asProtoClass() return newClass; } -void InternalClass::destroyAll() -{ - std::vector destroyStack; - destroyStack.reserve(64); - destroyStack.push_back(this); - - while (!destroyStack.empty()) { - InternalClass *next = destroyStack.back(); - destroyStack.pop_back(); - Q_ASSERT(next->engine); - next->engine = nullptr; - - for (size_t i = 0; i < next->transitions.size(); ++i) { - Q_ASSERT(next->transitions.at(i).lookup); - destroyStack.push_back(next->transitions.at(i).lookup); - } - - delete next; - } -} - -static void updateProtoUsage(Heap::Object *o, InternalClass *ic) +static void updateProtoUsage(Heap::Object *o, Heap::InternalClass *ic) { if (ic->prototype == o) ic->id = ic->engine->newInternalClassId(); for (auto &t : ic->transitions) { - Q_ASSERT(t.lookup); - updateProtoUsage(o, t.lookup); + if (t.lookup) + updateProtoUsage(o, t.lookup); } } @@ -591,30 +622,23 @@ static void updateProtoUsage(Heap::Object *o, InternalClass *ic) void InternalClass::updateProtoUsage(Heap::Object *o) { Q_ASSERT(isUsedAsProto); - InternalClass *ic = engine->internalClasses(EngineBase::Class_Empty); + Heap::InternalClass *ic = engine->internalClasses(EngineBase::Class_Empty); Q_ASSERT(!ic->prototype); - ::updateProtoUsage(o, ic); -} - -void InternalClass::updateInternalClassIdRecursive() -{ - id = engine->newInternalClassId(); - for (auto &t : transitions) { - Q_ASSERT(t.lookup); - t.lookup->updateInternalClassIdRecursive(); - } + Heap::updateProtoUsage(o, ic); } -void InternalClass::markObjects(InternalClass *ic, MarkStack *stack) +void InternalClass::markObjects(Heap::Base *b, MarkStack *stack) { + Heap::InternalClass *ic = static_cast(b); if (ic->prototype) ic->prototype->mark(stack); + if (ic->parent) + ic->parent->mark(stack); +} + +} - for (auto &t : ic->transitions) { - Q_ASSERT(t.lookup); - markObjects(t.lookup, stack); - } } QT_END_NAMESPACE diff --git a/src/qml/jsruntime/qv4internalclass_p.h b/src/qml/jsruntime/qv4internalclass_p.h index 7533253873..0e6f52da43 100644 --- a/src/qml/jsruntime/qv4internalclass_p.h +++ b/src/qml/jsruntime/qv4internalclass_p.h @@ -54,6 +54,7 @@ #include #include +#include QT_BEGIN_NAMESPACE @@ -240,7 +241,7 @@ struct InternalClassTransition const VTable *vtable; Heap::Object *prototype; }; - InternalClass *lookup; + Heap::InternalClass *lookup; int flags; enum { // range 0-0xff is reserved for attribute changes @@ -260,12 +261,14 @@ struct InternalClassTransition { return id < other.id || (id == other.id && flags < other.flags); } }; -struct InternalClass { - int id = 0; // unique across the engine, gets changed also when proto chain changes +namespace Heap { + +struct InternalClass : Base { + int id; // unique across the engine, gets changed also when proto chain changes ExecutionEngine *engine; const VTable *vtable; Heap::Object *prototype; - InternalClass *parent = nullptr; + InternalClass *parent; PropertyHash propertyTable; // id to valueIndex SharedInternalClassData nameMap; @@ -279,27 +282,21 @@ struct InternalClass { bool extensible; bool isSealed; bool isFrozen; - bool isUsedAsProto = false; + bool isUsedAsProto; + + void init(ExecutionEngine *engine); + void init(InternalClass *other); + void destroy(); 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); - Q_REQUIRED_RESULT InternalClass *addMember(String *string, PropertyAttributes data, uint *index = nullptr); + static void addMember(QV4::Object *object, QV4::String *string, PropertyAttributes data, uint *index); + Q_REQUIRED_RESULT InternalClass *addMember(QV4::String *string, PropertyAttributes data, uint *index = nullptr); Q_REQUIRED_RESULT InternalClass *addMember(Identifier *identifier, PropertyAttributes data, uint *index = nullptr); Q_REQUIRED_RESULT InternalClass *changeMember(Identifier *identifier, PropertyAttributes data, uint *index = nullptr); - static void changeMember(Object *object, String *string, PropertyAttributes data, uint *index = nullptr); - static void removeMember(Object *object, Identifier *id); - uint find(const String *string); + static void changeMember(QV4::Object *object, QV4::String *string, PropertyAttributes data, uint *index = nullptr); + static void removeMember(QV4::Object *object, Identifier *id); + uint find(const QV4::String *string); uint find(const Identifier *id) { uint index = propertyTable.lookup(id); @@ -315,23 +312,38 @@ struct InternalClass { Q_REQUIRED_RESULT InternalClass *asProtoClass(); - void destroyAll(); + 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); + } void updateProtoUsage(Heap::Object *o); - static void markObjects(InternalClass *ic, MarkStack *stack); - + static void markObjects(Heap::Base *ic, MarkStack *stack); 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); - void updateInternalClassIdRecursive(); + + void removeChildEntry(InternalClass *child); friend struct ExecutionEngine; - InternalClass(ExecutionEngine *engine); - InternalClass(InternalClass *other); }; +inline +void Base::markObjects(Base *b, MarkStack *stack) +{ + b->internalClass->mark(stack); +} + +} + } QT_END_NAMESPACE diff --git a/src/qml/jsruntime/qv4lookup.cpp b/src/qml/jsruntime/qv4lookup.cpp index 52ab03cd94..b93b314b63 100644 --- a/src/qml/jsruntime/qv4lookup.cpp +++ b/src/qml/jsruntime/qv4lookup.cpp @@ -347,7 +347,6 @@ ReturnedValue Lookup::getterProtoAccessor(Lookup *l, ExecutionEngine *engine, co return static_cast(getter)->call(&object, nullptr, 0); } - l->getter = getterTwoClasses; return getterTwoClasses(l, engine, object); } @@ -442,7 +441,7 @@ bool Lookup::resolveSetter(ExecutionEngine *engine, Object *object, const Value Scope scope(engine); ScopedString name(scope, scope.engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]); - InternalClass *c = object->internalClass(); + Heap::InternalClass *c = object->internalClass(); uint idx = c->find(name); if (idx != UINT_MAX) { if (object->isArrayObject() && idx == Heap::ArrayObject::LengthPropertyIndex) { @@ -599,4 +598,53 @@ bool Lookup::arrayLengthSetter(Lookup *, ExecutionEngine *engine, Value &object, return true; } +void Lookup::markObjects(MarkStack *stack) +{ + if (getter == getterGeneric || + getter == getterTwoClasses || + getter == getterFallback) { + ; + } else if (getter == getter0MemberData || + getter == getter0Inline || + getter == getterAccessor) { + objectLookup.ic->mark(stack); + } else if (getter == getterProto) { + ; + } else if (getter == getter0Inlinegetter0Inline || + getter == getter0Inlinegetter0MemberData || + getter == getter0MemberDatagetter0MemberData) { + objectLookupTwoClasses.ic->mark(stack); + objectLookupTwoClasses.ic2->mark(stack); + } else if (getter == getterProtoTwoClasses || + getter == getterProtoAccessor || + getter == getterProtoAccessorTwoClasses) { + + } else if (getter == primitiveGetterProto || + getter == primitiveGetterAccessor) { + primitiveLookup.proto->mark(stack); + } else if (getter == stringLengthGetter) { + ; + + } else if (globalGetter == globalGetterGeneric || + globalGetter == globalGetterProto || + globalGetter == globalGetterProtoAccessor) { + ; + + } else if (setter == setterGeneric || + setter == setterTwoClasses || + setter == setterFallback) { + ; + } else if (setter == setter0 || + setter == setter0Inline) { + objectLookup.ic->mark(stack); + } else if (setter == setter0setter0) { + objectLookupTwoClasses.ic->mark(stack); + objectLookupTwoClasses.ic2->mark(stack); + } else if (setter == setterInsert) { + insertionLookup.newClass->mark(stack); + } else if (setter == arrayLengthSetter) { + ; + } +} + QT_END_NAMESPACE diff --git a/src/qml/jsruntime/qv4lookup_p.h b/src/qml/jsruntime/qv4lookup_p.h index 5f507733fd..fb09e5958c 100644 --- a/src/qml/jsruntime/qv4lookup_p.h +++ b/src/qml/jsruntime/qv4lookup_p.h @@ -73,7 +73,7 @@ struct Lookup { }; union { struct { - InternalClass *ic; + Heap::InternalClass *ic; int offset; } objectLookup; struct { @@ -81,8 +81,8 @@ struct Lookup { int icIdentifier; } protoLookup; struct { - InternalClass *ic; - InternalClass *ic2; + Heap::InternalClass *ic; + Heap::InternalClass *ic2; int offset; int offset2; } objectLookupTwoClasses; @@ -100,7 +100,7 @@ struct Lookup { Heap::Object *proto; } primitiveLookup; struct { - InternalClass *newClass; + Heap::InternalClass *newClass; int icIdentifier; int offset; } insertionLookup; @@ -144,6 +144,8 @@ struct Lookup { static bool setter0setter0(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value); static bool setterInsert(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value); static bool arrayLengthSetter(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value); + + void markObjects(MarkStack *stack); }; Q_STATIC_ASSERT(std::is_standard_layout::value); diff --git a/src/qml/jsruntime/qv4managed.cpp b/src/qml/jsruntime/qv4managed.cpp index 082a3b42e4..c3def2f949 100644 --- a/src/qml/jsruntime/qv4managed.cpp +++ b/src/qml/jsruntime/qv4managed.cpp @@ -63,6 +63,8 @@ const VTable Managed::static_vtbl = isEqualTo }; +DEFINE_MANAGED_VTABLE(InternalClass); + QString Managed::className() const { @@ -114,6 +116,9 @@ QString Managed::className() const case Type_ForeachIteratorObject: s = "__ForeachIterator"; break; + case Type_InternalClass: + s = "__InternalClass"; + break; case Type_RegExp: s = "__RegExp"; break; diff --git a/src/qml/jsruntime/qv4managed_p.h b/src/qml/jsruntime/qv4managed_p.h index 64b425823e..b35788a711 100644 --- a/src/qml/jsruntime/qv4managed_p.h +++ b/src/qml/jsruntime/qv4managed_p.h @@ -92,14 +92,14 @@ inline void qYouForgotTheQ_MANAGED_Macro(T1, T2) {} QV4::Heap::DataClass *dptr = d_unchecked(); \ dptr->_checkIsInitialized(); \ return dptr; \ - } \ - Q_STATIC_ASSERT(std::is_trivial< QV4::Heap::DataClass >::value); + } #define V4_MANAGED(DataClass, superClass) \ private: \ DataClass() Q_DECL_EQ_DELETE; \ Q_DISABLE_COPY(DataClass) \ - V4_MANAGED_ITSELF(DataClass, superClass) + V4_MANAGED_ITSELF(DataClass, superClass) \ + Q_STATIC_ASSERT(std::is_trivial< QV4::Heap::DataClass >::value); #define Q_MANAGED_TYPE(type) \ public: \ @@ -154,7 +154,7 @@ const QV4::VTable classname::static_vtbl = DEFINE_MANAGED_VTABLE_INT(classname, QT_WARNING_SUPPRESS_GCC_TAUTOLOGICAL_COMPARE_OFF #define V4_INTERNALCLASS(c) \ - static QV4::InternalClass *defaultInternalClass(QV4::EngineBase *e) \ + static Heap::InternalClass *defaultInternalClass(QV4::EngineBase *e) \ { return e->internalClasses(QV4::EngineBase::Class_##c); } struct Q_QML_PRIVATE_EXPORT Managed : Value @@ -193,6 +193,7 @@ public: Type_MathObject, Type_ExecutionContext, + Type_InternalClass, Type_ForeachIteratorObject, Type_RegExp, @@ -200,7 +201,7 @@ public: }; Q_MANAGED_TYPE(Invalid) - InternalClass *internalClass() const { return d()->internalClass; } + Heap::InternalClass *internalClass() const { return d()->internalClass; } const VTable *vtable() const { return d()->internalClass->vtable; } inline ExecutionEngine *engine() const { return internalClass()->engine; } @@ -255,6 +256,32 @@ inline const Object *Value::as() const { return objectValue(); } + +struct InternalClass : Managed +{ + V4_MANAGED_ITSELF(InternalClass, Managed) + Q_MANAGED_TYPE(InternalClass) + V4_INTERNALCLASS(Empty) + V4_NEEDS_DESTROY + + Q_REQUIRED_RESULT Heap::InternalClass *changeVTable(const VTable *vt) { + return d()->changeVTable(vt); + } + Q_REQUIRED_RESULT Heap::InternalClass *changePrototype(Heap::Object *proto) { + return d()->changePrototype(proto); + } + Q_REQUIRED_RESULT Heap::InternalClass *addMember(QV4::String *string, PropertyAttributes data, uint *index = 0) { + return d()->addMember(string, data, index); + } + Q_REQUIRED_RESULT Heap::InternalClass *addMember(Identifier *identifier, PropertyAttributes data, uint *index = 0) { + return d()->addMember(identifier, data, index); + } + + void operator =(Heap::InternalClass *ic) { + Value::operator=(ic); + } +}; + } diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp index 8e9bf794a9..b90cfcc0ff 100644 --- a/src/qml/jsruntime/qv4object.cpp +++ b/src/qml/jsruntime/qv4object.cpp @@ -57,9 +57,9 @@ using namespace QV4; DEFINE_OBJECT_VTABLE(Object); -void Object::setInternalClass(InternalClass *ic) +void Object::setInternalClass(Heap::InternalClass *ic) { - d()->internalClass = ic; + d()->internalClass.set(engine(), ic); if (ic->isUsedAsProto) ic->updateProtoUsage(d()); Q_ASSERT(ic && ic->vtable); @@ -89,7 +89,7 @@ void Object::setProperty(uint index, const Property *p) void Heap::Object::setUsedAsProto() { - internalClass = internalClass->asProtoClass(); + internalClass.set(internalClass->engine, internalClass->asProtoClass()); } bool Object::setPrototype(Object *proto) @@ -121,7 +121,7 @@ ReturnedValue Object::getValue(const Value &thisObject, const Value &v, Property bool Object::putValue(uint memberIndex, const Value &value) { - QV4::InternalClass *ic = internalClass(); + Heap::InternalClass *ic = internalClass(); if (ic->engine->hasException) return false; @@ -228,6 +228,7 @@ void Object::defineReadonlyConfigurableProperty(String *name, const Value &value void Heap::Object::markObjects(Heap::Base *b, MarkStack *stack) { + Base::markObjects(b, stack); Object *o = static_cast(b); if (o->memberData) o->memberData->mark(stack); @@ -248,7 +249,7 @@ void Heap::Object::markObjects(Heap::Base *b, MarkStack *stack) void Object::insertMember(String *s, const Property *p, PropertyAttributes attributes) { uint idx; - InternalClass::addMember(this, s, attributes, &idx); + Heap::InternalClass::addMember(this, s, attributes, &idx); if (attributes.isAccessor()) { setProperty(idx + GetterOffset, p->value); @@ -776,7 +777,7 @@ bool Object::internalDeleteProperty(String *name) uint memberIdx = internalClass()->find(name->identifier()); if (memberIdx != UINT_MAX) { if (internalClass()->propertyData[memberIdx].isConfigurable()) { - InternalClass::removeMember(this, name->identifier()); + Heap::InternalClass::removeMember(this, name->identifier()); return true; } return false; @@ -832,7 +833,7 @@ bool Object::__defineOwnProperty__(ExecutionEngine *engine, String *name, const } if (attrs.hasWritable() && !attrs.isWritable()) { cattrs.setWritable(false); - InternalClass::changeMember(this, engine->id_length(), cattrs); + Heap::InternalClass::changeMember(this, engine->id_length(), cattrs); } if (!succeeded) return false; @@ -980,7 +981,7 @@ bool Object::__defineOwnProperty__(ExecutionEngine *engine, uint index, String * current->merge(cattrs, p, attrs); if (member) { - InternalClass::changeMember(this, member, cattrs); + Heap::InternalClass::changeMember(this, member, cattrs); setProperty(index, current); } else { setArrayAttributes(index, cattrs); diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h index 4743900196..79ffef47ba 100644 --- a/src/qml/jsruntime/qv4object_p.h +++ b/src/qml/jsruntime/qv4object_p.h @@ -222,7 +222,7 @@ struct Q_QML_EXPORT Object: Managed { SetterOffset = 1 }; - void setInternalClass(InternalClass *ic); + void setInternalClass(Heap::InternalClass *ic); const Value *propertyData(uint index) const { return d()->propertyData(index); } diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp index e2a7161e4d..46d7353eda 100644 --- a/src/qml/jsruntime/qv4runtime.cpp +++ b/src/qml/jsruntime/qv4runtime.cpp @@ -1217,8 +1217,8 @@ ReturnedValue Runtime::method_arrayLiteral(ExecutionEngine *engine, Value *value ReturnedValue Runtime::method_objectLiteral(ExecutionEngine *engine, const QV4::Value *args, int classId, int arrayValueCount, int arrayGetterSetterCountAndFlags) { Scope scope(engine); - QV4::InternalClass *klass = static_cast(engine->currentStackFrame->v4Function->compilationUnit)->runtimeClasses[classId]; - ScopedObject o(scope, engine->newObject(klass)); + Scoped klass(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeClasses[classId]); + ScopedObject o(scope, engine->newObject(klass->d())); { bool needSparseArray = arrayGetterSetterCountAndFlags >> 30; @@ -1226,7 +1226,7 @@ ReturnedValue Runtime::method_objectLiteral(ExecutionEngine *engine, const QV4:: o->initSparseArray(); } - for (uint i = 0; i < klass->size; ++i) + for (uint i = 0; i < klass->d()->size; ++i) o->setProperty(i, *args++); if (arrayValueCount > 0) { @@ -1259,13 +1259,13 @@ ReturnedValue Runtime::method_objectLiteral(ExecutionEngine *engine, const QV4:: QV4::ReturnedValue Runtime::method_createMappedArgumentsObject(ExecutionEngine *engine) { Q_ASSERT(engine->currentContext()->d()->type == Heap::ExecutionContext::Type_CallContext); - QV4::InternalClass *ic = engine->internalClasses(EngineBase::Class_ArgumentsObject); + Heap::InternalClass *ic = engine->internalClasses(EngineBase::Class_ArgumentsObject); return engine->memoryManager->allocObject(ic, engine->currentStackFrame)->asReturnedValue(); } QV4::ReturnedValue Runtime::method_createUnmappedArgumentsObject(ExecutionEngine *engine) { - QV4::InternalClass *ic = engine->internalClasses(EngineBase::Class_StrictArgumentsObject); + Heap::InternalClass *ic = engine->internalClasses(EngineBase::Class_StrictArgumentsObject); return engine->memoryManager->allocObject(ic, engine->currentStackFrame)->asReturnedValue(); } diff --git a/src/qml/jsruntime/qv4string.cpp b/src/qml/jsruntime/qv4string.cpp index f107860b26..57832a0068 100644 --- a/src/qml/jsruntime/qv4string.cpp +++ b/src/qml/jsruntime/qv4string.cpp @@ -54,6 +54,7 @@ using namespace QV4; void Heap::String::markObjects(Heap::Base *that, MarkStack *markStack) { + Base::markObjects(that, markStack); String *s = static_cast(that); if (s->subtype < StringType_Complex) return; diff --git a/src/qml/jsruntime/qv4typedarray.cpp b/src/qml/jsruntime/qv4typedarray.cpp index 194c8f5e28..ea931abd1c 100644 --- a/src/qml/jsruntime/qv4typedarray.cpp +++ b/src/qml/jsruntime/qv4typedarray.cpp @@ -351,9 +351,9 @@ 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, t); + Scope scope(e); + Scoped ic(scope, e->newInternalClass(staticVTable(), e->typedArrayPrototype + t)); + return e->memoryManager->allocObject(ic->d(), t); } ReturnedValue TypedArray::getIndexed(const Managed *m, uint index, bool *hasProperty) diff --git a/src/qml/memory/qv4heap_p.h b/src/qml/memory/qv4heap_p.h index 1ca37fe95f..f327388355 100644 --- a/src/qml/memory/qv4heap_p.h +++ b/src/qml/memory/qv4heap_p.h @@ -113,9 +113,9 @@ Q_STATIC_ASSERT(std::is_trivial< V4PointerCheck >::value); struct Q_QML_EXPORT Base { void *operator new(size_t) = delete; - static void markObjects(Base *, MarkStack *) {} + static void markObjects(Base *, MarkStack *); - InternalClass *internalClass; + Pointer internalClass; inline ReturnedValue asReturnedValue() const; inline void mark(QV4::MarkStack *markStack); @@ -195,7 +195,6 @@ Q_STATIC_ASSERT(std::is_standard_layout::value); Q_STATIC_ASSERT(offsetof(Base, internalClass) == 0); Q_STATIC_ASSERT(sizeof(Base) == QT_POINTER_SIZE); - inline void Base::mark(QV4::MarkStack *markStack) { diff --git a/src/qml/memory/qv4mm.cpp b/src/qml/memory/qv4mm.cpp index fcc00ff331..06313c3d30 100644 --- a/src/qml/memory/qv4mm.cpp +++ b/src/qml/memory/qv4mm.cpp @@ -643,8 +643,9 @@ void BlockAllocator::sweep() void BlockAllocator::freeAll() { - for (auto c : chunks) { + for (auto c : chunks) c->freeAll(engine); + for (auto c : chunks) { Q_V4_PROFILE_DEALLOC(engine, Chunk::DataSize, Profiling::HeapPage); chunkAllocator->free(c); } @@ -758,6 +759,7 @@ MemoryManager::MemoryManager(ExecutionEngine *engine) : engine(engine) , chunkAllocator(new ChunkAllocator) , blockAllocator(chunkAllocator, engine) + , icAllocator(chunkAllocator, engine) , hugeItemAllocator(chunkAllocator, engine) , m_persistentValues(new PersistentValueStorage(engine)) , m_weakValues(new PersistentValueStorage(engine)) @@ -884,7 +886,7 @@ Heap::Object *MemoryManager::allocObjectWithMemberData(const QV4::VTable *vtable Chunk::clearBit(c->extendsBitmap, index); } o->memberData.set(engine, m); - m->internalClass = engine->internalClasses(EngineBase::Class_MemberData); + m->internalClass.set(engine, engine->internalClasses(EngineBase::Class_MemberData)); Q_ASSERT(o->memberData->internalClass); m->values.alloc = static_cast((memberSize - sizeof(Heap::MemberData) + sizeof(Value))/sizeof(Value)); m->values.size = o->memberData->values.alloc; @@ -1017,8 +1019,11 @@ void MemoryManager::sweep(bool lastSweep, ClassDestroyStatsCallback classCountPt } } - blockAllocator.sweep(); - hugeItemAllocator.sweep(classCountPtr); + if (!lastSweep) { + blockAllocator.sweep(/*classCountPtr*/); + hugeItemAllocator.sweep(classCountPtr); + icAllocator.sweep(/*classCountPtr*/); + } } bool MemoryManager::shouldRunGC() const @@ -1167,6 +1172,7 @@ void MemoryManager::runGC() // reset all black bits blockAllocator.resetBlackBits(); hugeItemAllocator.resetBlackBits(); + icAllocator.resetBlackBits(); } size_t MemoryManager::getUsedMem() const @@ -1193,6 +1199,7 @@ MemoryManager::~MemoryManager() sweep(/*lastSweep*/true); blockAllocator.freeAll(); hugeItemAllocator.freeAll(); + icAllocator.freeAll(); delete m_weakValues; #ifdef V4_USE_VALGRIND diff --git a/src/qml/memory/qv4mm_p.h b/src/qml/memory/qv4mm_p.h index ae2153e7c4..bc9b7130c7 100644 --- a/src/qml/memory/qv4mm_p.h +++ b/src/qml/memory/qv4mm_p.h @@ -160,37 +160,52 @@ public: { return (size + Chunk::SlotSize - 1) & ~(Chunk::SlotSize - 1); } template - inline typename ManagedType::Data *allocManaged(std::size_t size, InternalClass *ic) + inline typename ManagedType::Data *allocManaged(std::size_t size, Heap::InternalClass *ic) { Q_STATIC_ASSERT(std::is_trivial< typename ManagedType::Data >::value); size = align(size); - Heap::Base *o = allocData(size); - o->internalClass = ic; - Q_ASSERT(o->internalClass && o->internalClass->vtable); + typename ManagedType::Data *d = static_cast(allocData(size)); + d->internalClass.set(engine, ic); + Q_ASSERT(d->internalClass && d->internalClass->vtable); Q_ASSERT(ic->vtable == ManagedType::staticVTable()); - return static_cast(o); + return d; + } + + template + inline typename ManagedType::Data *allocManaged(std::size_t size, InternalClass *ic) + { + return allocManaged(size, ic->d()); } template inline typename ManagedType::Data *allocManaged(std::size_t size) { - return allocManaged(size, ManagedType::defaultInternalClass(engine)); + Scope scope(engine); + Scoped ic(scope, ManagedType::defaultInternalClass(engine)); + return allocManaged(size, ic); } template - typename ObjectType::Data *allocateObject(InternalClass *ic) + typename ObjectType::Data *allocateObject(Heap::InternalClass *ic) { Heap::Object *o = allocObjectWithMemberData(ObjectType::staticVTable(), ic->size); - o->internalClass = ic; - Q_ASSERT(o->internalClass && o->internalClass->vtable); - Q_ASSERT(ic->vtable == ObjectType::staticVTable()); + o->internalClass.set(engine, ic); + Q_ASSERT(o->internalClass.get() && o->vtable()); + Q_ASSERT(o->vtable() == ObjectType::staticVTable()); return static_cast(o); } + template + typename ObjectType::Data *allocateObject(InternalClass *ic) + { + return allocateObject(ic->d()); + } + template typename ObjectType::Data *allocateObject() { - InternalClass *ic = ObjectType::defaultInternalClass(engine); + Scope scope(engine); + Scoped ic(scope, ObjectType::defaultInternalClass(engine)); ic = ic->changeVTable(ObjectType::staticVTable()); ic = ic->changePrototype(ObjectType::defaultPrototype(engine)->d()); return allocateObject(ic); @@ -200,18 +215,18 @@ public: typename ManagedType::Data *allocWithStringData(std::size_t unmanagedSize, Arg1 arg1) { typename ManagedType::Data *o = reinterpret_cast(allocString(unmanagedSize)); - o->internalClass = ManagedType::defaultInternalClass(engine); + o->internalClass.set(engine, ManagedType::defaultInternalClass(engine)); Q_ASSERT(o->internalClass && o->internalClass->vtable); o->init(arg1); return o; } - template - typename ObjectType::Data *allocObject(InternalClass *ic) + template + typename ObjectType::Data *allocObject(Heap::InternalClass *ic, Args... args) { Scope scope(engine); Scoped t(scope, allocateObject(ic)); - t->d_unchecked()->init(); + t->d_unchecked()->init(args...); return t->d(); } @@ -253,6 +268,14 @@ public: // called when a JS object grows itself. Specifically: Heap::String::append void changeUnmanagedHeapSizeUsage(qptrdiff delta) { unmanagedHeapSize += delta; } + template + typename ManagedType::Data *allocIC() + { + size_t size = align(sizeof(typename ManagedType::Data)); + Heap::Base *b = *icAllocator.allocate(size, true); + return static_cast(b); + } + protected: /// expects size to be aligned Heap::Base *allocString(std::size_t unmanagedSize); @@ -270,6 +293,7 @@ public: QV4::ExecutionEngine *engine; ChunkAllocator *chunkAllocator; BlockAllocator blockAllocator; + BlockAllocator icAllocator; HugeItemAllocator hugeItemAllocator; PersistentValueStorage *m_persistentValues; PersistentValueStorage *m_weakValues; diff --git a/src/qml/qml/v8/qv8engine.cpp b/src/qml/qml/v8/qv8engine.cpp index 7b2de8afd4..8a786e76cf 100644 --- a/src/qml/qml/v8/qv8engine.cpp +++ b/src/qml/qml/v8/qv8engine.cpp @@ -231,7 +231,7 @@ static void freeze_recursive(QV4::ExecutionEngine *v4, QV4::Object *object) if (!instanceOfObject) return; - QV4::InternalClass *frozen = object->internalClass()->propertiesFrozen(); + QV4::Heap::InternalClass *frozen = object->internalClass()->propertiesFrozen(); if (object->internalClass() == frozen) return; object->setInternalClass(frozen); -- cgit v1.2.3