free(runtimeStrings);
delete [] runtimeLookups;
delete [] runtimeRegularExpressions;
+ free(runtimeClasses);
}
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);
}
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
uint offsetToLookupTable;
uint regexpTableSize;
uint offsetToRegexpTable;
+ uint jsClassTableSize;
+ uint offsetToJSClassTable;
uint indexOfRootFunction;
quint32 sourceFileIndex;
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; }
, data(0)
, runtimeStrings(0)
, runtimeLookups(0)
+ , runtimeClasses(0)
{}
virtual ~CompilationUnit();
QV4::String **runtimeStrings; // Array
QV4::Lookup *runtimeLookups;
QV4::Value *runtimeRegularExpressions;
+ QV4::InternalClass **runtimeClasses;
QV4::Function *linkToEngine(QV4::ExecutionEngine *engine);
QV4::Compiler::JSUnitGenerator::JSUnitGenerator(QV4::ExecutionEngine *engine, QQmlJS::V4IR::Module *module)
: irModule(module)
, stringDataSize(0)
+ , jsClassDataSize(0)
{
}
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);
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) {
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));
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
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;
}
struct Unit;
struct Lookup;
struct RegExp;
+struct JSClassMember;
}
namespace Compiler {
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);
QList<CompiledData::Lookup> lookups;
QVector<CompiledData::RegExp> regexps;
QHash<QQmlJS::V4IR::Function *, QVector<uint> > lineNumberMappingsPerFunction;
+ QList<QList<CompiledData::JSClassMember> > jsClasses;
+ int jsClassDataSize;
};
}
};
struct instr_callBuiltinDefineObjectLiteral {
MOTH_INSTR_HEADER
- QV4::InternalClass *internalClass;
+ int internalClassId;
quint32 args;
Param result;
};
{
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);
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)
{
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);
}
Instruction::CallBuiltinDefineObjectLiteral call;
- call.internalClass = klass;
+ call.internalClassId = classId;
call.args = outgoingArgumentTempStart();
call.result = getResultParam(result);
addInstruction(call);
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);
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) {
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);
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)