V(MOD, 1) \
V(MOD_STRONG, 1) \
V(BIT_OR, 1) \
+ V(BIT_OR_STRONG, 1) \
V(BIT_AND, 1) \
+ V(BIT_AND_STRONG, 1) \
V(BIT_XOR, 1) \
+ V(BIT_XOR_STRONG, 1) \
V(SHL, 1) \
+ V(SHL_STRONG, 1) \
V(SAR, 1) \
+ V(SAR_STRONG, 1) \
V(SHR, 1) \
+ V(SHR_STRONG, 1) \
V(DELETE, 2) \
V(IN, 1) \
V(INSTANCE_OF, 1) \
const Operator* numberOp) {
JSBinopReduction r(this, node);
if (is_strong(OpParameter<LanguageMode>(node))) {
- if (r.left_type()->Is(Type::Number()) &&
- (r.right_type()->Is(Type::Number()))) {
+ if (r.BothInputsAre(Type::Number())) {
return r.ChangeToPureOperator(numberOp, Type::Number());
}
return NoChange();
Reduction JSTypedLowering::ReduceInt32Binop(Node* node, const Operator* intOp) {
JSBinopReduction r(this, node);
+ if (is_strong(OpParameter<LanguageMode>(node))) {
+ if (r.BothInputsAre(Type::Number())) {
+ r.ConvertInputsToUI32(kSigned, kSigned);
+ return r.ChangeToPureOperator(intOp, Type::Integral32());
+ }
+ return NoChange();
+ }
Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
r.ConvertInputsToNumber(frame_state);
r.ConvertInputsToUI32(kSigned, kSigned);
Signedness left_signedness,
const Operator* shift_op) {
JSBinopReduction r(this, node);
- if (r.BothInputsAre(Type::Primitive())) {
+ Type* reduce_type = is_strong(
+ OpParameter<LanguageMode>(node)) ? Type::Number() :
+ Type::Primitive();
+ if (r.BothInputsAre(reduce_type)) {
r.ConvertInputsForShift(left_signedness);
return r.ChangeToPureOperator(shift_op, Type::Integral32());
}
case Token::MUL: return Builtins::MUL_STRONG;
case Token::DIV: return Builtins::DIV_STRONG;
case Token::MOD: return Builtins::MOD_STRONG;
- case Token::BIT_OR: return Builtins::BIT_OR;
- case Token::BIT_AND: return Builtins::BIT_AND;
- case Token::BIT_XOR: return Builtins::BIT_XOR;
- case Token::SAR: return Builtins::SAR;
- case Token::SHR: return Builtins::SHR;
- case Token::SHL: return Builtins::SHL;
+ case Token::BIT_OR: return Builtins::BIT_OR_STRONG;
+ case Token::BIT_AND: return Builtins::BIT_AND_STRONG;
+ case Token::BIT_XOR: return Builtins::BIT_XOR_STRONG;
+ case Token::SAR: return Builtins::SAR_STRONG;
+ case Token::SHR: return Builtins::SHR_STRONG;
+ case Token::SHL: return Builtins::SHL_STRONG;
}
} else {
switch (op) {
}
+//ECMA-262, section 11.10, page 57.
+function BIT_OR_STRONG(y) {
+ if (IS_NUMBER(this) && IS_NUMBER(y)) {
+ return %NumberOr(this, y);
+ }
+ throw %MakeTypeError('strong_implicit_cast');
+}
+
+
// ECMA-262, section 11.10, page 57.
function BIT_AND(y) {
var x;
}
+//ECMA-262, section 11.10, page 57.
+function BIT_AND_STRONG(y) {
+ if (IS_NUMBER(this) && IS_NUMBER(y)) {
+ return %NumberAnd(this, y);
+ }
+ throw %MakeTypeError('strong_implicit_cast');
+}
+
+
// ECMA-262, section 11.10, page 57.
function BIT_XOR(y) {
var x = IS_NUMBER(this) ? this : %NonNumberToNumber(this);
}
+//ECMA-262, section 11.10, page 57.
+function BIT_XOR_STRONG(y) {
+ if (IS_NUMBER(this) && IS_NUMBER(y)) {
+ return %NumberXor(this, y);
+ }
+ throw %MakeTypeError('strong_implicit_cast');
+}
+
+
// ECMA-262, section 11.7.1, page 51.
function SHL(y) {
var x = IS_NUMBER(this) ? this : %NonNumberToNumber(this);
}
+//ECMA-262, section 11.7.1, page 51.
+function SHL_STRONG(y) {
+ if (IS_NUMBER(this) && IS_NUMBER(y)) {
+ return %NumberShl(this, y);
+ }
+ throw %MakeTypeError('strong_implicit_cast');
+}
+
+
// ECMA-262, section 11.7.2, page 51.
function SAR(y) {
var x;
}
+//ECMA-262, section 11.7.2, page 51.
+function SAR_STRONG(y) {
+ if (IS_NUMBER(this) && IS_NUMBER(y)) {
+ return %NumberSar(this, y);
+ }
+ throw %MakeTypeError('strong_implicit_cast');
+}
+
+
// ECMA-262, section 11.7.3, page 52.
function SHR(y) {
var x = IS_NUMBER(this) ? this : %NonNumberToNumber(this);
}
+//ECMA-262, section 11.7.3, page 52.
+function SHR_STRONG(y) {
+ if (IS_NUMBER(this) && IS_NUMBER(y)) {
+ return %NumberShr(this, y);
+ }
+ throw %MakeTypeError('strong_implicit_cast');
+}
+
/* -----------------------------
- - - H e l p e r s - - -
// Flags: --strong-mode --allow-natives-syntax
-'use strict';
+"use strict";
// TODO(conradw): Implement other strong operators
-let strong_arith = [
- "-",
- "*",
- "/",
- "%"
-]
-
-let nonnumber_values = [
- "{}",
- "'foo'",
- "(function(){})",
- "[]",
- "'0'",
- "'NaN'",
- "(class Foo {})"
-]
-
-let number_values = [
- "0",
- "(-0)",
- "1",
- "0.79",
- "(-0.79)",
- "4294967295",
- "4294967296",
- "(-4294967295)",
- "(-4294967296)",
- "9999999999999",
- "(-9999999999999)",
- "1.5e10",
- "(-1.5e10)",
- "0xFFF",
- "(-0xFFF)",
- "NaN",
- "Infinity",
- "(-Infinity)"
-]
+let strongBinops = [
+ "-",
+ "*",
+ "/",
+ "%",
+ "|",
+ "&",
+ "^",
+ "<<",
+ ">>",
+ ">>>",
+];
+
+let strongUnops = [
+ "~",
+ "+",
+ "-"
+];
+
+let nonNumberValues = [
+ "{}",
+ "'foo'",
+ "(function(){})",
+ "[]",
+ "'0'",
+ "'NaN'",
+ "(class Foo {})"
+];
+
+let numberValues = [
+ "0",
+ "(-0)",
+ "1",
+ "0.79",
+ "(-0.79)",
+ "4294967295",
+ "4294967296",
+ "(-4294967295)",
+ "(-4294967296)",
+ "9999999999999",
+ "(-9999999999999)",
+ "1.5e10",
+ "(-1.5e10)",
+ "0xFFF",
+ "(-0xFFF)",
+ "NaN",
+ "Infinity",
+ "(-Infinity)"
+];
function sub_strong(x, y) {
"use strong";
- let v = x - y;
- return v;
+ return x - y;
}
function mul_strong(x, y) {
"use strong";
- let v = x * y;
- return v;
+ return x * y;
}
function div_strong(x, y) {
"use strong";
- let v = x / y;
- return v;
+ return x / y;
}
function mod_strong(x, y) {
"use strong";
- let v = x % y;
- return v;
+ return x % y;
}
-let strong_funcs = [sub_strong, mul_strong, div_strong, mod_strong];
+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 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);
+}
+
+let strongFuncs = [sub_strong, mul_strong, div_strong, mod_strong, or_strong,
+ and_strong, xor_strong, shl_strong, shr_strong, sar_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];
function inline_sub_strong(x, y) {
"use strong";
return inline_sub(x, y);
}
-for (let op of strong_arith) {
- for (let left of number_values) {
- for (let right of number_values) {
- let expr = "(" + left + op + right + ")";
- assertEquals(eval(expr), eval("'use strong';" + expr));
- assertDoesNotThrow("'use strong'; " + expr + ";");
- assertDoesNotThrow("'use strong'; let v = " + expr + ";");
+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);
+}
+
+for (let op of strongBinops) {
+ for (let v1 of numberValues) {
+ let assignExpr = "foo " + op + "= " + v1 + ";";
+ for (let v2 of numberValues) {
+ assertDoesNotThrow("'use strong'; let foo = " + v2 + "; " + assignExpr);
+ assertStrongNonThrowBehaviour("(" + v1 + op + v2 + ")");
}
- }
- for (let left of number_values) {
- for (let right of nonnumber_values) {
- let expr = "(" + left + op + right + ")";
- assertDoesNotThrow("'use strict'; " + expr + ";");
- assertDoesNotThrow("'use strict'; let v = " + expr + ";");
- assertThrows("'use strong'; " + expr + ";", TypeError);
- assertThrows("'use strong'; let v = " + expr + ";", TypeError);
+ for (let v2 of nonNumberValues) {
+ assertThrows("'use strong'; let foo = " + v2 + "; " + assignExpr,
+ TypeError);
+ assertStrongThrowBehaviour("(" + v1 + op + v2 + ")");
}
}
- for (let left of nonnumber_values) {
- for (let right of number_values.concat(nonnumber_values)) {
- let expr = "(" + left + op + right + ")";
- assertDoesNotThrow("'use strict'; " + expr + ";");
- assertDoesNotThrow("'use strict'; let v = " + expr + ";");
- assertThrows("'use strong'; " + expr + ";", TypeError);
- assertThrows("'use strong'; let v = " + expr + ";", TypeError);
+ for (let v1 of nonNumberValues) {
+ let assignExpr = "foo " + op + "= " + v1 + ";";
+ for (let v2 of numberValues.concat(nonNumberValues)) {
+ assertThrows("'use strong'; let foo = " + v2 + "; " + assignExpr,
+ TypeError);
+ assertStrongThrowBehaviour("(" + v1 + op + v2 + ")");
}
}
}
-for (let func of strong_funcs) {
+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 strongFuncs) {
let a = func(4, 5);
let b = func(4, 5);
assertTrue(a === b);
%ClearFunctionTypeFeedback(func);
}
-for (let func of strong_funcs) {
+for (let func of strongFuncs) {
try {
let a = func(2, 3);
let b = func(2, 3);
%OptimizeFunctionOnNextCall(func);
let c = func(2, "foo");
assertUnreachable();
- } catch(e) {
- assertTrue(e instanceof TypeError);
+ } catch (e) {
+ assertInstanceof(e, TypeError);
assertUnoptimized(func);
assertThrows(function(){func(2, "foo");}, TypeError);
assertDoesNotThrow(function(){func(2, 3);});
Node* const effect = graph()->start();
Node* const control = graph()->start();
TRACED_FORRANGE(double, rhs, 0, 31) {
- Reduction r =
- Reduce(graph()->NewNode(javascript()->ShiftLeft(LanguageMode::SLOPPY),
- lhs, NumberConstant(rhs), context, effect,
- control));
- ASSERT_TRUE(r.Changed());
- EXPECT_THAT(r.replacement(),
- IsWord32Shl(lhs, IsNumberConstant(BitEq(rhs))));
+ TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) {
+ Reduction r =
+ Reduce(graph()->NewNode(javascript()->ShiftLeft(language_mode), lhs,
+ NumberConstant(rhs), context, effect,
+ control));
+ ASSERT_TRUE(r.Changed());
+ EXPECT_THAT(r.replacement(),
+ IsWord32Shl(lhs, IsNumberConstant(BitEq(rhs))));
+ }
}
}
Node* const context = UndefinedConstant();
Node* const effect = graph()->start();
Node* const control = graph()->start();
- Reduction r =
- Reduce(graph()->NewNode(javascript()->ShiftLeft(LanguageMode::SLOPPY),
- lhs, rhs, context, effect, control));
- ASSERT_TRUE(r.Changed());
- EXPECT_THAT(r.replacement(),
- IsWord32Shl(lhs, IsWord32And(rhs, IsInt32Constant(0x1f))));
+ TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) {
+ Reduction r =
+ Reduce(graph()->NewNode(javascript()->ShiftLeft(language_mode), lhs,
+ rhs, context, effect, control));
+ ASSERT_TRUE(r.Changed());
+ EXPECT_THAT(r.replacement(),
+ IsWord32Shl(lhs, IsWord32And(rhs, IsInt32Constant(0x1f))));
+ }
}
Node* const effect = graph()->start();
Node* const control = graph()->start();
TRACED_FORRANGE(double, rhs, 0, 31) {
- Reduction r =
- Reduce(graph()->NewNode(javascript()->
- ShiftRight(LanguageMode::SLOPPY), lhs,
- NumberConstant(rhs), context, effect, control));
- ASSERT_TRUE(r.Changed());
- EXPECT_THAT(r.replacement(),
- IsWord32Sar(lhs, IsNumberConstant(BitEq(rhs))));
+ TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) {
+ Reduction r =
+ Reduce(graph()->NewNode(javascript()-> ShiftRight(language_mode), lhs,
+ NumberConstant(rhs), context, effect,
+ control));
+ ASSERT_TRUE(r.Changed());
+ EXPECT_THAT(r.replacement(),
+ IsWord32Sar(lhs, IsNumberConstant(BitEq(rhs))));
+ }
}
}
Node* const context = UndefinedConstant();
Node* const effect = graph()->start();
Node* const control = graph()->start();
- Reduction r = Reduce(graph()->NewNode(javascript()->
- ShiftRight(LanguageMode::SLOPPY),
- lhs, rhs, context, effect, control));
- ASSERT_TRUE(r.Changed());
- EXPECT_THAT(r.replacement(),
- IsWord32Sar(lhs, IsWord32And(rhs, IsInt32Constant(0x1f))));
+ TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) {
+ Reduction r = Reduce(graph()->NewNode(javascript()->
+ ShiftRight(language_mode), lhs, rhs,
+ context, effect, control));
+ ASSERT_TRUE(r.Changed());
+ EXPECT_THAT(r.replacement(),
+ IsWord32Sar(lhs, IsWord32And(rhs, IsInt32Constant(0x1f))));
+ }
}
Node* const effect = graph()->start();
Node* const control = graph()->start();
TRACED_FORRANGE(double, rhs, 0, 31) {
- Reduction r =
- Reduce(graph()->NewNode(javascript()->
- ShiftRightLogical(LanguageMode::SLOPPY),
- lhs, NumberConstant(rhs), context, effect,
- control));
- ASSERT_TRUE(r.Changed());
- EXPECT_THAT(r.replacement(),
- IsWord32Shr(lhs, IsNumberConstant(BitEq(rhs))));
+ TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) {
+ Reduction r =
+ Reduce(graph()->NewNode(javascript()->
+ ShiftRightLogical(language_mode), lhs,
+ NumberConstant(rhs), context, effect,
+ control));
+ ASSERT_TRUE(r.Changed());
+ EXPECT_THAT(r.replacement(),
+ IsWord32Shr(lhs, IsNumberConstant(BitEq(rhs))));
+ }
}
}
Node* const context = UndefinedConstant();
Node* const effect = graph()->start();
Node* const control = graph()->start();
- Reduction r = Reduce(graph()->NewNode(javascript()->
- ShiftRightLogical(LanguageMode::SLOPPY),
- lhs, rhs, context, effect, control));
- ASSERT_TRUE(r.Changed());
- EXPECT_THAT(r.replacement(),
- IsWord32Shr(lhs, IsWord32And(rhs, IsInt32Constant(0x1f))));
+ TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) {
+ Reduction r = Reduce(graph()->NewNode(javascript()->
+ ShiftRightLogical(language_mode), lhs,
+ rhs, context, effect, control));
+ ASSERT_TRUE(r.Changed());
+ EXPECT_THAT(r.replacement(),
+ IsWord32Shr(lhs, IsWord32And(rhs, IsInt32Constant(0x1f))));
+ }
}