aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@digia.com>2013-08-16 13:21:31 +0200
committerLars Knoll <lars.knoll@digia.com>2013-08-16 16:52:18 +0200
commit944717a46c237e5a5b2d6e5ea2fd8389523638e4 (patch)
tree6e894837d1cd327bb578b00d7826e3de0cde816c /src
parent85e6b8e9e7e158b5cb4238c2dd5e28406bc913e2 (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')
-rw-r--r--src/qml/compiler/qv4compileddata.cpp15
-rw-r--r--src/qml/compiler/qv4compileddata_p.h31
-rw-r--r--src/qml/compiler/qv4compiler.cpp56
-rw-r--r--src/qml/compiler/qv4compiler_p.h5
-rw-r--r--src/qml/compiler/qv4instr_moth_p.h2
-rw-r--r--src/qml/compiler/qv4isel_masm.cpp7
-rw-r--r--src/qml/compiler/qv4isel_moth.cpp6
-rw-r--r--src/qml/compiler/qv4isel_p.h1
-rw-r--r--src/qml/jsruntime/qv4runtime.cpp5
-rw-r--r--src/qml/jsruntime/qv4runtime_p.h2
-rw-r--r--src/qml/jsruntime/qv4vme_moth.cpp2
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)