BailoutId RightId() const { return right_id_; }
TypeFeedbackId BinaryOperationFeedbackId() const { return reuse(id()); }
+ Maybe<int> fixed_right_arg() const { return fixed_right_arg_; }
+ void set_fixed_right_arg(Maybe<int> arg) { fixed_right_arg_ = arg; }
virtual void RecordToBooleanTypeFeedback(
TypeFeedbackOracle* oracle) V8_OVERRIDE;
Expression* left_;
Expression* right_;
+ // TODO(rossberg): the fixed arg should probably be represented as a Constant
+ // type for the RHS.
+ Maybe<int> fixed_right_arg_;
+
// The short-circuit logical operations need an AST ID for their
// right-hand subexpression.
const BailoutId right_id_;
Push(BuildBinaryOperation(
state.op(), left, right,
handle(Type::String(), isolate()), right_type,
- result_type));
+ result_type, state.fixed_right_arg()));
}
if_leftisstring.Else();
{
Push(BuildBinaryOperation(
state.op(), left, right,
- left_type, right_type, result_type));
+ left_type, right_type, result_type,
+ state.fixed_right_arg()));
}
if_leftisstring.End();
result = Pop();
Push(BuildBinaryOperation(
state.op(), left, right,
left_type, handle(Type::String(), isolate()),
- result_type));
+ result_type, state.fixed_right_arg()));
}
if_rightisstring.Else();
{
Push(BuildBinaryOperation(
state.op(), left, right,
- left_type, right_type, result_type));
+ left_type, right_type, result_type,
+ state.fixed_right_arg()));
}
if_rightisstring.End();
result = Pop();
} else {
result = BuildBinaryOperation(
state.op(), left, right,
- left_type, right_type, result_type);
+ left_type, right_type, result_type,
+ state.fixed_right_arg());
}
// If we encounter a generic argument, the number conversion is
Handle<Type> left_type = expr->left()->bounds().lower;
Handle<Type> right_type = expr->right()->bounds().lower;
Handle<Type> result_type = expr->bounds().lower;
+ Maybe<int> fixed_right_arg = expr->fixed_right_arg();
HValue* result = HGraphBuilder::BuildBinaryOperation(
- expr->op(), left, right, left_type, right_type, result_type);
+ expr->op(), left, right, left_type, right_type,
+ result_type, fixed_right_arg);
// Add a simulate after instructions with observable side effects, and
// after phis, which are the result of BuildBinaryOperation when we
// inlined some complex subgraph.
HValue* right,
Handle<Type> left_type,
Handle<Type> right_type,
- Handle<Type> result_type) {
+ Handle<Type> result_type,
+ Maybe<int> fixed_right_arg) {
Representation left_rep = Representation::FromType(left_type);
Representation right_rep = Representation::FromType(right_type);
+ bool maybe_string_add = op == Token::ADD &&
+ (left_type->Maybe(Type::String()) ||
+ right_type->Maybe(Type::String()));
+
if (left_type->Is(Type::None())) {
Add<HDeoptimize>("Insufficient type feedback for LHS of binary operation",
Deoptimizer::SOFT);
// TODO(rossberg): we should be able to get rid of non-continuous
// defaults.
left_type = handle(Type::Any(), isolate());
- } else if (left_type->IsConstant()) {
- HConstant* c_left = Add<HConstant>(left_type->AsConstant());
- IfBuilder if_same(this);
- if (c_left->HasDoubleValue()) {
- if_same.If<HCompareNumericAndBranch>(left, c_left, Token::EQ);
- } else {
- if_same.If<HCompareObjectEqAndBranch>(left, c_left);
- }
- if_same.Then();
- if_same.ElseDeopt("Unexpected LHS of binary operation");
- left = c_left;
+ } else {
+ if (!maybe_string_add) left = TruncateToNumber(left, &left_type);
+ left_rep = Representation::FromType(left_type);
}
if (right_type->Is(Type::None())) {
Add<HDeoptimize>("Insufficient type feedback for RHS of binary operation",
Deoptimizer::SOFT);
right_type = handle(Type::Any(), isolate());
- } else if (right_type->IsConstant()) {
- HConstant* c_right = Add<HConstant>(right_type->AsConstant());
- IfBuilder if_same(this);
- if (c_right->HasDoubleValue()) {
- if_same.If<HCompareNumericAndBranch>(right, c_right, Token::EQ);
- } else {
- if_same.If<HCompareObjectEqAndBranch>(right, c_right);
- }
- if_same.Then();
- if_same.ElseDeopt("Unexpected RHS of binary operation");
- right = c_right;
+ } else {
+ if (!maybe_string_add) right = TruncateToNumber(right, &right_type);
+ right_rep = Representation::FromType(right_type);
}
// Special case for string addition here.
return AddUncasted<HStringAdd>(left, right, STRING_ADD_CHECK_NONE);
}
- left = TruncateToNumber(left, &left_type);
- left_rep = Representation::FromType(left_type);
- right = TruncateToNumber(right, &right_type);
- right_rep = Representation::FromType(right_type);
-
if (graph()->info()->IsStub()) {
left = EnforceNumberType(left, left_type);
right = EnforceNumberType(right, right_type);
instr = AddUncasted<HMul>(left, right);
break;
case Token::MOD: {
+ if (fixed_right_arg.has_value) {
+ if (right->IsConstant()) {
+ HConstant* c_right = HConstant::cast(right);
+ if (c_right->HasInteger32Value()) {
+ ASSERT_EQ(fixed_right_arg.value, c_right->Integer32Value());
+ }
+ } else {
+ HConstant* fixed_right = Add<HConstant>(
+ static_cast<int>(fixed_right_arg.value));
+ IfBuilder if_same(this);
+ if_same.If<HCompareNumericAndBranch>(right, fixed_right, Token::EQ);
+ if_same.Then();
+ if_same.ElseDeopt("Unexpected RHS of binary operation");
+ right = fixed_right;
+ }
+ }
instr = AddUncasted<HMod>(left, right);
break;
}
HValue* right,
Handle<Type> left_type,
Handle<Type> right_type,
- Handle<Type> result_type);
+ Handle<Type> result_type,
+ Maybe<int> fixed_right_arg);
HLoadNamedField* AddLoadFixedArrayLength(HValue *object);
1 << FixedRightArgValueField::decode(extra_ic_state));
left_kind_ = LeftKindField::decode(extra_ic_state);
if (fixed_right_arg_.has_value) {
- // We have only 4 bits to encode the log2 of the fixed right arg, so the
- // max value is 2^(2^4), which is always a SMI.
- ASSERT(Smi::IsValid(fixed_right_arg_.value));
- right_kind_ = SMI;
+ right_kind_ = Smi::IsValid(fixed_right_arg_.value) ? SMI : INT32;
} else {
right_kind_ = RightKindField::decode(extra_ic_state);
}
}
-Handle<Type> BinaryOpIC::State::GetRightType(Isolate* isolate) const {
- if (fixed_right_arg_.has_value) {
- Handle<Smi> value = handle(Smi::FromInt(fixed_right_arg_.value), isolate);
- Handle<Type> type = handle(Type::Constant(value, isolate), isolate);
- ASSERT(type->Is(KindToType(right_kind_, isolate)));
- return type;
- }
- return KindToType(right_kind_, isolate);
-}
-
-
Handle<Type> BinaryOpIC::State::GetResultType(Isolate* isolate) const {
Kind result_kind = result_kind_;
if (HasSideEffects()) {
Token::Value op() const { return op_; }
OverwriteMode mode() const { return mode_; }
+ Maybe<int> fixed_right_arg() const { return fixed_right_arg_; }
Handle<Type> GetLeftType(Isolate* isolate) const {
return KindToType(left_kind_, isolate);
}
- Handle<Type> GetRightType(Isolate* isolate) const;
+ Handle<Type> GetRightType(Isolate* isolate) const {
+ return KindToType(right_kind_, isolate);
+ }
Handle<Type> GetResultType(Isolate* isolate) const;
void Print(StringStream* stream) const;
Handle<Type>* left,
Handle<Type>* right,
Handle<Type>* result,
+ Maybe<int>* fixed_right_arg,
Token::Value op) {
Handle<Object> object = GetInfo(id);
if (!object->IsCode()) {
ASSERT(op < BinaryOpIC::State::FIRST_TOKEN ||
op > BinaryOpIC::State::LAST_TOKEN);
*left = *right = *result = handle(Type::None(), isolate_);
+ *fixed_right_arg = Maybe<int>();
return;
}
Handle<Code> code = Handle<Code>::cast(object);
*left = state.GetLeftType(isolate());
*right = state.GetRightType(isolate());
*result = state.GetResultType(isolate());
+ *fixed_right_arg = state.fixed_right_arg();
}
Handle<Type>* left,
Handle<Type>* right,
Handle<Type>* result,
+ Maybe<int>* fixed_right_arg,
Token::Value operation);
void CompareType(TypeFeedbackId id,
void AstTyper::VisitBinaryOperation(BinaryOperation* expr) {
// Collect type feedback.
Handle<Type> type, left_type, right_type;
+ Maybe<int> fixed_right_arg;
oracle()->BinaryType(expr->BinaryOperationFeedbackId(),
- &left_type, &right_type, &type, expr->op());
+ &left_type, &right_type, &type, &fixed_right_arg, expr->op());
NarrowLowerType(expr, type);
NarrowLowerType(expr->left(), left_type);
NarrowLowerType(expr->right(), right_type);
+ expr->set_fixed_right_arg(fixed_right_arg);
if (expr->op() == Token::OR || expr->op() == Token::AND) {
expr->left()->RecordToBooleanTypeFeedback(oracle());
}