Javascript  |  413行  |  9.4 KB

// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Flags: --strong-mode --allow-natives-syntax

"use strict";

// Boolean indicates whether an operator can be part of a compound assignment.
let strongNumberBinops = [
  ["-", true],
  ["*", true],
  ["/", true],
  ["%", true],
  ["|", true],
  ["&", true],
  ["^", true],
  ["<<", true],
  [">>", true],
  [">>>", true]
];

let strongStringOrNumberBinops = [
  ["+", true],
  ["<", false],
  [">", false],
  ["<=", false],
  [">=", false]
];

let strongBinops = strongNumberBinops.concat(strongStringOrNumberBinops);

let strongUnops = [
  "~",
  "+",
  "-"
];

let nonStringOrNumberValues = [
  "null",
  "undefined",
  "{}",
  "false",
  "(function(){})",
  "[]",
  "(class Foo {})"
];

let stringValues = [
  "''",
  "'               '",
  "'foo'",
  "'f\\u006F\\u006F'",
  "'0'",
  "'NaN'"
];

let nonNumberValues = nonStringOrNumberValues.concat(stringValues);

let numberValues = [
  "0",
  "(-0)",
  "1",
  "(-4294967295)",
  "(-4294967296)",
  "9999999999999",
  "(-9999999999999)",
  "NaN",
  "Infinity",
  "(-Infinity)"
];

//******************************************************************************
// Relational comparison function declarations
function add_strong(x, y) {
  "use strong";
  return x + y;
}

function add_num_strong(x, y) {
  "use strong";
  return x + y;
}

function sub_strong(x, y) {
  "use strong";
  return x - y;
}

function mul_strong(x, y) {
  "use strong";
  return x * y;
}

function div_strong(x, y) {
  "use strong";
  return x / y;
}

function mod_strong(x, y) {
  "use strong";
  return x % y;
}

function or_strong(x, y) {
  "use strong";
  return x | y;
}

function and_strong(x, y) {
  "use strong";
  return x & y;
}

function xor_strong(x, y) {
  "use strong";
  return x ^ y;
}

function shl_strong(x, y) {
  "use strong";
  return x << y;
}

function shr_strong(x, y) {
  "use strong";
  return x >> y;
}

function sar_strong(x, y) {
  "use strong";
  return x >>> y;
}

function less_strong(x, y) {
  "use strong";
  return x < y;
}

function less_num_strong(x, y) {
  "use strong";
  return x < y;
}

function greater_strong(x, y) {
  "use strong";
  return x > y;
}

function greater_num_strong(x, y) {
  "use strong";
  return x > y;
}

function less_equal_strong(x, y) {
  "use strong";
  return x <= y;
}

function less_equal_num_strong(x, y) {
  "use strong";
  return x <= y;
}

function greater_equal_strong(x, y) {
  "use strong";
  return x >= y;
}

function greater_equal_num_strong(x, y) {
  "use strong";
  return x >= y;
}

function typed_add_strong(x, y) {
  "use strong";
  return (+x) + (+y);
}

function typed_sub_strong(x, y) {
  "use strong";
  return (+x) - (+y);
}

function typed_mul_strong(x, y) {
  "use strong";
  return (+x) * (+y);
}

function typed_div_strong(x, y) {
  "use strong";
  return (+x) / (+y);
}

function typed_mod_strong(x, y) {
  "use strong";
  return (+x) % (+y);
}

function typed_or_strong(x, y) {
  "use strong";
  return (+x) | (+y);
}

function typed_and_strong(x, y) {
  "use strong";
  return (+x) & (+y);
}

function typed_xor_strong(x, y) {
  "use strong";
  return (+x) ^ (+y);
}

function typed_shl_strong(x, y) {
  "use strong";
  return (+x) << (+y);
}

function typed_shr_strong(x, y) {
  "use strong";
  return (+x) >> (+y);
}

function typed_sar_strong(x, y) {
  "use strong";
  return (+x) >>> (+y);
}

function typed_less_strong(x, y) {
  "use strong";
  return (+x) < (+y);
}

function typed_greater_strong(x, y) {
  "use strong";
  return (+x) > (+y);
}

function typed_less_equal_strong(x, y) {
  "use strong";
  return (+x) <= (+y);
}

function typed_greater_equal_strong(x, y) {
  "use strong";
  return (+x) >= (+y);
}

//******************************************************************************
// (in)equality function declarations
function str_equal_strong(x, y) {
  "use strong";
  return x === y;
}

function str_ineq_strong(x, y) {
  "use strong";
  return x !== y;
}

let strongNumberFuncs = [add_num_strong, sub_strong, mul_strong, div_strong,
                         mod_strong, or_strong, and_strong, xor_strong,
                         shl_strong, shr_strong, sar_strong, less_num_strong,
                         greater_num_strong, less_equal_num_strong,
                         greater_equal_num_strong, typed_add_strong,
                         typed_sub_strong, typed_mul_strong, typed_div_strong,
                         typed_mod_strong, typed_or_strong,  typed_and_strong,
                         typed_xor_strong, typed_shl_strong, typed_shr_strong,
                         typed_sar_strong, typed_less_strong,
                         typed_greater_strong, typed_less_equal_strong,
                         typed_greater_equal_strong];

let strongStringOrNumberFuncs = [add_strong, less_strong, greater_strong,
                                 less_equal_strong, greater_equal_strong];

let strongFuncs = strongNumberFuncs.concat(strongStringOrNumberFuncs);

function assertStrongNonThrowBehaviour(expr) {
  assertEquals(eval(expr), eval("'use strong';" + expr));
  assertDoesNotThrow("'use strong'; " + expr + ";");
  assertDoesNotThrow("'use strong'; let v = " + expr + ";");
}

function assertStrongThrowBehaviour(expr) {
  assertDoesNotThrow("'use strict'; " + expr + ";");
  assertDoesNotThrow("'use strict'; let v = " + expr + ";");
  assertThrows("'use strong'; " + expr + ";", TypeError);
  assertThrows("'use strong'; let v = " + expr + ";", TypeError);
}

function checkArgumentCombinations(op, leftList, rightList, willThrow) {
  for (let v1 of leftList) {
    let assignExpr = "foo " + op[0] + "= " + v1 + ";";
    for (let v2 of rightList) {
      let compoundAssignment = "'use strong'; let foo = " + v2 + "; " +
                               assignExpr;
      if (willThrow) {
        if (op[1]) {
          assertThrows(compoundAssignment, TypeError);
        }
        assertStrongThrowBehaviour("(" + v1 + op[0] + v2 + ")");
      } else {
        if (op[1]) {
          assertDoesNotThrow(compoundAssignment);
        }
        assertStrongNonThrowBehaviour("(" + v1 + op[0] + v2 + ")");
      }
    }
  }
}

for (let op of strongBinops) {
  checkArgumentCombinations(op, numberValues, numberValues, false);
  checkArgumentCombinations(op, numberValues, nonNumberValues, true);
}

for (let op of strongNumberBinops) {
  checkArgumentCombinations(op, nonNumberValues,
                            numberValues.concat(nonNumberValues), true);
}

for (let op of strongStringOrNumberBinops) {
  checkArgumentCombinations(op, nonNumberValues,
                            numberValues.concat(nonStringOrNumberValues), true);
  checkArgumentCombinations(op, nonStringOrNumberValues, stringValues, true);
  checkArgumentCombinations(op, stringValues, stringValues, false);
}

for (let op of strongUnops) {
  for (let value of numberValues) {
    assertStrongNonThrowBehaviour("(" + op + value + ")");
  }
  for (let value of nonNumberValues) {
    assertStrongThrowBehaviour("(" + op + value + ")");
  }
}

for (let func of strongNumberFuncs) {
  // Check IC None*None->None throws
  for (let v of nonNumberValues) {
    let value = eval(v);
    assertThrows(function(){func(2, value);}, TypeError);
    %OptimizeFunctionOnNextCall(func);
    assertThrows(function(){func(2, value);}, TypeError);
    %DeoptimizeFunction(func);
  }
  func(4, 5);
  func(4, 5);
  // Check IC Smi*Smi->Smi throws
  for (let v of nonNumberValues) {
    let value = eval(v);
    assertThrows(function(){func(2, value);}, TypeError);
    %OptimizeFunctionOnNextCall(func);
    assertThrows(function(){func(2, value);}, TypeError);
    %DeoptimizeFunction(func);
  }
  func(NaN, NaN);
  func(NaN, NaN);
  // Check IC Number*Number->Number throws
  for (let v of nonNumberValues) {
    let value = eval(v);
    assertThrows(function(){func(2, value);}, TypeError);
    %OptimizeFunctionOnNextCall(func);
    assertThrows(function(){func(2, value);}, TypeError);
    %DeoptimizeFunction(func);
  }
}

for (let func of strongStringOrNumberFuncs) {
  // Check IC None*None->None throws
  for (let v of nonNumberValues) {
    let value = eval(v);
    assertThrows(function(){func(2, value);}, TypeError);
    %OptimizeFunctionOnNextCall(func);
    assertThrows(function(){func(2, value);}, TypeError);
    %DeoptimizeFunction(func);
  }
  func("foo", "bar");
  func("foo", "bar");
  // Check IC String*String->String throws
  for (let v of nonNumberValues) {
    let value = eval(v);
    assertThrows(function(){func(2, value);}, TypeError);
    %OptimizeFunctionOnNextCall(func);
    assertThrows(function(){func(2, value);}, TypeError);
    %DeoptimizeFunction(func);
  }
  func(NaN, NaN);
  func(NaN, NaN);
  // Check IC Generic*Generic->Generic throws
  for (let v of nonNumberValues) {
    let value = eval(v);
    assertThrows(function(){func(2, value);}, TypeError);
    %OptimizeFunctionOnNextCall(func);
    assertThrows(function(){func(2, value);}, TypeError);
    %DeoptimizeFunction(func);
  }
}

for (let func of [str_equal_strong, str_ineq_strong]) {
  assertDoesNotThrow(function(){func(2, undefined)});
  assertDoesNotThrow(function(){func(2, undefined)});
  %OptimizeFunctionOnNextCall(func);
  assertDoesNotThrow(function(){func(2, undefined)});
  %DeoptimizeFunction(func);
  assertDoesNotThrow(function(){func(true, {})});
  assertDoesNotThrow(function(){func(true, {})});
  %OptimizeFunctionOnNextCall(func);
  assertDoesNotThrow(function(){func(true, {})});
  %DeoptimizeFunction(func);
}