Clean up object literal handling with integral indices

* Object literals with array indices are now created with one
  run-time call, instead of an initial one for non-integral keys
  followed by sub-sequent define_builtin_property calls.

* Cleaned up propert name retrieval. Instead of using a visitor,
  it's easier to define a virtual method on the PropertyName type.  The visitor
  doesn't buy us much as it's not possible to recurse within property names, and
  this way we can use it also from the function scanner to correctly determine
  the number of arguments needed for object literal initalizations.

* Similarly the duplicated/common name member for all property assignments
  has been moved into PropertyName, for convenient access without AST casts.

* Removed now unused builtin_define_property/settergetter functions from IR,
  run-time and moth.

Change-Id: I90d54c81ea5f3f500f4f4a9c14f7caf5135e7f9f
Reviewed-by: Lars Knoll <lars.knoll@digia.com>
This commit is contained in:
Simon Hausmann 2014-02-15 02:16:43 +01:00 committed by The Qt Project
parent 00be968679
commit c78d1052c2
18 changed files with 292 additions and 314 deletions

View File

@ -261,6 +261,9 @@ bool Codegen::ScanFunctions::visit(ObjectLiteral *ast)
{
int argc = 0;
for (PropertyAssignmentList *it = ast->properties; it; it = it->next) {
QString key = it->assignment->name->asString();
if (QV4::String::toArrayIndex(key) != UINT_MAX)
++argc;
++argc;
if (AST::cast<AST::PropertyGetterSetter *>(it->assignment))
++argc;
@ -776,17 +779,6 @@ Codegen::Result Codegen::expression(ExpressionNode *ast)
return r;
}
QString Codegen::propertyName(PropertyName *ast)
{
QString p;
if (ast) {
qSwap(_property, p);
accept(ast);
qSwap(_property, p);
}
return p;
}
Codegen::Result Codegen::sourceElement(SourceElement *ast)
{
Result r(nx);
@ -1597,8 +1589,8 @@ bool Codegen::visit(ObjectLiteral *ast)
QMap<QString, ObjectPropertyValue> valueMap;
for (PropertyAssignmentList *it = ast->properties; it; it = it->next) {
QString name = it->assignment->name->asString();
if (PropertyNameAndValue *nv = AST::cast<AST::PropertyNameAndValue *>(it->assignment)) {
QString name = propertyName(nv->name);
Result value = expression(nv->value);
ObjectPropertyValue &v = valueMap[name];
if (v.hasGetter() || v.hasSetter() || (_function->isStrict && v.value)) {
@ -1609,7 +1601,6 @@ bool Codegen::visit(ObjectLiteral *ast)
valueMap[name].value = *value;
} else if (PropertyGetterSetter *gs = AST::cast<AST::PropertyGetterSetter *>(it->assignment)) {
QString name = propertyName(gs->name);
const int function = defineFunction(name, gs, gs->formals, gs->functionBody ? gs->functionBody->elements : 0);
ObjectPropertyValue &v = valueMap[name];
if (v.value ||
@ -1628,104 +1619,99 @@ bool Codegen::visit(ObjectLiteral *ast)
}
}
IR::ExprList *args = 0;
// The linked-list arguments to builtin_define_object_literal
// begin with a CONST counting the number of key/value pairs, followed by the
// key value pairs, followed by the array entries.
IR::ExprList *args = _function->New<IR::ExprList>();
if (!valueMap.isEmpty()) {
IR::ExprList *current;
for (QMap<QString, ObjectPropertyValue>::iterator it = valueMap.begin(); it != valueMap.end(); ) {
if (QV4::String::toArrayIndex(it.key()) != UINT_MAX) {
++it;
continue;
}
IR::Const *entryCountParam = _function->New<IR::Const>();
entryCountParam->init(IR::SInt32Type, 0);
args->expr = entryCountParam;
args->next = 0;
if (!args) {
args = _function->New<IR::ExprList>();
current = args;
IR::ExprList *keyValueEntries = 0;
IR::ExprList *currentKeyValueEntry = 0;
int keyValueEntryCount = 0;
IR::ExprList *arrayEntries = 0;
IR::ExprList *currentArrayEntry = 0;
for (QMap<QString, ObjectPropertyValue>::iterator it = valueMap.begin(); it != valueMap.end(); ) {
IR::ExprList **currentPtr = 0;
uint keyAsIndex = QV4::String::toArrayIndex(it.key());
if (keyAsIndex != UINT_MAX) {
if (!arrayEntries) {
arrayEntries = _function->New<IR::ExprList>();
currentArrayEntry = arrayEntries;
} else {
current->next = _function->New<IR::ExprList>();
current = current->next;
currentArrayEntry->next = _function->New<IR::ExprList>();
currentArrayEntry = currentArrayEntry->next;
}
current->expr = _block->NAME(it.key(), 0, 0);
if (it->value) {
current->next = _function->New<IR::ExprList>();
current = current->next;
current->expr = _block->CONST(IR::BoolType, true);
unsigned value = _block->newTemp();
move(_block->TEMP(value), it->value);
current->next = _function->New<IR::ExprList>();
current = current->next;
current->expr = _block->TEMP(value);
currentPtr = &currentArrayEntry;
IR::Const *idx = _function->New<IR::Const>();
idx->init(IR::UInt32Type, keyAsIndex);
(*currentPtr)->expr = idx;
} else {
if (!keyValueEntries) {
keyValueEntries = _function->New<IR::ExprList>();
currentKeyValueEntry = keyValueEntries;
} else {
current->next = _function->New<IR::ExprList>();
current = current->next;
current->expr = _block->CONST(IR::BoolType, false);
unsigned getter = _block->newTemp();
unsigned setter = _block->newTemp();
move(_block->TEMP(getter), it->hasGetter() ? _block->CLOSURE(it->getter) : _block->CONST(IR::UndefinedType, 0));
move(_block->TEMP(setter), it->hasSetter() ? _block->CLOSURE(it->setter) : _block->CONST(IR::UndefinedType, 0));
current->next = _function->New<IR::ExprList>();
current = current->next;
current->expr = _block->TEMP(getter);
current->next = _function->New<IR::ExprList>();
current = current->next;
current->expr = _block->TEMP(setter);
currentKeyValueEntry->next = _function->New<IR::ExprList>();
currentKeyValueEntry = currentKeyValueEntry->next;
}
it = valueMap.erase(it);
currentPtr = &currentKeyValueEntry;
(*currentPtr)->expr = _block->NAME(it.key(), 0, 0);
keyValueEntryCount++;
}
IR::ExprList *&current = *currentPtr;
if (it->value) {
current->next = _function->New<IR::ExprList>();
current = current->next;
current->expr = _block->CONST(IR::BoolType, true);
unsigned value = _block->newTemp();
move(_block->TEMP(value), it->value);
current->next = _function->New<IR::ExprList>();
current = current->next;
current->expr = _block->TEMP(value);
} else {
current->next = _function->New<IR::ExprList>();
current = current->next;
current->expr = _block->CONST(IR::BoolType, false);
unsigned getter = _block->newTemp();
unsigned setter = _block->newTemp();
move(_block->TEMP(getter), it->hasGetter() ? _block->CLOSURE(it->getter) : _block->CONST(IR::UndefinedType, 0));
move(_block->TEMP(setter), it->hasSetter() ? _block->CLOSURE(it->setter) : _block->CONST(IR::UndefinedType, 0));
current->next = _function->New<IR::ExprList>();
current = current->next;
current->expr = _block->TEMP(getter);
current->next = _function->New<IR::ExprList>();
current = current->next;
current->expr = _block->TEMP(setter);
}
it = valueMap.erase(it);
}
entryCountParam->value = keyValueEntryCount;
if (keyValueEntries)
args->next = keyValueEntries;
if (arrayEntries) {
if (currentKeyValueEntry)
currentKeyValueEntry->next = arrayEntries;
else
args->next = arrayEntries;
}
const unsigned t = _block->newTemp();
move(_block->TEMP(t), _block->CALL(_block->NAME(IR::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;
unsigned setter = 0;
for (QMap<QString, ObjectPropertyValue>::const_iterator it = valueMap.constBegin(); it != valueMap.constEnd(); ++it) {
IR::ExprList *args = _function->New<IR::ExprList>();
IR::ExprList *current = args;
current->expr = _block->TEMP(t);
current->next = _function->New<IR::ExprList>();
current = current->next;
current->expr = _block->NAME(it.key(), 0, 0);
current->next = _function->New<IR::ExprList>();
current = current->next;
if (it->value) {
if (!value)
value = _block->newTemp();
move(_block->TEMP(value), it->value);
// __qmljs_builtin_define_property(Value object, String *name, Value val, ExecutionContext *ctx)
current->expr = _block->TEMP(value);
_block->EXP(_block->CALL(_block->NAME(IR::Name::builtin_define_property, 0, 0), args));
} else {
if (!getter) {
getter = _block->newTemp();
setter = _block->newTemp();
}
move(_block->TEMP(getter), it->hasGetter() ? _block->CLOSURE(it->getter) : _block->CONST(IR::UndefinedType, 0));
move(_block->TEMP(setter), it->hasSetter() ? _block->CLOSURE(it->setter) : _block->CONST(IR::UndefinedType, 0));
// __qmljs_builtin_define_getter_setter(Value object, String *name, Value getter, Value setter, ExecutionContext *ctx);
current->expr = _block->TEMP(getter);
current->next = _function->New<IR::ExprList>();
current = current->next;
current->expr = _block->TEMP(setter);
_block->EXP(_block->CALL(_block->NAME(IR::Name::builtin_define_getter_setter, 0, 0), args));
}
}
}
_expr.code = _block->TEMP(t);
return false;
}
@ -2072,33 +2058,6 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
return functionIndex;
}
bool Codegen::visit(IdentifierPropertyName *ast)
{
if (hasError)
return false;
_property = ast->id.toString();
return false;
}
bool Codegen::visit(NumericLiteralPropertyName *ast)
{
if (hasError)
return false;
_property = QString::number(ast->id, 'g', 16);
return false;
}
bool Codegen::visit(StringLiteralPropertyName *ast)
{
if (hasError)
return false;
_property = ast->id.toString();
return false;
}
bool Codegen::visit(FunctionSourceElement *ast)
{
if (hasError)

View File

@ -315,7 +315,6 @@ protected:
void statement(AST::ExpressionNode *ast);
void condition(AST::ExpressionNode *ast, QV4::IR::BasicBlock *iftrue, QV4::IR::BasicBlock *iffalse);
Result expression(AST::ExpressionNode *ast);
QString propertyName(AST::PropertyName *ast);
Result sourceElement(AST::SourceElement *ast);
UiMember uiObjectMember(AST::UiObjectMember *ast);
@ -397,11 +396,6 @@ protected:
virtual bool visit(AST::VoidExpression *ast);
virtual bool visit(AST::FunctionDeclaration *ast);
// property names
virtual bool visit(AST::IdentifierPropertyName *ast);
virtual bool visit(AST::NumericLiteralPropertyName *ast);
virtual bool visit(AST::StringLiteralPropertyName *ast);
// source elements
virtual bool visit(AST::FunctionSourceElement *ast);
virtual bool visit(AST::StatementSourceElement *ast);

View File

@ -151,14 +151,14 @@ void QV4::Compiler::JSUnitGenerator::registerLineNumberMapping(QV4::IR::Function
lineNumberMappingsPerFunction.insert(function, mappings);
}
int QV4::Compiler::JSUnitGenerator::registerJSClass(QV4::IR::ExprList *args)
int QV4::Compiler::JSUnitGenerator::registerJSClass(int count, IR::ExprList *args)
{
// ### re-use existing class definitions.
QList<CompiledData::JSClassMember> members;
QV4::IR::ExprList *it = args;
while (it) {
IR::ExprList *it = args;
for (int i = 0; i < count; ++i, it = it->next) {
CompiledData::JSClassMember member;
QV4::IR::Name *name = it->expr->asName();
@ -173,8 +173,6 @@ int QV4::Compiler::JSUnitGenerator::registerJSClass(QV4::IR::ExprList *args)
if (!isData)
it = it->next;
it = it->next;
}
jsClasses << members;

View File

@ -79,7 +79,7 @@ struct Q_QML_EXPORT JSUnitGenerator {
void registerLineNumberMapping(IR::Function *function, const QVector<uint> &mappings);
int registerJSClass(IR::ExprList *args);
int registerJSClass(int count, IR::ExprList *args);
QV4::CompiledData::Unit *generateUnit(int *totalUnitSize = 0);
// Returns bytes written

View File

@ -95,8 +95,6 @@ QT_BEGIN_NAMESPACE
F(CallBuiltinTypeofName, callBuiltinTypeofName) \
F(CallBuiltinTypeofValue, callBuiltinTypeofValue) \
F(CallBuiltinDeclareVar, callBuiltinDeclareVar) \
F(CallBuiltinDefineGetterSetter, callBuiltinDefineGetterSetter) \
F(CallBuiltinDefineProperty, callBuiltinDefineProperty) \
F(CallBuiltinDefineArray, callBuiltinDefineArray) \
F(CallBuiltinDefineObjectLiteral, callBuiltinDefineObjectLiteral) \
F(CallBuiltinSetupArgumentsObject, callBuiltinSetupArgumentsObject) \
@ -481,19 +479,6 @@ union Instr
int varName;
bool isDeletable;
};
struct instr_callBuiltinDefineGetterSetter {
MOTH_INSTR_HEADER
int name;
Param object;
Param getter;
Param setter;
};
struct instr_callBuiltinDefineProperty {
MOTH_INSTR_HEADER
int name;
Param object;
Param value;
};
struct instr_callBuiltinDefineArray {
MOTH_INSTR_HEADER
quint32 argc;
@ -503,6 +488,8 @@ union Instr
struct instr_callBuiltinDefineObjectLiteral {
MOTH_INSTR_HEADER
int internalClassId;
int arrayValueCount;
int arrayGetterSetterCount;
quint32 args;
Param result;
};
@ -768,8 +755,6 @@ union Instr
instr_callBuiltinTypeofName callBuiltinTypeofName;
instr_callBuiltinTypeofValue callBuiltinTypeofValue;
instr_callBuiltinDeclareVar callBuiltinDeclareVar;
instr_callBuiltinDefineGetterSetter callBuiltinDefineGetterSetter;
instr_callBuiltinDefineProperty callBuiltinDefineProperty;
instr_callBuiltinDefineArray callBuiltinDefineArray;
instr_callBuiltinDefineObjectLiteral callBuiltinDefineObjectLiteral;
instr_callBuiltinSetupArgumentsObject callBuiltinSetupArgumentsObject;

View File

@ -1252,26 +1252,6 @@ void InstructionSelection::callBuiltinDeclareVar(bool deletable, const QString &
addInstruction(call);
}
void InstructionSelection::callBuiltinDefineGetterSetter(IR::Temp *object, const QString &name, IR::Temp *getter, IR::Temp *setter)
{
Instruction::CallBuiltinDefineGetterSetter call;
call.object = getParam(object);
call.name = registerString(name);
call.getter = getParam(getter);
call.setter = getParam(setter);
addInstruction(call);
}
void InstructionSelection::callBuiltinDefineProperty(IR::Temp *object, const QString &name,
IR::Expr *value)
{
Instruction::CallBuiltinDefineProperty call;
call.object = getParam(object);
call.name = registerString(name);
call.value = getParam(value);
addInstruction(call);
}
void InstructionSelection::callBuiltinDefineArray(IR::Temp *result, IR::ExprList *args)
{
Instruction::CallBuiltinDefineArray call;
@ -1280,13 +1260,16 @@ void InstructionSelection::callBuiltinDefineArray(IR::Temp *result, IR::ExprList
addInstruction(call);
}
void InstructionSelection::callBuiltinDefineObjectLiteral(IR::Temp *result, IR::ExprList *args)
void InstructionSelection::callBuiltinDefineObjectLiteral(IR::Temp *result, int keyValuePairCount, IR::ExprList *keyValuePairs, IR::ExprList *arrayEntries)
{
int argLocation = outgoingArgumentTempStart();
const int classId = registerJSClass(args);
IR::ExprList *it = args;
while (it) {
const int classId = registerJSClass(keyValuePairCount, keyValuePairs);
// Process key/value pairs first
IR::ExprList *it = keyValuePairs;
for (int i = 0; i < keyValuePairCount; ++i, it = it->next) {
// Skip name
it = it->next;
bool isData = it->expr->asConst()->value;
@ -1314,12 +1297,84 @@ void InstructionSelection::callBuiltinDefineObjectLiteral(IR::Temp *result, IR::
addInstruction(move);
++argLocation;
}
}
// Process array values
int arrayValueCount = 0;
it = arrayEntries;
while (it) {
IR::Const *index = it->expr->asConst();
it = it->next;
bool isData = it->expr->asConst()->value;
it = it->next;
if (!isData) {
it = it->next; // getter
it = it->next; // setter
continue;
}
++arrayValueCount;
Instruction::MoveConst indexMove;
indexMove.source = convertToValue(index).asReturnedValue();
indexMove.result = Param::createTemp(argLocation);
addInstruction(indexMove);
++argLocation;
Instruction::Move move;
move.source = getParam(it->expr);
move.result = Param::createTemp(argLocation);
addInstruction(move);
++argLocation;
it = it->next;
}
// Process array getter/setter pairs
int arrayGetterSetterCount = 0;
it = arrayEntries;
while (it) {
IR::Const *index = it->expr->asConst();
it = it->next;
bool isData = it->expr->asConst()->value;
it = it->next;
if (isData) {
it = it->next; // value
continue;
}
++arrayGetterSetterCount;
Instruction::MoveConst indexMove;
indexMove.source = convertToValue(index).asReturnedValue();
indexMove.result = Param::createTemp(argLocation);
addInstruction(indexMove);
++argLocation;
// getter
Instruction::Move moveGetter;
moveGetter.source = getParam(it->expr);
moveGetter.result = Param::createTemp(argLocation);
addInstruction(moveGetter);
++argLocation;
it = it->next;
// setter
Instruction::Move moveSetter;
moveSetter.source = getParam(it->expr);
moveSetter.result = Param::createTemp(argLocation);
addInstruction(moveSetter);
++argLocation;
it = it->next;
}
Instruction::CallBuiltinDefineObjectLiteral call;
call.internalClassId = classId;
call.arrayValueCount = arrayValueCount;
call.arrayGetterSetterCount = arrayGetterSetterCount;
call.args = outgoingArgumentTempStart();
call.result = getResultParam(result);
addInstruction(call);

View File

@ -98,10 +98,8 @@ protected:
virtual void callBuiltinPushWithScope(IR::Temp *arg);
virtual void callBuiltinPopScope();
virtual void callBuiltinDeclareVar(bool deletable, const QString &name);
virtual void callBuiltinDefineGetterSetter(IR::Temp *object, const QString &name, IR::Temp *getter, IR::Temp *setter);
virtual void callBuiltinDefineProperty(IR::Temp *object, const QString &name, IR::Expr *value);
virtual void callBuiltinDefineArray(IR::Temp *result, IR::ExprList *args);
virtual void callBuiltinDefineObjectLiteral(IR::Temp *result, IR::ExprList *args);
virtual void callBuiltinDefineObjectLiteral(IR::Temp *result, int keyValuePairCount, IR::ExprList *keyValuePairs, IR::ExprList *arrayEntries);
virtual void callBuiltinSetupArgumentObject(IR::Temp *result);
virtual void callBuiltinConvertThisToObject();
virtual void callValue(IR::Temp *value, IR::ExprList *args, IR::Temp *result);

View File

@ -347,48 +347,29 @@ void IRDecoder::callBuiltin(IR::Call *call, IR::Temp *result)
}
} return;
case IR::Name::builtin_define_getter_setter: {
if (!call->args)
return;
IR::ExprList *args = call->args;
IR::Temp *object = args->expr->asTemp();
assert(object);
args = args->next;
assert(args);
IR::Name *name = args->expr->asName();
args = args->next;
assert(args);
IR::Temp *getter = args->expr->asTemp();
args = args->next;
assert(args);
IR::Temp *setter = args->expr->asTemp();
callBuiltinDefineGetterSetter(object, *name->id, getter, setter);
} return;
case IR::Name::builtin_define_property: {
if (!call->args)
return;
IR::ExprList *args = call->args;
IR::Temp *object = args->expr->asTemp();
assert(object);
args = args->next;
assert(args);
IR::Name *name = args->expr->asName();
args = args->next;
assert(args);
IR::Expr *value = args->expr;
callBuiltinDefineProperty(object, *name->id, value);
} return;
case IR::Name::builtin_define_array:
callBuiltinDefineArray(result, call->args);
return;
case IR::Name::builtin_define_object_literal:
callBuiltinDefineObjectLiteral(result, call->args);
return;
case IR::Name::builtin_define_object_literal: {
IR::ExprList *args = call->args;
const int keyValuePairsCount = args->expr->asConst()->value;
args = args->next;
IR::ExprList *keyValuePairs = args;
for (int i = 0; i < keyValuePairsCount; ++i) {
args = args->next; // name
bool isData = args->expr->asConst()->value;
args = args->next; // isData flag
args = args->next; // value or getter
if (!isData)
args = args->next; // setter
}
IR::ExprList *arrayEntries = args;
callBuiltinDefineObjectLiteral(result, keyValuePairsCount, keyValuePairs, arrayEntries);
} return;
case IR::Name::builtin_setup_argument_object:
callBuiltinSetupArgumentObject(result);

View File

@ -76,7 +76,7 @@ public:
uint registerSetterLookup(const QString &name) { return jsGenerator->registerSetterLookup(name); }
uint registerGlobalGetterLookup(const QString &name) { return jsGenerator->registerGlobalGetterLookup(name); }
int registerRegExp(IR::RegExp *regexp) { return jsGenerator->registerRegExp(regexp); }
int registerJSClass(IR::ExprList *args) { return jsGenerator->registerJSClass(args); }
int registerJSClass(int count, IR::ExprList *args) { return jsGenerator->registerJSClass(count, args); }
QV4::Compiler::JSUnitGenerator *jsUnitGenerator() const { return jsGenerator; }
protected:
@ -130,10 +130,8 @@ public: // to implement by subclasses:
virtual void callBuiltinPushWithScope(IR::Temp *arg) = 0;
virtual void callBuiltinPopScope() = 0;
virtual void callBuiltinDeclareVar(bool deletable, const QString &name) = 0;
virtual void callBuiltinDefineGetterSetter(IR::Temp *object, const QString &name, IR::Temp *getter, IR::Temp *setter) = 0;
virtual void callBuiltinDefineProperty(IR::Temp *object, const QString &name, IR::Expr *value) = 0;
virtual void callBuiltinDefineArray(IR::Temp *result, IR::ExprList *args) = 0;
virtual void callBuiltinDefineObjectLiteral(IR::Temp *result, IR::ExprList *args) = 0;
virtual void callBuiltinDefineObjectLiteral(IR::Temp *result, int keyValuePairCount, IR::ExprList *keyValuePairs, IR::ExprList *arrayEntries) = 0;
virtual void callBuiltinSetupArgumentObject(IR::Temp *result) = 0;
virtual void callBuiltinConvertThisToObject() = 0;
virtual void callValue(IR::Temp *value, IR::ExprList *args, IR::Temp *result) = 0;

View File

@ -427,12 +427,8 @@ static const char *builtin_to_string(Name::Builtin b)
return "builtin_pop_scope";
case IR::Name::builtin_declare_vars:
return "builtin_declare_vars";
case IR::Name::builtin_define_property:
return "builtin_define_property";
case IR::Name::builtin_define_array:
return "builtin_define_array";
case IR::Name::builtin_define_getter_setter:
return "builtin_define_getter_setter";
case IR::Name::builtin_define_object_literal:
return "builtin_define_object_literal";
case IR::Name::builtin_setup_argument_object:

View File

@ -349,9 +349,7 @@ struct Name: Expr {
builtin_push_with_scope,
builtin_pop_scope,
builtin_declare_vars,
builtin_define_property,
builtin_define_array,
builtin_define_getter_setter,
builtin_define_object_literal,
builtin_setup_argument_object,
builtin_convert_this_to_object,

View File

@ -483,27 +483,6 @@ void InstructionSelection::callBuiltinDeclareVar(bool deletable, const QString &
Assembler::TrustedImm32(deletable), Assembler::PointerToString(name));
}
void InstructionSelection::callBuiltinDefineGetterSetter(IR::Temp *object, const QString &name, IR::Temp *getter, IR::Temp *setter)
{
Q_ASSERT(object);
Q_ASSERT(getter);
Q_ASSERT(setter);
generateFunctionCall(Assembler::Void, __qmljs_builtin_define_getter_setter, Assembler::ContextRegister,
Assembler::Reference(object), Assembler::PointerToString(name), Assembler::PointerToValue(getter), Assembler::PointerToValue(setter));
}
void InstructionSelection::callBuiltinDefineProperty(IR::Temp *object, const QString &name,
IR::Expr *value)
{
Q_ASSERT(object);
Q_ASSERT(value->asTemp() || value->asConst());
generateFunctionCall(Assembler::Void, __qmljs_builtin_define_property,
Assembler::ContextRegister, Assembler::Reference(object),
Assembler::PointerToString(name),
Assembler::PointerToValue(value));
}
void InstructionSelection::callBuiltinDefineArray(IR::Temp *result, IR::ExprList *args)
{
Q_ASSERT(result);
@ -513,16 +492,16 @@ void InstructionSelection::callBuiltinDefineArray(IR::Temp *result, IR::ExprList
baseAddressForCallArguments(), Assembler::TrustedImm32(length));
}
void InstructionSelection::callBuiltinDefineObjectLiteral(IR::Temp *result, IR::ExprList *args)
void InstructionSelection::callBuiltinDefineObjectLiteral(IR::Temp *result, int keyValuePairCount, IR::ExprList *keyValuePairs, IR::ExprList *arrayEntries)
{
Q_ASSERT(result);
int argc = 0;
const int classId = registerJSClass(args);
const int classId = registerJSClass(keyValuePairCount, keyValuePairs);
IR::ExprList *it = args;
while (it) {
IR::ExprList *it = keyValuePairs;
for (int i = 0; i < keyValuePairCount; ++i, it = it->next) {
it = it->next;
bool isData = it->expr->asConst()->value;
@ -534,12 +513,64 @@ void InstructionSelection::callBuiltinDefineObjectLiteral(IR::Temp *result, IR::
it = it->next;
_as->copyValue(_as->stackLayout().argumentAddressForCall(argc++), it->expr);
}
}
it = arrayEntries;
int arrayValueCount = 0;
while (it) {
uint index = it->expr->asConst()->value;
it = it->next;
bool isData = it->expr->asConst()->value;
it = it->next;
if (!isData) {
it = it->next; // getter
it = it->next; // setter
continue;
}
++arrayValueCount;
// Index
_as->storeValue(QV4::Primitive::fromUInt32(index), _as->stackLayout().argumentAddressForCall(argc++));
// Value
_as->copyValue(_as->stackLayout().argumentAddressForCall(argc++), it->expr);
it = it->next;
}
it = arrayEntries;
int arrayGetterSetterCount = 0;
while (it) {
uint index = it->expr->asConst()->value;
it = it->next;
bool isData = it->expr->asConst()->value;
it = it->next;
if (isData) {
it = it->next; // value
continue;
}
++arrayGetterSetterCount;
// Index
_as->storeValue(QV4::Primitive::fromUInt32(index), _as->stackLayout().argumentAddressForCall(argc++));
// Getter
_as->copyValue(_as->stackLayout().argumentAddressForCall(argc++), it->expr);
it = it->next;
// Setter
_as->copyValue(_as->stackLayout().argumentAddressForCall(argc++), it->expr);
it = it->next;
}
generateFunctionCall(result, __qmljs_builtin_define_object_literal, Assembler::ContextRegister,
baseAddressForCallArguments(), Assembler::TrustedImm32(classId));
baseAddressForCallArguments(), Assembler::TrustedImm32(classId),
Assembler::TrustedImm32(arrayValueCount), Assembler::TrustedImm32(arrayGetterSetterCount));
}
void InstructionSelection::callBuiltinSetupArgumentObject(IR::Temp *result)

View File

@ -94,10 +94,8 @@ protected:
virtual void callBuiltinPushWithScope(IR::Temp *arg);
virtual void callBuiltinPopScope();
virtual void callBuiltinDeclareVar(bool deletable, const QString &name);
virtual void callBuiltinDefineGetterSetter(IR::Temp *object, const QString &name, IR::Temp *getter, IR::Temp *setter);
virtual void callBuiltinDefineProperty(IR::Temp *object, const QString &name, IR::Expr *value);
virtual void callBuiltinDefineArray(IR::Temp *result, IR::ExprList *args);
virtual void callBuiltinDefineObjectLiteral(IR::Temp *result, IR::ExprList *args);
virtual void callBuiltinDefineObjectLiteral(IR::Temp *result, int keyValuePairCount, IR::ExprList *keyValuePairs, IR::ExprList *arrayEntries);
virtual void callBuiltinSetupArgumentObject(IR::Temp *result);
virtual void callBuiltinConvertThisToObject();
virtual void callValue(IR::Temp *value, IR::ExprList *args, IR::Temp *result);

View File

@ -213,10 +213,8 @@ protected: // IRDecoder
virtual void callBuiltinPushWithScope(IR::Temp *) {}
virtual void callBuiltinPopScope() {}
virtual void callBuiltinDeclareVar(bool , const QString &) {}
virtual void callBuiltinDefineGetterSetter(IR::Temp *, const QString &, IR::Temp *, IR::Temp *) {}
virtual void callBuiltinDefineProperty(IR::Temp *, const QString &, IR::Expr *) {}
virtual void callBuiltinDefineArray(IR::Temp *, IR::ExprList *) {}
virtual void callBuiltinDefineObjectLiteral(IR::Temp *, IR::ExprList *) {}
virtual void callBuiltinDefineObjectLiteral(IR::Temp *, int, IR::ExprList *, IR::ExprList *) {}
virtual void callBuiltinSetupArgumentObject(IR::Temp *) {}
virtual void callBuiltinConvertThisToObject() {}

View File

@ -1087,23 +1087,6 @@ void __qmljs_builtin_declare_var(ExecutionContext *ctx, bool deletable, const St
ctx->createMutableBinding(name, deletable);
}
void __qmljs_builtin_define_property(ExecutionContext *ctx, const ValueRef object, const StringRef name, ValueRef val)
{
Scope scope(ctx);
ScopedObject o(scope, object->asObject());
assert(o);
uint idx = name->asArrayIndex();
if (idx != UINT_MAX) {
if (idx > 16 && (!o->arrayData || idx > o->arrayData->length() * 2))
o->initSparseArray();
o->arraySet(idx, val);
} else {
ScopedValue v(scope, val ? *val : Primitive::undefinedValue());
o->insertMember(name, v);
}
}
ReturnedValue __qmljs_builtin_define_array(ExecutionContext *ctx, Value *values, uint length)
{
Scope scope(ctx);
@ -1117,24 +1100,7 @@ ReturnedValue __qmljs_builtin_define_array(ExecutionContext *ctx, Value *values,
return a.asReturnedValue();
}
void __qmljs_builtin_define_getter_setter(ExecutionContext *ctx, const ValueRef object, const StringRef name, const ValueRef getter, const ValueRef setter)
{
Scope scope(ctx);
ScopedObject o(scope, object->asObject());
Q_ASSERT(!!o);
uint idx = name->asArrayIndex();
Property pd;
pd.value = getter;
pd.set = setter;
if (idx != UINT_MAX) {
o->arraySet(idx, pd, Attr_Accessor);
} else {
o->insertMember(name, pd, Attr_Accessor);
}
}
ReturnedValue __qmljs_builtin_define_object_literal(QV4::ExecutionContext *ctx, const QV4::Value *args, int classId)
ReturnedValue __qmljs_builtin_define_object_literal(QV4::ExecutionContext *ctx, const QV4::Value *args, int classId, int arrayValueCount, int arrayGetterSetterCount)
{
Scope scope(ctx);
QV4::InternalClass *klass = ctx->compilationUnit->runtimeClasses[classId];
@ -1151,6 +1117,29 @@ ReturnedValue __qmljs_builtin_define_object_literal(QV4::ExecutionContext *ctx,
}
}
ScopedValue entry(scope);
for (int i = 0; i < arrayValueCount; ++i) {
uint idx = args->toUInt32();
if (idx > 16 && (!o->arrayData || idx > o->arrayData->length() * 2))
o->initSparseArray();
++args;
entry = *args++;
o->arraySet(idx, entry);
}
ScopedProperty pd(scope);
for (int i = 0; i < arrayGetterSetterCount; ++i) {
uint idx = args->toUInt32();
if (idx > 16 && (!o->arrayData || idx > o->arrayData->length() * 2))
o->initSparseArray();
++args;
pd->value = *args;
++args;
pd->set = *args;
++args;
o->arraySet(idx, pd, Attr_Accessor);
}
return o.asReturnedValue();
}

View File

@ -141,10 +141,8 @@ QV4::ExecutionContext *__qmljs_builtin_push_catch_scope(QV4::ExecutionContext *c
QV4::ExecutionContext *__qmljs_builtin_pop_scope(QV4::ExecutionContext *ctx);
ReturnedValue __qmljs_builtin_unwind_exception(ExecutionContext *ctx);
void __qmljs_builtin_declare_var(QV4::ExecutionContext *ctx, bool deletable, const QV4::StringRef name);
void __qmljs_builtin_define_property(QV4::ExecutionContext *ctx, const QV4::ValueRef object, const QV4::StringRef name, QV4::ValueRef val);
QV4::ReturnedValue __qmljs_builtin_define_array(QV4::ExecutionContext *ctx, Value *values, uint length);
void __qmljs_builtin_define_getter_setter(QV4::ExecutionContext *ctx, const QV4::ValueRef object, const QV4::StringRef name, const QV4::ValueRef getter, const QV4::ValueRef setter);
QV4::ReturnedValue __qmljs_builtin_define_object_literal(QV4::ExecutionContext *ctx, const QV4::Value *args, int classId);
QV4::ReturnedValue __qmljs_builtin_define_object_literal(QV4::ExecutionContext *ctx, const QV4::Value *args, int classId, int arrayValueCount, int arrayGetterSetterCount);
QV4::ReturnedValue __qmljs_builtin_setup_arguments_object(ExecutionContext *ctx);
void __qmljs_builtin_convert_this_to_object(ExecutionContext *ctx);

View File

@ -473,14 +473,6 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *code
__qmljs_builtin_declare_var(context, instr.isDeletable, runtimeStrings[instr.varName]);
MOTH_END_INSTR(CallBuiltinDeclareVar)
MOTH_BEGIN_INSTR(CallBuiltinDefineGetterSetter)
__qmljs_builtin_define_getter_setter(context, VALUEPTR(instr.object), runtimeStrings[instr.name], VALUEPTR(instr.getter), VALUEPTR(instr.setter));
MOTH_END_INSTR(CallBuiltinDefineGetterSetter)
MOTH_BEGIN_INSTR(CallBuiltinDefineProperty)
__qmljs_builtin_define_property(context, VALUEPTR(instr.object), runtimeStrings[instr.name], VALUEPTR(instr.value));
MOTH_END_INSTR(CallBuiltinDefineProperty)
MOTH_BEGIN_INSTR(CallBuiltinDefineArray)
Q_ASSERT(instr.args + instr.argc <= stackSize);
QV4::Value *args = stack + instr.args;
@ -489,7 +481,7 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *code
MOTH_BEGIN_INSTR(CallBuiltinDefineObjectLiteral)
QV4::Value *args = stack + instr.args;
STOREVALUE(instr.result, __qmljs_builtin_define_object_literal(context, args, instr.internalClassId));
STOREVALUE(instr.result, __qmljs_builtin_define_object_literal(context, args, instr.internalClassId, instr.arrayValueCount, instr.arrayGetterSetterCount));
MOTH_END_INSTR(CallBuiltinDefineObjectLiteral)
MOTH_BEGIN_INSTR(CallBuiltinSetupArgumentsObject)

View File

@ -603,6 +603,8 @@ public:
virtual SourceLocation lastSourceLocation() const
{ return propertyNameToken; }
virtual QString asString() const = 0;
// attributes
SourceLocation propertyNameToken;
};
@ -610,7 +612,11 @@ public:
class QML_PARSER_EXPORT PropertyAssignment: public Node
{
public:
PropertyAssignment() {}
PropertyAssignment(PropertyName *n)
: name(n)
{}
// attributes
PropertyName *name;
};
class QML_PARSER_EXPORT PropertyAssignmentList: public Node
@ -658,7 +664,7 @@ public:
QQMLJS_DECLARE_AST_NODE(PropertyNameAndValue)
PropertyNameAndValue(PropertyName *n, ExpressionNode *v)
: name(n), value(v)
: PropertyAssignment(n), value(v)
{ kind = K; }
virtual void accept0(Visitor *visitor);
@ -670,7 +676,6 @@ public:
{ return value->lastSourceLocation(); }
// attributes
PropertyName *name;
SourceLocation colonToken;
ExpressionNode *value;
SourceLocation commaToken;
@ -687,11 +692,11 @@ public:
};
PropertyGetterSetter(PropertyName *n, FunctionBody *b)
: type(Getter), name(n), formals(0), functionBody (b)
: PropertyAssignment(n), type(Getter), formals(0), functionBody (b)
{ kind = K; }
PropertyGetterSetter(PropertyName *n, FormalParameterList *f, FunctionBody *b)
: type(Setter), name(n), formals(f), functionBody (b)
: PropertyAssignment(n), type(Setter), formals(f), functionBody (b)
{ kind = K; }
virtual void accept0(Visitor *visitor);
@ -705,7 +710,6 @@ public:
// attributes
Type type;
SourceLocation getSetToken;
PropertyName *name;
SourceLocation lparenToken;
FormalParameterList *formals;
SourceLocation rparenToken;
@ -724,6 +728,8 @@ public:
virtual void accept0(Visitor *visitor);
virtual QString asString() const { return id.toString(); }
// attributes
QStringRef id;
};
@ -738,6 +744,8 @@ public:
virtual void accept0(Visitor *visitor);
virtual QString asString() const { return id.toString(); }
// attributes
QStringRef id;
};
@ -752,6 +760,8 @@ public:
virtual void accept0(Visitor *visitor);
virtual QString asString() const { return QString::number(id, 'g', 16); }
// attributes
double id;
};