Determine whether or not an object literal requires a sparse array at compile time
authorSimon Hausmann <simon.hausmann@digia.com>
Sat, 15 Feb 2014 03:39:33 +0000 (04:39 +0100)
committerThe Qt Project <gerrit-noreply@qt-project.org>
Mon, 24 Feb 2014 19:41:48 +0000 (20:41 +0100)
Change-Id: Ieb7f6ee97a4f251f1e2369850ebb9e2931f84ac1
Reviewed-by: Lars Knoll <lars.knoll@digia.com>
src/qml/compiler/qv4instr_moth_p.h
src/qml/compiler/qv4isel_moth.cpp
src/qml/compiler/qv4isel_moth_p.h
src/qml/compiler/qv4isel_p.cpp
src/qml/compiler/qv4isel_p.h
src/qml/jit/qv4isel_masm.cpp
src/qml/jit/qv4isel_masm_p.h
src/qml/jit/qv4regalloc.cpp
src/qml/jsruntime/qv4runtime.cpp
src/qml/jsruntime/qv4runtime_p.h
src/qml/jsruntime/qv4vme_moth.cpp

index 08c523c..c424407 100644 (file)
@@ -488,8 +488,8 @@ union Instr
     struct instr_callBuiltinDefineObjectLiteral {
         MOTH_INSTR_HEADER
         int internalClassId;
-        int arrayValueCount;
-        int arrayGetterSetterCount;
+        uint arrayValueCount;
+        uint arrayGetterSetterCountAndFlags; // 30 bits for count, 1 bit for needsSparseArray boolean
         quint32 args;
         Param result;
     };
index 8045b81..0dac3db 100644 (file)
@@ -1260,7 +1260,7 @@ void InstructionSelection::callBuiltinDefineArray(IR::Temp *result, IR::ExprList
     addInstruction(call);
 }
 
-void InstructionSelection::callBuiltinDefineObjectLiteral(IR::Temp *result, int keyValuePairCount, IR::ExprList *keyValuePairs, IR::ExprList *arrayEntries)
+void InstructionSelection::callBuiltinDefineObjectLiteral(IR::Temp *result, int keyValuePairCount, IR::ExprList *keyValuePairs, IR::ExprList *arrayEntries, bool needSparseArray)
 {
     int argLocation = outgoingArgumentTempStart();
 
@@ -1300,7 +1300,7 @@ void InstructionSelection::callBuiltinDefineObjectLiteral(IR::Temp *result, int
     }
 
     // Process array values
-    int arrayValueCount = 0;
+    uint arrayValueCount = 0;
     it = arrayEntries;
     while (it) {
         IR::Const *index = it->expr->asConst();
@@ -1332,7 +1332,7 @@ void InstructionSelection::callBuiltinDefineObjectLiteral(IR::Temp *result, int
     }
 
     // Process array getter/setter pairs
-    int arrayGetterSetterCount = 0;
+    uint arrayGetterSetterCount = 0;
     it = arrayEntries;
     while (it) {
         IR::Const *index = it->expr->asConst();
@@ -1374,7 +1374,7 @@ void InstructionSelection::callBuiltinDefineObjectLiteral(IR::Temp *result, int
     Instruction::CallBuiltinDefineObjectLiteral call;
     call.internalClassId = classId;
     call.arrayValueCount = arrayValueCount;
-    call.arrayGetterSetterCount = arrayGetterSetterCount;
+    call.arrayGetterSetterCountAndFlags = arrayGetterSetterCount | (needSparseArray << 30);
     call.args = outgoingArgumentTempStart();
     call.result = getResultParam(result);
     addInstruction(call);
index 732341c..000ff63 100644 (file)
@@ -99,7 +99,7 @@ protected:
     virtual void callBuiltinPopScope();
     virtual void callBuiltinDeclareVar(bool deletable, const QString &name);
     virtual void callBuiltinDefineArray(IR::Temp *result, IR::ExprList *args);
-    virtual void callBuiltinDefineObjectLiteral(IR::Temp *result, int keyValuePairCount, IR::ExprList *keyValuePairs, IR::ExprList *arrayEntries);
+    virtual void callBuiltinDefineObjectLiteral(IR::Temp *result, int keyValuePairCount, IR::ExprList *keyValuePairs, IR::ExprList *arrayEntries, bool needSparseArray);
     virtual void callBuiltinSetupArgumentObject(IR::Temp *result);
     virtual void callBuiltinConvertThisToObject();
     virtual void callValue(IR::Temp *value, IR::ExprList *args, IR::Temp *result);
index 2a73b55..f0092b7 100644 (file)
@@ -367,8 +367,21 @@ void IRDecoder::callBuiltin(IR::Call *call, IR::Temp *result)
         }
 
         IR::ExprList *arrayEntries = args;
+        bool needSparseArray = false;
+        for (IR::ExprList *it = arrayEntries; it; it = it->next) {
+            uint index = it->expr->asConst()->value;
+            if (index > 16)  {
+                needSparseArray = true;
+                break;
+            }
+            it = it->next;
+            bool isData = it->expr->asConst()->value;
+            it = it->next;
+            if (!isData)
+                it = it->next;
+        }
 
-        callBuiltinDefineObjectLiteral(result, keyValuePairsCount, keyValuePairs, arrayEntries);
+        callBuiltinDefineObjectLiteral(result, keyValuePairsCount, keyValuePairs, arrayEntries, needSparseArray);
     } return;
 
     case IR::Name::builtin_setup_argument_object:
index 7137979..f4aab41 100644 (file)
@@ -131,7 +131,7 @@ public: // to implement by subclasses:
     virtual void callBuiltinPopScope() = 0;
     virtual void callBuiltinDeclareVar(bool deletable, const QString &name) = 0;
     virtual void callBuiltinDefineArray(IR::Temp *result, IR::ExprList *args) = 0;
-    virtual void callBuiltinDefineObjectLiteral(IR::Temp *result, int keyValuePairCount, IR::ExprList *keyValuePairs, IR::ExprList *arrayEntries) = 0;
+    virtual void callBuiltinDefineObjectLiteral(IR::Temp *result, int keyValuePairCount, IR::ExprList *keyValuePairs, IR::ExprList *arrayEntries, bool needSparseArray) = 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;
index 2d05592..80f2255 100644 (file)
@@ -492,7 +492,7 @@ void InstructionSelection::callBuiltinDefineArray(IR::Temp *result, IR::ExprList
                          baseAddressForCallArguments(), Assembler::TrustedImm32(length));
 }
 
-void InstructionSelection::callBuiltinDefineObjectLiteral(IR::Temp *result, int keyValuePairCount, IR::ExprList *keyValuePairs, IR::ExprList *arrayEntries)
+void InstructionSelection::callBuiltinDefineObjectLiteral(IR::Temp *result, int keyValuePairCount, IR::ExprList *keyValuePairs, IR::ExprList *arrayEntries, bool needSparseArray)
 {
     Q_ASSERT(result);
 
@@ -516,7 +516,7 @@ void InstructionSelection::callBuiltinDefineObjectLiteral(IR::Temp *result, int
     }
 
     it = arrayEntries;
-    int arrayValueCount = 0;
+    uint arrayValueCount = 0;
     while (it) {
         uint index = it->expr->asConst()->value;
         it = it->next;
@@ -541,7 +541,7 @@ void InstructionSelection::callBuiltinDefineObjectLiteral(IR::Temp *result, int
     }
 
     it = arrayEntries;
-    int arrayGetterSetterCount = 0;
+    uint arrayGetterSetterCount = 0;
     while (it) {
         uint index = it->expr->asConst()->value;
         it = it->next;
@@ -570,7 +570,7 @@ void InstructionSelection::callBuiltinDefineObjectLiteral(IR::Temp *result, int
 
     generateFunctionCall(result, __qmljs_builtin_define_object_literal, Assembler::ContextRegister,
                          baseAddressForCallArguments(), Assembler::TrustedImm32(classId),
-                         Assembler::TrustedImm32(arrayValueCount), Assembler::TrustedImm32(arrayGetterSetterCount));
+                         Assembler::TrustedImm32(arrayValueCount), Assembler::TrustedImm32(arrayGetterSetterCount | (needSparseArray << 30)));
 }
 
 void InstructionSelection::callBuiltinSetupArgumentObject(IR::Temp *result)
index 5e4e773..62891e4 100644 (file)
@@ -95,7 +95,7 @@ protected:
     virtual void callBuiltinPopScope();
     virtual void callBuiltinDeclareVar(bool deletable, const QString &name);
     virtual void callBuiltinDefineArray(IR::Temp *result, IR::ExprList *args);
-    virtual void callBuiltinDefineObjectLiteral(IR::Temp *result, int keyValuePairCount, IR::ExprList *keyValuePairs, IR::ExprList *arrayEntries);
+    virtual void callBuiltinDefineObjectLiteral(IR::Temp *result, int keyValuePairCount, IR::ExprList *keyValuePairs, IR::ExprList *arrayEntries, bool needSparseArray);
     virtual void callBuiltinSetupArgumentObject(IR::Temp *result);
     virtual void callBuiltinConvertThisToObject();
     virtual void callValue(IR::Temp *value, IR::ExprList *args, IR::Temp *result);
index 76a0734..72ec66d 100644 (file)
@@ -214,7 +214,7 @@ protected: // IRDecoder
     virtual void callBuiltinPopScope() {}
     virtual void callBuiltinDeclareVar(bool , const QString &) {}
     virtual void callBuiltinDefineArray(IR::Temp *, IR::ExprList *) {}
-    virtual void callBuiltinDefineObjectLiteral(IR::Temp *, int, IR::ExprList *, IR::ExprList *) {}
+    virtual void callBuiltinDefineObjectLiteral(IR::Temp *, int, IR::ExprList *, IR::ExprList *, bool) {}
     virtual void callBuiltinSetupArgumentObject(IR::Temp *) {}
     virtual void callBuiltinConvertThisToObject() {}
 
index 7c7ce23..a3ba4b0 100644 (file)
@@ -1100,12 +1100,18 @@ ReturnedValue __qmljs_builtin_define_array(ExecutionContext *ctx, Value *values,
     return a.asReturnedValue();
 }
 
-ReturnedValue __qmljs_builtin_define_object_literal(QV4::ExecutionContext *ctx, const QV4::Value *args, int classId, int arrayValueCount, int arrayGetterSetterCount)
+ReturnedValue __qmljs_builtin_define_object_literal(QV4::ExecutionContext *ctx, const QV4::Value *args, int classId, int arrayValueCount, int arrayGetterSetterCountAndFlags)
 {
     Scope scope(ctx);
     QV4::InternalClass *klass = ctx->compilationUnit->runtimeClasses[classId];
     Scoped<Object> o(scope, ctx->engine->newObject(klass));
 
+    {
+        bool needSparseArray = arrayGetterSetterCountAndFlags >> 30;
+        if (needSparseArray)
+            o->initSparseArray();
+    }
+
     for (uint i = 0; i < klass->size; ++i) {
         if (klass->propertyData[i].isData())
             o->memberData[i].value = *args++;
@@ -1120,18 +1126,15 @@ 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 arrayGetterSetterCount = arrayGetterSetterCountAndFlags & ((1 << 30) - 1);
+    for (uint 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;
index dbe7e03..dbdb891 100644 (file)
@@ -142,7 +142,7 @@ 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);
 QV4::ReturnedValue __qmljs_builtin_define_array(QV4::ExecutionContext *ctx, Value *values, uint length);
-QV4::ReturnedValue __qmljs_builtin_define_object_literal(QV4::ExecutionContext *ctx, const QV4::Value *args, int classId, int arrayValueCount, int arrayGetterSetterCount);
+QV4::ReturnedValue __qmljs_builtin_define_object_literal(QV4::ExecutionContext *ctx, const QV4::Value *args, int classId, int arrayValueCount, int arrayGetterSetterCountAndFlags);
 QV4::ReturnedValue __qmljs_builtin_setup_arguments_object(ExecutionContext *ctx);
 void __qmljs_builtin_convert_this_to_object(ExecutionContext *ctx);
 
index 5ae0b3d..a657b34 100644 (file)
@@ -481,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, instr.arrayValueCount, instr.arrayGetterSetterCount));
+    STOREVALUE(instr.result, __qmljs_builtin_define_object_literal(context, args, instr.internalClassId, instr.arrayValueCount, instr.arrayGetterSetterCountAndFlags));
     MOTH_END_INSTR(CallBuiltinDefineObjectLiteral)
 
     MOTH_BEGIN_INSTR(CallBuiltinSetupArgumentsObject)