F(CallBuiltinDefineGetterSetter, callBuiltinDefineGetterSetter) \
F(CallBuiltinDefineProperty, callBuiltinDefineProperty) \
F(CallBuiltinDefineArray, callBuiltinDefineArray) \
+ F(CallBuiltinDefineObjectLiteral, callBuiltinDefineObjectLiteral) \
F(CreateValue, createValue) \
F(CreateProperty, createProperty) \
F(CreateActivationProperty, createActivationProperty) \
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;
instr_callBuiltinDefineGetterSetter callBuiltinDefineGetterSetter;
instr_callBuiltinDefineProperty callBuiltinDefineProperty;
instr_callBuiltinDefineArray callBuiltinDefineArray;
+ instr_callBuiltinDefineObjectLiteral callBuiltinDefineObjectLiteral;
instr_createValue createValue;
instr_createProperty createProperty;
instr_createActivationProperty createActivationProperty;
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
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);
__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;
virtual bool visit(ObjectLiteral *ast)
{
+ int argc = 0;
+ for (PropertyAssignmentList *it = ast->properties; it; it = it->next) {
+ ++argc;
+ if (AST::cast<AST::PropertyGetterSetter *>(it->assignment))
+ ++argc;
+ }
+ _env->maxNumberOfArguments = qMax(_env->maxNumberOfArguments, argc);
+
TemporaryBoolAssignment allowFuncDecls(_allowFuncDecls, true);
Node::accept(ast->properties, this);
return false;
{
QMap<QString, ObjectPropertyValue> 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<AST::PropertyNameAndValue *>(it->assignment)) {
QString name = propertyName(nv->name);
Q_UNREACHABLE();
}
}
+
+ V4IR::ExprList *args = 0;
+
+ if (!valueMap.isEmpty()) {
+ V4IR::ExprList *current;
+ for (QMap<QString, ObjectPropertyValue>::iterator it = valueMap.begin(); it != valueMap.end(); ) {
+ if (QV4::String(it.key()).asArrayIndex() != UINT_MAX) {
+ ++it;
+ continue;
+ }
+
+ if (!args) {
+ args = _function->New<V4IR::ExprList>();
+ current = args;
+ } else {
+ current->next = _function->New<V4IR::ExprList>();
+ current = current->next;
+ }
+
+ current->expr = _block->NAME(it.key(), 0, 0);
+
+ if (it->value) {
+ current->next = _function->New<V4IR::ExprList>();
+ current = current->next;
+ current->expr = _block->CONST(V4IR::BoolType, true);
+
+ unsigned value = _block->newTemp();
+ move(_block->TEMP(value), it->value);
+
+ current->next = _function->New<V4IR::ExprList>();
+ current = current->next;
+ current->expr = _block->TEMP(value);
+ } else {
+ current->next = _function->New<V4IR::ExprList>();
+ 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<V4IR::ExprList>();
+ current = current->next;
+ current->expr = _block->TEMP(getter);
+ current->next = _function->New<V4IR::ExprList>();
+ 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;
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);
BoundFunction *newBoundFunction(ExecutionContext *scope, FunctionObject *target, Value boundThis, const QVector<Value> &boundArgs);
Object *newObject();
+ Object *newObject(InternalClass *internalClass);
String *newString(const QString &s);
String *newIdentifier(const QString &text);
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);
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);
callBuiltinDefineArray(result, call->args);
return;
+ case V4IR::Name::builtin_define_object_literal:
+ callBuiltinDefineObjectLiteral(result, call->args);
+ return;
+
default:
break;
}
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;
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)";
};
builtin_declare_vars,
builtin_define_property,
builtin_define_array,
- builtin_define_getter_setter
+ builtin_define_getter_setter,
+ builtin_define_object_literal
};
const QString *id;
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;
Object(ExecutionEngine *engine);
Object(ExecutionContext *context);
+ Object(ExecutionEngine *engine, InternalClass *internalClass);
~Object();
Property *__getOwnProperty__(String *name, PropertyAttributes *attrs = 0);
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);
struct ArrayObject;
struct ErrorObject;
struct ExecutionEngine;
+struct InternalClass;
struct Q_QML_EXPORT Exception {
explicit Exception(ExecutionContext *throwingContext, const Value &exceptionValue);
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);