diff options
author | Simon Hausmann <simon.hausmann@digia.com> | 2013-08-16 13:21:31 +0200 |
---|---|---|
committer | Lars Knoll <lars.knoll@digia.com> | 2013-08-16 16:52:18 +0200 |
commit | 944717a46c237e5a5b2d6e5ea2fd8389523638e4 (patch) | |
tree | 6e894837d1cd327bb578b00d7826e3de0cde816c /src/qml | |
parent | 85e6b8e9e7e158b5cb4238c2dd5e28406bc913e2 (diff) |
Ported the compile-time class setup for object literals to be run-time based
Change-Id: I21225e4bf0f66914229cf64fa29ce870548c0e93
Reviewed-by: Lars Knoll <lars.knoll@digia.com>
Diffstat (limited to 'src/qml')
-rw-r--r-- | src/qml/compiler/qv4compileddata.cpp | 15 | ||||
-rw-r--r-- | src/qml/compiler/qv4compileddata_p.h | 31 | ||||
-rw-r--r-- | src/qml/compiler/qv4compiler.cpp | 56 | ||||
-rw-r--r-- | src/qml/compiler/qv4compiler_p.h | 5 | ||||
-rw-r--r-- | src/qml/compiler/qv4instr_moth_p.h | 2 | ||||
-rw-r--r-- | src/qml/compiler/qv4isel_masm.cpp | 7 | ||||
-rw-r--r-- | src/qml/compiler/qv4isel_moth.cpp | 6 | ||||
-rw-r--r-- | src/qml/compiler/qv4isel_p.h | 1 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4runtime.cpp | 5 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4runtime_p.h | 2 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4vme_moth.cpp | 2 |
11 files changed, 116 insertions, 16 deletions
diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp index 6ac7a4843d..4b7f132d97 100644 --- a/src/qml/compiler/qv4compileddata.cpp +++ b/src/qml/compiler/qv4compileddata.cpp @@ -57,6 +57,7 @@ CompilationUnit::~CompilationUnit() free(runtimeStrings); delete [] runtimeLookups; delete [] runtimeRegularExpressions; + free(runtimeClasses); } QV4::Function *CompilationUnit::linkToEngine(ExecutionEngine *engine) @@ -105,6 +106,20 @@ QV4::Function *CompilationUnit::linkToEngine(ExecutionEngine *engine) } } + if (data->jsClassTableSize) { + runtimeClasses = (QV4::InternalClass**)malloc(data->jsClassTableSize * sizeof(QV4::InternalClass*)); + + for (int i = 0; i < data->jsClassTableSize; ++i) { + int memberCount = 0; + const CompiledData::JSClassMember *member = data->jsClassAt(i, &memberCount); + QV4::InternalClass *klass = engine->emptyClass; + for (int j = 0; j < memberCount; ++j, ++member) + klass = klass->addMember(runtimeStrings[member->nameOffset], member->isAccessor ? QV4::Attr_Accessor : QV4::Attr_Data); + + runtimeClasses[i] = klass; + } + } + return linkBackendToEngine(engine); } diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h index 7b27d08405..f050c4cc93 100644 --- a/src/qml/compiler/qv4compileddata_p.h +++ b/src/qml/compiler/qv4compileddata_p.h @@ -94,6 +94,20 @@ struct Lookup static int calculateSize() { return sizeof(Lookup); } }; +struct JSClassMember +{ + uint nameOffset : 31; + uint isAccessor : 1; +}; + +struct JSClass +{ + uint nMembers; + // JSClassMember[nMembers] + + static int calculateSize(int nMembers) { return (sizeof(JSClass) + nMembers * sizeof(JSClassMember) + 7) & ~7; } +}; + static const char magic_str[] = "qv4cdata"; struct Unit @@ -115,6 +129,8 @@ struct Unit uint offsetToLookupTable; uint regexpTableSize; uint offsetToRegexpTable; + uint jsClassTableSize; + uint offsetToJSClassTable; uint indexOfRootFunction; quint32 sourceFileIndex; @@ -135,10 +151,19 @@ struct Unit return reinterpret_cast<const RegExp*>(reinterpret_cast<const char *>(this) + offsetToRegexpTable + index * sizeof(RegExp)); } + const JSClassMember *jsClassAt(int idx, int *nMembers) const { + const uint *offsetTable = reinterpret_cast<const uint *>(reinterpret_cast<const char *>(this) + offsetToJSClassTable); + const uint offset = offsetTable[idx]; + const char *ptr = reinterpret_cast<const char *>(this) + offset; + const JSClass *klass = reinterpret_cast<const JSClass *>(ptr); + *nMembers = klass->nMembers; + return reinterpret_cast<const JSClassMember*>(ptr + sizeof(JSClass)); + } + static int calculateSize(uint nStrings, uint nFunctions, uint nRegExps, - uint nLookups) { + uint nLookups, uint nClasses) { return (sizeof(Unit) - + (nStrings + nFunctions) * sizeof(uint) + + (nStrings + nFunctions + nClasses) * sizeof(uint) + nRegExps * RegExp::calculateSize() + nLookups * Lookup::calculateSize() + 7) & ~7; } @@ -287,6 +312,7 @@ struct CompilationUnit , data(0) , runtimeStrings(0) , runtimeLookups(0) + , runtimeClasses(0) {} virtual ~CompilationUnit(); @@ -302,6 +328,7 @@ struct CompilationUnit QV4::String **runtimeStrings; // Array QV4::Lookup *runtimeLookups; QV4::Value *runtimeRegularExpressions; + QV4::InternalClass **runtimeClasses; QV4::Function *linkToEngine(QV4::ExecutionEngine *engine); diff --git a/src/qml/compiler/qv4compiler.cpp b/src/qml/compiler/qv4compiler.cpp index 385f668b42..8e09e57525 100644 --- a/src/qml/compiler/qv4compiler.cpp +++ b/src/qml/compiler/qv4compiler.cpp @@ -47,6 +47,7 @@ QV4::Compiler::JSUnitGenerator::JSUnitGenerator(QV4::ExecutionEngine *engine, QQmlJS::V4IR::Module *module) : irModule(module) , stringDataSize(0) + , jsClassDataSize(0) { } @@ -116,6 +117,37 @@ void QV4::Compiler::JSUnitGenerator::registerLineNumberMapping(QQmlJS::V4IR::Fun lineNumberMappingsPerFunction.insert(function, mappings); } +int QV4::Compiler::JSUnitGenerator::registerJSClass(QQmlJS::V4IR::ExprList *args) +{ + // ### re-use existing class definitions. + + QList<CompiledData::JSClassMember> members; + + QQmlJS::V4IR::ExprList *it = args; + while (it) { + CompiledData::JSClassMember member; + + QQmlJS::V4IR::Name *name = it->expr->asName(); + it = it->next; + + const bool isData = it->expr->asConst()->value; + it = it->next; + + member.nameOffset = registerString(*name->id); + member.isAccessor = !isData; + members << member; + + if (!isData) + it = it->next; + + it = it->next; + } + + jsClasses << members; + jsClassDataSize += CompiledData::JSClass::calculateSize(members.count()); + return jsClasses.size() - 1; +} + QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit() { registerString(irModule->fileName); @@ -127,7 +159,7 @@ QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit() registerString(*f->locals.at(i)); } - int unitSize = QV4::CompiledData::Unit::calculateSize(strings.size(), irModule->functions.size(), regexps.size(), lookups.size()); + int unitSize = QV4::CompiledData::Unit::calculateSize(strings.size(), irModule->functions.size(), regexps.size(), lookups.size(), jsClasses.count()); uint functionDataSize = 0; for (int i = 0; i < irModule->functions.size(); ++i) { @@ -142,7 +174,7 @@ QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit() functionDataSize += QV4::CompiledData::Function::calculateSize(f->formals.size(), f->locals.size(), f->nestedFunctions.size(), lineNumberMappingCount); } - char *data = (char *)malloc(unitSize + functionDataSize + stringDataSize); + char *data = (char *)malloc(unitSize + functionDataSize + stringDataSize + jsClassDataSize); QV4::CompiledData::Unit *unit = (QV4::CompiledData::Unit*)data; memcpy(unit->magic, QV4::CompiledData::magic_str, sizeof(unit->magic)); @@ -157,6 +189,8 @@ QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit() unit->offsetToLookupTable = unit->offsetToFunctionTable + unit->functionTableSize * sizeof(uint); unit->regexpTableSize = regexps.size(); unit->offsetToRegexpTable = unit->offsetToLookupTable + unit->lookupTableSize * CompiledData::Lookup::calculateSize(); + unit->jsClassTableSize = jsClasses.count(); + unit->offsetToJSClassTable = unit->offsetToRegexpTable + unit->regexpTableSize * CompiledData::RegExp::calculateSize(); unit->sourceFileIndex = getStringId(irModule->fileName); // write strings and string table @@ -200,6 +234,24 @@ QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit() CompiledData::RegExp *regexpTable = (CompiledData::RegExp *)(data + unit->offsetToRegexpTable); memcpy(regexpTable, regexps.constData(), regexps.size() * sizeof(*regexpTable)); + // write js classes and js class lookup table + uint *jsClassTable = (uint*)(data + unit->offsetToJSClassTable); + char *jsClass = data + unitSize + stringDataSize + functionDataSize; + for (int i = 0; i < jsClasses.count(); ++i) { + jsClassTable[i] = jsClass - data; + + const QList<CompiledData::JSClassMember> members = jsClasses.at(i); + + CompiledData::JSClass *c = reinterpret_cast<CompiledData::JSClass*>(jsClass); + c->nMembers = members.count(); + + CompiledData::JSClassMember *memberToWrite = reinterpret_cast<CompiledData::JSClassMember*>(jsClass + sizeof(CompiledData::JSClass)); + foreach (const CompiledData::JSClassMember &member, members) + *memberToWrite++ = member; + + jsClass += CompiledData::JSClass::calculateSize(members.count()); + } + return unit; } diff --git a/src/qml/compiler/qv4compiler_p.h b/src/qml/compiler/qv4compiler_p.h index 1032369a53..c6dacfd2fe 100644 --- a/src/qml/compiler/qv4compiler_p.h +++ b/src/qml/compiler/qv4compiler_p.h @@ -52,6 +52,7 @@ namespace CompiledData { struct Unit; struct Lookup; struct RegExp; +struct JSClassMember; } namespace Compiler { @@ -72,6 +73,8 @@ struct JSUnitGenerator { void registerLineNumberMapping(QQmlJS::V4IR::Function *function, const QVector<uint> &mappings); + int registerJSClass(QQmlJS::V4IR::ExprList *args); + QV4::CompiledData::Unit *generateUnit(); // Returns bytes written int writeFunction(char *f, int index, QQmlJS::V4IR::Function *irFunction); @@ -83,6 +86,8 @@ struct JSUnitGenerator { QList<CompiledData::Lookup> lookups; QVector<CompiledData::RegExp> regexps; QHash<QQmlJS::V4IR::Function *, QVector<uint> > lineNumberMappingsPerFunction; + QList<QList<CompiledData::JSClassMember> > jsClasses; + int jsClassDataSize; }; } diff --git a/src/qml/compiler/qv4instr_moth_p.h b/src/qml/compiler/qv4instr_moth_p.h index 69c7c36880..2cc1b3e8d7 100644 --- a/src/qml/compiler/qv4instr_moth_p.h +++ b/src/qml/compiler/qv4instr_moth_p.h @@ -436,7 +436,7 @@ union Instr }; struct instr_callBuiltinDefineObjectLiteral { MOTH_INSTR_HEADER - QV4::InternalClass *internalClass; + int internalClassId; quint32 args; Param result; }; diff --git a/src/qml/compiler/qv4isel_masm.cpp b/src/qml/compiler/qv4isel_masm.cpp index df5fa94c59..8e7d7a1c6e 100644 --- a/src/qml/compiler/qv4isel_masm.cpp +++ b/src/qml/compiler/qv4isel_masm.cpp @@ -1000,15 +1000,14 @@ void InstructionSelection::callBuiltinDefineObjectLiteral(V4IR::Temp *result, V4 { int argc = 0; - InternalClass *klass = engine()->emptyClass; + const int classId = registerJSClass(args); + V4IR::ExprList *it = args; while (it) { - V4IR::Name *name = it->expr->asName(); it = it->next; bool isData = it->expr->asConst()->value; it = it->next; - klass = klass->addMember(engine()->newIdentifier(*name->id), isData ? QV4::Attr_Data : QV4::Attr_Accessor); _as->copyValue(argumentAddressForCall(argc++), it->expr); @@ -1022,7 +1021,7 @@ void InstructionSelection::callBuiltinDefineObjectLiteral(V4IR::Temp *result, V4 generateFunctionCall(Assembler::Void, __qmljs_builtin_define_object_literal, Assembler::ContextRegister, Assembler::PointerToValue(result), baseAddressForCallArguments(), - Assembler::TrustedImmPtr(klass)); + Assembler::TrustedImm32(classId)); } void InstructionSelection::callValue(V4IR::Temp *value, V4IR::ExprList *args, V4IR::Temp *result) diff --git a/src/qml/compiler/qv4isel_moth.cpp b/src/qml/compiler/qv4isel_moth.cpp index f7ff490fed..f7dd4d2e47 100644 --- a/src/qml/compiler/qv4isel_moth.cpp +++ b/src/qml/compiler/qv4isel_moth.cpp @@ -965,15 +965,13 @@ void InstructionSelection::callBuiltinDefineObjectLiteral(V4IR::Temp *result, V4 { int argLocation = outgoingArgumentTempStart(); - QV4::InternalClass *klass = engine()->emptyClass; + const int classId = registerJSClass(args); V4IR::ExprList *it = args; while (it) { - V4IR::Name *name = it->expr->asName(); it = it->next; bool isData = it->expr->asConst()->value; it = it->next; - klass = klass->addMember(identifier(*name->id), isData ? QV4::Attr_Data : QV4::Attr_Accessor); Instruction::MoveTemp move; move.source = getParam(it->expr); @@ -995,7 +993,7 @@ void InstructionSelection::callBuiltinDefineObjectLiteral(V4IR::Temp *result, V4 } Instruction::CallBuiltinDefineObjectLiteral call; - call.internalClass = klass; + call.internalClassId = classId; call.args = outgoingArgumentTempStart(); call.result = getResultParam(result); addInstruction(call); diff --git a/src/qml/compiler/qv4isel_p.h b/src/qml/compiler/qv4isel_p.h index 3553d9dc78..314af517f9 100644 --- a/src/qml/compiler/qv4isel_p.h +++ b/src/qml/compiler/qv4isel_p.h @@ -74,6 +74,7 @@ public: uint registerSetterLookup(const QString &str) { return jsUnitGenerator.registerSetterLookup(str); } uint registerGlobalGetterLookup(const QString &str) { return jsUnitGenerator.registerGlobalGetterLookup(str); } void registerLineNumberMapping(V4IR::Function *function, const QVector<uint> &mappings) { jsUnitGenerator.registerLineNumberMapping(function, mappings); } + int registerJSClass(QQmlJS::V4IR::ExprList *args) { return jsUnitGenerator.registerJSClass(args); } protected: QV4::Function *createFunctionMapping(QV4::Function *outer, V4IR::Function *irFunction); diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp index 7d99a8e8f5..3e0cf9ad0d 100644 --- a/src/qml/jsruntime/qv4runtime.cpp +++ b/src/qml/jsruntime/qv4runtime.cpp @@ -1179,8 +1179,11 @@ void __qmljs_builtin_define_getter_setter(ExecutionContext *ctx, const Value &ob pd->setSetter(setter ? setter->asFunctionObject() : 0); } -void __qmljs_builtin_define_object_literal(QV4::ExecutionContext *ctx, QV4::Value *result, const QV4::Value *args, QV4::InternalClass *klass) +void __qmljs_builtin_define_object_literal(QV4::ExecutionContext *ctx, QV4::Value *result, const QV4::Value *args, int classId) { + const QV4::Function *runtimeFunction = ctx->runtimeFunction(); + Q_ASSERT(runtimeFunction); + QV4::InternalClass *klass = runtimeFunction->compilationUnit->runtimeClasses[classId]; Object *o = ctx->engine->newObject(klass); for (int i = 0; i < klass->size; ++i) { diff --git a/src/qml/jsruntime/qv4runtime_p.h b/src/qml/jsruntime/qv4runtime_p.h index 6f00d5bf94..ba6681e2bb 100644 --- a/src/qml/jsruntime/qv4runtime_p.h +++ b/src/qml/jsruntime/qv4runtime_p.h @@ -124,7 +124,7 @@ void __qmljs_builtin_declare_var(QV4::ExecutionContext *ctx, bool deletable, QV4 void __qmljs_builtin_define_property(QV4::ExecutionContext *ctx, const QV4::Value &object, QV4::String *name, QV4::Value *val); void __qmljs_builtin_define_array(QV4::ExecutionContext *ctx, QV4::Value *array, QV4::Value *values, uint length); void __qmljs_builtin_define_getter_setter(QV4::ExecutionContext *ctx, const QV4::Value &object, QV4::String *name, const QV4::Value *getter, const QV4::Value *setter); -void __qmljs_builtin_define_object_literal(QV4::ExecutionContext *ctx, QV4::Value *result, const QV4::Value *args, QV4::InternalClass *klass); +void __qmljs_builtin_define_object_literal(QV4::ExecutionContext *ctx, QV4::Value *result, const QV4::Value *args, int classId); void __qmljs_value_from_string(QV4::Value *result, QV4::String *string); void __qmljs_lookup_runtime_regexp(QV4::ExecutionContext *ctx, QV4::Value *result, int id); diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp index a06ce4139a..b5e6fc1ab9 100644 --- a/src/qml/jsruntime/qv4vme_moth.cpp +++ b/src/qml/jsruntime/qv4vme_moth.cpp @@ -464,7 +464,7 @@ QV4::Value VME::run(QV4::ExecutionContext *context, const uchar *&code, MOTH_BEGIN_INSTR(CallBuiltinDefineObjectLiteral) QV4::Value *args = stack + instr.args; - __qmljs_builtin_define_object_literal(context, VALUEPTR(instr.result), args, instr.internalClass); + __qmljs_builtin_define_object_literal(context, VALUEPTR(instr.result), args, instr.internalClassId); MOTH_END_INSTR(CallBuiltinDefineObjectLiteral) MOTH_BEGIN_INSTR(CreateValue) |