Always enable value type support in v4.
[profile/ivi/qtdeclarative.git] / src / qml / qml / v4 / qv4compiler.cpp
index d61fd58..c9495e8 100644 (file)
@@ -54,7 +54,6 @@ QT_BEGIN_NAMESPACE
 
 DEFINE_BOOL_CONFIG_OPTION(bindingsDump, QML_BINDINGS_DUMP)
 DEFINE_BOOL_CONFIG_OPTION(qmlDisableOptimizer, QML_DISABLE_OPTIMIZER)
-DEFINE_BOOL_CONFIG_OPTION(qmlExperimental, QML_EXPERIMENTAL)
 DEFINE_BOOL_CONFIG_OPTION(qmlVerboseCompiler, QML_VERBOSE_COMPILER)
 DEFINE_BOOL_CONFIG_OPTION(qmlBindingsTestEnv, QML_BINDINGS_TEST)
 
@@ -63,7 +62,7 @@ static bool qmlEnableV4 = true;
 
 using namespace QQmlJS;
 QV4CompilerPrivate::QV4CompilerPrivate()
-: _function(0) , _block(0) , _discarded(false)
+    : _function(0) , _block(0) , _discarded(false), registerCount(0)
 {
 }
 
@@ -75,6 +74,7 @@ void QV4CompilerPrivate::trace(int line, int column)
     bytecode.clear();
 
     this->currentReg = _function->tempCount;
+    this->registerCount = qMax(this->registerCount, this->currentReg);
 
     foreach (IR::BasicBlock *bb, _function->basicBlocks) {
         if (! bb->isTerminated() && (bb->index + 1) < _function->basicBlocks.size())
@@ -233,6 +233,12 @@ void QV4CompilerPrivate::visitConst(IR::Const *e)
         gen(i);
         } break;
 
+    case IR::NullType: {
+        Instr::LoadNull i;
+        i.reg = currentReg;
+        gen(i);
+        } break;
+
     default:
         if (qmlVerboseCompiler())
             qWarning() << Q_FUNC_INFO << "unexpected type";
@@ -317,6 +323,22 @@ void QV4CompilerPrivate::visitName(IR::Name *e)
         gen(attached);
     } break;
 
+    case IR::Name::ModuleObject: {
+        /*
+          Existing module object lookup methods include:
+              1. string -> module object (search via importCache->query(name))
+              2. QQmlMetaType::ModuleApi -> module object (via QQmlEnginePrivate::moduleApiInstance() cache)
+          We currently use 1, which is not ideal for performance
+        */
+        _subscribeName << *e->id;
+
+        registerLiteralString(currentReg, e->id);
+
+        Instr::LoadModuleObject module;
+        module.reg = currentReg;
+        gen(module);
+    } break;
+
     case IR::Name::Property: {
         _subscribeName << *e->id;
 
@@ -344,6 +366,9 @@ void QV4CompilerPrivate::visitName(IR::Name *e)
         case QMetaType::QUrl:
             regType = QUrlType;
             break;
+        case QMetaType::QColor:
+            regType = QColorType;
+            break;
 
         default:
             if (propTy == QQmlMetaType::QQuickAnchorLineMetaTypeId()) {
@@ -581,6 +606,12 @@ void QV4CompilerPrivate::convertToBool(IR::Expr *expr, int reg)
         gen(i);
         } return;
 
+    case IR::ColorType: {
+        Instr::ConvertColorToBool i;
+        i.output = i.src = reg;
+        gen(i);
+        } return;
+
     default:
         discard();
         break;
@@ -656,21 +687,29 @@ quint8 QV4CompilerPrivate::instructionOpcode(IR::Binop *e)
         return V4Instr::LeReal;
 
     case IR::OpEqual:
+        if (e->left->type == IR::ObjectType || e->right->type == IR::ObjectType)
+            return V4Instr::EqualObject;
         if (e->left->type == IR::StringType)
             return V4Instr::EqualString;
         return V4Instr::EqualReal;
 
     case IR::OpNotEqual:
+        if (e->left->type == IR::ObjectType || e->right->type == IR::ObjectType)
+            return V4Instr::NotEqualObject;
         if (e->left->type == IR::StringType)
             return V4Instr::NotEqualString;
         return V4Instr::NotEqualReal;
 
     case IR::OpStrictEqual:
+        if (e->left->type == IR::ObjectType || e->right->type == IR::ObjectType)
+            return V4Instr::StrictEqualObject;
         if (e->left->type == IR::StringType)
             return V4Instr::StrictEqualString;
         return V4Instr::StrictEqualReal;
 
     case IR::OpStrictNotEqual:
+        if (e->left->type == IR::ObjectType || e->right->type == IR::ObjectType)
+            return V4Instr::StrictNotEqualObject;
         if (e->left->type == IR::StringType)
             return V4Instr::StrictNotEqualString;
         return V4Instr::StrictNotEqualReal;
@@ -686,29 +725,20 @@ quint8 QV4CompilerPrivate::instructionOpcode(IR::Binop *e)
 
 void QV4CompilerPrivate::visitBinop(IR::Binop *e)
 {
+    if (e->type == IR::InvalidType) {
+        discard();
+        return;
+    }
+
     int left = currentReg;
     int right = currentReg + 1; 
 
-    if (e->left->asTemp() && e->type != IR::StringType)  // Not sure if the e->type != String test is needed
-        left = e->left->asTemp()->index;
-    else
-        traceExpression(e->left, left);
+    traceExpression(e->left, left);
+    traceExpression(e->right, right);
 
-    if (IR::Temp *t = e->right->asTemp())
-        right = t->index;
-    else
-        traceExpression(e->right, right);
-
-    if (e->left->type != e->right->type) {
-        if (qmlVerboseCompiler())
-            qWarning().nospace() << "invalid operands to binary operator " << IR::binaryOperator(e->op)
-                                 << "(`" << IR::binaryOperator(e->left->type)
-                                 << "' and `"
-                                 << IR::binaryOperator(e->right->type)
-                                 << "'";
-        discard();
-        return;
-    }
+    // At this point it is possible that the type of the
+    // subexpressions is different. This can happen because
+    // we keep BINOP expressions in HIR.
 
     switch (e->op) {
     case IR::OpInvalid:
@@ -757,7 +787,7 @@ void QV4CompilerPrivate::visitBinop(IR::Binop *e)
     case IR::OpNotEqual:
     case IR::OpStrictEqual:
     case IR::OpStrictNotEqual:
-        if (e->left->type != IR::StringType) {
+        if (e->left->type >= IR::FirstNumberType) {
             convertToReal(e->left, left);
             convertToReal(e->right, right);
         }
@@ -802,6 +832,12 @@ void QV4CompilerPrivate::visitCall(IR::Call *call)
                 gen(i);
                 } return;
 
+            case IR::MathAbsBuiltinFunction: {
+                Instr::MathAbsReal i;
+                i.output = i.src = currentReg;
+                gen(i);
+                } return;
+
             case IR::MathRoundBultinFunction: {
                 Instr::MathRoundReal i;
                 i.output = i.src = currentReg;
@@ -814,9 +850,49 @@ void QV4CompilerPrivate::visitCall(IR::Call *call)
                 gen(i);
                 } return;
 
+            case IR::MathCeilBuiltinFunction: {
+                Instr::MathCeilReal i;
+                i.output = i.src = currentReg;
+                gen(i);
+                } return;
+
             case IR::MathPIBuiltinConstant:
+            default:
                 break;
             } // switch
+        } else {
+            if (name->builtin == IR::MathMaxBuiltinFunction ||
+                name->builtin == IR::MathMinBuiltinFunction) {
+
+                //only handles the most common case of exactly two arguments
+                if (call->args && call->args->next && !call->args->next->next) {
+                    IR::Expr *arg1 = call->args->expr;
+                    IR::Expr *arg2 = call->args->next->expr;
+
+                    if (arg1 != 0 && arg1->type == IR::RealType &&
+                        arg2 != 0 && arg2->type == IR::RealType) {
+
+                        traceExpression(arg1, currentReg);
+                        traceExpression(arg2, currentReg + 1);
+
+                        if (name->builtin == IR::MathMaxBuiltinFunction) {
+                            Instr::MathMaxReal i;
+                            i.left = currentReg;
+                            i.right = currentReg + 1;
+                            i.output = currentReg;
+                            gen(i);
+                            return;
+                        } else if (name->builtin == IR::MathMinBuiltinFunction) {
+                            Instr::MathMinReal i;
+                            i.left = currentReg;
+                            i.right = currentReg + 1;
+                            i.output = currentReg;
+                            gen(i);
+                            return;
+                        }
+                    }
+                }
+            }
         }
     }
 
@@ -880,6 +956,8 @@ void QV4CompilerPrivate::visitMove(IR::Move *s)
             case IR::RealType: opcode = V4Instr::ConvertRealToBool; break;
             case IR::StringType: opcode = V4Instr::ConvertStringToBool; break;
             case IR::UrlType: opcode = V4Instr::ConvertUrlToBool; break;
+            case IR::ColorType: opcode = V4Instr::ConvertColorToBool; break;
+            case IR::ObjectType: opcode = V4Instr::ConvertObjectToBool; break;
             default: break;
             } // switch
         } else if (targetTy == IR::IntType) {
@@ -908,6 +986,7 @@ void QV4CompilerPrivate::visitMove(IR::Move *s)
             case IR::IntType:  opcode = V4Instr::ConvertIntToString; break;
             case IR::RealType: opcode = V4Instr::ConvertRealToString; break;
             case IR::UrlType: opcode = V4Instr::ConvertUrlToString; break;
+            case IR::ColorType: opcode = V4Instr::ConvertColorToString; break;
             default: break;
             } // switch
         } else if (targetTy == IR::UrlType) {
@@ -920,11 +999,22 @@ void QV4CompilerPrivate::visitMove(IR::Move *s)
             case IR::BoolType: gen(V4Instr::ConvertBoolToString, convToString); sourceTy = IR::StringType; break;
             case IR::IntType:  gen(V4Instr::ConvertIntToString,  convToString); sourceTy = IR::StringType; break;
             case IR::RealType: gen(V4Instr::ConvertRealToString, convToString); sourceTy = IR::StringType; break;
+            case IR::ColorType: gen(V4Instr::ConvertColorToString, convToString); sourceTy = IR::StringType; break;
             default: break;
             } // switch
 
             if (sourceTy == IR::StringType)
                 opcode = V4Instr::ConvertStringToUrl;
+        } else if (targetTy == IR::ColorType) {
+            switch (sourceTy) {
+            case IR::StringType: opcode = V4Instr::ConvertStringToColor; break;
+            default: break;
+            } // switch
+        } else if (targetTy == IR::ObjectType) {
+            switch (sourceTy) {
+            case IR::NullType: opcode = V4Instr::ConvertNullToObject; break;
+            default: break;
+            } // switch
         }
         if (opcode != V4Instr::Noop) {
             V4Instr conv;
@@ -989,6 +1079,9 @@ void QV4CompilerPrivate::visitRet(IR::Ret *s)
         case IR::UrlType:
             test.regType = QMetaType::QUrl;
             break;
+        case IR::ColorType:
+            test.regType = QMetaType::QColor;
+            break;
         case IR::SGAnchorLineType:
             test.regType = QQmlMetaType::QQuickAnchorLineMetaTypeId();
             break;
@@ -1119,7 +1212,7 @@ bool QV4CompilerPrivate::compile(QQmlJS::AST::Node *node)
         qerr << endl;
     }
 
-    if (discarded || subscriptionIds.count() > 0xFFFF || registeredStrings.count() > 0xFFFF)
+    if (discarded || subscriptionIds.count() > 0xFFFF || registeredStrings.count() > 0xFFFF || registerCount > 31)
         return false;
 
     return true;
@@ -1266,9 +1359,6 @@ int QV4Compiler::compile(const Expression &expression, QQmlEnginePrivate *engine
 {
     if (!expression.expression.asAST()) return false;
 
-    if (!qmlExperimental() && expression.property->isValueTypeSubProperty)
-        return -1;
-
     if (qmlDisableOptimizer() || !qmlEnableV4)
         return -1;