// Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
// Test deoptimization.

class SmiCompares {
  // Test deoptimization when one argument is known to be Smi.
  static bool smiCompareLessThan2(a) {
    return a < 2;
  }

  // Test deoptimization when one argument is known to be Smi.
  static bool smiCompareGreaterThan2(a) {
    return 2 < a;
  }

  // Test deoptimization when both arguments unknown.
  static bool smiCompareLessThan(a, b) {
    return a < b;
  }

  // Test deoptimization when both arguments unknown.
  static bool smiCompareGreaterThan(a, b) {
    return a > b;
  }

  static smiComparesTest() {
    for (int i = 0; i < 2000; i++) {
      Expect.equals(true, smiCompareLessThan2(1));
      Expect.equals(false, smiCompareLessThan2(3));
      Expect.equals(false, smiCompareGreaterThan2(1));
      Expect.equals(true, smiCompareGreaterThan2(3));
      Expect.equals(true, smiCompareLessThan(1, 2));
      Expect.equals(false, smiCompareGreaterThan(1, 2));
    }
    // Deoptimize by passing a double instead of Smi
    Expect.equals(true, smiCompareLessThan2(1.0));
    Expect.equals(false, smiCompareGreaterThan2(1.0));
    Expect.equals(true, smiCompareLessThan(1.0, 2));
    Expect.equals(false, smiCompareGreaterThan(1, 2.0));
  }
}


class SmiBinop {
  static subWithLiteral(a) {
    return a - 1;
  }

  static void smiBinopTest() {
    for (int i = 0; i < 2000; i++) {
      Expect.equals(2, subWithLiteral(3));
    }
    // Deoptimize.
    Expect.equals(2.0, subWithLiteral(3.0));
  }
}


class ObjectsEquality {
  static bool compareEqual(a, b) {
    return a == b;
  }
  
  static bool compareNotEqual(a, b) {
    return a != b;
  }

  // Use only Object.==.
  static void objectsEqualityTest() {
    var a = new ObjectsEquality();
    var b = new ObjectsEquality();
    final nan = 0.0/0.0;
    for (int i = 0; i < 1000; i++) {
      Expect.equals(true, compareEqual(a, a));
      Expect.equals(true, compareEqual(null, null));
      Expect.equals(false, compareEqual(null, a));
      Expect.equals(false, compareEqual(a, null));
      Expect.equals(true, compareEqual(b, b));
      Expect.equals(false, compareEqual(a, b));

      Expect.equals(false, compareNotEqual(a, a));
      Expect.equals(false, compareNotEqual(null, null));
      Expect.equals(true, compareNotEqual(null, a));
      Expect.equals(true, compareNotEqual(a, null));
      Expect.equals(false, compareNotEqual(b, b));
      Expect.equals(true, compareNotEqual(a, b));
    }
    var c = new SmiBinop();
    // Deoptimize.
    Expect.equals(true, compareEqual(c, c));
    Expect.equals(false, compareEqual(c, null));
    Expect.equals(false, compareNotEqual(c, c));
    Expect.equals(true, compareNotEqual(c, null));
  }
}

class DeoptimizationTest {
  static foo(a, b) {
    return a - b;
  }

  static test1() {
    for (int i = 0; i < 2000; i++) {
      Expect.equals(2, foo(3, 1));  // <-- Optimizes 'foo',
    }
    Expect.equals(2.2, foo(1.2, -1.0));  // <-- Deoptimizes 'foo'.
    for (int i = 0; i < 10000; i++) {
       Expect.equals(2, foo(3, 1));  // <-- Optimizes 'foo'.
    }
    Expect.equals(2.2, foo(1.2, -1));  // <-- Deoptimizes 'foo'.
  }

  static moo(n) {
    return ++n;
  }

  static test2() {
    for (int i = 0; i < 2000; i++) {
      Expect.equals(4, moo(3));  // <-- Optimizes 'moo',
    }
    Expect.equals(2.2, moo(1.2));  // <-- Deoptimizes 'moo'.
    for (int i = 0; i < 10000; i++) {
       Expect.equals(4, moo(3));  // <-- Optimizes 'moo'.
    }
    Expect.equals(2.2, moo(1.2));  // <-- Deoptimizes 'moo'.
  }

  static test3() {
    for (int i = 0; i < 2000; i++) {
      Expect.equals(2.0, foo(3.0, 1.0));  // <-- Optimizes 'foo',
    }
    Expect.equals(2, foo(1, -1));  // <-- Deoptimizes 'foo'.
    for (int i = 0; i < 2000; i++) {
      Expect.equals(2.0, foo(3.0, 1.0));  // <-- Optimizes 'foo',
    }
    Expect.equals(2.2, moo(1.2));  // <-- Deoptimizes 'moo'.
  }

  static bool compareInt(a, b) {
    return a < b;
  }

  static bool compareDouble(a, b) {
    return a < b;
  }

  static test4() {
    for (int i = 0; i < 2000; i++) {
      Expect.equals(true, compareInt(1, 2));
      Expect.equals(true, compareDouble(1.0, 2.0));
    }
    // Trigger deoptimization in compareInt and compareDouble.
    Expect.equals(true, compareInt(1, 2.0));
    Expect.equals(true, compareDouble(1.0, 2));
  }



  static void testMain() {
    test1();
    test2();
    test3();
    test4();
    SmiCompares.smiComparesTest();
    SmiBinop.smiBinopTest();
    ObjectsEquality.objectsEqualityTest();
  }
}

main() {
  DeoptimizationTest.testMain();
}
