aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp2
-rw-r--r--src/plugins/qmltooling/qmldbg_nativedebugger/qqmlnativedebugservice.cpp2
-rw-r--r--src/qml/compiler/qv4compileddata.cpp36
-rw-r--r--src/qml/compiler/qv4compileddata_p.h5
-rw-r--r--src/qml/jsruntime/qv4engine.cpp67
-rw-r--r--src/qml/jsruntime/qv4engine_p.h8
-rw-r--r--src/qml/jsruntime/qv4enginebase_p.h4
-rw-r--r--src/qml/jsruntime/qv4errorobject_p.h16
-rw-r--r--src/qml/jsruntime/qv4function.cpp10
-rw-r--r--src/qml/jsruntime/qv4function_p.h2
-rw-r--r--src/qml/jsruntime/qv4functionobject.cpp17
-rw-r--r--src/qml/jsruntime/qv4functionobject_p.h10
-rw-r--r--src/qml/jsruntime/qv4global_p.h1
-rw-r--r--src/qml/jsruntime/qv4internalclass.cpp226
-rw-r--r--src/qml/jsruntime/qv4internalclass_p.h64
-rw-r--r--src/qml/jsruntime/qv4lookup.cpp52
-rw-r--r--src/qml/jsruntime/qv4lookup_p.h10
-rw-r--r--src/qml/jsruntime/qv4managed.cpp5
-rw-r--r--src/qml/jsruntime/qv4managed_p.h37
-rw-r--r--src/qml/jsruntime/qv4object.cpp17
-rw-r--r--src/qml/jsruntime/qv4object_p.h2
-rw-r--r--src/qml/jsruntime/qv4runtime.cpp10
-rw-r--r--src/qml/jsruntime/qv4string.cpp1
-rw-r--r--src/qml/jsruntime/qv4typedarray.cpp6
-rw-r--r--src/qml/memory/qv4heap_p.h5
-rw-r--r--src/qml/memory/qv4mm.cpp15
-rw-r--r--src/qml/memory/qv4mm_p.h54
-rw-r--r--src/qml/qml/v8/qv8engine.cpp2
28 files changed, 431 insertions, 255 deletions
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<QV4::CallContext> 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<CompilationUnitBase>::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<QV4::Function *> runtimeFunctions;
mutable QQmlNullableValue<QUrl> m_url;
mutable QQmlNullableValue<QUrl> 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<InternalClass>();
+ 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<ObjectPrototype>(ic);
+ Scope scope(this);
+ Scoped<InternalClass> ic(scope);
+ ic = classes[Class_Empty]->changeVTable(QV4::Object::staticVTable());
+ jsObjects[ObjectProto] = memoryManager->allocObject<ObjectPrototype>(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<ArrayPrototype>(ic);
+ Q_ASSERT(ic->d()->prototype);
+ jsObjects[ArrayProto] = memoryManager->allocObject<ArrayPrototype>(ic->d());
classes[Class_ArrayObject] = ic->changePrototype(arrayPrototype()->d());
jsObjects[PropertyListProto] = memoryManager->allocate<PropertyListPrototype>();
- InternalClass *argsClass = newInternalClass(ArgumentsObject::staticVTable(), objectPrototype());
+ Scoped<InternalClass> 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<StringPrototype>(ic);
+ jsObjects[StringProto] = memoryManager->allocObject<StringPrototype>(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<FunctionPrototype>(ic);
+ jsObjects[FunctionProto] = memoryManager->allocObject<FunctionPrototype>(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<RegExpPrototype>(ic);
+ jsObjects[RegExpProto] = memoryManager->allocObject<RegExpPrototype>(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<ErrorPrototype>(classes[Class_ErrorProto]);
- jsObjects[EvalErrorProto] = memoryManager->allocObject<EvalErrorPrototype>(classes[Class_ErrorProto]->changePrototype(errorPrototype()->d()));
- jsObjects[RangeErrorProto] = memoryManager->allocObject<RangeErrorPrototype>(classes[Class_ErrorProto]->changePrototype(errorPrototype()->d()));
- jsObjects[ReferenceErrorProto] = memoryManager->allocObject<ReferenceErrorPrototype>(classes[Class_ErrorProto]->changePrototype(errorPrototype()->d()));
- jsObjects[SyntaxErrorProto] = memoryManager->allocObject<SyntaxErrorPrototype>(classes[Class_ErrorProto]->changePrototype(errorPrototype()->d()));
- jsObjects[TypeErrorProto] = memoryManager->allocObject<TypeErrorPrototype>(classes[Class_ErrorProto]->changePrototype(errorPrototype()->d()));
- jsObjects[URIErrorProto] = memoryManager->allocObject<URIErrorPrototype>(classes[Class_ErrorProto]->changePrototype(errorPrototype()->d()));
+ ic = classes[Class_ErrorProto]->changePrototype(errorPrototype()->d());
+ jsObjects[EvalErrorProto] = memoryManager->allocObject<EvalErrorPrototype>(ic->d());
+ jsObjects[RangeErrorProto] = memoryManager->allocObject<RangeErrorPrototype>(ic->d());
+ jsObjects[ReferenceErrorProto] = memoryManager->allocObject<ReferenceErrorPrototype>(ic->d());
+ jsObjects[SyntaxErrorProto] = memoryManager->allocObject<SyntaxErrorPrototype>(ic->d());
+ jsObjects[TypeErrorProto] = memoryManager->allocObject<TypeErrorPrototype>(ic->d());
+ jsObjects[URIErrorProto] = memoryManager->allocObject<URIErrorPrototype>(ic->d());
jsObjects[VariantProto] = memoryManager->allocate<VariantPrototype>();
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<SequencePrototype>(ic));
+ jsObjects[SequenceProto] = ScopedValue(scope, memoryManager->allocObject<SequencePrototype>(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<InternalClass>();
+ 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<InternalClass> 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<Object>();
}
-Heap::Object *ExecutionEngine::newObject(InternalClass *internalClass)
+Heap::Object *ExecutionEngine::newObject(Heap::InternalClass *internalClass)
{
return memoryManager->allocObject<Object>(internalClass);
}
@@ -624,7 +633,7 @@ Heap::ArrayObject *ExecutionEngine::newArrayObject(const QStringList &list)
return memoryManager->allocate<ArrayObject>(list);
}
-Heap::ArrayObject *ExecutionEngine::newArrayObject(InternalClass *internalClass)
+Heap::ArrayObject *ExecutionEngine::newArrayObject(Heap::InternalClass *internalClass)
{
return memoryManager->allocObject<ArrayObject>(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 <typename T>
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<T>(ic, message);
+ Scope scope(e);
+ Scoped<InternalClass> ic(scope, e->internalClasses(klass)->changePrototype(T::defaultPrototype(e)->d()));
+ return e->memoryManager->allocObject<T>(ic->d(), message);
}
template <typename T>
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<T>(ic, v);
+ Scoped<InternalClass> ic(scope, e->internalClasses(klass)->changePrototype(T::defaultPrototype(e)->d()));
+ return e->memoryManager->allocObject<T>(ic->d(), v);
}
template <typename T>
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<T>(ic, v, filename, line, column);
+ Scoped<InternalClass> ic(scope, e->internalClasses(klass)->changePrototype(T::defaultPrototype(e)->d()));
+ return e->memoryManager->allocObject<T>(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<InternalClass> 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<const ScriptFunction *>(fo);
Scope scope(v4);
- InternalClass *ic = f->classForConstructor();
- ScopedValue thisObject(scope, v4->memoryManager->allocObject<Object>(ic));
+ ScopedValue thisObject(scope, v4->memoryManager->allocObject<Object>(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<InternalClass> 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<Identifier *>();
+ new (&propertyData) SharedInternalClassData<PropertyAttributes>();
+ new (&transitions) std::vector<Transition>();
+
+ 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<Identifier *>(other->nameMap);
+ new (&propertyData) SharedInternalClassData<PropertyAttributes>(other->propertyData);
+ new (&transitions) std::vector<Transition>();
+
+ 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<Identifier *>();
+ propertyData.~SharedInternalClassData<PropertyAttributes>();
+ transitions.~vector<Transition>();
+ 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<Heap::InternalClass *>(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<QV4::InternalClass> 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<InternalClass *> 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<Heap::InternalClass *>(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 <QHash>
#include <private/qv4identifier_p.h>
+#include <private/qv4heap_p.h>
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<Identifier *> 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<const FunctionObject *>(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<Lookup>::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<Object *>(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<CompiledData::CompilationUnit*>(engine->currentStackFrame->v4Function->compilationUnit)->runtimeClasses[classId];
- ScopedObject o(scope, engine->newObject(klass));
+ Scoped<InternalClass> 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<ArgumentsObject>(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<StrictArgumentsObject>(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<String *>(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<TypedArray>(ic, t);
+ Scope scope(e);
+ Scoped<InternalClass> ic(scope, e->newInternalClass(staticVTable(), e->typedArrayPrototype + t));
+ return e->memoryManager->allocObject<TypedArray>(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 *, 0> internalClass;
inline ReturnedValue asReturnedValue() const;
inline void mark(QV4::MarkStack *markStack);
@@ -195,7 +195,6 @@ Q_STATIC_ASSERT(std::is_standard_layout<Base>::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<uint>((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<typename ManagedType>
- 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<typename ManagedType::Data *>(allocData(size));
+ d->internalClass.set(engine, ic);
+ Q_ASSERT(d->internalClass && d->internalClass->vtable);
Q_ASSERT(ic->vtable == ManagedType::staticVTable());
- return static_cast<typename ManagedType::Data *>(o);
+ return d;
+ }
+
+ template<typename ManagedType>
+ inline typename ManagedType::Data *allocManaged(std::size_t size, InternalClass *ic)
+ {
+ return allocManaged<ManagedType>(size, ic->d());
}
template<typename ManagedType>
inline typename ManagedType::Data *allocManaged(std::size_t size)
{
- return allocManaged<ManagedType>(size, ManagedType::defaultInternalClass(engine));
+ Scope scope(engine);
+ Scoped<InternalClass> ic(scope, ManagedType::defaultInternalClass(engine));
+ return allocManaged<ManagedType>(size, ic);
}
template <typename ObjectType>
- 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<typename ObjectType::Data *>(o);
}
template <typename ObjectType>
+ typename ObjectType::Data *allocateObject(InternalClass *ic)
+ {
+ return allocateObject<ObjectType>(ic->d());
+ }
+
+ template <typename ObjectType>
typename ObjectType::Data *allocateObject()
{
- InternalClass *ic = ObjectType::defaultInternalClass(engine);
+ Scope scope(engine);
+ Scoped<InternalClass> ic(scope, ObjectType::defaultInternalClass(engine));
ic = ic->changeVTable(ObjectType::staticVTable());
ic = ic->changePrototype(ObjectType::defaultPrototype(engine)->d());
return allocateObject<ObjectType>(ic);
@@ -200,18 +215,18 @@ public:
typename ManagedType::Data *allocWithStringData(std::size_t unmanagedSize, Arg1 arg1)
{
typename ManagedType::Data *o = reinterpret_cast<typename ManagedType::Data *>(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>
- typename ObjectType::Data *allocObject(InternalClass *ic)
+ template <typename ObjectType, typename... Args>
+ typename ObjectType::Data *allocObject(Heap::InternalClass *ic, Args... args)
{
Scope scope(engine);
Scoped<ObjectType> t(scope, allocateObject<ObjectType>(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>
+ typename ManagedType::Data *allocIC()
+ {
+ size_t size = align(sizeof(typename ManagedType::Data));
+ Heap::Base *b = *icAllocator.allocate(size, true);
+ return static_cast<typename ManagedType::Data *>(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);