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 <simon.hausmann@qt.io>
This commit is contained in:
parent
3932536b59
commit
6002b48c3c
|
@ -269,7 +269,7 @@ bool QV4DataCollector::collectScope(QJsonObject *dict, int frameNr, int scopeNr)
|
||||||
|
|
||||||
Refs collectedRefs;
|
Refs collectedRefs;
|
||||||
QV4::ScopedValue v(scope);
|
QV4::ScopedValue v(scope);
|
||||||
QV4::InternalClass *ic = ctxt->internalClass();
|
QV4::Heap::InternalClass *ic = ctxt->internalClass();
|
||||||
for (uint i = 0; i < ic->size; ++i) {
|
for (uint i = 0; i < ic->size; ++i) {
|
||||||
QString name = ic->nameMap[i]->string;
|
QString name = ic->nameMap[i]->string;
|
||||||
names.append(name);
|
names.append(name);
|
||||||
|
|
|
@ -491,7 +491,7 @@ void NativeDebugger::handleVariables(QJsonObject *response, const QJsonObject &a
|
||||||
collector.collect(&output, QString(), QStringLiteral("this"), thisObject);
|
collector.collect(&output, QString(), QStringLiteral("this"), thisObject);
|
||||||
QV4::Scoped<QV4::CallContext> callContext(scope, frame->callContext());
|
QV4::Scoped<QV4::CallContext> callContext(scope, frame->callContext());
|
||||||
if (callContext) {
|
if (callContext) {
|
||||||
QV4::InternalClass *ic = callContext->internalClass();
|
QV4::Heap::InternalClass *ic = callContext->internalClass();
|
||||||
QV4::ScopedValue v(scope);
|
QV4::ScopedValue v(scope);
|
||||||
for (uint i = 0; i < ic->size; ++i) {
|
for (uint i = 0; i < ic->size; ++i) {
|
||||||
QString name = ic->nameMap[i]->string;
|
QString name = ic->nameMap[i]->string;
|
||||||
|
|
|
@ -96,8 +96,9 @@ static QString cacheFilePath(const QUrl &url)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
CompilationUnit::CompilationUnit(const Unit *unitData)
|
CompilationUnit::CompilationUnit(const Unit *unitData)
|
||||||
: data(unitData)
|
{
|
||||||
{}
|
data = unitData;
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef V4_BOOTSTRAP
|
#ifndef V4_BOOTSTRAP
|
||||||
CompilationUnit::~CompilationUnit()
|
CompilationUnit::~CompilationUnit()
|
||||||
|
@ -157,15 +158,15 @@ QV4::Function *CompilationUnit::linkToEngine(ExecutionEngine *engine)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data->jsClassTableSize) {
|
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) {
|
for (uint i = 0; i < data->jsClassTableSize; ++i) {
|
||||||
int memberCount = 0;
|
int memberCount = 0;
|
||||||
const CompiledData::JSClassMember *member = data->jsClassAt(i, &memberCount);
|
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)
|
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] = runtimeClasses[i]->addMember(engine->identifierTable->identifier(runtimeStrings[member->nameOffset]), member->isAccessor ? QV4::Attr_Accessor : QV4::Attr_Data);
|
||||||
|
|
||||||
runtimeClasses[i] = klass;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -244,13 +245,28 @@ void CompilationUnit::unlink()
|
||||||
|
|
||||||
void CompilationUnit::markObjects(QV4::MarkStack *markStack)
|
void CompilationUnit::markObjects(QV4::MarkStack *markStack)
|
||||||
{
|
{
|
||||||
|
if (runtimeStrings) {
|
||||||
for (uint i = 0; i < data->stringTableSize; ++i)
|
for (uint i = 0; i < data->stringTableSize; ++i)
|
||||||
if (runtimeStrings[i])
|
if (runtimeStrings[i])
|
||||||
runtimeStrings[i]->mark(markStack);
|
runtimeStrings[i]->mark(markStack);
|
||||||
|
}
|
||||||
if (runtimeRegularExpressions) {
|
if (runtimeRegularExpressions) {
|
||||||
for (uint i = 0; i < data->regexpTableSize; ++i)
|
for (uint i = 0; i < data->regexpTableSize; ++i)
|
||||||
runtimeRegularExpressions[i].mark(markStack);
|
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)
|
IdentifierHash CompilationUnit::namedObjectsPerComponent(int componentObjectIndex)
|
||||||
|
|
|
@ -881,6 +881,8 @@ struct Q_QML_PRIVATE_EXPORT CompilationUnitBase
|
||||||
QV4::Heap::String **runtimeStrings = nullptr; // Array
|
QV4::Heap::String **runtimeStrings = nullptr; // Array
|
||||||
const Value* constants = nullptr;
|
const Value* constants = nullptr;
|
||||||
QV4::Value *runtimeRegularExpressions = nullptr;
|
QV4::Value *runtimeRegularExpressions = nullptr;
|
||||||
|
const Unit *data = nullptr;
|
||||||
|
QV4::Heap::InternalClass **runtimeClasses = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
Q_STATIC_ASSERT(std::is_standard_layout<CompilationUnitBase>::value);
|
Q_STATIC_ASSERT(std::is_standard_layout<CompilationUnitBase>::value);
|
||||||
|
@ -915,8 +917,6 @@ public:
|
||||||
return refCount.load();
|
return refCount.load();
|
||||||
}
|
}
|
||||||
|
|
||||||
const Unit *data = nullptr;
|
|
||||||
|
|
||||||
// Called only when building QML, when we build the header for JS first and append QML data
|
// Called only when building QML, when we build the header for JS first and append QML data
|
||||||
QV4::CompiledData::Unit *createUnitData(QmlIR::Document *irDocument);
|
QV4::CompiledData::Unit *createUnitData(QmlIR::Document *irDocument);
|
||||||
|
|
||||||
|
@ -943,7 +943,6 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
QV4::Lookup *runtimeLookups = nullptr;
|
QV4::Lookup *runtimeLookups = nullptr;
|
||||||
QV4::InternalClass **runtimeClasses = nullptr;
|
|
||||||
QVector<QV4::Function *> runtimeFunctions;
|
QVector<QV4::Function *> runtimeFunctions;
|
||||||
mutable QQmlNullableValue<QUrl> m_url;
|
mutable QQmlNullableValue<QUrl> m_url;
|
||||||
mutable QQmlNullableValue<QUrl> m_finalUrl;
|
mutable QQmlNullableValue<QUrl> m_finalUrl;
|
||||||
|
|
|
@ -199,7 +199,10 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine)
|
||||||
|
|
||||||
identifierTable = new IdentifierTable(this);
|
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_String] = classes[Class_Empty]->changeVTable(QV4::String::staticVTable());
|
||||||
classes[Class_MemberData] = classes[Class_Empty]->changeVTable(QV4::MemberData::staticVTable());
|
classes[Class_MemberData] = classes[Class_Empty]->changeVTable(QV4::MemberData::staticVTable());
|
||||||
classes[Class_SimpleArrayData] = classes[Class_Empty]->changeVTable(QV4::SimpleArrayData::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_buffer] = newIdentifier(QStringLiteral("buffer"));
|
||||||
jsStrings[String_lastIndex] = newIdentifier(QStringLiteral("lastIndex"));
|
jsStrings[String_lastIndex] = newIdentifier(QStringLiteral("lastIndex"));
|
||||||
|
|
||||||
InternalClass *ic = classes[Class_Empty]->changeVTable(QV4::Object::staticVTable());
|
Scope scope(this);
|
||||||
jsObjects[ObjectProto] = memoryManager->allocObject<ObjectPrototype>(ic);
|
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[Class_Object] = ic->changePrototype(objectPrototype()->d());
|
||||||
classes[EngineBase::Class_QmlContextWrapper] = classes[Class_Object]->changeVTable(QV4::QQmlContextWrapper::staticVTable());
|
classes[EngineBase::Class_QmlContextWrapper] = classes[Class_Object]->changeVTable(QV4::QQmlContextWrapper::staticVTable());
|
||||||
|
|
||||||
ic = newInternalClass(ArrayPrototype::staticVTable(), objectPrototype());
|
ic = newInternalClass(ArrayPrototype::staticVTable(), objectPrototype());
|
||||||
Q_ASSERT(ic->prototype);
|
Q_ASSERT(ic->d()->prototype);
|
||||||
ic = ic->addMember(id_length(), Attr_NotConfigurable|Attr_NotEnumerable);
|
ic = ic->addMember(id_length(), Attr_NotConfigurable|Attr_NotEnumerable);
|
||||||
Q_ASSERT(ic->prototype);
|
Q_ASSERT(ic->d()->prototype);
|
||||||
jsObjects[ArrayProto] = memoryManager->allocObject<ArrayPrototype>(ic);
|
jsObjects[ArrayProto] = memoryManager->allocObject<ArrayPrototype>(ic->d());
|
||||||
classes[Class_ArrayObject] = ic->changePrototype(arrayPrototype()->d());
|
classes[Class_ArrayObject] = ic->changePrototype(arrayPrototype()->d());
|
||||||
jsObjects[PropertyListProto] = memoryManager->allocate<PropertyListPrototype>();
|
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);
|
argsClass = argsClass->addMember(id_length(), Attr_NotEnumerable);
|
||||||
classes[Class_ArgumentsObject] = argsClass->addMember(id_callee(), Attr_Data|Attr_NotEnumerable);
|
classes[Class_ArgumentsObject] = argsClass->addMember(id_callee(), Attr_Data|Attr_NotEnumerable);
|
||||||
argsClass = newInternalClass(StrictArgumentsObject::staticVTable(), objectPrototype());
|
argsClass = newInternalClass(StrictArgumentsObject::staticVTable(), objectPrototype());
|
||||||
|
@ -273,7 +279,7 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine)
|
||||||
|
|
||||||
ic = newInternalClass(QV4::StringObject::staticVTable(), objectPrototype());
|
ic = newInternalClass(QV4::StringObject::staticVTable(), objectPrototype());
|
||||||
ic = ic->addMember(id_length(), Attr_ReadOnly);
|
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());
|
classes[Class_StringObject] = ic->changePrototype(stringPrototype()->d());
|
||||||
Q_ASSERT(classes[Class_StringObject]->find(id_length()) == Heap::StringObject::LengthPropertyIndex);
|
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 = newInternalClass(QV4::FunctionPrototype::staticVTable(), objectPrototype());
|
||||||
ic = ic->addMember(id_prototype(), Attr_NotEnumerable, &index);
|
ic = ic->addMember(id_prototype(), Attr_NotEnumerable, &index);
|
||||||
Q_ASSERT(index == Heap::FunctionObject::Index_Prototype);
|
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 = newInternalClass(FunctionObject::staticVTable(), functionPrototype());
|
||||||
ic = ic->addMember(id_prototype(), Attr_NotEnumerable|Attr_NotConfigurable, &index);
|
ic = ic->addMember(id_prototype(), Attr_NotEnumerable|Attr_NotConfigurable, &index);
|
||||||
Q_ASSERT(index == Heap::FunctionObject::Index_Prototype);
|
Q_ASSERT(index == Heap::FunctionObject::Index_Prototype);
|
||||||
classes[Class_FunctionObject] = ic;
|
classes[Class_FunctionObject] = ic->d();
|
||||||
ic = ic->addMember(id_name(), Attr_ReadOnly, &index);
|
ic = ic->addMember(id_name(), Attr_ReadOnly, &index);
|
||||||
Q_ASSERT(index == Heap::ScriptFunction::Index_Name);
|
Q_ASSERT(index == Heap::ScriptFunction::Index_Name);
|
||||||
ic = ic->changeVTable(ScriptFunction::staticVTable());
|
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);
|
classes[Class_ObjectProto] = classes[Class_Object]->addMember(id_constructor(), Attr_NotEnumerable, &index);
|
||||||
Q_ASSERT(index == Heap::FunctionObject::Index_ProtoConstructor);
|
Q_ASSERT(index == Heap::FunctionObject::Index_ProtoConstructor);
|
||||||
|
|
||||||
Scope scope(this);
|
|
||||||
ScopedString str(scope);
|
ScopedString str(scope);
|
||||||
classes[Class_RegExp] = classes[Class_Empty]->changeVTable(QV4::RegExp::staticVTable());
|
classes[Class_RegExp] = classes[Class_Empty]->changeVTable(QV4::RegExp::staticVTable());
|
||||||
ic = newInternalClass(QV4::RegExpObject::staticVTable(), objectPrototype());
|
ic = newInternalClass(QV4::RegExpObject::staticVTable(), objectPrototype());
|
||||||
|
@ -312,7 +317,7 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine)
|
||||||
Q_ASSERT(index == RegExpObject::Index_IgnoreCase);
|
Q_ASSERT(index == RegExpObject::Index_IgnoreCase);
|
||||||
ic = ic->addMember((str = newIdentifier(QStringLiteral("multiline"))), Attr_ReadOnly, &index);
|
ic = ic->addMember((str = newIdentifier(QStringLiteral("multiline"))), Attr_ReadOnly, &index);
|
||||||
Q_ASSERT(index == RegExpObject::Index_Multiline);
|
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());
|
classes[Class_RegExpObject] = ic->changePrototype(regExpPrototype()->d());
|
||||||
|
|
||||||
ic = classes[Class_ArrayObject]->addMember(id_index(), Attr_Data, &index);
|
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);
|
ic = ic->addMember((str = newIdentifier(QStringLiteral("fileName"))), Attr_Data|Attr_NotEnumerable, &index);
|
||||||
Q_ASSERT(index == ErrorObject::Index_FileName);
|
Q_ASSERT(index == ErrorObject::Index_FileName);
|
||||||
ic = ic->addMember((str = newIdentifier(QStringLiteral("lineNumber"))), Attr_Data|Attr_NotEnumerable, &index);
|
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);
|
Q_ASSERT(index == ErrorObject::Index_LineNumber);
|
||||||
classes[Class_ErrorObjectWithMessage] = ic->addMember((str = newIdentifier(QStringLiteral("message"))), Attr_Data|Attr_NotEnumerable, &index);
|
classes[Class_ErrorObjectWithMessage] = ic->addMember((str = newIdentifier(QStringLiteral("message"))), Attr_Data|Attr_NotEnumerable, &index);
|
||||||
Q_ASSERT(index == ErrorObject::Index_Message);
|
Q_ASSERT(index == ErrorObject::Index_Message);
|
||||||
|
@ -342,19 +347,20 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine)
|
||||||
getStackFunction()->defineReadonlyProperty(id_length(), Primitive::fromInt32(0));
|
getStackFunction()->defineReadonlyProperty(id_length(), Primitive::fromInt32(0));
|
||||||
|
|
||||||
jsObjects[ErrorProto] = memoryManager->allocObject<ErrorPrototype>(classes[Class_ErrorProto]);
|
jsObjects[ErrorProto] = memoryManager->allocObject<ErrorPrototype>(classes[Class_ErrorProto]);
|
||||||
jsObjects[EvalErrorProto] = memoryManager->allocObject<EvalErrorPrototype>(classes[Class_ErrorProto]->changePrototype(errorPrototype()->d()));
|
ic = classes[Class_ErrorProto]->changePrototype(errorPrototype()->d());
|
||||||
jsObjects[RangeErrorProto] = memoryManager->allocObject<RangeErrorPrototype>(classes[Class_ErrorProto]->changePrototype(errorPrototype()->d()));
|
jsObjects[EvalErrorProto] = memoryManager->allocObject<EvalErrorPrototype>(ic->d());
|
||||||
jsObjects[ReferenceErrorProto] = memoryManager->allocObject<ReferenceErrorPrototype>(classes[Class_ErrorProto]->changePrototype(errorPrototype()->d()));
|
jsObjects[RangeErrorProto] = memoryManager->allocObject<RangeErrorPrototype>(ic->d());
|
||||||
jsObjects[SyntaxErrorProto] = memoryManager->allocObject<SyntaxErrorPrototype>(classes[Class_ErrorProto]->changePrototype(errorPrototype()->d()));
|
jsObjects[ReferenceErrorProto] = memoryManager->allocObject<ReferenceErrorPrototype>(ic->d());
|
||||||
jsObjects[TypeErrorProto] = memoryManager->allocObject<TypeErrorPrototype>(classes[Class_ErrorProto]->changePrototype(errorPrototype()->d()));
|
jsObjects[SyntaxErrorProto] = memoryManager->allocObject<SyntaxErrorPrototype>(ic->d());
|
||||||
jsObjects[URIErrorProto] = memoryManager->allocObject<URIErrorPrototype>(classes[Class_ErrorProto]->changePrototype(errorPrototype()->d()));
|
jsObjects[TypeErrorProto] = memoryManager->allocObject<TypeErrorPrototype>(ic->d());
|
||||||
|
jsObjects[URIErrorProto] = memoryManager->allocObject<URIErrorPrototype>(ic->d());
|
||||||
|
|
||||||
jsObjects[VariantProto] = memoryManager->allocate<VariantPrototype>();
|
jsObjects[VariantProto] = memoryManager->allocate<VariantPrototype>();
|
||||||
Q_ASSERT(variantPrototype()->prototype() == objectPrototype()->d());
|
Q_ASSERT(variantPrototype()->prototype() == objectPrototype()->d());
|
||||||
|
|
||||||
#if QT_CONFIG(qml_sequence_object)
|
#if QT_CONFIG(qml_sequence_object)
|
||||||
ic = newInternalClass(SequencePrototype::staticVTable(), SequencePrototype::defaultPrototype(this));
|
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
|
#endif
|
||||||
|
|
||||||
ExecutionContext *global = rootContext();
|
ExecutionContext *global = rootContext();
|
||||||
|
@ -496,7 +502,6 @@ ExecutionEngine::~ExecutionEngine()
|
||||||
while (!compilationUnits.isEmpty())
|
while (!compilationUnits.isEmpty())
|
||||||
(*compilationUnits.begin())->unlink();
|
(*compilationUnits.begin())->unlink();
|
||||||
|
|
||||||
internalClasses(Class_Empty)->destroyAll();
|
|
||||||
delete bumperPointerAllocator;
|
delete bumperPointerAllocator;
|
||||||
delete regExpCache;
|
delete regExpCache;
|
||||||
delete regExpAllocator;
|
delete regExpAllocator;
|
||||||
|
@ -532,14 +537,18 @@ void ExecutionEngine::initRootContext()
|
||||||
jsObjects[IntegerNull] = Encode((int)0);
|
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()
|
Heap::Object *ExecutionEngine::newObject()
|
||||||
|
@ -547,7 +556,7 @@ Heap::Object *ExecutionEngine::newObject()
|
||||||
return memoryManager->allocate<Object>();
|
return memoryManager->allocate<Object>();
|
||||||
}
|
}
|
||||||
|
|
||||||
Heap::Object *ExecutionEngine::newObject(InternalClass *internalClass)
|
Heap::Object *ExecutionEngine::newObject(Heap::InternalClass *internalClass)
|
||||||
{
|
{
|
||||||
return memoryManager->allocObject<Object>(internalClass);
|
return memoryManager->allocObject<Object>(internalClass);
|
||||||
}
|
}
|
||||||
|
@ -624,7 +633,7 @@ Heap::ArrayObject *ExecutionEngine::newArrayObject(const QStringList &list)
|
||||||
return memoryManager->allocate<ArrayObject>(list);
|
return memoryManager->allocate<ArrayObject>(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
Heap::ArrayObject *ExecutionEngine::newArrayObject(InternalClass *internalClass)
|
Heap::ArrayObject *ExecutionEngine::newArrayObject(Heap::InternalClass *internalClass)
|
||||||
{
|
{
|
||||||
return memoryManager->allocObject<ArrayObject>(internalClass);
|
return memoryManager->allocObject<ArrayObject>(internalClass);
|
||||||
}
|
}
|
||||||
|
@ -916,7 +925,9 @@ void ExecutionEngine::markObjects(MarkStack *markStack)
|
||||||
setter->mark(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();
|
markStack->drain();
|
||||||
|
|
||||||
for (auto compilationUnit: compilationUnits) {
|
for (auto compilationUnit: compilationUnits) {
|
||||||
|
|
|
@ -400,10 +400,10 @@ public:
|
||||||
|
|
||||||
int newInternalClassId() { return ++internalClassIdCount; }
|
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();
|
||||||
Heap::Object *newObject(InternalClass *internalClass);
|
Heap::Object *newObject(Heap::InternalClass *internalClass);
|
||||||
|
|
||||||
Heap::String *newString(const QString &s = QString());
|
Heap::String *newString(const QString &s = QString());
|
||||||
Heap::String *newIdentifier(const QString &text);
|
Heap::String *newIdentifier(const QString &text);
|
||||||
|
@ -415,7 +415,7 @@ public:
|
||||||
Heap::ArrayObject *newArrayObject(int count = 0);
|
Heap::ArrayObject *newArrayObject(int count = 0);
|
||||||
Heap::ArrayObject *newArrayObject(const Value *values, int length);
|
Heap::ArrayObject *newArrayObject(const Value *values, int length);
|
||||||
Heap::ArrayObject *newArrayObject(const QStringList &list);
|
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(const QByteArray &array);
|
||||||
Heap::ArrayBuffer *newArrayBuffer(size_t length);
|
Heap::ArrayBuffer *newArrayBuffer(size_t length);
|
||||||
|
@ -455,7 +455,7 @@ public:
|
||||||
|
|
||||||
void initRootContext();
|
void initRootContext();
|
||||||
|
|
||||||
InternalClass *newClass(InternalClass *other);
|
Heap::InternalClass *newClass(Heap::InternalClass *other);
|
||||||
|
|
||||||
StackTrace exceptionStackTrace;
|
StackTrace exceptionStackTrace;
|
||||||
|
|
||||||
|
|
|
@ -115,8 +115,8 @@ struct Q_QML_EXPORT EngineBase {
|
||||||
Class_QmlContextWrapper,
|
Class_QmlContextWrapper,
|
||||||
NClasses
|
NClasses
|
||||||
};
|
};
|
||||||
InternalClass *classes[NClasses];
|
Heap::InternalClass *classes[NClasses];
|
||||||
InternalClass *internalClasses(InternalClassType icType) { return classes[icType]; }
|
Heap::InternalClass *internalClasses(InternalClassType icType) { return classes[icType]; }
|
||||||
};
|
};
|
||||||
#if defined(Q_CC_MSVC) || defined(Q_CC_GNU)
|
#if defined(Q_CC_MSVC) || defined(Q_CC_GNU)
|
||||||
#pragma pack(pop)
|
#pragma pack(pop)
|
||||||
|
|
|
@ -329,27 +329,25 @@ inline SyntaxErrorObject *ErrorObject::asSyntaxError()
|
||||||
template <typename T>
|
template <typename T>
|
||||||
Heap::Object *ErrorObject::create(ExecutionEngine *e, const Value &message) {
|
Heap::Object *ErrorObject::create(ExecutionEngine *e, const Value &message) {
|
||||||
EngineBase::InternalClassType klass = message.isUndefined() ? EngineBase::Class_ErrorObject : EngineBase::Class_ErrorObjectWithMessage;
|
EngineBase::InternalClassType klass = message.isUndefined() ? EngineBase::Class_ErrorObject : EngineBase::Class_ErrorObjectWithMessage;
|
||||||
InternalClass *ic = e->internalClasses(klass);
|
Scope scope(e);
|
||||||
ic = ic->changePrototype(T::defaultPrototype(e)->d());
|
Scoped<InternalClass> ic(scope, e->internalClasses(klass)->changePrototype(T::defaultPrototype(e)->d()));
|
||||||
return e->memoryManager->allocObject<T>(ic, message);
|
return e->memoryManager->allocObject<T>(ic->d(), message);
|
||||||
}
|
}
|
||||||
template <typename T>
|
template <typename T>
|
||||||
Heap::Object *ErrorObject::create(ExecutionEngine *e, const QString &message) {
|
Heap::Object *ErrorObject::create(ExecutionEngine *e, const QString &message) {
|
||||||
Scope scope(e);
|
Scope scope(e);
|
||||||
ScopedValue v(scope, message.isEmpty() ? Encode::undefined() : e->newString(message)->asReturnedValue());
|
ScopedValue v(scope, message.isEmpty() ? Encode::undefined() : e->newString(message)->asReturnedValue());
|
||||||
EngineBase::InternalClassType klass = v->isUndefined() ? EngineBase::Class_ErrorObject : EngineBase::Class_ErrorObjectWithMessage;
|
EngineBase::InternalClassType klass = v->isUndefined() ? EngineBase::Class_ErrorObject : EngineBase::Class_ErrorObjectWithMessage;
|
||||||
InternalClass *ic = e->internalClasses(klass);
|
Scoped<InternalClass> ic(scope, e->internalClasses(klass)->changePrototype(T::defaultPrototype(e)->d()));
|
||||||
ic = ic->changePrototype(T::defaultPrototype(e)->d());
|
return e->memoryManager->allocObject<T>(ic->d(), v);
|
||||||
return e->memoryManager->allocObject<T>(ic, v);
|
|
||||||
}
|
}
|
||||||
template <typename T>
|
template <typename T>
|
||||||
Heap::Object *ErrorObject::create(ExecutionEngine *e, const QString &message, const QString &filename, int line, int column) {
|
Heap::Object *ErrorObject::create(ExecutionEngine *e, const QString &message, const QString &filename, int line, int column) {
|
||||||
Scope scope(e);
|
Scope scope(e);
|
||||||
ScopedValue v(scope, message.isEmpty() ? Encode::undefined() : e->newString(message)->asReturnedValue());
|
ScopedValue v(scope, message.isEmpty() ? Encode::undefined() : e->newString(message)->asReturnedValue());
|
||||||
EngineBase::InternalClassType klass = v->isUndefined() ? EngineBase::Class_ErrorObject : EngineBase::Class_ErrorObjectWithMessage;
|
EngineBase::InternalClassType klass = v->isUndefined() ? EngineBase::Class_ErrorObject : EngineBase::Class_ErrorObjectWithMessage;
|
||||||
InternalClass *ic = e->internalClasses(klass);
|
Scoped<InternalClass> ic(scope, e->internalClasses(klass)->changePrototype(T::defaultPrototype(e)->d()));
|
||||||
ic = ic->changePrototype(T::defaultPrototype(e)->d());
|
return e->memoryManager->allocObject<T>(ic->d(), v, filename, line, column);
|
||||||
return e->memoryManager->allocObject<T>(ic, v, filename, line, column);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -61,18 +61,18 @@ Function::Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit,
|
||||||
, codeRef(nullptr)
|
, codeRef(nullptr)
|
||||||
, hasQmlDependencies(function->hasQmlDependencies())
|
, hasQmlDependencies(function->hasQmlDependencies())
|
||||||
{
|
{
|
||||||
Q_UNUSED(engine);
|
Scope scope(engine);
|
||||||
|
Scoped<InternalClass> ic(scope, engine->internalClasses(EngineBase::Class_CallContext));
|
||||||
internalClass = engine->internalClasses(EngineBase::Class_CallContext);
|
|
||||||
|
|
||||||
// first locals
|
// first locals
|
||||||
const quint32_le *localsIndices = compiledFunction->localsTable();
|
const quint32_le *localsIndices = compiledFunction->localsTable();
|
||||||
for (quint32 i = 0; i < compiledFunction->nLocals; ++i)
|
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();
|
const quint32_le *formalsIndices = compiledFunction->formalsTable();
|
||||||
for (quint32 i = 0; i < compiledFunction->nFormals; ++i)
|
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;
|
nFormals = compiledFunction->nFormals;
|
||||||
}
|
}
|
||||||
|
|
|
@ -81,7 +81,7 @@ struct Q_QML_EXPORT Function {
|
||||||
JSC::MacroAssemblerCodeRef *codeRef;
|
JSC::MacroAssemblerCodeRef *codeRef;
|
||||||
|
|
||||||
// first nArguments names in internalClass are the actual arguments
|
// first nArguments names in internalClass are the actual arguments
|
||||||
InternalClass *internalClass;
|
Heap::InternalClass *internalClass;
|
||||||
uint nFormals;
|
uint nFormals;
|
||||||
int interpreterCallCount = 0;
|
int interpreterCallCount = 0;
|
||||||
bool hasQmlDependencies;
|
bool hasQmlDependencies;
|
||||||
|
|
|
@ -371,8 +371,7 @@ ReturnedValue ScriptFunction::callAsConstructor(const FunctionObject *fo, const
|
||||||
const ScriptFunction *f = static_cast<const ScriptFunction *>(fo);
|
const ScriptFunction *f = static_cast<const ScriptFunction *>(fo);
|
||||||
|
|
||||||
Scope scope(v4);
|
Scope scope(v4);
|
||||||
InternalClass *ic = f->classForConstructor();
|
ScopedValue thisObject(scope, v4->memoryManager->allocObject<Object>(f->classForConstructor()));
|
||||||
ScopedValue thisObject(scope, v4->memoryManager->allocObject<Object>(ic));
|
|
||||||
|
|
||||||
ReturnedValue result = Moth::VME::exec(fo, thisObject, argv, argc);
|
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();
|
const Object *o = d()->protoProperty();
|
||||||
InternalClass *ic = d()->cachedClassForConstructor;
|
if (d()->cachedClassForConstructor && d()->cachedClassForConstructor->prototype == o->d())
|
||||||
if (ic && ic->prototype == o->d())
|
return d()->cachedClassForConstructor;
|
||||||
return ic;
|
|
||||||
|
|
||||||
ic = engine()->internalClasses(EngineBase::Class_Object);
|
Scope scope(engine());
|
||||||
|
Scoped<InternalClass> ic(scope, engine()->internalClasses(EngineBase::Class_Object));
|
||||||
if (o)
|
if (o)
|
||||||
ic = ic->changePrototype(o->d());
|
ic = ic->changePrototype(o->d());
|
||||||
d()->cachedClassForConstructor = ic;
|
d()->cachedClassForConstructor.set(scope.engine, ic->d());
|
||||||
|
|
||||||
return ic;
|
return ic->d();
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFINE_OBJECT_VTABLE(IndexedBuiltinFunction);
|
DEFINE_OBJECT_VTABLE(IndexedBuiltinFunction);
|
||||||
|
|
|
@ -109,14 +109,16 @@ struct IndexedBuiltinFunction : FunctionObject {
|
||||||
uint index;
|
uint index;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ScriptFunction : FunctionObject {
|
#define ScriptFunctionMembers(class, Member) \
|
||||||
|
Member(class, Pointer, InternalClass *, cachedClassForConstructor)
|
||||||
|
|
||||||
|
DECLARE_HEAP_OBJECT(ScriptFunction, FunctionObject) {
|
||||||
|
DECLARE_MARKOBJECTS(ScriptFunction)
|
||||||
enum {
|
enum {
|
||||||
Index_Name = FunctionObject::Index_Prototype + 1,
|
Index_Name = FunctionObject::Index_Prototype + 1,
|
||||||
Index_Length
|
Index_Length
|
||||||
};
|
};
|
||||||
void init(QV4::ExecutionContext *scope, Function *function);
|
void init(QV4::ExecutionContext *scope, Function *function);
|
||||||
|
|
||||||
QV4::InternalClass *cachedClassForConstructor;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#define BoundFunctionMembers(class, Member) \
|
#define BoundFunctionMembers(class, Member) \
|
||||||
|
@ -225,7 +227,7 @@ struct ScriptFunction : FunctionObject {
|
||||||
static ReturnedValue callAsConstructor(const FunctionObject *, const Value *argv, int argc);
|
static ReturnedValue callAsConstructor(const FunctionObject *, const Value *argv, int argc);
|
||||||
static ReturnedValue call(const FunctionObject *f, const Value *thisObject, 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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -168,6 +168,7 @@ namespace Heap {
|
||||||
struct CallContext;
|
struct CallContext;
|
||||||
struct QmlContext;
|
struct QmlContext;
|
||||||
struct ScriptFunction;
|
struct ScriptFunction;
|
||||||
|
struct InternalClass;
|
||||||
|
|
||||||
struct BooleanObject;
|
struct BooleanObject;
|
||||||
struct NumberObject;
|
struct NumberObject;
|
||||||
|
|
|
@ -47,7 +47,7 @@
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
using namespace QV4;
|
namespace QV4 {
|
||||||
|
|
||||||
static const uchar prime_deltas[] = {
|
static const uchar prime_deltas[] = {
|
||||||
0, 0, 1, 3, 1, 5, 3, 3, 1, 9, 7, 5, 3, 9, 25, 3,
|
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;
|
d = dd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace Heap {
|
||||||
|
|
||||||
InternalClass::InternalClass(ExecutionEngine *engine)
|
void InternalClass::init(ExecutionEngine *engine)
|
||||||
: engine(engine)
|
|
||||||
, vtable(nullptr)
|
|
||||||
, prototype(nullptr)
|
|
||||||
, parent(nullptr)
|
|
||||||
, size(0)
|
|
||||||
, extensible(true)
|
|
||||||
, isSealed(false)
|
|
||||||
, isFrozen(false)
|
|
||||||
{
|
{
|
||||||
|
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();
|
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)
|
void InternalClass::init(Heap::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)
|
|
||||||
{
|
{
|
||||||
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();
|
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();
|
Heap::Object *o = object->d();
|
||||||
ExecutionEngine *v4 = o->internalClass->engine;
|
ExecutionEngine *v4 = o->internalClass->engine;
|
||||||
|
@ -168,7 +202,7 @@ static void insertHoleIntoPropertyData(Object *object, int idx)
|
||||||
o->setProperty(v4, i, *o->propertyData(i - 1));
|
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();
|
Heap::Object *o = object->d();
|
||||||
ExecutionEngine *v4 = o->internalClass->engine;
|
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());
|
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;
|
uint idx;
|
||||||
InternalClass *oldClass = object->internalClass();
|
Heap::InternalClass *oldClass = object->internalClass();
|
||||||
InternalClass *newClass = oldClass->changeMember(string->identifier(), data, &idx);
|
Heap::InternalClass *newClass = oldClass->changeMember(string->identifier(), data, &idx);
|
||||||
if (index)
|
if (index)
|
||||||
*index = idx;
|
*index = idx;
|
||||||
|
|
||||||
|
uint oldSize = oldClass->size;
|
||||||
object->setInternalClass(newClass);
|
object->setInternalClass(newClass);
|
||||||
if (newClass->size > oldClass->size) {
|
// don't use oldClass anymore, it could be GC'ed
|
||||||
Q_ASSERT(newClass->size == oldClass->size + 1);
|
if (newClass->size > oldSize) {
|
||||||
|
Q_ASSERT(newClass->size == oldSize + 1);
|
||||||
insertHoleIntoPropertyData(object, idx);
|
insertHoleIntoPropertyData(object, idx);
|
||||||
} else if (newClass->size < oldClass->size) {
|
} else if (newClass->size < oldSize) {
|
||||||
Q_ASSERT(newClass->size == oldClass->size - 1);
|
Q_ASSERT(newClass->size == oldSize - 1);
|
||||||
removeFromPropertyData(object, idx + 1);
|
removeFromPropertyData(object, idx + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -218,7 +254,7 @@ static void addDummyEntry(InternalClass *newClass, PropertyHash::Entry e)
|
||||||
++newClass->size;
|
++newClass->size;
|
||||||
}
|
}
|
||||||
|
|
||||||
InternalClass *InternalClass::changeMember(Identifier *identifier, PropertyAttributes data, uint *index)
|
Heap::InternalClass *InternalClass::changeMember(Identifier *identifier, PropertyAttributes data, uint *index)
|
||||||
{
|
{
|
||||||
data.resolve();
|
data.resolve();
|
||||||
uint idx = find(identifier);
|
uint idx = find(identifier);
|
||||||
|
@ -228,7 +264,7 @@ InternalClass *InternalClass::changeMember(Identifier *identifier, PropertyAttri
|
||||||
*index = idx;
|
*index = idx;
|
||||||
|
|
||||||
if (data == propertyData.at(idx))
|
if (data == propertyData.at(idx))
|
||||||
return this;
|
return static_cast<Heap::InternalClass *>(this);
|
||||||
|
|
||||||
Transition temp = { { identifier }, nullptr, (int)data.flags() };
|
Transition temp = { { identifier }, nullptr, (int)data.flags() };
|
||||||
Transition &t = lookupOrInsertTransition(temp);
|
Transition &t = lookupOrInsertTransition(temp);
|
||||||
|
@ -236,7 +272,7 @@ InternalClass *InternalClass::changeMember(Identifier *identifier, PropertyAttri
|
||||||
return t.lookup;
|
return t.lookup;
|
||||||
|
|
||||||
// create a new class and add it to the tree
|
// 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()) {
|
if (data.isAccessor() != propertyData.at(idx).isAccessor()) {
|
||||||
// this changes the layout of the class, so we need to rebuild the data
|
// this changes the layout of the class, so we need to rebuild the data
|
||||||
newClass->propertyTable = PropertyHash();
|
newClass->propertyTable = PropertyHash();
|
||||||
|
@ -271,8 +307,10 @@ InternalClass *InternalClass::changeMember(Identifier *identifier, PropertyAttri
|
||||||
return newClass;
|
return newClass;
|
||||||
}
|
}
|
||||||
|
|
||||||
InternalClass *InternalClass::changePrototypeImpl(Heap::Object *proto)
|
Heap::InternalClass *InternalClass::changePrototypeImpl(Heap::Object *proto)
|
||||||
{
|
{
|
||||||
|
Scope scope(engine);
|
||||||
|
ScopedValue protectThis(scope, this);
|
||||||
if (proto)
|
if (proto)
|
||||||
proto->setUsedAsProto();
|
proto->setUsedAsProto();
|
||||||
Q_ASSERT(prototype != proto);
|
Q_ASSERT(prototype != proto);
|
||||||
|
@ -286,7 +324,7 @@ InternalClass *InternalClass::changePrototypeImpl(Heap::Object *proto)
|
||||||
return t.lookup;
|
return t.lookup;
|
||||||
|
|
||||||
// create a new class and add it to the tree
|
// create a new class and add it to the tree
|
||||||
InternalClass *newClass = engine->newClass(this);
|
Heap::InternalClass *newClass = engine->newClass(this);
|
||||||
newClass->prototype = proto;
|
newClass->prototype = proto;
|
||||||
|
|
||||||
t.lookup = newClass;
|
t.lookup = newClass;
|
||||||
|
@ -294,7 +332,7 @@ InternalClass *InternalClass::changePrototypeImpl(Heap::Object *proto)
|
||||||
return newClass;
|
return newClass;
|
||||||
}
|
}
|
||||||
|
|
||||||
InternalClass *InternalClass::changeVTableImpl(const VTable *vt)
|
Heap::InternalClass *InternalClass::changeVTableImpl(const VTable *vt)
|
||||||
{
|
{
|
||||||
Q_ASSERT(vtable != vt);
|
Q_ASSERT(vtable != vt);
|
||||||
|
|
||||||
|
@ -306,7 +344,7 @@ InternalClass *InternalClass::changeVTableImpl(const VTable *vt)
|
||||||
return t.lookup;
|
return t.lookup;
|
||||||
|
|
||||||
// create a new class and add it to the tree
|
// create a new class and add it to the tree
|
||||||
InternalClass *newClass = engine->newClass(this);
|
Heap::InternalClass *newClass = engine->newClass(this);
|
||||||
newClass->vtable = vt;
|
newClass->vtable = vt;
|
||||||
|
|
||||||
t.lookup = newClass;
|
t.lookup = newClass;
|
||||||
|
@ -315,7 +353,7 @@ InternalClass *InternalClass::changeVTableImpl(const VTable *vt)
|
||||||
return newClass;
|
return newClass;
|
||||||
}
|
}
|
||||||
|
|
||||||
InternalClass *InternalClass::nonExtensible()
|
Heap::InternalClass *InternalClass::nonExtensible()
|
||||||
{
|
{
|
||||||
if (!extensible)
|
if (!extensible)
|
||||||
return this;
|
return this;
|
||||||
|
@ -325,7 +363,7 @@ InternalClass *InternalClass::nonExtensible()
|
||||||
if (t.lookup)
|
if (t.lookup)
|
||||||
return t.lookup;
|
return t.lookup;
|
||||||
|
|
||||||
InternalClass *newClass = engine->newClass(this);
|
Heap::InternalClass *newClass = engine->newClass(this);
|
||||||
newClass->extensible = false;
|
newClass->extensible = false;
|
||||||
|
|
||||||
t.lookup = newClass;
|
t.lookup = newClass;
|
||||||
|
@ -333,7 +371,7 @@ InternalClass *InternalClass::nonExtensible()
|
||||||
return newClass;
|
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();
|
data.resolve();
|
||||||
object->internalClass()->engine->identifierTable->identifier(string);
|
object->internalClass()->engine->identifierTable->identifier(string);
|
||||||
|
@ -343,20 +381,20 @@ void InternalClass::addMember(Object *object, String *string, PropertyAttributes
|
||||||
}
|
}
|
||||||
|
|
||||||
uint idx;
|
uint idx;
|
||||||
InternalClass *newClass = object->internalClass()->addMemberImpl(string->identifier(), data, &idx);
|
Heap::InternalClass *newClass = object->internalClass()->addMemberImpl(string->identifier(), data, &idx);
|
||||||
if (index)
|
if (index)
|
||||||
*index = idx;
|
*index = idx;
|
||||||
|
|
||||||
object->setInternalClass(newClass);
|
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);
|
engine->identifierTable->identifier(string);
|
||||||
return addMember(string->identifier(), data, index);
|
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();
|
data.resolve();
|
||||||
|
|
||||||
|
@ -366,7 +404,7 @@ InternalClass *InternalClass::addMember(Identifier *identifier, PropertyAttribut
|
||||||
return addMemberImpl(identifier, data, index);
|
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 temp = { { identifier }, nullptr, (int)data.flags() };
|
||||||
Transition &t = lookupOrInsertTransition(temp);
|
Transition &t = lookupOrInsertTransition(temp);
|
||||||
|
@ -378,7 +416,7 @@ InternalClass *InternalClass::addMemberImpl(Identifier *identifier, PropertyAttr
|
||||||
return t.lookup;
|
return t.lookup;
|
||||||
|
|
||||||
// create a new class and add it to the tree
|
// 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 };
|
PropertyHash::Entry e = { identifier, newClass->size };
|
||||||
newClass->propertyTable.addEntry(e, newClass->size);
|
newClass->propertyTable.addEntry(e, newClass->size);
|
||||||
|
|
||||||
|
@ -393,9 +431,22 @@ InternalClass *InternalClass::addMemberImpl(Identifier *identifier, PropertyAttr
|
||||||
return newClass;
|
return newClass;
|
||||||
}
|
}
|
||||||
|
|
||||||
void InternalClass::removeMember(Object *object, Identifier *id)
|
void InternalClass::removeChildEntry(InternalClass *child)
|
||||||
{
|
{
|
||||||
InternalClass *oldClass = object->internalClass();
|
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)
|
||||||
|
{
|
||||||
|
Heap::InternalClass *oldClass = object->internalClass();
|
||||||
Q_ASSERT(oldClass->propertyTable.lookup(id) < oldClass->size);
|
Q_ASSERT(oldClass->propertyTable.lookup(id) < oldClass->size);
|
||||||
|
|
||||||
Transition temp = { { id }, nullptr, Transition::RemoveMember };
|
Transition temp = { { id }, nullptr, Transition::RemoveMember };
|
||||||
|
@ -403,7 +454,7 @@ void InternalClass::removeMember(Object *object, Identifier *id)
|
||||||
|
|
||||||
if (!t.lookup) {
|
if (!t.lookup) {
|
||||||
// create a new class and add it to the tree
|
// 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
|
// simply make the entry inaccessible
|
||||||
int idx = newClass->propertyTable.removeIdentifier(id, oldClass->size);
|
int idx = newClass->propertyTable.removeIdentifier(id, oldClass->size);
|
||||||
newClass->nameMap.set(idx, nullptr);
|
newClass->nameMap.set(idx, nullptr);
|
||||||
|
@ -417,7 +468,7 @@ void InternalClass::removeMember(Object *object, Identifier *id)
|
||||||
Q_ASSERT(object->internalClass()->size == oldClass->size);
|
Q_ASSERT(object->internalClass()->size == oldClass->size);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint InternalClass::find(const String *string)
|
uint InternalClass::find(const QV4::String *string)
|
||||||
{
|
{
|
||||||
engine->identifierTable->identifier(string);
|
engine->identifierTable->identifier(string);
|
||||||
const Identifier *id = string->d()->identifier;
|
const Identifier *id = string->d()->identifier;
|
||||||
|
@ -429,7 +480,7 @@ uint InternalClass::find(const String *string)
|
||||||
return UINT_MAX;
|
return UINT_MAX;
|
||||||
}
|
}
|
||||||
|
|
||||||
InternalClass *InternalClass::sealed()
|
Heap::InternalClass *InternalClass::sealed()
|
||||||
{
|
{
|
||||||
if (isSealed)
|
if (isSealed)
|
||||||
return this;
|
return this;
|
||||||
|
@ -458,7 +509,7 @@ InternalClass *InternalClass::sealed()
|
||||||
return t.lookup;
|
return t.lookup;
|
||||||
}
|
}
|
||||||
|
|
||||||
InternalClass *s = engine->newClass(this);
|
Heap::InternalClass *s = engine->newClass(this);
|
||||||
|
|
||||||
for (uint i = 0; i < size; ++i) {
|
for (uint i = 0; i < size; ++i) {
|
||||||
PropertyAttributes attrs = propertyData.at(i);
|
PropertyAttributes attrs = propertyData.at(i);
|
||||||
|
@ -474,7 +525,7 @@ InternalClass *InternalClass::sealed()
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
InternalClass *InternalClass::frozen()
|
Heap::InternalClass *InternalClass::frozen()
|
||||||
{
|
{
|
||||||
if (isFrozen)
|
if (isFrozen)
|
||||||
return this;
|
return this;
|
||||||
|
@ -504,7 +555,7 @@ InternalClass *InternalClass::frozen()
|
||||||
return t.lookup;
|
return t.lookup;
|
||||||
}
|
}
|
||||||
|
|
||||||
InternalClass *f = engine->newClass(this);
|
Heap::InternalClass *f = engine->newClass(this);
|
||||||
|
|
||||||
for (uint i = 0; i < size; ++i) {
|
for (uint i = 0; i < size; ++i) {
|
||||||
PropertyAttributes attrs = propertyData.at(i);
|
PropertyAttributes attrs = propertyData.at(i);
|
||||||
|
@ -523,9 +574,10 @@ InternalClass *InternalClass::frozen()
|
||||||
return f;
|
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);
|
frozen = frozen->changePrototype(prototype);
|
||||||
for (uint i = 0; i < size; ++i) {
|
for (uint i = 0; i < size; ++i) {
|
||||||
PropertyAttributes attrs = propertyData.at(i);
|
PropertyAttributes attrs = propertyData.at(i);
|
||||||
|
@ -535,10 +587,10 @@ InternalClass *InternalClass::propertiesFrozen() const
|
||||||
attrs.setConfigurable(false);
|
attrs.setConfigurable(false);
|
||||||
frozen = frozen->addMember(nameMap.at(i), attrs);
|
frozen = frozen->addMember(nameMap.at(i), attrs);
|
||||||
}
|
}
|
||||||
return frozen;
|
return frozen->d();
|
||||||
}
|
}
|
||||||
|
|
||||||
InternalClass *InternalClass::asProtoClass()
|
Heap::InternalClass *InternalClass::asProtoClass()
|
||||||
{
|
{
|
||||||
if (isUsedAsProto)
|
if (isUsedAsProto)
|
||||||
return this;
|
return this;
|
||||||
|
@ -548,7 +600,7 @@ InternalClass *InternalClass::asProtoClass()
|
||||||
if (t.lookup)
|
if (t.lookup)
|
||||||
return t.lookup;
|
return t.lookup;
|
||||||
|
|
||||||
InternalClass *newClass = engine->newClass(this);
|
Heap::InternalClass *newClass = engine->newClass(this);
|
||||||
newClass->isUsedAsProto = true;
|
newClass->isUsedAsProto = true;
|
||||||
|
|
||||||
t.lookup = newClass;
|
t.lookup = newClass;
|
||||||
|
@ -556,33 +608,12 @@ InternalClass *InternalClass::asProtoClass()
|
||||||
return newClass;
|
return newClass;
|
||||||
}
|
}
|
||||||
|
|
||||||
void InternalClass::destroyAll()
|
static void updateProtoUsage(Heap::Object *o, Heap::InternalClass *ic)
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
if (ic->prototype == o)
|
if (ic->prototype == o)
|
||||||
ic->id = ic->engine->newInternalClassId();
|
ic->id = ic->engine->newInternalClassId();
|
||||||
for (auto &t : ic->transitions) {
|
for (auto &t : ic->transitions) {
|
||||||
Q_ASSERT(t.lookup);
|
if (t.lookup)
|
||||||
updateProtoUsage(o, t.lookup);
|
updateProtoUsage(o, t.lookup);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -591,30 +622,23 @@ static void updateProtoUsage(Heap::Object *o, InternalClass *ic)
|
||||||
void InternalClass::updateProtoUsage(Heap::Object *o)
|
void InternalClass::updateProtoUsage(Heap::Object *o)
|
||||||
{
|
{
|
||||||
Q_ASSERT(isUsedAsProto);
|
Q_ASSERT(isUsedAsProto);
|
||||||
InternalClass *ic = engine->internalClasses(EngineBase::Class_Empty);
|
Heap::InternalClass *ic = engine->internalClasses(EngineBase::Class_Empty);
|
||||||
Q_ASSERT(!ic->prototype);
|
Q_ASSERT(!ic->prototype);
|
||||||
|
|
||||||
::updateProtoUsage(o, ic);
|
Heap::updateProtoUsage(o, ic);
|
||||||
}
|
}
|
||||||
|
|
||||||
void InternalClass::updateInternalClassIdRecursive()
|
void InternalClass::markObjects(Heap::Base *b, MarkStack *stack)
|
||||||
{
|
|
||||||
id = engine->newInternalClassId();
|
|
||||||
for (auto &t : transitions) {
|
|
||||||
Q_ASSERT(t.lookup);
|
|
||||||
t.lookup->updateInternalClassIdRecursive();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void InternalClass::markObjects(InternalClass *ic, MarkStack *stack)
|
|
||||||
{
|
{
|
||||||
|
Heap::InternalClass *ic = static_cast<Heap::InternalClass *>(b);
|
||||||
if (ic->prototype)
|
if (ic->prototype)
|
||||||
ic->prototype->mark(stack);
|
ic->prototype->mark(stack);
|
||||||
|
if (ic->parent)
|
||||||
for (auto &t : ic->transitions) {
|
ic->parent->mark(stack);
|
||||||
Q_ASSERT(t.lookup);
|
|
||||||
markObjects(t.lookup, stack);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
|
|
@ -54,6 +54,7 @@
|
||||||
|
|
||||||
#include <QHash>
|
#include <QHash>
|
||||||
#include <private/qv4identifier_p.h>
|
#include <private/qv4identifier_p.h>
|
||||||
|
#include <private/qv4heap_p.h>
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
|
@ -240,7 +241,7 @@ struct InternalClassTransition
|
||||||
const VTable *vtable;
|
const VTable *vtable;
|
||||||
Heap::Object *prototype;
|
Heap::Object *prototype;
|
||||||
};
|
};
|
||||||
InternalClass *lookup;
|
Heap::InternalClass *lookup;
|
||||||
int flags;
|
int flags;
|
||||||
enum {
|
enum {
|
||||||
// range 0-0xff is reserved for attribute changes
|
// range 0-0xff is reserved for attribute changes
|
||||||
|
@ -260,12 +261,14 @@ struct InternalClassTransition
|
||||||
{ return id < other.id || (id == other.id && flags < other.flags); }
|
{ return id < other.id || (id == other.id && flags < other.flags); }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct InternalClass {
|
namespace Heap {
|
||||||
int id = 0; // unique across the engine, gets changed also when proto chain changes
|
|
||||||
|
struct InternalClass : Base {
|
||||||
|
int id; // unique across the engine, gets changed also when proto chain changes
|
||||||
ExecutionEngine *engine;
|
ExecutionEngine *engine;
|
||||||
const VTable *vtable;
|
const VTable *vtable;
|
||||||
Heap::Object *prototype;
|
Heap::Object *prototype;
|
||||||
InternalClass *parent = nullptr;
|
InternalClass *parent;
|
||||||
|
|
||||||
PropertyHash propertyTable; // id to valueIndex
|
PropertyHash propertyTable; // id to valueIndex
|
||||||
SharedInternalClassData<Identifier *> nameMap;
|
SharedInternalClassData<Identifier *> nameMap;
|
||||||
|
@ -279,27 +282,21 @@ struct InternalClass {
|
||||||
bool extensible;
|
bool extensible;
|
||||||
bool isSealed;
|
bool isSealed;
|
||||||
bool isFrozen;
|
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 *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);
|
static void addMember(QV4::Object *object, QV4::String *string, PropertyAttributes data, uint *index);
|
||||||
Q_REQUIRED_RESULT InternalClass *addMember(String *string, PropertyAttributes data, uint *index = nullptr);
|
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 *addMember(Identifier *identifier, PropertyAttributes data, uint *index = nullptr);
|
||||||
Q_REQUIRED_RESULT InternalClass *changeMember(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 changeMember(QV4::Object *object, QV4::String *string, PropertyAttributes data, uint *index = nullptr);
|
||||||
static void removeMember(Object *object, Identifier *id);
|
static void removeMember(QV4::Object *object, Identifier *id);
|
||||||
uint find(const String *string);
|
uint find(const QV4::String *string);
|
||||||
uint find(const Identifier *id)
|
uint find(const Identifier *id)
|
||||||
{
|
{
|
||||||
uint index = propertyTable.lookup(id);
|
uint index = propertyTable.lookup(id);
|
||||||
|
@ -315,23 +312,38 @@ struct InternalClass {
|
||||||
|
|
||||||
Q_REQUIRED_RESULT InternalClass *asProtoClass();
|
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);
|
void updateProtoUsage(Heap::Object *o);
|
||||||
|
|
||||||
static void markObjects(InternalClass *ic, MarkStack *stack);
|
static void markObjects(Heap::Base *ic, MarkStack *stack);
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Q_QML_EXPORT InternalClass *changeVTableImpl(const VTable *vt);
|
Q_QML_EXPORT InternalClass *changeVTableImpl(const VTable *vt);
|
||||||
Q_QML_EXPORT InternalClass *changePrototypeImpl(Heap::Object *proto);
|
Q_QML_EXPORT InternalClass *changePrototypeImpl(Heap::Object *proto);
|
||||||
InternalClass *addMemberImpl(Identifier *identifier, PropertyAttributes data, uint *index);
|
InternalClass *addMemberImpl(Identifier *identifier, PropertyAttributes data, uint *index);
|
||||||
void updateInternalClassIdRecursive();
|
|
||||||
|
void removeChildEntry(InternalClass *child);
|
||||||
friend struct ExecutionEngine;
|
friend struct ExecutionEngine;
|
||||||
InternalClass(ExecutionEngine *engine);
|
|
||||||
InternalClass(InternalClass *other);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
inline
|
||||||
|
void Base::markObjects(Base *b, MarkStack *stack)
|
||||||
|
{
|
||||||
|
b->internalClass->mark(stack);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
|
|
@ -347,7 +347,6 @@ ReturnedValue Lookup::getterProtoAccessor(Lookup *l, ExecutionEngine *engine, co
|
||||||
|
|
||||||
return static_cast<const FunctionObject *>(getter)->call(&object, nullptr, 0);
|
return static_cast<const FunctionObject *>(getter)->call(&object, nullptr, 0);
|
||||||
}
|
}
|
||||||
l->getter = getterTwoClasses;
|
|
||||||
return getterTwoClasses(l, engine, object);
|
return getterTwoClasses(l, engine, object);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -442,7 +441,7 @@ bool Lookup::resolveSetter(ExecutionEngine *engine, Object *object, const Value
|
||||||
Scope scope(engine);
|
Scope scope(engine);
|
||||||
ScopedString name(scope, scope.engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]);
|
ScopedString name(scope, scope.engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]);
|
||||||
|
|
||||||
InternalClass *c = object->internalClass();
|
Heap::InternalClass *c = object->internalClass();
|
||||||
uint idx = c->find(name);
|
uint idx = c->find(name);
|
||||||
if (idx != UINT_MAX) {
|
if (idx != UINT_MAX) {
|
||||||
if (object->isArrayObject() && idx == Heap::ArrayObject::LengthPropertyIndex) {
|
if (object->isArrayObject() && idx == Heap::ArrayObject::LengthPropertyIndex) {
|
||||||
|
@ -599,4 +598,53 @@ bool Lookup::arrayLengthSetter(Lookup *, ExecutionEngine *engine, Value &object,
|
||||||
return true;
|
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
|
QT_END_NAMESPACE
|
||||||
|
|
|
@ -73,7 +73,7 @@ struct Lookup {
|
||||||
};
|
};
|
||||||
union {
|
union {
|
||||||
struct {
|
struct {
|
||||||
InternalClass *ic;
|
Heap::InternalClass *ic;
|
||||||
int offset;
|
int offset;
|
||||||
} objectLookup;
|
} objectLookup;
|
||||||
struct {
|
struct {
|
||||||
|
@ -81,8 +81,8 @@ struct Lookup {
|
||||||
int icIdentifier;
|
int icIdentifier;
|
||||||
} protoLookup;
|
} protoLookup;
|
||||||
struct {
|
struct {
|
||||||
InternalClass *ic;
|
Heap::InternalClass *ic;
|
||||||
InternalClass *ic2;
|
Heap::InternalClass *ic2;
|
||||||
int offset;
|
int offset;
|
||||||
int offset2;
|
int offset2;
|
||||||
} objectLookupTwoClasses;
|
} objectLookupTwoClasses;
|
||||||
|
@ -100,7 +100,7 @@ struct Lookup {
|
||||||
Heap::Object *proto;
|
Heap::Object *proto;
|
||||||
} primitiveLookup;
|
} primitiveLookup;
|
||||||
struct {
|
struct {
|
||||||
InternalClass *newClass;
|
Heap::InternalClass *newClass;
|
||||||
int icIdentifier;
|
int icIdentifier;
|
||||||
int offset;
|
int offset;
|
||||||
} insertionLookup;
|
} insertionLookup;
|
||||||
|
@ -144,6 +144,8 @@ struct Lookup {
|
||||||
static bool setter0setter0(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value);
|
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 setterInsert(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value);
|
||||||
static bool arrayLengthSetter(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);
|
Q_STATIC_ASSERT(std::is_standard_layout<Lookup>::value);
|
||||||
|
|
|
@ -63,6 +63,8 @@ const VTable Managed::static_vtbl =
|
||||||
isEqualTo
|
isEqualTo
|
||||||
};
|
};
|
||||||
|
|
||||||
|
DEFINE_MANAGED_VTABLE(InternalClass);
|
||||||
|
|
||||||
|
|
||||||
QString Managed::className() const
|
QString Managed::className() const
|
||||||
{
|
{
|
||||||
|
@ -114,6 +116,9 @@ QString Managed::className() const
|
||||||
case Type_ForeachIteratorObject:
|
case Type_ForeachIteratorObject:
|
||||||
s = "__ForeachIterator";
|
s = "__ForeachIterator";
|
||||||
break;
|
break;
|
||||||
|
case Type_InternalClass:
|
||||||
|
s = "__InternalClass";
|
||||||
|
break;
|
||||||
case Type_RegExp:
|
case Type_RegExp:
|
||||||
s = "__RegExp";
|
s = "__RegExp";
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -92,14 +92,14 @@ inline void qYouForgotTheQ_MANAGED_Macro(T1, T2) {}
|
||||||
QV4::Heap::DataClass *dptr = d_unchecked(); \
|
QV4::Heap::DataClass *dptr = d_unchecked(); \
|
||||||
dptr->_checkIsInitialized(); \
|
dptr->_checkIsInitialized(); \
|
||||||
return dptr; \
|
return dptr; \
|
||||||
} \
|
}
|
||||||
Q_STATIC_ASSERT(std::is_trivial< QV4::Heap::DataClass >::value);
|
|
||||||
|
|
||||||
#define V4_MANAGED(DataClass, superClass) \
|
#define V4_MANAGED(DataClass, superClass) \
|
||||||
private: \
|
private: \
|
||||||
DataClass() Q_DECL_EQ_DELETE; \
|
DataClass() Q_DECL_EQ_DELETE; \
|
||||||
Q_DISABLE_COPY(DataClass) \
|
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) \
|
#define Q_MANAGED_TYPE(type) \
|
||||||
public: \
|
public: \
|
||||||
|
@ -154,7 +154,7 @@ const QV4::VTable classname::static_vtbl = DEFINE_MANAGED_VTABLE_INT(classname,
|
||||||
QT_WARNING_SUPPRESS_GCC_TAUTOLOGICAL_COMPARE_OFF
|
QT_WARNING_SUPPRESS_GCC_TAUTOLOGICAL_COMPARE_OFF
|
||||||
|
|
||||||
#define V4_INTERNALCLASS(c) \
|
#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); }
|
{ return e->internalClasses(QV4::EngineBase::Class_##c); }
|
||||||
|
|
||||||
struct Q_QML_PRIVATE_EXPORT Managed : Value
|
struct Q_QML_PRIVATE_EXPORT Managed : Value
|
||||||
|
@ -193,6 +193,7 @@ public:
|
||||||
Type_MathObject,
|
Type_MathObject,
|
||||||
|
|
||||||
Type_ExecutionContext,
|
Type_ExecutionContext,
|
||||||
|
Type_InternalClass,
|
||||||
Type_ForeachIteratorObject,
|
Type_ForeachIteratorObject,
|
||||||
Type_RegExp,
|
Type_RegExp,
|
||||||
|
|
||||||
|
@ -200,7 +201,7 @@ public:
|
||||||
};
|
};
|
||||||
Q_MANAGED_TYPE(Invalid)
|
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; }
|
const VTable *vtable() const { return d()->internalClass->vtable; }
|
||||||
inline ExecutionEngine *engine() const { return internalClass()->engine; }
|
inline ExecutionEngine *engine() const { return internalClass()->engine; }
|
||||||
|
|
||||||
|
@ -255,6 +256,32 @@ inline const Object *Value::as() const {
|
||||||
return objectValue();
|
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);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -57,9 +57,9 @@ using namespace QV4;
|
||||||
|
|
||||||
DEFINE_OBJECT_VTABLE(Object);
|
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)
|
if (ic->isUsedAsProto)
|
||||||
ic->updateProtoUsage(d());
|
ic->updateProtoUsage(d());
|
||||||
Q_ASSERT(ic && ic->vtable);
|
Q_ASSERT(ic && ic->vtable);
|
||||||
|
@ -89,7 +89,7 @@ void Object::setProperty(uint index, const Property *p)
|
||||||
|
|
||||||
void Heap::Object::setUsedAsProto()
|
void Heap::Object::setUsedAsProto()
|
||||||
{
|
{
|
||||||
internalClass = internalClass->asProtoClass();
|
internalClass.set(internalClass->engine, internalClass->asProtoClass());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Object::setPrototype(Object *proto)
|
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)
|
bool Object::putValue(uint memberIndex, const Value &value)
|
||||||
{
|
{
|
||||||
QV4::InternalClass *ic = internalClass();
|
Heap::InternalClass *ic = internalClass();
|
||||||
if (ic->engine->hasException)
|
if (ic->engine->hasException)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -228,6 +228,7 @@ void Object::defineReadonlyConfigurableProperty(String *name, const Value &value
|
||||||
|
|
||||||
void Heap::Object::markObjects(Heap::Base *b, MarkStack *stack)
|
void Heap::Object::markObjects(Heap::Base *b, MarkStack *stack)
|
||||||
{
|
{
|
||||||
|
Base::markObjects(b, stack);
|
||||||
Object *o = static_cast<Object *>(b);
|
Object *o = static_cast<Object *>(b);
|
||||||
if (o->memberData)
|
if (o->memberData)
|
||||||
o->memberData->mark(stack);
|
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)
|
void Object::insertMember(String *s, const Property *p, PropertyAttributes attributes)
|
||||||
{
|
{
|
||||||
uint idx;
|
uint idx;
|
||||||
InternalClass::addMember(this, s, attributes, &idx);
|
Heap::InternalClass::addMember(this, s, attributes, &idx);
|
||||||
|
|
||||||
if (attributes.isAccessor()) {
|
if (attributes.isAccessor()) {
|
||||||
setProperty(idx + GetterOffset, p->value);
|
setProperty(idx + GetterOffset, p->value);
|
||||||
|
@ -776,7 +777,7 @@ bool Object::internalDeleteProperty(String *name)
|
||||||
uint memberIdx = internalClass()->find(name->identifier());
|
uint memberIdx = internalClass()->find(name->identifier());
|
||||||
if (memberIdx != UINT_MAX) {
|
if (memberIdx != UINT_MAX) {
|
||||||
if (internalClass()->propertyData[memberIdx].isConfigurable()) {
|
if (internalClass()->propertyData[memberIdx].isConfigurable()) {
|
||||||
InternalClass::removeMember(this, name->identifier());
|
Heap::InternalClass::removeMember(this, name->identifier());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -832,7 +833,7 @@ bool Object::__defineOwnProperty__(ExecutionEngine *engine, String *name, const
|
||||||
}
|
}
|
||||||
if (attrs.hasWritable() && !attrs.isWritable()) {
|
if (attrs.hasWritable() && !attrs.isWritable()) {
|
||||||
cattrs.setWritable(false);
|
cattrs.setWritable(false);
|
||||||
InternalClass::changeMember(this, engine->id_length(), cattrs);
|
Heap::InternalClass::changeMember(this, engine->id_length(), cattrs);
|
||||||
}
|
}
|
||||||
if (!succeeded)
|
if (!succeeded)
|
||||||
return false;
|
return false;
|
||||||
|
@ -980,7 +981,7 @@ bool Object::__defineOwnProperty__(ExecutionEngine *engine, uint index, String *
|
||||||
|
|
||||||
current->merge(cattrs, p, attrs);
|
current->merge(cattrs, p, attrs);
|
||||||
if (member) {
|
if (member) {
|
||||||
InternalClass::changeMember(this, member, cattrs);
|
Heap::InternalClass::changeMember(this, member, cattrs);
|
||||||
setProperty(index, current);
|
setProperty(index, current);
|
||||||
} else {
|
} else {
|
||||||
setArrayAttributes(index, cattrs);
|
setArrayAttributes(index, cattrs);
|
||||||
|
|
|
@ -222,7 +222,7 @@ struct Q_QML_EXPORT Object: Managed {
|
||||||
SetterOffset = 1
|
SetterOffset = 1
|
||||||
};
|
};
|
||||||
|
|
||||||
void setInternalClass(InternalClass *ic);
|
void setInternalClass(Heap::InternalClass *ic);
|
||||||
|
|
||||||
const Value *propertyData(uint index) const { return d()->propertyData(index); }
|
const Value *propertyData(uint index) const { return d()->propertyData(index); }
|
||||||
|
|
||||||
|
|
|
@ -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)
|
ReturnedValue Runtime::method_objectLiteral(ExecutionEngine *engine, const QV4::Value *args, int classId, int arrayValueCount, int arrayGetterSetterCountAndFlags)
|
||||||
{
|
{
|
||||||
Scope scope(engine);
|
Scope scope(engine);
|
||||||
QV4::InternalClass *klass = static_cast<CompiledData::CompilationUnit*>(engine->currentStackFrame->v4Function->compilationUnit)->runtimeClasses[classId];
|
Scoped<InternalClass> klass(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeClasses[classId]);
|
||||||
ScopedObject o(scope, engine->newObject(klass));
|
ScopedObject o(scope, engine->newObject(klass->d()));
|
||||||
|
|
||||||
{
|
{
|
||||||
bool needSparseArray = arrayGetterSetterCountAndFlags >> 30;
|
bool needSparseArray = arrayGetterSetterCountAndFlags >> 30;
|
||||||
|
@ -1226,7 +1226,7 @@ ReturnedValue Runtime::method_objectLiteral(ExecutionEngine *engine, const QV4::
|
||||||
o->initSparseArray();
|
o->initSparseArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (uint i = 0; i < klass->size; ++i)
|
for (uint i = 0; i < klass->d()->size; ++i)
|
||||||
o->setProperty(i, *args++);
|
o->setProperty(i, *args++);
|
||||||
|
|
||||||
if (arrayValueCount > 0) {
|
if (arrayValueCount > 0) {
|
||||||
|
@ -1259,13 +1259,13 @@ ReturnedValue Runtime::method_objectLiteral(ExecutionEngine *engine, const QV4::
|
||||||
QV4::ReturnedValue Runtime::method_createMappedArgumentsObject(ExecutionEngine *engine)
|
QV4::ReturnedValue Runtime::method_createMappedArgumentsObject(ExecutionEngine *engine)
|
||||||
{
|
{
|
||||||
Q_ASSERT(engine->currentContext()->d()->type == Heap::ExecutionContext::Type_CallContext);
|
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();
|
return engine->memoryManager->allocObject<ArgumentsObject>(ic, engine->currentStackFrame)->asReturnedValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
QV4::ReturnedValue Runtime::method_createUnmappedArgumentsObject(ExecutionEngine *engine)
|
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();
|
return engine->memoryManager->allocObject<StrictArgumentsObject>(ic, engine->currentStackFrame)->asReturnedValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -54,6 +54,7 @@ using namespace QV4;
|
||||||
|
|
||||||
void Heap::String::markObjects(Heap::Base *that, MarkStack *markStack)
|
void Heap::String::markObjects(Heap::Base *that, MarkStack *markStack)
|
||||||
{
|
{
|
||||||
|
Base::markObjects(that, markStack);
|
||||||
String *s = static_cast<String *>(that);
|
String *s = static_cast<String *>(that);
|
||||||
if (s->subtype < StringType_Complex)
|
if (s->subtype < StringType_Complex)
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -351,9 +351,9 @@ void Heap::TypedArray::init(Type t)
|
||||||
|
|
||||||
Heap::TypedArray *TypedArray::create(ExecutionEngine *e, Heap::TypedArray::Type t)
|
Heap::TypedArray *TypedArray::create(ExecutionEngine *e, Heap::TypedArray::Type t)
|
||||||
{
|
{
|
||||||
QV4::InternalClass *ic = e->internalClasses(EngineBase::Class_Empty)->changeVTable(staticVTable());
|
Scope scope(e);
|
||||||
ic = ic->changePrototype(e->typedArrayPrototype[t].d());
|
Scoped<InternalClass> ic(scope, e->newInternalClass(staticVTable(), e->typedArrayPrototype + t));
|
||||||
return e->memoryManager->allocObject<TypedArray>(ic, t);
|
return e->memoryManager->allocObject<TypedArray>(ic->d(), t);
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnedValue TypedArray::getIndexed(const Managed *m, uint index, bool *hasProperty)
|
ReturnedValue TypedArray::getIndexed(const Managed *m, uint index, bool *hasProperty)
|
||||||
|
|
|
@ -113,9 +113,9 @@ Q_STATIC_ASSERT(std::is_trivial< V4PointerCheck >::value);
|
||||||
struct Q_QML_EXPORT Base {
|
struct Q_QML_EXPORT Base {
|
||||||
void *operator new(size_t) = delete;
|
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 ReturnedValue asReturnedValue() const;
|
||||||
inline void mark(QV4::MarkStack *markStack);
|
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(offsetof(Base, internalClass) == 0);
|
||||||
Q_STATIC_ASSERT(sizeof(Base) == QT_POINTER_SIZE);
|
Q_STATIC_ASSERT(sizeof(Base) == QT_POINTER_SIZE);
|
||||||
|
|
||||||
|
|
||||||
inline
|
inline
|
||||||
void Base::mark(QV4::MarkStack *markStack)
|
void Base::mark(QV4::MarkStack *markStack)
|
||||||
{
|
{
|
||||||
|
|
|
@ -643,8 +643,9 @@ void BlockAllocator::sweep()
|
||||||
|
|
||||||
void BlockAllocator::freeAll()
|
void BlockAllocator::freeAll()
|
||||||
{
|
{
|
||||||
for (auto c : chunks) {
|
for (auto c : chunks)
|
||||||
c->freeAll(engine);
|
c->freeAll(engine);
|
||||||
|
for (auto c : chunks) {
|
||||||
Q_V4_PROFILE_DEALLOC(engine, Chunk::DataSize, Profiling::HeapPage);
|
Q_V4_PROFILE_DEALLOC(engine, Chunk::DataSize, Profiling::HeapPage);
|
||||||
chunkAllocator->free(c);
|
chunkAllocator->free(c);
|
||||||
}
|
}
|
||||||
|
@ -758,6 +759,7 @@ MemoryManager::MemoryManager(ExecutionEngine *engine)
|
||||||
: engine(engine)
|
: engine(engine)
|
||||||
, chunkAllocator(new ChunkAllocator)
|
, chunkAllocator(new ChunkAllocator)
|
||||||
, blockAllocator(chunkAllocator, engine)
|
, blockAllocator(chunkAllocator, engine)
|
||||||
|
, icAllocator(chunkAllocator, engine)
|
||||||
, hugeItemAllocator(chunkAllocator, engine)
|
, hugeItemAllocator(chunkAllocator, engine)
|
||||||
, m_persistentValues(new PersistentValueStorage(engine))
|
, m_persistentValues(new PersistentValueStorage(engine))
|
||||||
, m_weakValues(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);
|
Chunk::clearBit(c->extendsBitmap, index);
|
||||||
}
|
}
|
||||||
o->memberData.set(engine, m);
|
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);
|
Q_ASSERT(o->memberData->internalClass);
|
||||||
m->values.alloc = static_cast<uint>((memberSize - sizeof(Heap::MemberData) + sizeof(Value))/sizeof(Value));
|
m->values.alloc = static_cast<uint>((memberSize - sizeof(Heap::MemberData) + sizeof(Value))/sizeof(Value));
|
||||||
m->values.size = o->memberData->values.alloc;
|
m->values.size = o->memberData->values.alloc;
|
||||||
|
@ -1017,8 +1019,11 @@ void MemoryManager::sweep(bool lastSweep, ClassDestroyStatsCallback classCountPt
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
blockAllocator.sweep();
|
if (!lastSweep) {
|
||||||
|
blockAllocator.sweep(/*classCountPtr*/);
|
||||||
hugeItemAllocator.sweep(classCountPtr);
|
hugeItemAllocator.sweep(classCountPtr);
|
||||||
|
icAllocator.sweep(/*classCountPtr*/);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MemoryManager::shouldRunGC() const
|
bool MemoryManager::shouldRunGC() const
|
||||||
|
@ -1167,6 +1172,7 @@ void MemoryManager::runGC()
|
||||||
// reset all black bits
|
// reset all black bits
|
||||||
blockAllocator.resetBlackBits();
|
blockAllocator.resetBlackBits();
|
||||||
hugeItemAllocator.resetBlackBits();
|
hugeItemAllocator.resetBlackBits();
|
||||||
|
icAllocator.resetBlackBits();
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t MemoryManager::getUsedMem() const
|
size_t MemoryManager::getUsedMem() const
|
||||||
|
@ -1193,6 +1199,7 @@ MemoryManager::~MemoryManager()
|
||||||
sweep(/*lastSweep*/true);
|
sweep(/*lastSweep*/true);
|
||||||
blockAllocator.freeAll();
|
blockAllocator.freeAll();
|
||||||
hugeItemAllocator.freeAll();
|
hugeItemAllocator.freeAll();
|
||||||
|
icAllocator.freeAll();
|
||||||
|
|
||||||
delete m_weakValues;
|
delete m_weakValues;
|
||||||
#ifdef V4_USE_VALGRIND
|
#ifdef V4_USE_VALGRIND
|
||||||
|
|
|
@ -160,37 +160,52 @@ public:
|
||||||
{ return (size + Chunk::SlotSize - 1) & ~(Chunk::SlotSize - 1); }
|
{ return (size + Chunk::SlotSize - 1) & ~(Chunk::SlotSize - 1); }
|
||||||
|
|
||||||
template<typename ManagedType>
|
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);
|
Q_STATIC_ASSERT(std::is_trivial< typename ManagedType::Data >::value);
|
||||||
size = align(size);
|
size = align(size);
|
||||||
Heap::Base *o = allocData(size);
|
typename ManagedType::Data *d = static_cast<typename ManagedType::Data *>(allocData(size));
|
||||||
o->internalClass = ic;
|
d->internalClass.set(engine, ic);
|
||||||
Q_ASSERT(o->internalClass && o->internalClass->vtable);
|
Q_ASSERT(d->internalClass && d->internalClass->vtable);
|
||||||
Q_ASSERT(ic->vtable == ManagedType::staticVTable());
|
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>
|
template<typename ManagedType>
|
||||||
inline typename ManagedType::Data *allocManaged(std::size_t size)
|
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(Heap::InternalClass *ic)
|
||||||
|
{
|
||||||
|
Heap::Object *o = allocObjectWithMemberData(ObjectType::staticVTable(), ic->size);
|
||||||
|
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>
|
template <typename ObjectType>
|
||||||
typename ObjectType::Data *allocateObject(InternalClass *ic)
|
typename ObjectType::Data *allocateObject(InternalClass *ic)
|
||||||
{
|
{
|
||||||
Heap::Object *o = allocObjectWithMemberData(ObjectType::staticVTable(), ic->size);
|
return allocateObject<ObjectType>(ic->d());
|
||||||
o->internalClass = ic;
|
|
||||||
Q_ASSERT(o->internalClass && o->internalClass->vtable);
|
|
||||||
Q_ASSERT(ic->vtable == ObjectType::staticVTable());
|
|
||||||
return static_cast<typename ObjectType::Data *>(o);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename ObjectType>
|
template <typename ObjectType>
|
||||||
typename ObjectType::Data *allocateObject()
|
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->changeVTable(ObjectType::staticVTable());
|
||||||
ic = ic->changePrototype(ObjectType::defaultPrototype(engine)->d());
|
ic = ic->changePrototype(ObjectType::defaultPrototype(engine)->d());
|
||||||
return allocateObject<ObjectType>(ic);
|
return allocateObject<ObjectType>(ic);
|
||||||
|
@ -200,18 +215,18 @@ public:
|
||||||
typename ManagedType::Data *allocWithStringData(std::size_t unmanagedSize, Arg1 arg1)
|
typename ManagedType::Data *allocWithStringData(std::size_t unmanagedSize, Arg1 arg1)
|
||||||
{
|
{
|
||||||
typename ManagedType::Data *o = reinterpret_cast<typename ManagedType::Data *>(allocString(unmanagedSize));
|
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);
|
Q_ASSERT(o->internalClass && o->internalClass->vtable);
|
||||||
o->init(arg1);
|
o->init(arg1);
|
||||||
return o;
|
return o;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename ObjectType>
|
template <typename ObjectType, typename... Args>
|
||||||
typename ObjectType::Data *allocObject(InternalClass *ic)
|
typename ObjectType::Data *allocObject(Heap::InternalClass *ic, Args... args)
|
||||||
{
|
{
|
||||||
Scope scope(engine);
|
Scope scope(engine);
|
||||||
Scoped<ObjectType> t(scope, allocateObject<ObjectType>(ic));
|
Scoped<ObjectType> t(scope, allocateObject<ObjectType>(ic));
|
||||||
t->d_unchecked()->init();
|
t->d_unchecked()->init(args...);
|
||||||
return t->d();
|
return t->d();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -253,6 +268,14 @@ public:
|
||||||
// called when a JS object grows itself. Specifically: Heap::String::append
|
// called when a JS object grows itself. Specifically: Heap::String::append
|
||||||
void changeUnmanagedHeapSizeUsage(qptrdiff delta) { unmanagedHeapSize += delta; }
|
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:
|
protected:
|
||||||
/// expects size to be aligned
|
/// expects size to be aligned
|
||||||
Heap::Base *allocString(std::size_t unmanagedSize);
|
Heap::Base *allocString(std::size_t unmanagedSize);
|
||||||
|
@ -270,6 +293,7 @@ public:
|
||||||
QV4::ExecutionEngine *engine;
|
QV4::ExecutionEngine *engine;
|
||||||
ChunkAllocator *chunkAllocator;
|
ChunkAllocator *chunkAllocator;
|
||||||
BlockAllocator blockAllocator;
|
BlockAllocator blockAllocator;
|
||||||
|
BlockAllocator icAllocator;
|
||||||
HugeItemAllocator hugeItemAllocator;
|
HugeItemAllocator hugeItemAllocator;
|
||||||
PersistentValueStorage *m_persistentValues;
|
PersistentValueStorage *m_persistentValues;
|
||||||
PersistentValueStorage *m_weakValues;
|
PersistentValueStorage *m_weakValues;
|
||||||
|
|
|
@ -231,7 +231,7 @@ static void freeze_recursive(QV4::ExecutionEngine *v4, QV4::Object *object)
|
||||||
if (!instanceOfObject)
|
if (!instanceOfObject)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
QV4::InternalClass *frozen = object->internalClass()->propertiesFrozen();
|
QV4::Heap::InternalClass *frozen = object->internalClass()->propertiesFrozen();
|
||||||
if (object->internalClass() == frozen)
|
if (object->internalClass() == frozen)
|
||||||
return;
|
return;
|
||||||
object->setInternalClass(frozen);
|
object->setInternalClass(frozen);
|
||||||
|
|
Loading…
Reference in New Issue