void BinaryOpStub::GenerateSmiStub(MacroAssembler* masm) {
Label right_arg_changed, call_runtime;
- if (op_ == Token::MOD && has_fixed_right_arg_) {
+ if (op_ == Token::MOD && encoded_right_arg_.has_value) {
// It is guaranteed that the value will fit into a Smi, because if it
// didn't, we wouldn't be here, see BinaryOp_Patch.
__ cmp(r0, Operand(Smi::FromInt(fixed_right_arg_value())));
// to type transition.
} else {
- if (has_fixed_right_arg_) {
+ if (encoded_right_arg_.has_value) {
__ Vmov(d8, fixed_right_arg_value(), scratch1);
__ VFPCompareAndSetFlags(d1, d8);
__ b(ne, &transition);
instr->CheckFlag(HValue::kBailoutOnMinusZero))
? AssignEnvironment(result)
: result;
- } else if (instr->has_fixed_right_arg()) {
+ } else if (instr->fixed_right_arg().has_value) {
LModI* mod = new(zone()) LModI(UseRegisterAtStart(left),
UseRegisterAtStart(right));
return AssignEnvironment(DefineAsRegister(mod));
__ and_(result_reg, left_reg, Operand(divisor - 1));
__ bind(&done);
- } else if (hmod->has_fixed_right_arg()) {
+ } else if (hmod->fixed_right_arg().has_value) {
Register left_reg = ToRegister(instr->left());
Register right_reg = ToRegister(instr->right());
Register result_reg = ToRegister(instr->result());
- int32_t divisor = hmod->fixed_right_arg_value();
+ int32_t divisor = hmod->fixed_right_arg().value;
ASSERT(IsPowerOf2(divisor));
// Check if our assumption of a fixed right operand still holds.
// ----------------------------------------------------------------------------
// Recording of type feedback
+// TODO(rossberg): all RecordTypeFeedback functions should disappear
+// once we use the common type field in the AST consistently.
+
+
void ForInStatement::RecordTypeFeedback(TypeFeedbackOracle* oracle) {
for_in_type_ = static_cast<ForInType>(oracle->ForInType(this));
}
}
-void UnaryOperation::RecordTypeFeedback(TypeFeedbackOracle* oracle) {
- type_ = oracle->UnaryType(UnaryOperationFeedbackId());
-}
-
-
-void BinaryOperation::RecordTypeFeedback(TypeFeedbackOracle* oracle) {
- oracle->BinaryType(BinaryOperationFeedbackId(),
- &left_type_, &right_type_, &result_type_,
- &has_fixed_right_arg_, &fixed_right_arg_value_);
-}
-
-
-// TODO(rossberg): this function (and all other RecordTypeFeedback functions)
-// should disappear once we use the common type field in the AST consistently.
-void CompareOperation::RecordTypeFeedback(TypeFeedbackOracle* oracle) {
- oracle->CompareTypes(CompareOperationFeedbackId(),
- &left_type_, &right_type_, &overall_type_, &compare_nil_type_);
-}
-
-
// ----------------------------------------------------------------------------
// Implementation of AstVisitor
// True iff the expression is the undefined literal.
bool IsUndefinedLiteral();
- // Expression type
- Handle<Type> type() { return type_; }
- void set_type(Handle<Type> type) { type_ = type; }
+ // Expression type bounds
+ Handle<Type> upper_type() { return upper_type_; }
+ Handle<Type> lower_type() { return lower_type_; }
+ void set_upper_type(Handle<Type> type) { upper_type_ = type; }
+ void set_lower_type(Handle<Type> type) { lower_type_ = type; }
// Type feedback information for assignments and properties.
virtual bool IsMonomorphic() {
protected:
explicit Expression(Isolate* isolate)
- : type_(Type::None(), isolate),
+ : upper_type_(Type::Any(), isolate),
+ lower_type_(Type::None(), isolate),
id_(GetNextId(isolate)),
test_id_(GetNextId(isolate)) {}
private:
- Handle<Type> type_;
+ Handle<Type> upper_type_;
+ Handle<Type> lower_type_;
byte to_boolean_types_;
const BailoutId id_;
BailoutId MaterializeFalseId() { return materialize_false_id_; }
TypeFeedbackId UnaryOperationFeedbackId() const { return reuse(id()); }
- void RecordTypeFeedback(TypeFeedbackOracle* oracle);
- Handle<Type> type() const { return type_; }
protected:
UnaryOperation(Isolate* isolate,
Expression* expression_;
int pos_;
- Handle<Type> type_;
-
// For unary not (Token::NOT), the AST ids where true and false will
// actually be materialized, respectively.
const BailoutId materialize_true_id_;
BailoutId RightId() const { return right_id_; }
TypeFeedbackId BinaryOperationFeedbackId() const { return reuse(id()); }
- void RecordTypeFeedback(TypeFeedbackOracle* oracle);
- Handle<Type> left_type() const { return left_type_; }
- Handle<Type> right_type() const { return right_type_; }
+ // TODO(rossberg): result_type should be subsumed by lower_type.
Handle<Type> result_type() const { return result_type_; }
- bool has_fixed_right_arg() const { return has_fixed_right_arg_; }
- int fixed_right_arg_value() const { return fixed_right_arg_value_; }
+ void set_result_type(Handle<Type> type) { result_type_ = type; }
+ Maybe<int> fixed_right_arg() const { return fixed_right_arg_; }
+ void set_fixed_right_arg(Maybe<int> arg) { fixed_right_arg_ = arg; }
protected:
BinaryOperation(Isolate* isolate,
Expression* right_;
int pos_;
- Handle<Type> left_type_;
- Handle<Type> right_type_;
Handle<Type> result_type_;
- bool has_fixed_right_arg_;
- int fixed_right_arg_value_;
+ // 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.
// Type feedback information.
TypeFeedbackId CompareOperationFeedbackId() const { return reuse(id()); }
- void RecordTypeFeedback(TypeFeedbackOracle* oracle);
- Handle<Type> left_type() const { return left_type_; }
- Handle<Type> right_type() const { return right_type_; }
- Handle<Type> overall_type() const { return overall_type_; }
- Handle<Type> compare_nil_type() const { return compare_nil_type_; }
+ Handle<Type> combined_type() const { return combined_type_; }
+ void set_combined_type(Handle<Type> type) { combined_type_ = type; }
// Match special cases.
bool IsLiteralCompareTypeof(Expression** expr, Handle<String>* check);
Expression* right_;
int pos_;
- Handle<Type> left_type_;
- Handle<Type> right_type_;
- Handle<Type> overall_type_;
- Handle<Type> compare_nil_type_;
+ Handle<Type> combined_type_;
};
left_type_(BinaryOpIC::UNINITIALIZED),
right_type_(BinaryOpIC::UNINITIALIZED),
result_type_(BinaryOpIC::UNINITIALIZED),
- has_fixed_right_arg_(false),
- encoded_right_arg_(encode_arg_value(1)) {
+ encoded_right_arg_(false, encode_arg_value(1)) {
Initialize();
ASSERT(OpBits::is_valid(Token::NUM_TOKENS));
}
BinaryOpIC::TypeInfo left_type,
BinaryOpIC::TypeInfo right_type,
BinaryOpIC::TypeInfo result_type,
- bool has_fixed_right_arg,
- int32_t fixed_right_arg_value)
+ Maybe<int32_t> fixed_right_arg)
: op_(OpBits::decode(key)),
mode_(ModeBits::decode(key)),
platform_specific_bit_(PlatformSpecificBits::decode(key)),
left_type_(left_type),
right_type_(right_type),
result_type_(result_type),
- has_fixed_right_arg_(has_fixed_right_arg),
- encoded_right_arg_(encode_arg_value(fixed_right_arg_value)) { }
+ encoded_right_arg_(fixed_right_arg.has_value,
+ encode_arg_value(fixed_right_arg.value)) { }
static void decode_types_from_minor_key(int minor_key,
BinaryOpIC::TypeInfo* left_type,
return static_cast<Token::Value>(OpBits::decode(minor_key));
}
- static bool decode_has_fixed_right_arg_from_minor_key(int minor_key) {
- return HasFixedRightArgBits::decode(minor_key);
- }
-
- static int decode_fixed_right_arg_value_from_minor_key(int minor_key) {
- return decode_arg_value(FixedRightArgValueBits::decode(minor_key));
+ static Maybe<int> decode_fixed_right_arg_from_minor_key(int minor_key) {
+ return Maybe<int>(
+ HasFixedRightArgBits::decode(minor_key),
+ decode_arg_value(FixedRightArgValueBits::decode(minor_key)));
}
int fixed_right_arg_value() const {
- return decode_arg_value(encoded_right_arg_);
+ return decode_arg_value(encoded_right_arg_.value);
}
static bool can_encode_arg_value(int32_t value) {
BinaryOpIC::TypeInfo right_type_;
BinaryOpIC::TypeInfo result_type_;
- bool has_fixed_right_arg_;
- int encoded_right_arg_;
+ Maybe<int> encoded_right_arg_;
static int encode_arg_value(int32_t value) {
ASSERT(can_encode_arg_value(value));
| LeftTypeBits::encode(left_type_)
| RightTypeBits::encode(right_type_)
| ResultTypeBits::encode(result_type_)
- | HasFixedRightArgBits::encode(has_fixed_right_arg_)
- | FixedRightArgValueBits::encode(encoded_right_arg_);
+ | HasFixedRightArgBits::encode(encoded_right_arg_.has_value)
+ | FixedRightArgValueBits::encode(encoded_right_arg_.value);
}
static byte ExtractTypesFromExtraICState(Code::ExtraICState state) {
return state & ((1 << NUMBER_OF_TYPES) - 1);
}
+ static NilValue ExtractNilValueFromExtraICState(Code::ExtraICState state) {
+ return NilValueField::decode(state);
+ }
void Record(Handle<Object> object);
};
+// A simple Maybe type, that can be passed by value.
+template<class T>
+struct Maybe {
+ Maybe() : has_value(false) {}
+ explicit Maybe(T t) : has_value(true), value(t) {}
+ Maybe(bool has, T t) : has_value(has), value(t) {}
+
+ bool has_value;
+ T value;
+};
+
+
// The Strict Mode (ECMA-262 5th edition, 4.2.2).
//
// This flag is used in the backend to represent the language mode. So far
HValue* context,
HValue* left,
HValue* right,
- bool has_fixed_right_arg,
- int fixed_right_arg_value) {
+ Maybe<int> fixed_right_arg) {
if (FLAG_fold_constants && left->IsConstant() && right->IsConstant()) {
HConstant* c_left = HConstant::cast(left);
HConstant* c_right = HConstant::cast(right);
}
}
}
- return new(zone) HMod(context,
- left,
- right,
- has_fixed_right_arg,
- fixed_right_arg_value);
+ return new(zone) HMod(context, left, right, fixed_right_arg);
}
HValue* context,
HValue* left,
HValue* right,
- bool has_fixed_right_arg,
- int fixed_right_arg_value);
+ Maybe<int> fixed_right_arg);
- bool has_fixed_right_arg() const { return has_fixed_right_arg_; }
- int fixed_right_arg_value() const { return fixed_right_arg_value_; }
+ Maybe<int> fixed_right_arg() const { return fixed_right_arg_; }
bool HasPowerOf2Divisor() {
if (right()->IsConstant() &&
HMod(HValue* context,
HValue* left,
HValue* right,
- bool has_fixed_right_arg,
- int fixed_right_arg_value)
+ Maybe<int> fixed_right_arg)
: HArithmeticBinaryOperation(context, left, right),
- has_fixed_right_arg_(has_fixed_right_arg),
- fixed_right_arg_value_(fixed_right_arg_value) {
+ fixed_right_arg_(fixed_right_arg) {
SetFlag(kCanBeDivByZero);
SetFlag(kCanOverflow);
}
- const bool has_fixed_right_arg_;
- const int fixed_right_arg_value_;
+ const Maybe<int> fixed_right_arg_;
};
HValue* context = environment()->LookupContext();
HInstruction* instr =
HMul::New(zone(), context, value, graph()->GetConstantMinus1());
- Handle<Type> type = expr->type();
- Representation rep = ToRepresentation(type);
- if (type->Is(Type::None())) {
+ Handle<Type> operand_type = expr->expression()->lower_type();
+ Representation rep = ToRepresentation(operand_type);
+ if (operand_type->Is(Type::None())) {
AddSoftDeoptimize();
- type = handle(Type::Any(), isolate());
}
if (instr->IsBinaryOperation()) {
HBinaryOperation::cast(instr)->set_observed_input_representation(1, rep);
void HOptimizedGraphBuilder::VisitBitNot(UnaryOperation* expr) {
CHECK_ALIVE(VisitForValue(expr->expression()));
HValue* value = Pop();
- Handle<Type> info = expr->type();
- if (info->Is(Type::None())) {
+ Handle<Type> operand_type = expr->expression()->lower_type();
+ if (operand_type->Is(Type::None())) {
AddSoftDeoptimize();
}
HInstruction* instr = new(zone()) HBitNot(value);
HValue* left,
HValue* right) {
HValue* context = environment()->LookupContext();
- Handle<Type> left_type = expr->left_type();
- Handle<Type> right_type = expr->right_type();
+ Handle<Type> left_type = expr->left()->lower_type();
+ Handle<Type> right_type = expr->right()->lower_type();
Handle<Type> result_type = expr->result_type();
- bool has_fixed_right_arg = expr->has_fixed_right_arg();
- int fixed_right_arg_value = expr->fixed_right_arg_value();
+ Maybe<int> fixed_right_arg = expr->fixed_right_arg();
Representation left_rep = ToRepresentation(left_type);
Representation right_rep = ToRepresentation(right_type);
Representation result_rep = ToRepresentation(result_type);
if (left_type->Is(Type::None())) {
AddSoftDeoptimize();
+ // TODO(rossberg): we should be able to get rid of non-continuous defaults.
left_type = handle(Type::Any(), isolate());
}
if (right_type->Is(Type::None())) {
instr = HMul::New(zone(), context, left, right);
break;
case Token::MOD:
- instr = HMod::New(zone(),
- context,
- left,
- right,
- has_fixed_right_arg,
- fixed_right_arg_value);
+ instr = HMod::New(zone(), context, left, right, fixed_right_arg);
break;
case Token::DIV:
instr = HDiv::New(zone(), context, left, right);
return ast_context()->ReturnControl(instr, expr->id());
}
- Handle<Type> left_type = expr->left_type();
- Handle<Type> right_type = expr->right_type();
- Handle<Type> overall_type = expr->overall_type();
- Representation combined_rep = ToRepresentation(overall_type);
+ Handle<Type> left_type = expr->left()->lower_type();
+ Handle<Type> right_type = expr->right()->lower_type();
+ Handle<Type> combined_type = expr->combined_type();
+ Representation combined_rep = ToRepresentation(combined_type);
Representation left_rep = ToRepresentation(left_type);
Representation right_rep = ToRepresentation(right_type);
// Check if this expression was ever executed according to type feedback.
// Note that for the special typeof/null/undefined cases we get unknown here.
- if (overall_type->Is(Type::None())) {
+ if (combined_type->Is(Type::None())) {
AddSoftDeoptimize();
- overall_type = left_type = right_type = handle(Type::Any(), isolate());
+ combined_type = left_type = right_type = handle(Type::Any(), isolate());
}
CHECK_ALIVE(VisitForValue(expr->left()));
HIn* result = new(zone()) HIn(context, left, right);
result->set_position(expr->position());
return ast_context()->ReturnInstruction(result, expr->id());
- } else if (overall_type->Is(Type::Receiver())) {
+ } else if (combined_type->Is(Type::Receiver())) {
switch (op) {
case Token::EQ:
case Token::EQ_STRICT: {
// Can we get away with map check and not instance type check?
- if (overall_type->IsClass()) {
- Handle<Map> map = overall_type->AsClass();
+ if (combined_type->IsClass()) {
+ Handle<Map> map = combined_type->AsClass();
AddCheckMapsWithTransitions(left, map);
AddCheckMapsWithTransitions(right, map);
HCompareObjectEqAndBranch* result =
default:
return Bailout("Unsupported non-primitive compare");
}
- } else if (overall_type->Is(Type::InternalizedString()) &&
+ } else if (combined_type->Is(Type::InternalizedString()) &&
Token::IsEqualityOp(op)) {
BuildCheckNonSmi(left);
AddInstruction(HCheckInstanceType::NewIsInternalizedString(left, zone()));
if_nil.CaptureContinuation(&continuation);
return ast_context()->ReturnContinuation(&continuation, expr->id());
}
- Handle<Type> type = expr->compare_nil_type()->Is(Type::None())
- ? handle(Type::Any(), isolate_) : expr->compare_nil_type();
+ Handle<Type> type = expr->combined_type()->Is(Type::None())
+ ? handle(Type::Any(), isolate_) : expr->combined_type();
BuildCompareNil(value, type, expr->position(), &continuation);
return ast_context()->ReturnContinuation(&continuation, expr->id());
}
UNREACHABLE();
}
- if (op_ == Token::MOD && has_fixed_right_arg_) {
+ if (op_ == Token::MOD && encoded_right_arg_.has_value) {
// It is guaranteed that the value will fit into a Smi, because if it
// didn't, we wouldn't be here, see BinaryOp_Patch.
__ cmp(eax, Immediate(Smi::FromInt(fixed_right_arg_value())));
FloatingPointHelper::CheckSSE2OperandIsInt32(
masm, ¬_int32, xmm1, edi, ecx, xmm2);
if (op_ == Token::MOD) {
- if (has_fixed_right_arg_) {
+ if (encoded_right_arg_.has_value) {
__ cmp(edi, Immediate(fixed_right_arg_value()));
__ j(not_equal, &right_arg_changed);
}
__ and_(left_reg, divisor - 1);
__ bind(&done);
- } else if (hmod->has_fixed_right_arg()) {
+ } else if (hmod->fixed_right_arg().has_value) {
Register left_reg = ToRegister(instr->left());
ASSERT(left_reg.is(ToRegister(instr->result())));
Register right_reg = ToRegister(instr->right());
- int32_t divisor = hmod->fixed_right_arg_value();
+ int32_t divisor = hmod->fixed_right_arg().value;
ASSERT(IsPowerOf2(divisor));
// Check if our assumption of a fixed right operand still holds.
instr->CheckFlag(HValue::kBailoutOnMinusZero))
? AssignEnvironment(result)
: result;
- } else if (instr->has_fixed_right_arg()) {
+ } else if (instr->fixed_right_arg().has_value) {
LModI* mod = new(zone()) LModI(UseRegister(left),
UseRegisterAtStart(right),
NULL);
#ifdef DEBUG
static void TraceBinaryOp(BinaryOpIC::TypeInfo left,
BinaryOpIC::TypeInfo right,
- bool has_fixed_right_arg,
- int32_t fixed_right_arg_value,
+ Maybe<int32_t> fixed_right_arg,
BinaryOpIC::TypeInfo result) {
PrintF("%s*%s", BinaryOpIC::GetName(left), BinaryOpIC::GetName(right));
- if (has_fixed_right_arg) PrintF("{%d}", fixed_right_arg_value);
+ if (fixed_right_arg.has_value) PrintF("{%d}", fixed_right_arg.value);
PrintF("->%s", BinaryOpIC::GetName(result));
}
#endif
BinaryOpIC::TypeInfo new_overall = Max(new_left, new_right);
BinaryOpIC::TypeInfo previous_overall = Max(previous_left, previous_right);
- bool previous_has_fixed_right_arg =
- BinaryOpStub::decode_has_fixed_right_arg_from_minor_key(key);
- int previous_fixed_right_arg_value =
- BinaryOpStub::decode_fixed_right_arg_value_from_minor_key(key);
+ Maybe<int> previous_fixed_right_arg =
+ BinaryOpStub::decode_fixed_right_arg_from_minor_key(key);
int32_t value;
bool new_has_fixed_right_arg =
right->ToInt32(&value) &&
BinaryOpStub::can_encode_arg_value(value) &&
(previous_overall == BinaryOpIC::UNINITIALIZED ||
- (previous_has_fixed_right_arg &&
- previous_fixed_right_arg_value == value));
- int32_t new_fixed_right_arg_value = new_has_fixed_right_arg ? value : 1;
+ (previous_fixed_right_arg.has_value &&
+ previous_fixed_right_arg.value == value));
+ Maybe<int32_t> new_fixed_right_arg(
+ new_has_fixed_right_arg, new_has_fixed_right_arg ? value : 1);
- if (previous_has_fixed_right_arg == new_has_fixed_right_arg) {
+ if (previous_fixed_right_arg.has_value == new_fixed_right_arg.has_value) {
if (new_overall == BinaryOpIC::SMI && previous_overall == BinaryOpIC::SMI) {
if (op == Token::DIV ||
op == Token::MUL ||
}
}
- BinaryOpStub stub(key, new_left, new_right, result_type,
- new_has_fixed_right_arg, new_fixed_right_arg_value);
+ BinaryOpStub stub(key, new_left, new_right, result_type, new_fixed_right_arg);
Handle<Code> code = stub.GetCode(isolate);
if (!code.is_null()) {
#ifdef DEBUG
PrintF("[BinaryOpIC in ");
JavaScriptFrame::PrintTop(isolate, stdout, false, true);
PrintF(" ");
- TraceBinaryOp(previous_left, previous_right, previous_has_fixed_right_arg,
- previous_fixed_right_arg_value, previous_result);
+ TraceBinaryOp(previous_left, previous_right, previous_fixed_right_arg,
+ previous_result);
PrintF(" => ");
- TraceBinaryOp(new_left, new_right, new_has_fixed_right_arg,
- new_fixed_right_arg_value, result_type);
+ TraceBinaryOp(new_left, new_right, new_fixed_right_arg, result_type);
PrintF(" #%s @ %p]\n", Token::Name(op), static_cast<void*>(*code));
}
#endif
extended_extra_ic_state());
}
+byte Code::compare_nil_value() {
+ ASSERT(is_compare_nil_ic_stub());
+ return CompareNilICStub::ExtractNilValueFromExtraICState(
+ extended_extra_ic_state());
+}
+
void Code::InvalidateRelocation() {
set_relocation_info(GetHeap()->empty_byte_array());
// [compare_nil]: For kind COMPARE_NIL_IC tells what state the stub is in.
byte compare_nil_state();
+ byte compare_nil_value();
// [has_function_cache]: For kind STUB tells whether there is a function
// cache is passed to the stub.
}
-void TypeFeedbackOracle::CompareTypes(TypeFeedbackId id,
- Handle<Type>* left_type,
- Handle<Type>* right_type,
- Handle<Type>* overall_type,
- Handle<Type>* compare_nil_type) {
- *left_type = *right_type = *overall_type = *compare_nil_type =
- handle(Type::Any(), isolate_);
+void TypeFeedbackOracle::CompareType(TypeFeedbackId id,
+ Handle<Type>* left_type,
+ Handle<Type>* right_type,
+ Handle<Type>* combined_type) {
+ *left_type = *right_type = *combined_type = handle(Type::Any(), isolate_);
Handle<Object> info = GetInfo(id);
if (!info->IsCode()) return;
Handle<Code> code = Handle<Code>::cast(info);
if (code->is_compare_ic_stub()) {
int stub_minor_key = code->stub_info();
CompareIC::StubInfoToType(
- stub_minor_key, left_type, right_type, overall_type, map, isolate());
+ stub_minor_key, left_type, right_type, combined_type, map, isolate());
} else if (code->is_compare_nil_ic_stub()) {
CompareNilICStub::State state(code->compare_nil_state());
- *compare_nil_type = CompareNilICStub::StateToType(isolate_, state, map);
+ *combined_type = CompareNilICStub::StateToType(isolate_, state, map);
+ Handle<Type> nil_type = handle(code->compare_nil_value() == kNullValue
+ ? Type::Null() : Type::Undefined(), isolate_);
+ *left_type = *right_type =
+ handle(Type::Union(*combined_type, nil_type), isolate_);
}
}
Handle<Type>* left,
Handle<Type>* right,
Handle<Type>* result,
- bool* has_fixed_right_arg,
- int* fixed_right_arg_value) {
+ Maybe<int>* fixed_right_arg) {
Handle<Object> object = GetInfo(id);
*left = *right = *result = handle(Type::Any(), isolate_);
if (!object->IsCode()) return;
int minor_key = code->stub_info();
BinaryOpIC::StubInfoToType(minor_key, left, right, result, isolate());
- *has_fixed_right_arg =
- BinaryOpStub::decode_has_fixed_right_arg_from_minor_key(minor_key);
- *fixed_right_arg_value =
- BinaryOpStub::decode_fixed_right_arg_value_from_minor_key(minor_key);
+ *fixed_right_arg =
+ BinaryOpStub::decode_fixed_right_arg_from_minor_key(minor_key);
}
Handle<Type>* left,
Handle<Type>* right,
Handle<Type>* result,
- bool* has_fixed_right_arg,
- int* fixed_right_arg_value);
-
- void CompareTypes(TypeFeedbackId id,
- Handle<Type>* left_type,
- Handle<Type>* right_type,
- Handle<Type>* overall_type,
- Handle<Type>* compare_nil_type);
+ Maybe<int>* fixed_right_arg);
+
+ void CompareType(TypeFeedbackId id,
+ Handle<Type>* left_type,
+ Handle<Type>* right_type,
+ Handle<Type>* combined_type);
Handle<Type> ClauseType(TypeFeedbackId id);
return from_bitset(type1->as_bitset() | type2->as_bitset());
}
+ // Fast case: top or bottom types.
+ if (type1->SameValue(Type::Any())) return *type1;
+ if (type2->SameValue(Type::Any())) return *type2;
+ if (type1->SameValue(Type::None())) return *type2;
+ if (type2->SameValue(Type::None())) return *type1;
+
// Semi-fast case: Unioned objects are neither involved nor produced.
if (!(type1->is_union() || type2->is_union())) {
if (type1->Is(type2)) return *type2;
return from_bitset(type1->as_bitset() & type2->as_bitset());
}
+ // Fast case: top or bottom types.
+ if (type1->SameValue(Type::None())) return *type1;
+ if (type2->SameValue(Type::None())) return *type2;
+ if (type1->SameValue(Type::Any())) return *type2;
+ if (type2->SameValue(Type::Any())) return *type1;
+
// Semi-fast case: Unioned objects are neither involved nor produced.
if (!(type1->is_union() || type2->is_union())) {
if (type1->Is(type2)) return *type1;
ASSERT(!HasStackOverflow());
CHECK_ALIVE(Visit(expr->expression()));
- expr->RecordTypeFeedback(oracle());
+ // Collect type feedback.
+ Handle<Type> op_type = oracle()->UnaryType(expr->UnaryOperationFeedbackId());
+ MergeLowerType(expr->expression(), op_type);
if (expr->op() == Token::NOT) {
// TODO(rossberg): only do in test or value context.
expr->expression()->RecordToBooleanTypeFeedback(oracle());
CHECK_ALIVE(Visit(expr->left()));
CHECK_ALIVE(Visit(expr->right()));
- expr->RecordTypeFeedback(oracle());
+ // Collect type feedback.
+ Handle<Type> left_type, right_type, result_type;
+ Maybe<int> fixed_right_arg;
+ oracle()->BinaryType(expr->BinaryOperationFeedbackId(),
+ &left_type, &right_type, &result_type, &fixed_right_arg);
+ MergeLowerType(expr->left(), left_type);
+ MergeLowerType(expr->right(), right_type);
+ expr->set_result_type(result_type);
+ expr->set_fixed_right_arg(fixed_right_arg);
if (expr->op() == Token::OR || expr->op() == Token::AND) {
expr->left()->RecordToBooleanTypeFeedback(oracle());
}
CHECK_ALIVE(Visit(expr->left()));
CHECK_ALIVE(Visit(expr->right()));
- expr->RecordTypeFeedback(oracle());
+ // Collect type feedback.
+ Handle<Type> left_type, right_type, combined_type;
+ oracle()->CompareType(expr->CompareOperationFeedbackId(),
+ &left_type, &right_type, &combined_type);
+ MergeLowerType(expr->left(), left_type);
+ MergeLowerType(expr->right(), right_type);
+ expr->set_combined_type(combined_type);
}
TypeFeedbackOracle* oracle() { return &oracle_; }
Zone* zone() const { return info_->zone(); }
+ void MergeLowerType(Expression* e, Handle<Type> t) {
+ e->set_lower_type(handle(Type::Union(e->lower_type(), t), isolate_));
+ }
+ void MergeUpperType(Expression* e, Handle<Type> t) {
+ e->set_upper_type(handle(Type::Intersect(e->upper_type(), t), isolate_));
+ }
+
void VisitDeclarations(ZoneList<Declaration*>* declarations);
void VisitStatements(ZoneList<Statement*>* statements);
void BinaryOpStub::GenerateSmiStub(MacroAssembler* masm) {
Label right_arg_changed, call_runtime;
- if (op_ == Token::MOD && has_fixed_right_arg_) {
+ if (op_ == Token::MOD && encoded_right_arg_.has_value) {
// It is guaranteed that the value will fit into a Smi, because if it
// didn't, we wouldn't be here, see BinaryOp_Patch.
__ Cmp(rax, Smi::FromInt(fixed_right_arg_value()));
__ andl(left_reg, Immediate(divisor - 1));
__ bind(&done);
- } else if (hmod->has_fixed_right_arg()) {
+ } else if (hmod->fixed_right_arg().has_value) {
Register left_reg = ToRegister(instr->left());
ASSERT(left_reg.is(ToRegister(instr->result())));
Register right_reg = ToRegister(instr->right());
- int32_t divisor = hmod->fixed_right_arg_value();
+ int32_t divisor = hmod->fixed_right_arg().value;
ASSERT(IsPowerOf2(divisor));
// Check if our assumption of a fixed right operand still holds.
instr->CheckFlag(HValue::kBailoutOnMinusZero))
? AssignEnvironment(result)
: result;
- } else if (instr->has_fixed_right_arg()) {
+ } else if (instr->fixed_right_arg().has_value) {
LModI* mod = new(zone()) LModI(UseRegister(left),
UseRegisterAtStart(right),
NULL);