blob: cd8acf70857bf31050a07ff5d5fd24615c449d57 [file] [log] [blame]
// 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);
}