From: Simon Hausmann Date: Tue, 23 Apr 2013 05:31:02 +0000 (+0200) Subject: Speed up object literal construction X-Git-Tag: upstream/5.2.1~669^2~608 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=659f4ffe1f09069980efba4eb5673fcf55d9d603;p=platform%2Fupstream%2Fqtdeclarative.git Speed up object literal construction Define the internal class at compile (isel) time, so that creation of the object at run-time is very fast. Change-Id: Ie153cda695cefde9d7118a7a65f1ff7e78f120cc Reviewed-by: Lars Knoll --- diff --git a/src/qml/qml/v4vm/moth/qv4instr_moth_p.h b/src/qml/qml/v4vm/moth/qv4instr_moth_p.h index 1c2dd6f..ed762af 100644 --- a/src/qml/qml/v4vm/moth/qv4instr_moth_p.h +++ b/src/qml/qml/v4vm/moth/qv4instr_moth_p.h @@ -46,6 +46,7 @@ F(CallBuiltinDefineGetterSetter, callBuiltinDefineGetterSetter) \ F(CallBuiltinDefineProperty, callBuiltinDefineProperty) \ F(CallBuiltinDefineArray, callBuiltinDefineArray) \ + F(CallBuiltinDefineObjectLiteral, callBuiltinDefineObjectLiteral) \ F(CreateValue, createValue) \ F(CreateProperty, createProperty) \ F(CreateActivationProperty, createActivationProperty) \ @@ -376,6 +377,12 @@ union Instr quint32 args; Param result; }; + struct instr_callBuiltinDefineObjectLiteral { + MOTH_INSTR_HEADER + QV4::InternalClass *internalClass; + quint32 args; + Param result; + }; struct instr_createValue { MOTH_INSTR_HEADER quint32 argc; @@ -487,6 +494,7 @@ union Instr instr_callBuiltinDefineGetterSetter callBuiltinDefineGetterSetter; instr_callBuiltinDefineProperty callBuiltinDefineProperty; instr_callBuiltinDefineArray callBuiltinDefineArray; + instr_callBuiltinDefineObjectLiteral callBuiltinDefineObjectLiteral; instr_createValue createValue; instr_createProperty createProperty; instr_createActivationProperty createActivationProperty; diff --git a/src/qml/qml/v4vm/moth/qv4isel_moth.cpp b/src/qml/qml/v4vm/moth/qv4isel_moth.cpp index 2425008..678127a 100644 --- a/src/qml/qml/v4vm/moth/qv4isel_moth.cpp +++ b/src/qml/qml/v4vm/moth/qv4isel_moth.cpp @@ -750,6 +750,46 @@ void InstructionSelection::callBuiltinDefineArray(V4IR::Temp *result, V4IR::Expr addInstruction(call); } +void InstructionSelection::callBuiltinDefineObjectLiteral(V4IR::Temp *result, V4IR::ExprList *args) +{ + int argLocation = outgoingArgumentTempStart(); + + QV4::InternalClass *klass = engine()->emptyClass; + 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); + move.result = Instr::Param::createTemp(argLocation); + addInstruction(move); + ++argLocation; + + if (!isData) { + it = it->next; + + Instruction::MoveTemp move; + move.source = getParam(it->expr); + move.result = Instr::Param::createTemp(argLocation); + addInstruction(move); + ++argLocation; + } + + it = it->next; + } + + Instruction::CallBuiltinDefineObjectLiteral call; + call.internalClass = klass; + call.args = outgoingArgumentTempStart(); + call.result = getResultParam(result); + addInstruction(call); +} + ptrdiff_t InstructionSelection::addInstructionHelper(Instr::Type type, Instr &instr) { #ifdef MOTH_THREADED_INTERPRETER diff --git a/src/qml/qml/v4vm/moth/qv4isel_moth_p.h b/src/qml/qml/v4vm/moth/qv4isel_moth_p.h index 8bbcc2f..23ca930 100644 --- a/src/qml/qml/v4vm/moth/qv4isel_moth_p.h +++ b/src/qml/qml/v4vm/moth/qv4isel_moth_p.h @@ -53,6 +53,7 @@ protected: virtual void callBuiltinDefineGetterSetter(V4IR::Temp *object, const QString &name, V4IR::Temp *getter, V4IR::Temp *setter); virtual void callBuiltinDefineProperty(V4IR::Temp *object, const QString &name, V4IR::Temp *value); virtual void callBuiltinDefineArray(V4IR::Temp *result, V4IR::ExprList *args); + virtual void callBuiltinDefineObjectLiteral(V4IR::Temp *result, V4IR::ExprList *args); virtual void callValue(V4IR::Temp *value, V4IR::ExprList *args, V4IR::Temp *result); virtual void callProperty(V4IR::Temp *base, const QString &name, V4IR::ExprList *args, V4IR::Temp *result); virtual void callSubscript(V4IR::Temp *base, V4IR::Temp *index, V4IR::ExprList *args, V4IR::Temp *result); diff --git a/src/qml/qml/v4vm/moth/qv4vme_moth.cpp b/src/qml/qml/v4vm/moth/qv4vme_moth.cpp index a4dde96..4a7e189 100644 --- a/src/qml/qml/v4vm/moth/qv4vme_moth.cpp +++ b/src/qml/qml/v4vm/moth/qv4vme_moth.cpp @@ -434,6 +434,11 @@ QV4::Value VME::run(QV4::ExecutionContext *context, const uchar *&code, __qmljs_builtin_define_array(context, VALUEPTR(instr.result), args, instr.argc); MOTH_END_INSTR(CallBuiltinDefineArray) + MOTH_BEGIN_INSTR(CallBuiltinDefineObjectLiteral) + QV4::Value *args = stack + instr.args; + __qmljs_builtin_define_object_literal(context, VALUEPTR(instr.result), args, instr.internalClass); + MOTH_END_INSTR(CallBuiltinDefineObjectLiteral) + MOTH_BEGIN_INSTR(CreateValue) Q_ASSERT(instr.args + instr.argc <= stackSize); QV4::Value *args = stack + instr.args; diff --git a/src/qml/qml/v4vm/qv4codegen.cpp b/src/qml/qml/v4vm/qv4codegen.cpp index 6942761..6196a03 100644 --- a/src/qml/qml/v4vm/qv4codegen.cpp +++ b/src/qml/qml/v4vm/qv4codegen.cpp @@ -821,6 +821,14 @@ protected: virtual bool visit(ObjectLiteral *ast) { + int argc = 0; + for (PropertyAssignmentList *it = ast->properties; it; it = it->next) { + ++argc; + if (AST::cast(it->assignment)) + ++argc; + } + _env->maxNumberOfArguments = qMax(_env->maxNumberOfArguments, argc); + TemporaryBoolAssignment allowFuncDecls(_allowFuncDecls, true); Node::accept(ast->properties, this); return false; @@ -2070,8 +2078,6 @@ bool Codegen::visit(ObjectLiteral *ast) { QMap valueMap; - const unsigned t = _block->newTemp(); - move(_block->TEMP(t), _block->NEW(_block->NAME(QStringLiteral("Object"), ast->firstSourceLocation().startLine, ast->firstSourceLocation().startColumn))); for (PropertyAssignmentList *it = ast->properties; it; it = it->next) { if (PropertyNameAndValue *nv = AST::cast(it->assignment)) { QString name = propertyName(nv->name); @@ -2101,6 +2107,65 @@ bool Codegen::visit(ObjectLiteral *ast) Q_UNREACHABLE(); } } + + V4IR::ExprList *args = 0; + + if (!valueMap.isEmpty()) { + V4IR::ExprList *current; + for (QMap::iterator it = valueMap.begin(); it != valueMap.end(); ) { + if (QV4::String(it.key()).asArrayIndex() != UINT_MAX) { + ++it; + continue; + } + + if (!args) { + args = _function->New(); + current = args; + } else { + current->next = _function->New(); + current = current->next; + } + + current->expr = _block->NAME(it.key(), 0, 0); + + if (it->value) { + current->next = _function->New(); + current = current->next; + current->expr = _block->CONST(V4IR::BoolType, true); + + unsigned value = _block->newTemp(); + move(_block->TEMP(value), it->value); + + current->next = _function->New(); + current = current->next; + current->expr = _block->TEMP(value); + } else { + current->next = _function->New(); + current = current->next; + current->expr = _block->CONST(V4IR::BoolType, false); + + unsigned getter = _block->newTemp(); + unsigned setter = _block->newTemp(); + move(_block->TEMP(getter), it->getter ? _block->CLOSURE(it->getter) : _block->CONST(V4IR::UndefinedType, 0)); + move(_block->TEMP(setter), it->setter ? _block->CLOSURE(it->setter) : _block->CONST(V4IR::UndefinedType, 0)); + + current->next = _function->New(); + current = current->next; + current->expr = _block->TEMP(getter); + current->next = _function->New(); + current = current->next; + current->expr = _block->TEMP(setter); + } + + it = valueMap.erase(it); + } + } + + const unsigned t = _block->newTemp(); + move(_block->TEMP(t), _block->CALL(_block->NAME(V4IR::Name::builtin_define_object_literal, + ast->firstSourceLocation().startLine, ast->firstSourceLocation().startColumn), args)); + + // What's left are array entries if (!valueMap.isEmpty()) { unsigned value = 0; unsigned getter = 0; diff --git a/src/qml/qml/v4vm/qv4engine.cpp b/src/qml/qml/v4vm/qv4engine.cpp index 9e9a7fc..ac28069 100644 --- a/src/qml/qml/v4vm/qv4engine.cpp +++ b/src/qml/qml/v4vm/qv4engine.cpp @@ -363,6 +363,13 @@ Object *ExecutionEngine::newObject() return object; } +Object *ExecutionEngine::newObject(InternalClass *internalClass) +{ + Object *object = new (memoryManager) Object(this, internalClass); + object->prototype = objectPrototype; + return object; +} + String *ExecutionEngine::newString(const QString &s) { return new (memoryManager) String(s); diff --git a/src/qml/qml/v4vm/qv4engine_p.h b/src/qml/qml/v4vm/qv4engine_p.h index 02e470d..dc9783f 100644 --- a/src/qml/qml/v4vm/qv4engine_p.h +++ b/src/qml/qml/v4vm/qv4engine_p.h @@ -216,6 +216,7 @@ struct Q_QML_EXPORT ExecutionEngine BoundFunction *newBoundFunction(ExecutionContext *scope, FunctionObject *target, Value boundThis, const QVector &boundArgs); Object *newObject(); + Object *newObject(InternalClass *internalClass); String *newString(const QString &s); String *newIdentifier(const QString &text); diff --git a/src/qml/qml/v4vm/qv4isel_masm.cpp b/src/qml/qml/v4vm/qv4isel_masm.cpp index 9e6ba84..fd034a5 100644 --- a/src/qml/qml/v4vm/qv4isel_masm.cpp +++ b/src/qml/qml/v4vm/qv4isel_masm.cpp @@ -813,6 +813,37 @@ void InstructionSelection::callBuiltinDefineArray(V4IR::Temp *result, V4IR::Expr baseAddressForCallArguments(), Assembler::TrustedImm32(length)); } +void InstructionSelection::callBuiltinDefineObjectLiteral(V4IR::Temp *result, V4IR::ExprList *args) +{ + int argc = 0; + + InternalClass *klass = engine()->emptyClass; + 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); + + _as->copyValue(argumentAddressForCall(argc++), it->expr); + + if (!isData) { + it = it->next; + _as->copyValue(argumentAddressForCall(argc++), it->expr); + } + + it = it->next; + } + + _as->move(Assembler::TrustedImmPtr(klass), Assembler::ReturnValueRegister); + + generateFunctionCall(Assembler::Void, __qmljs_builtin_define_object_literal, Assembler::ContextRegister, + Assembler::PointerToValue(result), baseAddressForCallArguments(), + Assembler::ReturnValueRegister); +} + void InstructionSelection::callValue(V4IR::Temp *value, V4IR::ExprList *args, V4IR::Temp *result) { int argc = prepareVariableArguments(args); diff --git a/src/qml/qml/v4vm/qv4isel_masm_p.h b/src/qml/qml/v4vm/qv4isel_masm_p.h index 505cafc..8e1740e 100644 --- a/src/qml/qml/v4vm/qv4isel_masm_p.h +++ b/src/qml/qml/v4vm/qv4isel_masm_p.h @@ -813,6 +813,7 @@ protected: virtual void callBuiltinDefineGetterSetter(V4IR::Temp *object, const QString &name, V4IR::Temp *getter, V4IR::Temp *setter); virtual void callBuiltinDefineProperty(V4IR::Temp *object, const QString &name, V4IR::Temp *value); virtual void callBuiltinDefineArray(V4IR::Temp *result, V4IR::ExprList *args); + virtual void callBuiltinDefineObjectLiteral(V4IR::Temp *result, V4IR::ExprList *args); virtual void callProperty(V4IR::Temp *base, const QString &name, V4IR::ExprList *args, V4IR::Temp *result); virtual void callSubscript(V4IR::Temp *base, V4IR::Temp *index, V4IR::ExprList *args, V4IR::Temp *result); virtual void callValue(V4IR::Temp *value, V4IR::ExprList *args, V4IR::Temp *result); diff --git a/src/qml/qml/v4vm/qv4isel_p.cpp b/src/qml/qml/v4vm/qv4isel_p.cpp index e190833..478fea4 100644 --- a/src/qml/qml/v4vm/qv4isel_p.cpp +++ b/src/qml/qml/v4vm/qv4isel_p.cpp @@ -387,6 +387,10 @@ void InstructionSelection::callBuiltin(V4IR::Call *call, V4IR::Temp *result) callBuiltinDefineArray(result, call->args); return; + case V4IR::Name::builtin_define_object_literal: + callBuiltinDefineObjectLiteral(result, call->args); + return; + default: break; } diff --git a/src/qml/qml/v4vm/qv4isel_p.h b/src/qml/qml/v4vm/qv4isel_p.h index 59a4b76..b3efacc 100644 --- a/src/qml/qml/v4vm/qv4isel_p.h +++ b/src/qml/qml/v4vm/qv4isel_p.h @@ -124,6 +124,7 @@ public: // to implement by subclasses: virtual void callBuiltinDefineGetterSetter(V4IR::Temp *object, const QString &name, V4IR::Temp *getter, V4IR::Temp *setter) = 0; virtual void callBuiltinDefineProperty(V4IR::Temp *object, const QString &name, V4IR::Temp *value) = 0; virtual void callBuiltinDefineArray(V4IR::Temp *result, V4IR::ExprList *args) = 0; + virtual void callBuiltinDefineObjectLiteral(V4IR::Temp *result, V4IR::ExprList *args) = 0; virtual void callValue(V4IR::Temp *value, V4IR::ExprList *args, V4IR::Temp *result) = 0; virtual void callProperty(V4IR::Temp *base, const QString &name, V4IR::ExprList *args, V4IR::Temp *result) = 0; virtual void callSubscript(V4IR::Temp *base, V4IR::Temp *index, V4IR::ExprList *args, V4IR::Temp *result) = 0; diff --git a/src/qml/qml/v4vm/qv4jsir.cpp b/src/qml/qml/v4vm/qv4jsir.cpp index 3dad094..e94aa1b 100644 --- a/src/qml/qml/v4vm/qv4jsir.cpp +++ b/src/qml/qml/v4vm/qv4jsir.cpp @@ -388,6 +388,8 @@ static const char *builtin_to_string(Name::Builtin b) return "builtin_define_array"; case V4IR::Name::builtin_define_getter_setter: return "builtin_define_getter_setter"; + case V4IR::Name::builtin_define_object_literal: + return "builtin_define_object_literal"; } return "builtin_(###FIXME)"; }; diff --git a/src/qml/qml/v4vm/qv4jsir_p.h b/src/qml/qml/v4vm/qv4jsir_p.h index 1285c71..cc0f2e9 100644 --- a/src/qml/qml/v4vm/qv4jsir_p.h +++ b/src/qml/qml/v4vm/qv4jsir_p.h @@ -299,7 +299,8 @@ struct Name: Expr { builtin_declare_vars, builtin_define_property, builtin_define_array, - builtin_define_getter_setter + builtin_define_getter_setter, + builtin_define_object_literal }; const QString *id; diff --git a/src/qml/qml/v4vm/qv4object.cpp b/src/qml/qml/v4vm/qv4object.cpp index fc54899..42ec8f2 100644 --- a/src/qml/qml/v4vm/qv4object.cpp +++ b/src/qml/qml/v4vm/qv4object.cpp @@ -89,6 +89,22 @@ Object::Object(ExecutionContext *context) type = Type_Object; } +Object::Object(ExecutionEngine *engine, InternalClass *internalClass) + : prototype(0) + , internalClass(internalClass) + , memberDataAlloc(InlinePropertySize), memberData(inlineProperties) + , arrayOffset(0), arrayDataLen(0), arrayAlloc(0), arrayAttributes(0), arrayData(0), sparseArray(0) + , externalResource(0) +{ + vtbl = &static_vtbl; + type = Type_Object; + + if (internalClass->size >= memberDataAlloc) { + memberDataAlloc = internalClass->size; + memberData = new Property[memberDataAlloc]; + } +} + Object::~Object() { delete externalResource; diff --git a/src/qml/qml/v4vm/qv4object_p.h b/src/qml/qml/v4vm/qv4object_p.h index a273a47..675c149 100644 --- a/src/qml/qml/v4vm/qv4object_p.h +++ b/src/qml/qml/v4vm/qv4object_p.h @@ -130,6 +130,7 @@ struct Q_QML_EXPORT Object: Managed { Object(ExecutionEngine *engine); Object(ExecutionContext *context); + Object(ExecutionEngine *engine, InternalClass *internalClass); ~Object(); Property *__getOwnProperty__(String *name, PropertyAttributes *attrs = 0); diff --git a/src/qml/qml/v4vm/qv4runtime.cpp b/src/qml/qml/v4vm/qv4runtime.cpp index 0adb99d..b510d4c 100644 --- a/src/qml/qml/v4vm/qv4runtime.cpp +++ b/src/qml/qml/v4vm/qv4runtime.cpp @@ -1263,6 +1263,24 @@ 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) +{ + Object *o = ctx->engine->newObject(klass); + + for (int i = 0; i < klass->size; ++i) { + if (klass->propertyData[i].isData()) + o->memberData[i].value = *args++; + else { + o->memberData[i].setGetter(args->asFunctionObject()); + args++; + o->memberData[i].setSetter(args->asFunctionObject()); + args++; + } + } + + *result = Value::fromObject(o); +} + void __qmljs_increment(Value *result, const Value &value) { TRACE1(value); diff --git a/src/qml/qml/v4vm/qv4runtime_p.h b/src/qml/qml/v4vm/qv4runtime_p.h index 755e8b7..61a6bb0 100644 --- a/src/qml/qml/v4vm/qv4runtime_p.h +++ b/src/qml/qml/v4vm/qv4runtime_p.h @@ -86,6 +86,7 @@ struct RegExpObject; struct ArrayObject; struct ErrorObject; struct ExecutionEngine; +struct InternalClass; struct Q_QML_EXPORT Exception { explicit Exception(ExecutionContext *throwingContext, const Value &exceptionValue); @@ -144,6 +145,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); // constructors void __qmljs_init_closure(QV4::ExecutionContext *ctx, QV4::Value *result, QV4::Function *clos);