[strong] Implement strong mode semantics for the count operation.
Also fixes a crankshaft bug with strong implicit conversions. It turns out that the implicit conversion of oddball values is smushed into so many places in crankshaft that it would have been pretty invasive surgery to make everything fall out naturally. BUG=v8:3956 LOG=N Review URL: https://codereview.chromium.org/1216463003 Cr-Commit-Position: refs/heads/master@{#29381}
This commit is contained in:
parent
7374e6dc89
commit
f5cc091f8f
@ -5024,9 +5024,11 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
|
||||
__ jmp(&stub_call);
|
||||
__ bind(&slow);
|
||||
}
|
||||
ToNumberStub convert_stub(isolate());
|
||||
__ CallStub(&convert_stub);
|
||||
PrepareForBailoutForId(expr->ToNumberId(), TOS_REG);
|
||||
if (!is_strong(language_mode())) {
|
||||
ToNumberStub convert_stub(isolate());
|
||||
__ CallStub(&convert_stub);
|
||||
PrepareForBailoutForId(expr->ToNumberId(), TOS_REG);
|
||||
}
|
||||
|
||||
// Save result for postfix expressions.
|
||||
if (expr->is_postfix()) {
|
||||
@ -5068,6 +5070,9 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
|
||||
patch_site.EmitPatchInfo();
|
||||
__ bind(&done);
|
||||
|
||||
if (is_strong(language_mode())) {
|
||||
PrepareForBailoutForId(expr->ToNumberId(), TOS_REG);
|
||||
}
|
||||
// Store the value returned in r0.
|
||||
switch (assign_type) {
|
||||
case VARIABLE:
|
||||
|
@ -4712,9 +4712,11 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
|
||||
__ B(&stub_call);
|
||||
__ Bind(&slow);
|
||||
}
|
||||
ToNumberStub convert_stub(isolate());
|
||||
__ CallStub(&convert_stub);
|
||||
PrepareForBailoutForId(expr->ToNumberId(), TOS_REG);
|
||||
if (!is_strong(language_mode())) {
|
||||
ToNumberStub convert_stub(isolate());
|
||||
__ CallStub(&convert_stub);
|
||||
PrepareForBailoutForId(expr->ToNumberId(), TOS_REG);
|
||||
}
|
||||
|
||||
// Save result for postfix expressions.
|
||||
if (expr->is_postfix()) {
|
||||
@ -4759,6 +4761,9 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
|
||||
}
|
||||
__ Bind(&done);
|
||||
|
||||
if (is_strong(language_mode())) {
|
||||
PrepareForBailoutForId(expr->ToNumberId(), TOS_REG);
|
||||
}
|
||||
// Store the value returned in x0.
|
||||
switch (assign_type) {
|
||||
case VARIABLE:
|
||||
|
@ -2661,9 +2661,11 @@ void AstGraphBuilder::VisitCountOperation(CountOperation* expr) {
|
||||
}
|
||||
|
||||
// Convert old value into a number.
|
||||
old_value = NewNode(javascript()->ToNumber(), old_value);
|
||||
PrepareFrameState(old_value, expr->ToNumberId(),
|
||||
OutputFrameStateCombine::Push());
|
||||
if (!is_strong(language_mode())) {
|
||||
old_value = NewNode(javascript()->ToNumber(), old_value);
|
||||
PrepareFrameState(old_value, expr->ToNumberId(),
|
||||
OutputFrameStateCombine::Push());
|
||||
}
|
||||
|
||||
// TODO(titzer): combine this framestate with the above?
|
||||
FrameStateBeforeAndAfter store_states(this, assign_type == KEYED_PROPERTY
|
||||
@ -2679,9 +2681,10 @@ void AstGraphBuilder::VisitCountOperation(CountOperation* expr) {
|
||||
FrameStateBeforeAndAfter states(this, BailoutId::None());
|
||||
value =
|
||||
BuildBinaryOp(old_value, jsgraph()->OneConstant(), expr->binary_op());
|
||||
// This should never deoptimize because we have converted to number
|
||||
// before.
|
||||
states.AddToNode(value, BailoutId::None(),
|
||||
// This should never deoptimize outside strong mode because otherwise we
|
||||
// have converted to number before.
|
||||
states.AddToNode(value, is_strong(language_mode()) ? expr->ToNumberId()
|
||||
: BailoutId::None(),
|
||||
OutputFrameStateCombine::Ignore());
|
||||
}
|
||||
|
||||
|
@ -3404,7 +3404,7 @@ void HCompareNumericAndBranch::InferRepresentation(
|
||||
// (false). Therefore, any comparisons other than ordered relational
|
||||
// comparisons must cause a deopt when one of their arguments is undefined.
|
||||
// See also v8:1434
|
||||
if (Token::IsOrderedRelationalCompareOp(token_)) {
|
||||
if (Token::IsOrderedRelationalCompareOp(token_) && !is_strong(strength())) {
|
||||
SetFlag(kAllowUndefinedAsNaN);
|
||||
}
|
||||
}
|
||||
|
@ -4151,7 +4151,7 @@ class HBitwiseBinaryOperation : public HBinaryOperation {
|
||||
: HBinaryOperation(context, left, right, strength, type) {
|
||||
SetFlag(kFlexibleRepresentation);
|
||||
SetFlag(kTruncatingToInt32);
|
||||
SetFlag(kAllowUndefinedAsNaN);
|
||||
if (!is_strong(strength)) SetFlag(kAllowUndefinedAsNaN);
|
||||
SetAllSideEffects();
|
||||
}
|
||||
|
||||
@ -4232,7 +4232,7 @@ class HArithmeticBinaryOperation : public HBinaryOperation {
|
||||
HType::TaggedNumber()) {
|
||||
SetAllSideEffects();
|
||||
SetFlag(kFlexibleRepresentation);
|
||||
SetFlag(kAllowUndefinedAsNaN);
|
||||
if (!is_strong(strength)) SetFlag(kAllowUndefinedAsNaN);
|
||||
}
|
||||
|
||||
void RepresentationChanged(Representation to) override {
|
||||
@ -4289,11 +4289,22 @@ class HCompareGeneric final : public HBinaryOperation {
|
||||
|
||||
class HCompareNumericAndBranch : public HTemplateControlInstruction<2, 2> {
|
||||
public:
|
||||
DECLARE_INSTRUCTION_FACTORY_P3(HCompareNumericAndBranch,
|
||||
HValue*, HValue*, Token::Value);
|
||||
DECLARE_INSTRUCTION_FACTORY_P5(HCompareNumericAndBranch,
|
||||
HValue*, HValue*, Token::Value,
|
||||
HBasicBlock*, HBasicBlock*);
|
||||
static HCompareNumericAndBranch* New(Isolate* isolate, Zone* zone,
|
||||
HValue* context, HValue* left,
|
||||
HValue* right, Token::Value token,
|
||||
HBasicBlock* true_target = NULL,
|
||||
HBasicBlock* false_target = NULL,
|
||||
Strength strength = Strength::WEAK) {
|
||||
return new (zone) HCompareNumericAndBranch(left, right, token, true_target,
|
||||
false_target, strength);
|
||||
}
|
||||
static HCompareNumericAndBranch* New(Isolate* isolate, Zone* zone,
|
||||
HValue* context, HValue* left,
|
||||
HValue* right, Token::Value token,
|
||||
Strength strength) {
|
||||
return new (zone)
|
||||
HCompareNumericAndBranch(left, right, token, NULL, NULL, strength);
|
||||
}
|
||||
|
||||
HValue* left() const { return OperandAt(0); }
|
||||
HValue* right() const { return OperandAt(1); }
|
||||
@ -4316,6 +4327,8 @@ class HCompareNumericAndBranch : public HTemplateControlInstruction<2, 2> {
|
||||
|
||||
bool KnownSuccessorBlock(HBasicBlock** block) override;
|
||||
|
||||
Strength strength() const { return strength_; }
|
||||
|
||||
std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
|
||||
|
||||
void SetOperandPositions(Zone* zone, SourcePosition left_pos,
|
||||
@ -4327,12 +4340,10 @@ class HCompareNumericAndBranch : public HTemplateControlInstruction<2, 2> {
|
||||
DECLARE_CONCRETE_INSTRUCTION(CompareNumericAndBranch)
|
||||
|
||||
private:
|
||||
HCompareNumericAndBranch(HValue* left,
|
||||
HValue* right,
|
||||
Token::Value token,
|
||||
HBasicBlock* true_target = NULL,
|
||||
HBasicBlock* false_target = NULL)
|
||||
: token_(token) {
|
||||
HCompareNumericAndBranch(HValue* left, HValue* right, Token::Value token,
|
||||
HBasicBlock* true_target, HBasicBlock* false_target,
|
||||
Strength strength)
|
||||
: token_(token), strength_(strength) {
|
||||
SetFlag(kFlexibleRepresentation);
|
||||
DCHECK(Token::IsCompareOp(token));
|
||||
SetOperandAt(0, left);
|
||||
@ -4343,6 +4354,7 @@ class HCompareNumericAndBranch : public HTemplateControlInstruction<2, 2> {
|
||||
|
||||
Representation observed_input_representation_[2];
|
||||
Token::Value token_;
|
||||
Strength strength_;
|
||||
};
|
||||
|
||||
|
||||
|
@ -10305,7 +10305,7 @@ HInstruction* HOptimizedGraphBuilder::BuildIncrement(
|
||||
rep = Representation::Smi();
|
||||
}
|
||||
|
||||
if (returns_original_input) {
|
||||
if (returns_original_input && !is_strong(function_language_mode())) {
|
||||
// We need an explicit HValue representing ToNumber(input). The
|
||||
// actual HChange instruction we need is (sometimes) added in a later
|
||||
// phase, so it is not available now to be used as an input to HAdd and
|
||||
@ -10331,8 +10331,12 @@ HInstruction* HOptimizedGraphBuilder::BuildIncrement(
|
||||
add->set_observed_input_representation(1, rep);
|
||||
add->set_observed_input_representation(2, Representation::Smi());
|
||||
}
|
||||
if (!is_strong(function_language_mode())) {
|
||||
instr->ClearAllSideEffects();
|
||||
} else {
|
||||
Add<HSimulate>(expr->ToNumberId(), REMOVABLE_SIMULATE);
|
||||
}
|
||||
instr->SetFlag(HInstruction::kCannotBeTagged);
|
||||
instr->ClearAllSideEffects();
|
||||
return instr;
|
||||
}
|
||||
|
||||
@ -10616,10 +10620,10 @@ HValue* HOptimizedGraphBuilder::BuildBinaryOperation(
|
||||
if (FLAG_allocation_site_pretenuring && !allocation_site.is_null()) {
|
||||
allocation_mode = HAllocationMode(allocation_site);
|
||||
}
|
||||
|
||||
HValue* result = HGraphBuilder::BuildBinaryOperation(
|
||||
expr->op(), left, right, left_type, right_type, result_type,
|
||||
fixed_right_arg, allocation_mode, strength(function_language_mode()));
|
||||
fixed_right_arg, allocation_mode, strength(function_language_mode()),
|
||||
expr->id());
|
||||
// Add a simulate after instructions with observable side effects, and
|
||||
// after phis, which are the result of BuildBinaryOperation when we
|
||||
// inlined some complex subgraph.
|
||||
@ -10636,12 +10640,10 @@ HValue* HOptimizedGraphBuilder::BuildBinaryOperation(
|
||||
}
|
||||
|
||||
|
||||
HValue* HGraphBuilder::BuildBinaryOperation(Token::Value op, HValue* left,
|
||||
HValue* right, Type* left_type,
|
||||
Type* right_type, Type* result_type,
|
||||
Maybe<int> fixed_right_arg,
|
||||
HAllocationMode allocation_mode,
|
||||
Strength strength) {
|
||||
HValue* HGraphBuilder::BuildBinaryOperation(
|
||||
Token::Value op, HValue* left, HValue* right, Type* left_type,
|
||||
Type* right_type, Type* result_type, Maybe<int> fixed_right_arg,
|
||||
HAllocationMode allocation_mode, Strength strength, BailoutId opt_id) {
|
||||
bool maybe_string_add = false;
|
||||
if (op == Token::ADD) {
|
||||
// If we are adding constant string with something for which we don't have
|
||||
@ -10684,7 +10686,7 @@ HValue* HGraphBuilder::BuildBinaryOperation(Token::Value op, HValue* left,
|
||||
maybe_string_add = op == Token::ADD;
|
||||
}
|
||||
|
||||
if (!maybe_string_add) {
|
||||
if (!maybe_string_add && !is_strong(strength)) {
|
||||
left = TruncateToNumber(left, &left_type);
|
||||
right = TruncateToNumber(right, &right_type);
|
||||
}
|
||||
@ -10794,6 +10796,20 @@ HValue* HGraphBuilder::BuildBinaryOperation(Token::Value op, HValue* left,
|
||||
Add<HPushArguments>(left, right);
|
||||
instr = AddUncasted<HInvokeFunction>(function, 2);
|
||||
} else {
|
||||
if (is_strong(strength) && Token::IsBitOp(op)) {
|
||||
IfBuilder if_builder(this);
|
||||
if_builder.If<HHasInstanceTypeAndBranch>(left, ODDBALL_TYPE);
|
||||
if_builder.OrIf<HHasInstanceTypeAndBranch>(right, ODDBALL_TYPE);
|
||||
if_builder.Then();
|
||||
Add<HCallRuntime>(
|
||||
isolate()->factory()->empty_string(),
|
||||
Runtime::FunctionForId(Runtime::kThrowStrongModeImplicitConversion),
|
||||
0);
|
||||
if (!graph()->info()->IsStub()) {
|
||||
Add<HSimulate>(opt_id, REMOVABLE_SIMULATE);
|
||||
}
|
||||
if_builder.End();
|
||||
}
|
||||
switch (op) {
|
||||
case Token::ADD:
|
||||
instr = AddUncasted<HAdd>(left, right, strength);
|
||||
@ -11251,8 +11267,8 @@ HControlInstruction* HOptimizedGraphBuilder::BuildCompareInstruction(
|
||||
HBranch* branch = New<HBranch>(result);
|
||||
return branch;
|
||||
} else {
|
||||
HCompareNumericAndBranch* result =
|
||||
New<HCompareNumericAndBranch>(left, right, op);
|
||||
HCompareNumericAndBranch* result = New<HCompareNumericAndBranch>(
|
||||
left, right, op, strength(function_language_mode()));
|
||||
result->set_observed_input_representation(left_rep, right_rep);
|
||||
if (top_info()->is_tracking_positions()) {
|
||||
result->SetOperandPositions(zone(), left_position, right_position);
|
||||
|
@ -1433,7 +1433,8 @@ class HGraphBuilder {
|
||||
Type* left_type, Type* right_type,
|
||||
Type* result_type, Maybe<int> fixed_right_arg,
|
||||
HAllocationMode allocation_mode,
|
||||
Strength strength);
|
||||
Strength strength,
|
||||
BailoutId opt_id = BailoutId::None());
|
||||
|
||||
HLoadNamedField* AddLoadFixedArrayLength(HValue *object,
|
||||
HValue *dependency = NULL);
|
||||
|
@ -4961,9 +4961,11 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
|
||||
__ jmp(&stub_call, Label::kNear);
|
||||
__ bind(&slow);
|
||||
}
|
||||
ToNumberStub convert_stub(isolate());
|
||||
__ CallStub(&convert_stub);
|
||||
PrepareForBailoutForId(expr->ToNumberId(), TOS_REG);
|
||||
if (!is_strong(language_mode())) {
|
||||
ToNumberStub convert_stub(isolate());
|
||||
__ CallStub(&convert_stub);
|
||||
PrepareForBailoutForId(expr->ToNumberId(), TOS_REG);
|
||||
}
|
||||
|
||||
// Save result for postfix expressions.
|
||||
if (expr->is_postfix()) {
|
||||
@ -5004,6 +5006,9 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
|
||||
patch_site.EmitPatchInfo();
|
||||
__ bind(&done);
|
||||
|
||||
if (is_strong(language_mode())) {
|
||||
PrepareForBailoutForId(expr->ToNumberId(), TOS_REG);
|
||||
}
|
||||
// Store the value returned in eax.
|
||||
switch (assign_type) {
|
||||
case VARIABLE:
|
||||
|
@ -223,6 +223,7 @@ Type* BinaryOpICState::GetResultType(Zone* zone) const {
|
||||
std::ostream& operator<<(std::ostream& os, const BinaryOpICState& s) {
|
||||
os << "(" << Token::Name(s.op_);
|
||||
if (s.CouldCreateAllocationMementos()) os << "_CreateAllocationMementos";
|
||||
if (is_strong(s.strength())) os << "_Strong";
|
||||
os << ":" << BinaryOpICState::KindToString(s.left_kind_) << "*";
|
||||
if (s.fixed_right_arg_.IsJust()) {
|
||||
os << s.fixed_right_arg_.FromJust();
|
||||
|
@ -230,7 +230,8 @@ class CallSite {
|
||||
"In strong mode, calling a function with too few arguments is deprecated") \
|
||||
T(StrongDeleteProperty, \
|
||||
"On strong object %, deletion of property % is deprecated") \
|
||||
T(StrongImplicitCast, "In strong mode, implicit conversions are deprecated") \
|
||||
T(StrongImplicitConversion, \
|
||||
"In strong mode, implicit conversions are deprecated") \
|
||||
T(StrongRedefineDisallowed, \
|
||||
"On strong object %, redefining writable, non-configurable property '%' " \
|
||||
"to be non-writable is deprecated") \
|
||||
|
@ -5043,9 +5043,11 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
|
||||
__ jmp(&stub_call);
|
||||
__ bind(&slow);
|
||||
}
|
||||
ToNumberStub convert_stub(isolate());
|
||||
__ CallStub(&convert_stub);
|
||||
PrepareForBailoutForId(expr->ToNumberId(), TOS_REG);
|
||||
if (!is_strong(language_mode())) {
|
||||
ToNumberStub convert_stub(isolate());
|
||||
__ CallStub(&convert_stub);
|
||||
PrepareForBailoutForId(expr->ToNumberId(), TOS_REG);
|
||||
}
|
||||
|
||||
// Save result for postfix expressions.
|
||||
if (expr->is_postfix()) {
|
||||
@ -5086,6 +5088,9 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
|
||||
patch_site.EmitPatchInfo();
|
||||
__ bind(&done);
|
||||
|
||||
if (is_strong(language_mode())) {
|
||||
PrepareForBailoutForId(expr->ToNumberId(), TOS_REG);
|
||||
}
|
||||
// Store the value returned in v0.
|
||||
switch (assign_type) {
|
||||
case VARIABLE:
|
||||
|
@ -5045,9 +5045,11 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
|
||||
__ jmp(&stub_call);
|
||||
__ bind(&slow);
|
||||
}
|
||||
ToNumberStub convert_stub(isolate());
|
||||
__ CallStub(&convert_stub);
|
||||
PrepareForBailoutForId(expr->ToNumberId(), TOS_REG);
|
||||
if (!is_strong(language_mode())) {
|
||||
ToNumberStub convert_stub(isolate());
|
||||
__ CallStub(&convert_stub);
|
||||
PrepareForBailoutForId(expr->ToNumberId(), TOS_REG);
|
||||
}
|
||||
|
||||
// Save result for postfix expressions.
|
||||
if (expr->is_postfix()) {
|
||||
@ -5088,6 +5090,9 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
|
||||
patch_site.EmitPatchInfo();
|
||||
__ bind(&done);
|
||||
|
||||
if (is_strong(language_mode())) {
|
||||
PrepareForBailoutForId(expr->ToNumberId(), TOS_REG);
|
||||
}
|
||||
// Store the value returned in v0.
|
||||
switch (assign_type) {
|
||||
case VARIABLE:
|
||||
|
@ -5050,9 +5050,11 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
|
||||
__ b(&stub_call);
|
||||
__ bind(&slow);
|
||||
}
|
||||
ToNumberStub convert_stub(isolate());
|
||||
__ CallStub(&convert_stub);
|
||||
PrepareForBailoutForId(expr->ToNumberId(), TOS_REG);
|
||||
if (!is_strong(language_mode())) {
|
||||
ToNumberStub convert_stub(isolate());
|
||||
__ CallStub(&convert_stub);
|
||||
PrepareForBailoutForId(expr->ToNumberId(), TOS_REG);
|
||||
}
|
||||
|
||||
// Save result for postfix expressions.
|
||||
if (expr->is_postfix()) {
|
||||
@ -5093,6 +5095,9 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
|
||||
patch_site.EmitPatchInfo();
|
||||
__ bind(&done);
|
||||
|
||||
if (is_strong(language_mode())) {
|
||||
PrepareForBailoutForId(expr->ToNumberId(), TOS_REG);
|
||||
}
|
||||
// Store the value returned in r3.
|
||||
switch (assign_type) {
|
||||
case VARIABLE:
|
||||
|
@ -211,7 +211,7 @@ COMPARE_STRONG = function COMPARE_STRONG(x, ncr) {
|
||||
if (IS_STRING(this) && IS_STRING(x)) return %_StringCompare(this, x);
|
||||
if (IS_NUMBER(this) && IS_NUMBER(x)) return %NumberCompare(this, x, ncr);
|
||||
|
||||
throw %MakeTypeError(kStrongImplicitCast);
|
||||
throw %MakeTypeError(kStrongImplicitConversion);
|
||||
}
|
||||
|
||||
|
||||
@ -246,7 +246,7 @@ ADD_STRONG = function ADD_STRONG(x) {
|
||||
if (IS_NUMBER(this) && IS_NUMBER(x)) return %NumberAdd(this, x);
|
||||
if (IS_STRING(this) && IS_STRING(x)) return %_StringAdd(this, x);
|
||||
|
||||
throw %MakeTypeError(kStrongImplicitCast);
|
||||
throw %MakeTypeError(kStrongImplicitConversion);
|
||||
}
|
||||
|
||||
|
||||
@ -270,7 +270,7 @@ STRING_ADD_LEFT_STRONG = function STRING_ADD_LEFT_STRONG(y) {
|
||||
if (IS_STRING(y)) {
|
||||
return %_StringAdd(this, y);
|
||||
}
|
||||
throw %MakeTypeError(kStrongImplicitCast);
|
||||
throw %MakeTypeError(kStrongImplicitConversion);
|
||||
}
|
||||
|
||||
|
||||
@ -295,7 +295,7 @@ STRING_ADD_RIGHT_STRONG = function STRING_ADD_RIGHT_STRONG(y) {
|
||||
if (IS_STRING(this)) {
|
||||
return %_StringAdd(this, y);
|
||||
}
|
||||
throw %MakeTypeError(kStrongImplicitCast);
|
||||
throw %MakeTypeError(kStrongImplicitConversion);
|
||||
}
|
||||
|
||||
|
||||
@ -312,7 +312,7 @@ SUB_STRONG = function SUB_STRONG(y) {
|
||||
if (IS_NUMBER(this) && IS_NUMBER(y)) {
|
||||
return %NumberSub(this, y);
|
||||
}
|
||||
throw %MakeTypeError(kStrongImplicitCast);
|
||||
throw %MakeTypeError(kStrongImplicitConversion);
|
||||
}
|
||||
|
||||
|
||||
@ -329,7 +329,7 @@ MUL_STRONG = function MUL_STRONG(y) {
|
||||
if (IS_NUMBER(this) && IS_NUMBER(y)) {
|
||||
return %NumberMul(this, y);
|
||||
}
|
||||
throw %MakeTypeError(kStrongImplicitCast);
|
||||
throw %MakeTypeError(kStrongImplicitConversion);
|
||||
}
|
||||
|
||||
|
||||
@ -346,7 +346,7 @@ DIV_STRONG = function DIV_STRONG(y) {
|
||||
if (IS_NUMBER(this) && IS_NUMBER(y)) {
|
||||
return %NumberDiv(this, y);
|
||||
}
|
||||
throw %MakeTypeError(kStrongImplicitCast);
|
||||
throw %MakeTypeError(kStrongImplicitConversion);
|
||||
}
|
||||
|
||||
|
||||
@ -363,7 +363,7 @@ MOD_STRONG = function MOD_STRONG(y) {
|
||||
if (IS_NUMBER(this) && IS_NUMBER(y)) {
|
||||
return %NumberMod(this, y);
|
||||
}
|
||||
throw %MakeTypeError(kStrongImplicitCast);
|
||||
throw %MakeTypeError(kStrongImplicitConversion);
|
||||
}
|
||||
|
||||
|
||||
@ -385,7 +385,7 @@ BIT_OR_STRONG = function BIT_OR_STRONG(y) {
|
||||
if (IS_NUMBER(this) && IS_NUMBER(y)) {
|
||||
return %NumberOr(this, y);
|
||||
}
|
||||
throw %MakeTypeError(kStrongImplicitCast);
|
||||
throw %MakeTypeError(kStrongImplicitConversion);
|
||||
}
|
||||
|
||||
|
||||
@ -416,7 +416,7 @@ BIT_AND_STRONG = function BIT_AND_STRONG(y) {
|
||||
if (IS_NUMBER(this) && IS_NUMBER(y)) {
|
||||
return %NumberAnd(this, y);
|
||||
}
|
||||
throw %MakeTypeError(kStrongImplicitCast);
|
||||
throw %MakeTypeError(kStrongImplicitConversion);
|
||||
}
|
||||
|
||||
|
||||
@ -433,7 +433,7 @@ BIT_XOR_STRONG = function BIT_XOR_STRONG(y) {
|
||||
if (IS_NUMBER(this) && IS_NUMBER(y)) {
|
||||
return %NumberXor(this, y);
|
||||
}
|
||||
throw %MakeTypeError(kStrongImplicitCast);
|
||||
throw %MakeTypeError(kStrongImplicitConversion);
|
||||
}
|
||||
|
||||
|
||||
@ -450,7 +450,7 @@ SHL_STRONG = function SHL_STRONG(y) {
|
||||
if (IS_NUMBER(this) && IS_NUMBER(y)) {
|
||||
return %NumberShl(this, y);
|
||||
}
|
||||
throw %MakeTypeError(kStrongImplicitCast);
|
||||
throw %MakeTypeError(kStrongImplicitConversion);
|
||||
}
|
||||
|
||||
|
||||
@ -481,7 +481,7 @@ SAR_STRONG = function SAR_STRONG(y) {
|
||||
if (IS_NUMBER(this) && IS_NUMBER(y)) {
|
||||
return %NumberSar(this, y);
|
||||
}
|
||||
throw %MakeTypeError(kStrongImplicitCast);
|
||||
throw %MakeTypeError(kStrongImplicitConversion);
|
||||
}
|
||||
|
||||
|
||||
@ -498,7 +498,7 @@ SHR_STRONG = function SHR_STRONG(y) {
|
||||
if (IS_NUMBER(this) && IS_NUMBER(y)) {
|
||||
return %NumberShr(this, y);
|
||||
}
|
||||
throw %MakeTypeError(kStrongImplicitCast);
|
||||
throw %MakeTypeError(kStrongImplicitConversion);
|
||||
}
|
||||
|
||||
|
||||
|
@ -103,6 +103,14 @@ RUNTIME_FUNCTION(Runtime_ThrowIteratorResultNotAnObject) {
|
||||
}
|
||||
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_ThrowStrongModeImplicitConversion) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK(args.length() == 0);
|
||||
THROW_NEW_ERROR_RETURN_FAILURE(
|
||||
isolate, NewTypeError(MessageTemplate::kStrongImplicitConversion));
|
||||
}
|
||||
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_PromiseRejectEvent) {
|
||||
DCHECK(args.length() == 3);
|
||||
HandleScope scope(isolate);
|
||||
|
@ -300,6 +300,7 @@ namespace internal {
|
||||
F(NewSyntaxError, 2, 1) \
|
||||
F(NewReferenceError, 2, 1) \
|
||||
F(ThrowIteratorResultNotAnObject, 1, 1) \
|
||||
F(ThrowStrongModeImplicitConversion, 0, 1) \
|
||||
F(PromiseRejectEvent, 3, 1) \
|
||||
F(PromiseRevokeReject, 1, 1) \
|
||||
F(PromiseHasHandlerSymbol, 0, 1) \
|
||||
|
@ -4981,10 +4981,11 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
|
||||
__ jmp(&stub_call, Label::kNear);
|
||||
__ bind(&slow);
|
||||
}
|
||||
|
||||
ToNumberStub convert_stub(isolate());
|
||||
__ CallStub(&convert_stub);
|
||||
PrepareForBailoutForId(expr->ToNumberId(), TOS_REG);
|
||||
if (!is_strong(language_mode())) {
|
||||
ToNumberStub convert_stub(isolate());
|
||||
__ CallStub(&convert_stub);
|
||||
PrepareForBailoutForId(expr->ToNumberId(), TOS_REG);
|
||||
}
|
||||
|
||||
// Save result for postfix expressions.
|
||||
if (expr->is_postfix()) {
|
||||
@ -5025,6 +5026,9 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
|
||||
patch_site.EmitPatchInfo();
|
||||
__ bind(&done);
|
||||
|
||||
if (is_strong(language_mode())) {
|
||||
PrepareForBailoutForId(expr->ToNumberId(), TOS_REG);
|
||||
}
|
||||
// Store the value returned in rax.
|
||||
switch (assign_type) {
|
||||
case VARIABLE:
|
||||
|
@ -4943,9 +4943,11 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
|
||||
__ jmp(&stub_call, Label::kNear);
|
||||
__ bind(&slow);
|
||||
}
|
||||
ToNumberStub convert_stub(isolate());
|
||||
__ CallStub(&convert_stub);
|
||||
PrepareForBailoutForId(expr->ToNumberId(), TOS_REG);
|
||||
if (!is_strong(language_mode())) {
|
||||
ToNumberStub convert_stub(isolate());
|
||||
__ CallStub(&convert_stub);
|
||||
PrepareForBailoutForId(expr->ToNumberId(), TOS_REG);
|
||||
}
|
||||
|
||||
// Save result for postfix expressions.
|
||||
if (expr->is_postfix()) {
|
||||
@ -4986,6 +4988,9 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
|
||||
patch_site.EmitPatchInfo();
|
||||
__ bind(&done);
|
||||
|
||||
if (is_strong(language_mode())) {
|
||||
PrepareForBailoutForId(expr->ToNumberId(), TOS_REG);
|
||||
}
|
||||
// Store the value returned in eax.
|
||||
switch (assign_type) {
|
||||
case VARIABLE:
|
||||
|
203
test/mjsunit/strong/implicit-conversions-constants.js
Normal file
203
test/mjsunit/strong/implicit-conversions-constants.js
Normal file
@ -0,0 +1,203 @@
|
||||
// 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";
|
||||
|
||||
function getTestFuncs() {
|
||||
"use strong";
|
||||
return [
|
||||
function(x){return 1 + true;},
|
||||
function(x){return 1 - true;},
|
||||
function(x){return 1 * true;},
|
||||
function(x){return 1 / true;},
|
||||
function(x){return 1 % true;},
|
||||
function(x){return 1 | true;},
|
||||
function(x){return 1 & true;},
|
||||
function(x){return 1 ^ true;},
|
||||
function(x){return 1 << true;},
|
||||
function(x){return 1 >> true;},
|
||||
function(x){return 1 >>> true;},
|
||||
function(x){return 1 < true;},
|
||||
function(x){return 1 > true;},
|
||||
function(x){return 1 <= true;},
|
||||
function(x){return 1 >= true;},
|
||||
function(x){return 1 + undefined;},
|
||||
function(x){return 1 - undefined;},
|
||||
function(x){return 1 * undefined;},
|
||||
function(x){return 1 / undefined;},
|
||||
function(x){return 1 % undefined;},
|
||||
function(x){return 1 | undefined;},
|
||||
function(x){return 1 & undefined;},
|
||||
function(x){return 1 ^ undefined;},
|
||||
function(x){return 1 << undefined;},
|
||||
function(x){return 1 >> undefined;},
|
||||
function(x){return 1 >>> undefined;},
|
||||
function(x){return 1 < undefined;},
|
||||
function(x){return 1 > undefined;},
|
||||
function(x){return 1 <= undefined;},
|
||||
function(x){return 1 >= undefined;},
|
||||
function(x){return 1 + null;},
|
||||
function(x){return 1 - null;},
|
||||
function(x){return 1 * null;},
|
||||
function(x){return 1 / null;},
|
||||
function(x){return 1 % null;},
|
||||
function(x){return 1 | null;},
|
||||
function(x){return 1 & null;},
|
||||
function(x){return 1 ^ null;},
|
||||
function(x){return 1 << null;},
|
||||
function(x){return 1 >> null;},
|
||||
function(x){return 1 >>> null;},
|
||||
function(x){return 1 < null;},
|
||||
function(x){return 1 > null;},
|
||||
function(x){return 1 <= null;},
|
||||
function(x){return 1 >= null;},
|
||||
function(x){return NaN + true;},
|
||||
function(x){return NaN - true;},
|
||||
function(x){return NaN * true;},
|
||||
function(x){return NaN / true;},
|
||||
function(x){return NaN % true;},
|
||||
function(x){return NaN | true;},
|
||||
function(x){return NaN & true;},
|
||||
function(x){return NaN ^ true;},
|
||||
function(x){return NaN << true;},
|
||||
function(x){return NaN >> true;},
|
||||
function(x){return NaN >>> true;},
|
||||
function(x){return NaN < true;},
|
||||
function(x){return NaN > true;},
|
||||
function(x){return NaN <= true;},
|
||||
function(x){return NaN >= true;},
|
||||
function(x){return NaN + undefined;},
|
||||
function(x){return NaN - undefined;},
|
||||
function(x){return NaN * undefined;},
|
||||
function(x){return NaN / undefined;},
|
||||
function(x){return NaN % undefined;},
|
||||
function(x){return NaN | undefined;},
|
||||
function(x){return NaN & undefined;},
|
||||
function(x){return NaN ^ undefined;},
|
||||
function(x){return NaN << undefined;},
|
||||
function(x){return NaN >> undefined;},
|
||||
function(x){return NaN >>> undefined;},
|
||||
function(x){return NaN < undefined;},
|
||||
function(x){return NaN > undefined;},
|
||||
function(x){return NaN <= undefined;},
|
||||
function(x){return NaN >= undefined;},
|
||||
function(x){return NaN + null;},
|
||||
function(x){return NaN - null;},
|
||||
function(x){return NaN * null;},
|
||||
function(x){return NaN / null;},
|
||||
function(x){return NaN % null;},
|
||||
function(x){return NaN | null;},
|
||||
function(x){return NaN & null;},
|
||||
function(x){return NaN ^ null;},
|
||||
function(x){return NaN << null;},
|
||||
function(x){return NaN >> null;},
|
||||
function(x){return NaN >>> null;},
|
||||
function(x){return NaN < null;},
|
||||
function(x){return NaN > null;},
|
||||
function(x){return NaN <= null;},
|
||||
function(x){return NaN >= null;},
|
||||
function(x){return true + 1;},
|
||||
function(x){return true - 1;},
|
||||
function(x){return true * 1;},
|
||||
function(x){return true / 1;},
|
||||
function(x){return true % 1;},
|
||||
function(x){return true | 1;},
|
||||
function(x){return true & 1;},
|
||||
function(x){return true ^ 1;},
|
||||
function(x){return true << 1;},
|
||||
function(x){return true >> 1;},
|
||||
function(x){return true >>> 1;},
|
||||
function(x){return true < 1;},
|
||||
function(x){return true > 1;},
|
||||
function(x){return true <= 1;},
|
||||
function(x){return true >= 1;},
|
||||
function(x){return undefined + 1;},
|
||||
function(x){return undefined - 1;},
|
||||
function(x){return undefined * 1;},
|
||||
function(x){return undefined / 1;},
|
||||
function(x){return undefined % 1;},
|
||||
function(x){return undefined | 1;},
|
||||
function(x){return undefined & 1;},
|
||||
function(x){return undefined ^ 1;},
|
||||
function(x){return undefined << 1;},
|
||||
function(x){return undefined >> 1;},
|
||||
function(x){return undefined >>> 1;},
|
||||
function(x){return undefined < 1;},
|
||||
function(x){return undefined > 1;},
|
||||
function(x){return undefined <= 1;},
|
||||
function(x){return undefined >= 1;},
|
||||
function(x){return null + 1;},
|
||||
function(x){return null - 1;},
|
||||
function(x){return null * 1;},
|
||||
function(x){return null / 1;},
|
||||
function(x){return null % 1;},
|
||||
function(x){return null | 1;},
|
||||
function(x){return null & 1;},
|
||||
function(x){return null ^ 1;},
|
||||
function(x){return null << 1;},
|
||||
function(x){return null >> 1;},
|
||||
function(x){return null >>> 1;},
|
||||
function(x){return null < 1;},
|
||||
function(x){return null > 1;},
|
||||
function(x){return null <= 1;},
|
||||
function(x){return null >= 1;},
|
||||
function(x){return true + NaN;},
|
||||
function(x){return true - NaN;},
|
||||
function(x){return true * NaN;},
|
||||
function(x){return true / NaN;},
|
||||
function(x){return true % NaN;},
|
||||
function(x){return true | NaN;},
|
||||
function(x){return true & NaN;},
|
||||
function(x){return true ^ NaN;},
|
||||
function(x){return true << NaN;},
|
||||
function(x){return true >> NaN;},
|
||||
function(x){return true >>> NaN;},
|
||||
function(x){return true < NaN;},
|
||||
function(x){return true > NaN;},
|
||||
function(x){return true <= NaN;},
|
||||
function(x){return true >= NaN;},
|
||||
function(x){return undefined + NaN;},
|
||||
function(x){return undefined - NaN;},
|
||||
function(x){return undefined * NaN;},
|
||||
function(x){return undefined / NaN;},
|
||||
function(x){return undefined % NaN;},
|
||||
function(x){return undefined | NaN;},
|
||||
function(x){return undefined & NaN;},
|
||||
function(x){return undefined ^ NaN;},
|
||||
function(x){return undefined << NaN;},
|
||||
function(x){return undefined >> NaN;},
|
||||
function(x){return undefined >>> NaN;},
|
||||
function(x){return undefined < NaN;},
|
||||
function(x){return undefined > NaN;},
|
||||
function(x){return undefined <= NaN;},
|
||||
function(x){return undefined >= NaN;},
|
||||
function(x){return null + NaN;},
|
||||
function(x){return null - NaN;},
|
||||
function(x){return null * NaN;},
|
||||
function(x){return null / NaN;},
|
||||
function(x){return null % NaN;},
|
||||
function(x){return null | NaN;},
|
||||
function(x){return null & NaN;},
|
||||
function(x){return null ^ NaN;},
|
||||
function(x){return null << NaN;},
|
||||
function(x){return null >> NaN;},
|
||||
function(x){return null >>> NaN;},
|
||||
function(x){return null < NaN;},
|
||||
function(x){return null > NaN;},
|
||||
function(x){return null <= NaN;},
|
||||
function(x){return null >= NaN;}
|
||||
];
|
||||
}
|
||||
|
||||
for (let func of getTestFuncs()) {
|
||||
assertThrows(func, TypeError);
|
||||
assertThrows(func, TypeError);
|
||||
assertThrows(func, TypeError);
|
||||
%OptimizeFunctionOnNextCall(func);
|
||||
assertThrows(func, TypeError);
|
||||
%DeoptimizeFunction(func);
|
||||
assertThrows(func, TypeError);
|
||||
}
|
168
test/mjsunit/strong/implicit-conversions-count.js
Normal file
168
test/mjsunit/strong/implicit-conversions-count.js
Normal file
@ -0,0 +1,168 @@
|
||||
// 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";
|
||||
|
||||
function pre_inc(x) {
|
||||
return ++x;
|
||||
}
|
||||
|
||||
function post_inc(x) {
|
||||
return x++;
|
||||
}
|
||||
|
||||
function pre_dec(x) {
|
||||
return --x;
|
||||
}
|
||||
|
||||
function post_dec(x) {
|
||||
return x--;
|
||||
}
|
||||
|
||||
function getTestFuncs() {
|
||||
return [
|
||||
function(x){
|
||||
"use strong";
|
||||
let y = x;
|
||||
assertEquals(++y, pre_inc(x));
|
||||
try {
|
||||
assertEquals(x+1, y)
|
||||
} catch (e) {
|
||||
assertUnreachable();
|
||||
}
|
||||
},
|
||||
function(x){
|
||||
"use strong";
|
||||
let y = x;
|
||||
assertEquals(y++, post_inc(x));
|
||||
try {
|
||||
assertEquals(x+1, y)
|
||||
} catch (e) {
|
||||
assertUnreachable();
|
||||
}
|
||||
},
|
||||
function(x){
|
||||
"use strong";
|
||||
let y = x;
|
||||
assertEquals(--y, pre_dec(x));
|
||||
try {
|
||||
assertEquals(x-1, y)
|
||||
} catch (e) {
|
||||
assertUnreachable();
|
||||
}
|
||||
},
|
||||
function(x){
|
||||
"use strong";
|
||||
let y = x;
|
||||
assertEquals(y--, post_dec(x));
|
||||
try {
|
||||
assertEquals(x-1, y)
|
||||
} catch (e) {
|
||||
assertUnreachable();
|
||||
}
|
||||
},
|
||||
function(x){
|
||||
"use strong";
|
||||
let obj = { foo: x };
|
||||
let y = ++obj.foo;
|
||||
assertEquals(y, pre_inc(x));
|
||||
try {
|
||||
assertEquals(x+1, obj.foo)
|
||||
} catch (e) {
|
||||
assertUnreachable();
|
||||
}
|
||||
},
|
||||
function(x){
|
||||
"use strong";
|
||||
let obj = { foo: x };
|
||||
let y = obj.foo++;
|
||||
assertEquals(y, post_inc(x));
|
||||
try {
|
||||
assertEquals(x+1, obj.foo)
|
||||
} catch (e) {
|
||||
assertUnreachable();
|
||||
}
|
||||
},
|
||||
function(x){
|
||||
"use strong";
|
||||
let obj = { foo: x };
|
||||
let y = --obj.foo;
|
||||
assertEquals(y, pre_dec(x));
|
||||
try {
|
||||
assertEquals(x-1, obj.foo)
|
||||
} catch (e) {
|
||||
assertUnreachable();
|
||||
}
|
||||
},
|
||||
function(x){
|
||||
"use strong";
|
||||
let obj = { foo: x };
|
||||
let y = obj.foo--;
|
||||
assertEquals(y, post_dec(x));
|
||||
try {
|
||||
assertEquals(x-1, obj.foo)
|
||||
} catch (e) {
|
||||
assertUnreachable();
|
||||
}
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
let nonNumberValues = [
|
||||
{},
|
||||
(function(){}),
|
||||
[],
|
||||
(class Foo {}),
|
||||
"",
|
||||
"foo",
|
||||
"NaN",
|
||||
Object(""),
|
||||
false,
|
||||
null,
|
||||
undefined
|
||||
];
|
||||
|
||||
// Check prior input of None works
|
||||
for (let func of getTestFuncs()) {
|
||||
for (let value of nonNumberValues) {
|
||||
assertThrows(function(){func(value)}, TypeError);
|
||||
assertThrows(function(){func(value)}, TypeError);
|
||||
assertThrows(function(){func(value)}, TypeError);
|
||||
%OptimizeFunctionOnNextCall(func);
|
||||
assertThrows(function(){func(value)}, TypeError);
|
||||
%DeoptimizeFunction(func);
|
||||
}
|
||||
}
|
||||
|
||||
// Check prior input of Smi works
|
||||
for (let func of getTestFuncs()) {
|
||||
func(1);
|
||||
func(1);
|
||||
func(1);
|
||||
for (let value of nonNumberValues) {
|
||||
assertThrows(function(){func(value)}, TypeError);
|
||||
assertThrows(function(){func(value)}, TypeError);
|
||||
assertThrows(function(){func(value)}, TypeError);
|
||||
%OptimizeFunctionOnNextCall(func);
|
||||
assertThrows(function(){func(value)}, TypeError);
|
||||
%DeoptimizeFunction(func);
|
||||
}
|
||||
}
|
||||
|
||||
// Check prior input of Number works
|
||||
for (let func of getTestFuncs()) {
|
||||
func(9999999999999);
|
||||
func(9999999999999);
|
||||
func(9999999999999);
|
||||
for (let value of nonNumberValues) {
|
||||
assertThrows(function(){func(value)}, TypeError);
|
||||
assertThrows(function(){func(value)}, TypeError);
|
||||
assertThrows(function(){func(value)}, TypeError);
|
||||
%OptimizeFunctionOnNextCall(func);
|
||||
assertThrows(function(){func(value)}, TypeError);
|
||||
%DeoptimizeFunction(func);
|
||||
}
|
||||
}
|
@ -61,23 +61,17 @@ let numberValues = [
|
||||
"0",
|
||||
"(-0)",
|
||||
"1",
|
||||
"0.79",
|
||||
"(-0.79)",
|
||||
"4294967295",
|
||||
"4294967296",
|
||||
"(-4294967295)",
|
||||
"(-4294967296)",
|
||||
"9999999999999",
|
||||
"(-9999999999999)",
|
||||
"1.5e10",
|
||||
"(-1.5e10)",
|
||||
"0xFFF",
|
||||
"(-0xFFF)",
|
||||
"NaN",
|
||||
"Infinity",
|
||||
"(-Infinity)"
|
||||
];
|
||||
|
||||
//******************************************************************************
|
||||
// Relational comparison function declarations
|
||||
function add_strong(x, y) {
|
||||
"use strong";
|
||||
return x + y;
|
||||
@ -253,6 +247,18 @@ function typed_greater_equal_strong(x, y) {
|
||||
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,
|
||||
@ -332,44 +338,75 @@ for (let op of strongUnops) {
|
||||
|
||||
for (let func of strongNumberFuncs) {
|
||||
// Check IC None*None->None throws
|
||||
assertThrows(function(){func(2, "foo");}, TypeError);
|
||||
%OptimizeFunctionOnNextCall(func);
|
||||
assertThrows(function(){func(2, "foo");}, TypeError);
|
||||
%DeoptimizeFunction(func);
|
||||
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
|
||||
assertThrows(function(){func(2, "foo");}, TypeError);
|
||||
%OptimizeFunctionOnNextCall(func);
|
||||
assertThrows(function(){func(2, "foo");}, TypeError);
|
||||
%DeoptimizeFunction(func);
|
||||
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
|
||||
assertThrows(function(){func(2, "foo");}, TypeError);
|
||||
%OptimizeFunctionOnNextCall(func);
|
||||
assertThrows(function(){func(2, "foo");}, TypeError);
|
||||
%DeoptimizeFunction(func);
|
||||
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
|
||||
assertThrows(function(){func(2, "foo");}, TypeError);
|
||||
%OptimizeFunctionOnNextCall(func);
|
||||
assertThrows(function(){func(2, "foo");}, TypeError);
|
||||
%DeoptimizeFunction(func);
|
||||
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
|
||||
assertThrows(function(){func(2, "foo");}, TypeError);
|
||||
%OptimizeFunctionOnNextCall(func);
|
||||
assertThrows(function(){func(2, "foo");}, TypeError);
|
||||
%DeoptimizeFunction(func);
|
||||
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
|
||||
assertThrows(function(){func(2, "foo");}, TypeError);
|
||||
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);
|
||||
assertThrows(function(){func(2, "foo");}, TypeError);
|
||||
assertDoesNotThrow(function(){func(2, undefined)});
|
||||
%DeoptimizeFunction(func);
|
||||
assertDoesNotThrow(function(){func(true, {})});
|
||||
assertDoesNotThrow(function(){func(true, {})});
|
||||
%OptimizeFunctionOnNextCall(func);
|
||||
assertDoesNotThrow(function(){func(true, {})});
|
||||
%DeoptimizeFunction(func);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user