LInstruction* LChunkBuilder::DoCheckHeapObject(HCheckHeapObject* instr) {
LOperand* value = UseRegisterAtStart(instr->value());
LInstruction* result = new(zone()) LCheckNonSmi(value);
- if (!instr->value()->IsHeapObject()) result = AssignEnvironment(result);
+ if (!instr->value()->type().IsHeapObject()) {
+ result = AssignEnvironment(result);
+ }
return result;
}
Register temp1 = ToRegister(instr->temp());
SmiCheck check_needed =
- instr->hydrogen()->value()->IsHeapObject()
+ instr->hydrogen()->value()->type().IsHeapObject()
? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
Condition true_cond =
EmitIsString(reg, temp1, instr->FalseLabel(chunk_), check_needed);
Register input = ToRegister(instr->value());
Register temp = ToRegister(instr->temp());
- if (!instr->hydrogen()->value()->IsHeapObject()) {
+ if (!instr->hydrogen()->value()->type().IsHeapObject()) {
__ JumpIfSmi(input, instr->FalseLabel(chunk_));
}
__ ldr(temp, FieldMemOperand(input, HeapObject::kMapOffset));
Register scratch = scratch0();
Register input = ToRegister(instr->value());
- if (!instr->hydrogen()->value()->IsHeapObject()) {
+ if (!instr->hydrogen()->value()->type().IsHeapObject()) {
__ JumpIfSmi(input, instr->FalseLabel(chunk_));
}
__ str(value, target);
if (instr->hydrogen()->NeedsWriteBarrier()) {
SmiCheck check_needed =
- instr->hydrogen()->value()->IsHeapObject()
+ instr->hydrogen()->value()->type().IsHeapObject()
? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
__ RecordWriteContextSlot(context,
target.offset(),
if (instr->hydrogen()->NeedsWriteBarrier()) {
SmiCheck check_needed =
- instr->hydrogen()->value()->IsHeapObject()
+ instr->hydrogen()->value()->type().IsHeapObject()
? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
// Compute address of modified element and store it into key register.
__ add(key, store_base, Operand(offset));
void LCodeGen::DoCheckNonSmi(LCheckNonSmi* instr) {
- if (!instr->hydrogen()->value()->IsHeapObject()) {
+ if (!instr->hydrogen()->value()->type().IsHeapObject()) {
LOperand* input = instr->value();
__ SmiTst(ToRegister(input));
DeoptimizeIf(eq, instr->environment());
LInstruction* LChunkBuilder::DoCheckHeapObject(HCheckHeapObject* instr) {
LOperand* value = UseRegisterAtStart(instr->value());
LInstruction* result = new(zone()) LCheckNonSmi(value);
- if (!instr->value()->IsHeapObject()) result = AssignEnvironment(result);
+ if (!instr->value()->type().IsHeapObject()) {
+ result = AssignEnvironment(result);
+ }
return result;
}
void LCodeGen::DoCheckNonSmi(LCheckNonSmi* instr) {
- if (!instr->hydrogen()->value()->IsHeapObject()) {
+ if (!instr->hydrogen()->value()->type().IsHeapObject()) {
DeoptimizeIfSmi(ToRegister(instr->value()), instr->environment());
}
}
Register input = ToRegister(instr->value());
Register scratch = ToRegister(instr->temp());
- if (!instr->hydrogen()->value()->IsHeapObject()) {
+ if (!instr->hydrogen()->value()->type().IsHeapObject()) {
__ JumpIfSmi(input, instr->FalseLabel(chunk_));
}
__ CompareObjectType(input, scratch, scratch, TestType(instr->hydrogen()));
Register scratch = ToRegister(instr->temp());
SmiCheck check_needed =
- instr->hydrogen()->value()->IsHeapObject()
+ instr->hydrogen()->value()->type().IsHeapObject()
? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
Condition true_cond =
EmitIsString(val, scratch, instr->FalseLabel(chunk_), check_needed);
Register input = ToRegister(instr->value());
Register temp = ToRegister(instr->temp());
- if (!instr->hydrogen()->value()->IsHeapObject()) {
+ if (!instr->hydrogen()->value()->type().IsHeapObject()) {
__ JumpIfSmi(input, instr->FalseLabel(chunk_));
}
__ Ldr(temp, FieldMemOperand(input, HeapObject::kMapOffset));
__ Str(value, target);
if (instr->hydrogen()->NeedsWriteBarrier()) {
SmiCheck check_needed =
- instr->hydrogen()->value()->IsHeapObject()
+ instr->hydrogen()->value()->type().IsHeapObject()
? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
__ RecordWriteContextSlot(context,
target.offset(),
// This assignment may cause element_addr to alias store_base.
Register element_addr = scratch;
SmiCheck check_needed =
- instr->hydrogen()->value()->IsHeapObject()
+ instr->hydrogen()->value()->type().IsHeapObject()
? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
// Compute address of modified element and store it into key register.
__ Add(element_addr, mem_op.base(), mem_op.OffsetAsOperand());
// Allocate the context in new space.
HAllocate* function_context = Add<HAllocate>(
Add<HConstant>(length * kPointerSize + FixedArray::kHeaderSize),
- HType::Tagged(), NOT_TENURED, FIXED_ARRAY_TYPE);
+ HType::HeapObject(), NOT_TENURED, FIXED_ARRAY_TYPE);
// Set up the object header.
AddStoreMapConstant(function_context,
}
-const char* HType::ToString() {
- // Note: The c1visualizer syntax for locals allows only a sequence of the
- // following characters: A-Za-z0-9_-|:
- switch (type_) {
- case kNone: return "none";
- case kTagged: return "tagged";
- case kTaggedPrimitive: return "primitive";
- case kTaggedNumber: return "number";
- case kSmi: return "smi";
- case kHeapNumber: return "heap-number";
- case kString: return "string";
- case kBoolean: return "boolean";
- case kNonPrimitive: return "non-primitive";
- case kJSArray: return "array";
- case kJSObject: return "object";
- }
- UNREACHABLE();
- return "unreachable";
-}
-
-
-HType HType::TypeFromValue(Handle<Object> value) {
- HType result = HType::Tagged();
- if (value->IsSmi()) {
- result = HType::Smi();
- } else if (value->IsHeapNumber()) {
- result = HType::HeapNumber();
- } else if (value->IsString()) {
- result = HType::String();
- } else if (value->IsBoolean()) {
- result = HType::Boolean();
- } else if (value->IsJSObject()) {
- result = HType::JSObject();
- } else if (value->IsJSArray()) {
- result = HType::JSArray();
- } else if (value->IsHeapObject()) {
- result = HType::NonPrimitive();
- }
- return result;
-}
-
-
bool HValue::IsDefinedAfter(HBasicBlock* other) const {
return block()->block_id() > other->block_id();
}
HValue* HCheckInstanceType::Canonicalize() {
- if (check_ == IS_STRING && value()->type().IsString()) {
+ if ((check_ == IS_SPEC_OBJECT && value()->type().IsJSObject()) ||
+ (check_ == IS_JS_ARRAY && value()->type().IsJSArray()) ||
+ (check_ == IS_STRING && value()->type().IsString())) {
return value();
}
HConstant::HConstant(Handle<Object> object, Representation r)
- : HTemplateInstruction<0>(HType::TypeFromValue(object)),
+ : HTemplateInstruction<0>(HType::FromValue(object)),
object_(Unique<Object>::CreateUninitialized(object)),
object_map_(Handle<Map>::null()),
has_stable_map_value_(false),
is_undetectable_(is_undetectable),
instance_type_(instance_type) {
ASSERT(!object.handle().is_null());
- ASSERT(!type.IsTaggedNumber());
+ ASSERT(!type.IsTaggedNumber() || type.IsNone());
Initialize(r);
}
HConstant::HConstant(ExternalReference reference)
- : HTemplateInstruction<0>(HType::None()),
+ : HTemplateInstruction<0>(HType::Any()),
object_(Unique<Object>(Handle<Object>::null())),
object_map_(Handle<Map>::null()),
has_stable_map_value_(false),
#include "conversions.h"
#include "data-flow.h"
#include "deoptimizer.h"
+#include "hydrogen-types.h"
#include "small-pointer-list.h"
#include "string-stream.h"
#include "unique.h"
};
-class HType V8_FINAL {
- public:
- static HType None() { return HType(kNone); }
- static HType Tagged() { return HType(kTagged); }
- static HType TaggedPrimitive() { return HType(kTaggedPrimitive); }
- static HType TaggedNumber() { return HType(kTaggedNumber); }
- static HType Smi() { return HType(kSmi); }
- static HType HeapNumber() { return HType(kHeapNumber); }
- static HType String() { return HType(kString); }
- static HType Boolean() { return HType(kBoolean); }
- static HType NonPrimitive() { return HType(kNonPrimitive); }
- static HType JSArray() { return HType(kJSArray); }
- static HType JSObject() { return HType(kJSObject); }
-
- // Return the weakest (least precise) common type.
- HType Combine(HType other) {
- return HType(static_cast<Type>(type_ & other.type_));
- }
-
- bool Equals(const HType& other) const {
- return type_ == other.type_;
- }
-
- bool IsSubtypeOf(const HType& other) {
- return Combine(other).Equals(other);
- }
-
- bool IsTaggedPrimitive() const {
- return ((type_ & kTaggedPrimitive) == kTaggedPrimitive);
- }
-
- bool IsTaggedNumber() const {
- return ((type_ & kTaggedNumber) == kTaggedNumber);
- }
-
- bool IsSmi() const {
- return ((type_ & kSmi) == kSmi);
- }
-
- bool IsHeapNumber() const {
- return ((type_ & kHeapNumber) == kHeapNumber);
- }
-
- bool IsString() const {
- return ((type_ & kString) == kString);
- }
-
- bool IsNonString() const {
- return IsTaggedPrimitive() || IsSmi() || IsHeapNumber() ||
- IsBoolean() || IsJSArray();
- }
-
- bool IsBoolean() const {
- return ((type_ & kBoolean) == kBoolean);
- }
-
- bool IsNonPrimitive() const {
- return ((type_ & kNonPrimitive) == kNonPrimitive);
- }
-
- bool IsJSArray() const {
- return ((type_ & kJSArray) == kJSArray);
- }
-
- bool IsJSObject() const {
- return ((type_ & kJSObject) == kJSObject);
- }
-
- bool IsHeapObject() const {
- return IsHeapNumber() || IsString() || IsBoolean() || IsNonPrimitive();
- }
-
- bool ToStringOrToNumberCanBeObserved(Representation representation) {
- switch (type_) {
- case kTaggedPrimitive: // fallthru
- case kTaggedNumber: // fallthru
- case kSmi: // fallthru
- case kHeapNumber: // fallthru
- case kString: // fallthru
- case kBoolean:
- return false;
- case kJSArray: // fallthru
- case kJSObject:
- return true;
- case kTagged:
- break;
- }
- return !representation.IsSmiOrInteger32() && !representation.IsDouble();
- }
-
- static HType TypeFromValue(Handle<Object> value);
-
- const char* ToString();
-
- private:
- enum Type {
- kNone = 0x0, // 0000 0000 0000 0000
- kTagged = 0x1, // 0000 0000 0000 0001
- kTaggedPrimitive = 0x5, // 0000 0000 0000 0101
- kTaggedNumber = 0xd, // 0000 0000 0000 1101
- kSmi = 0x1d, // 0000 0000 0001 1101
- kHeapNumber = 0x2d, // 0000 0000 0010 1101
- kString = 0x45, // 0000 0000 0100 0101
- kBoolean = 0x85, // 0000 0000 1000 0101
- kNonPrimitive = 0x101, // 0000 0001 0000 0001
- kJSObject = 0x301, // 0000 0011 0000 0001
- kJSArray = 0x701 // 0000 0111 0000 0001
- };
-
- // Make sure type fits in int16.
- STATIC_ASSERT(kJSArray < (1 << (2 * kBitsPerByte)));
-
- explicit HType(Type t) : type_(t) { }
-
- int16_t type_;
-};
-
-
class HUseListNode: public ZoneObject {
public:
HUseListNode(HValue* value, int index, HUseListNode* tail)
type_ = new_type;
}
- bool IsHeapObject() {
- return representation_.IsHeapObject() || type_.IsHeapObject();
- }
-
// There are HInstructions that do not really change a value, they
// only add pieces of information to it (like bounds checks, map checks,
// smi checks...).
// Returns true conservatively if the program might be able to observe a
// ToString() operation on this value.
bool ToStringCanBeObserved() const {
- return type().ToStringOrToNumberCanBeObserved(representation());
+ return ToStringOrToNumberCanBeObserved();
}
// Returns true conservatively if the program might be able to observe a
// ToNumber() operation on this value.
bool ToNumberCanBeObserved() const {
- return type().ToStringOrToNumberCanBeObserved(representation());
+ return ToStringOrToNumberCanBeObserved();
}
MinusZeroMode GetMinusZeroMode() {
return false;
}
+ bool ToStringOrToNumberCanBeObserved() const {
+ if (type().IsTaggedPrimitive()) return false;
+ if (type().IsJSObject()) return true;
+ return !representation().IsSmiOrInteger32() && !representation().IsDouble();
+ }
+
virtual Representation RepresentationFromInputs() {
return representation();
}
virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
return Representation::Tagged();
}
+
+ virtual HType CalculateInferredType() V8_OVERRIDE {
+ if (value()->type().IsHeapObject()) return value()->type();
+ return HType::HeapObject();
+ }
+
virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE;
- HValue* value() { return OperandAt(0); }
- HValue* typecheck() { return OperandAt(1); }
+ HValue* value() const { return OperandAt(0); }
+ HValue* typecheck() const { return OperandAt(1); }
const UniqueSet<Map>* maps() const { return maps_; }
void set_maps(const UniqueSet<Map>* maps) { maps_ = maps; }
private:
HCheckMaps(HValue* value, const UniqueSet<Map>* maps, bool maps_are_stable)
- : HTemplateInstruction<2>(value->type()), maps_(maps),
+ : HTemplateInstruction<2>(HType::HeapObject()), maps_(maps),
has_migration_target_(false), is_stability_check_(false),
maps_are_stable_(maps_are_stable) {
ASSERT_NE(0, maps->size());
}
HCheckMaps(HValue* value, const UniqueSet<Map>* maps, HValue* typecheck)
- : HTemplateInstruction<2>(value->type()), maps_(maps),
+ : HTemplateInstruction<2>(HType::HeapObject()), maps_(maps),
has_migration_target_(false), is_stability_check_(false),
maps_are_stable_(true) {
ASSERT_NE(0, maps->size());
return Representation::Tagged();
}
+ virtual HType CalculateInferredType() V8_OVERRIDE {
+ switch (check_) {
+ case IS_SPEC_OBJECT: return HType::JSObject();
+ case IS_JS_ARRAY: return HType::JSArray();
+ case IS_STRING: return HType::String();
+ case IS_INTERNALIZED_STRING: return HType::String();
+ }
+ UNREACHABLE();
+ return HType::Tagged();
+ }
+
virtual HValue* Canonicalize() V8_OVERRIDE;
bool is_interval_check() const { return check_ <= LAST_INTERVAL_CHECK; }
const char* GetCheckName();
HCheckInstanceType(HValue* value, Check check)
- : HUnaryOperation(value), check_(check) {
+ : HUnaryOperation(value, HType::HeapObject()), check_(check) {
set_representation(Representation::Tagged());
SetFlag(kUseGVN);
}
return Representation::Tagged();
}
+ virtual HType CalculateInferredType() V8_OVERRIDE {
+ if (value()->type().IsHeapObject()) return value()->type();
+ return HType::HeapObject();
+ }
+
#ifdef DEBUG
virtual void Verify() V8_OVERRIDE;
#endif
virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
private:
- explicit HCheckHeapObject(HValue* value)
- : HUnaryOperation(value, HType::NonPrimitive()) {
+ explicit HCheckHeapObject(HValue* value) : HUnaryOperation(value) {
set_representation(Representation::Tagged());
SetFlag(kUseGVN);
}
HInstruction* instruction) {
return instruction->Prepend(new(zone) HConstant(
map, Unique<Map>(Handle<Map>::null()), map_is_stable,
- Representation::Tagged(), HType::Tagged(), true,
+ Representation::Tagged(), HType::HeapObject(), true,
false, false, MAP_TYPE));
}
HInstruction* instruction) {
return instruction->Append(new(zone) HConstant(
map, Unique<Map>(Handle<Map>::null()), map_is_stable,
- Representation::Tagged(), HType::Tagged(), true,
+ Representation::Tagged(), HType::HeapObject(), true,
false, false, MAP_TYPE));
}
class HBitwiseBinaryOperation : public HBinaryOperation {
public:
HBitwiseBinaryOperation(HValue* context, HValue* left, HValue* right,
- HType type = HType::Tagged())
+ HType type = HType::TaggedNumber())
: HBinaryOperation(context, left, right, type) {
SetFlag(kFlexibleRepresentation);
SetFlag(kTruncatingToInt32);
Token::Value op,
HValue* left,
HValue* right)
- : HBitwiseBinaryOperation(context, left, right, HType::TaggedNumber()),
+ : HBitwiseBinaryOperation(context, left, right),
op_(op) {
ASSERT(op == Token::BIT_AND || op == Token::BIT_OR || op == Token::BIT_XOR);
// BIT_AND with a smi-range positive value will always unset the
HValue* context,
HValue* value,
HValue* offset,
- HType type = HType::Tagged()) {
+ HType type) {
return new(zone) HInnerAllocatedObject(value, offset, type);
}
private:
HInnerAllocatedObject(HValue* value,
HValue* offset,
- HType type = HType::Tagged())
- : HTemplateInstruction<2>(type) {
+ HType type) : HTemplateInstruction<2>(type) {
ASSERT(value->IsAllocate());
+ ASSERT(type.IsHeapObject());
SetOperandAt(0, value);
SetOperandAt(1, offset);
- set_type(type);
set_representation(Representation::Tagged());
}
};
inline bool StoringValueNeedsWriteBarrier(HValue* value) {
- return !value->type().IsBoolean()
- && !value->type().IsSmi()
+ return !value->type().IsSmi()
+ && !value->type().IsNull()
+ && !value->type().IsBoolean()
+ && !value->type().IsUndefined()
&& !(value->IsConstant() && HConstant::cast(value)->ImmortalImmovable());
}
representation.IsInteger32()) {
set_representation(representation);
} else if (representation.IsHeapObject()) {
- // TODO(bmeurer): This is probably broken. What we actually want to to
- // instead is set_representation(Representation::HeapObject()).
- set_type(HType::NonPrimitive());
+ set_type(HType::HeapObject());
set_representation(Representation::Tagged());
} else {
set_representation(Representation::Tagged());
SetOperandAt(1, dependency ? dependency : object);
ASSERT(access.representation().IsHeapObject());
- // TODO(bmeurer): This is probably broken. What we actually want to to
- // instead is set_representation(Representation::HeapObject()).
- if (!type.IsHeapObject()) set_type(HType::NonPrimitive());
+ ASSERT(type.IsHeapObject());
set_representation(Representation::Tagged());
access.SetGVNFlags(this, LOAD);
SmiCheck SmiCheckForWriteBarrier() const {
if (field_representation().IsHeapObject()) return OMIT_SMI_CHECK;
- if (value()->IsHeapObject()) return OMIT_SMI_CHECK;
+ if (value()->type().IsHeapObject()) return OMIT_SMI_CHECK;
return INLINE_SMI_CHECK;
}
virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE;
virtual HType CalculateInferredType() V8_OVERRIDE {
- return HType::Tagged();
+ if (value()->type().IsHeapObject()) return value()->type();
+ return HType::HeapObject();
}
- HValue* value() { return OperandAt(0); }
- HValue* map() { return OperandAt(1); }
+ HValue* value() const { return OperandAt(0); }
+ HValue* map() const { return OperandAt(1); }
virtual HValue* Canonicalize() V8_OVERRIDE;
}
private:
- HCheckMapValue(HValue* value,
- HValue* map) {
+ HCheckMapValue(HValue* value, HValue* map)
+ : HTemplateInstruction<2>(HType::HeapObject()) {
SetOperandAt(0, value);
SetOperandAt(1, map);
set_representation(Representation::Tagged());
--- /dev/null
+// Copyright 2014 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.
+
+#include "hydrogen-types.h"
+
+#include "types-inl.h"
+
+
+namespace v8 {
+namespace internal {
+
+// static
+template <class T>
+HType HType::FromType(typename T::TypeHandle type) {
+ if (T::Any()->Is(type)) return HType::Any();
+ if (type->Is(T::None())) return HType::None();
+ if (type->Is(T::SignedSmall())) return HType::Smi();
+ if (type->Is(T::Number())) return HType::TaggedNumber();
+ if (type->Is(T::Null())) return HType::Null();
+ if (type->Is(T::String())) return HType::String();
+ if (type->Is(T::Boolean())) return HType::Boolean();
+ if (type->Is(T::Undefined())) return HType::Undefined();
+ if (type->Is(T::Array())) return HType::JSArray();
+ if (type->Is(T::Object())) return HType::JSObject();
+ return HType::Tagged();
+}
+
+
+// static
+template
+HType HType::FromType<Type>(Type* type);
+
+
+// static
+template
+HType HType::FromType<HeapType>(Handle<HeapType> type);
+
+
+// static
+HType HType::FromValue(Handle<Object> value) {
+ if (value->IsSmi()) return HType::Smi();
+ if (value->IsNull()) return HType::Null();
+ if (value->IsHeapNumber()) return HType::HeapNumber();
+ if (value->IsString()) return HType::String();
+ if (value->IsBoolean()) return HType::Boolean();
+ if (value->IsUndefined()) return HType::Undefined();
+ if (value->IsJSArray()) return HType::JSArray();
+ if (value->IsJSObject()) return HType::JSObject();
+ ASSERT(value->IsHeapObject());
+ return HType::HeapObject();
+}
+
+
+const char* HType::ToString() const {
+ // Note: The c1visualizer syntax for locals allows only a sequence of the
+ // following characters: A-Za-z0-9_-|:
+ switch (kind_) {
+ #define DEFINE_CASE(Name, mask) case k##Name: return #Name;
+ HTYPE_LIST(DEFINE_CASE)
+ #undef DEFINE_CASE
+ }
+ UNREACHABLE();
+ return NULL;
+}
+
+} } // namespace v8::internal
--- /dev/null
+// Copyright 2014 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.
+
+#ifndef HYDROGEN_TYPES_H_
+#define HYDROGEN_TYPES_H_
+
+#include <climits>
+
+#include "base/macros.h"
+
+namespace v8 {
+namespace internal {
+
+// Forward declarations.
+template <typename T> class Handle;
+class Object;
+
+#define HTYPE_LIST(V) \
+ V(Any, 0x0) /* 0000 0000 0000 0000 */ \
+ V(Tagged, 0x1) /* 0000 0000 0000 0001 */ \
+ V(TaggedPrimitive, 0x5) /* 0000 0000 0000 0101 */ \
+ V(TaggedNumber, 0xd) /* 0000 0000 0000 1101 */ \
+ V(Smi, 0x1d) /* 0000 0000 0001 1101 */ \
+ V(HeapObject, 0x21) /* 0000 0000 0010 0001 */ \
+ V(HeapPrimitive, 0x25) /* 0000 0000 0010 0101 */ \
+ V(Null, 0x27) /* 0000 0000 0010 0111 */ \
+ V(HeapNumber, 0x2d) /* 0000 0000 0010 1101 */ \
+ V(String, 0x65) /* 0000 0000 0110 0101 */ \
+ V(Boolean, 0xa5) /* 0000 0000 1010 0101 */ \
+ V(Undefined, 0x125) /* 0000 0001 0010 0101 */ \
+ V(JSObject, 0x221) /* 0000 0010 0010 0001 */ \
+ V(JSArray, 0x621) /* 0000 0110 0010 0001 */ \
+ V(None, 0x7ff) /* 0000 0111 1111 1111 */
+
+class HType V8_FINAL {
+ public:
+ #define DECLARE_CONSTRUCTOR(Name, mask) \
+ static HType Name() V8_WARN_UNUSED_RESULT { return HType(k##Name); }
+ HTYPE_LIST(DECLARE_CONSTRUCTOR)
+ #undef DECLARE_CONSTRUCTOR
+
+ // Return the weakest (least precise) common type.
+ HType Combine(HType other) const V8_WARN_UNUSED_RESULT {
+ return HType(static_cast<Kind>(kind_ & other.kind_));
+ }
+
+ bool Equals(HType other) const V8_WARN_UNUSED_RESULT {
+ return kind_ == other.kind_;
+ }
+
+ bool IsSubtypeOf(HType other) const V8_WARN_UNUSED_RESULT {
+ return Combine(other).Equals(other);
+ }
+
+ #define DECLARE_IS_TYPE(Name, mask) \
+ bool Is##Name() const V8_WARN_UNUSED_RESULT { \
+ return IsSubtypeOf(HType::Name()); \
+ }
+ HTYPE_LIST(DECLARE_IS_TYPE)
+ #undef DECLARE_IS_TYPE
+
+ template <class T>
+ static HType FromType(typename T::TypeHandle type) V8_WARN_UNUSED_RESULT;
+ static HType FromValue(Handle<Object> value) V8_WARN_UNUSED_RESULT;
+
+ const char* ToString() const V8_WARN_UNUSED_RESULT;
+
+ private:
+ enum Kind {
+ #define DECLARE_TYPE(Name, mask) k##Name = mask,
+ HTYPE_LIST(DECLARE_TYPE)
+ #undef DECLARE_TYPE
+ LAST_KIND = kNone
+ };
+
+ // Make sure type fits in int16.
+ STATIC_ASSERT(LAST_KIND < (1 << (CHAR_BIT * sizeof(int16_t))));
+
+ explicit HType(Kind kind) : kind_(kind) { }
+
+ int16_t kind_;
+};
+
+} } // namespace v8::internal
+
+#endif // HYDROGEN_TYPES_H_
}
-DEFINE_GET_CONSTANT(Undefined, undefined, undefined, HType::Tagged(), false)
+DEFINE_GET_CONSTANT(Undefined, undefined, undefined, HType::Undefined(), false)
DEFINE_GET_CONSTANT(True, true, boolean, HType::Boolean(), true)
DEFINE_GET_CONSTANT(False, false, boolean, HType::Boolean(), false)
-DEFINE_GET_CONSTANT(Hole, the_hole, the_hole, HType::Tagged(), false)
-DEFINE_GET_CONSTANT(Null, null, null, HType::Tagged(), false)
+DEFINE_GET_CONSTANT(Hole, the_hole, the_hole, HType::None(), false)
+DEFINE_GET_CONSTANT(Null, null, null, HType::Null(), false)
#undef DEFINE_GET_CONSTANT
// Determine the elements FixedArray.
HValue* elements = Add<HInnerAllocatedObject>(
- result, Add<HConstant>(JSRegExpResult::kSize));
+ result, Add<HConstant>(JSRegExpResult::kSize), HType::HeapObject());
// Initialize the JSRegExpResult header.
HValue* global_object = Add<HLoadNamedField>(
HValue* total_size = AddUncasted<HAdd>(mul, header_size);
total_size->ClearFlag(HValue::kCanOverflow);
- return Add<HAllocate>(total_size, HType::NonPrimitive(), NOT_TENURED,
+ return Add<HAllocate>(total_size, HType::HeapObject(), NOT_TENURED,
instance_type);
}
}
HInnerAllocatedObject* elements = Add<HInnerAllocatedObject>(
- array, Add<HConstant>(elements_location));
+ array, Add<HConstant>(elements_location), HType::HeapObject());
Add<HStoreNamedField>(array, HObjectAccess::ForElementsPointer(), elements);
return elements;
}
if (extra_size != NULL) {
HValue* elements = Add<HInnerAllocatedObject>(object,
- Add<HConstant>(array_size));
+ Add<HConstant>(array_size), HType::HeapObject());
if (return_elements != NULL) *return_elements = elements;
}
HValue* allocation_site) {
ASSERT(allocation_site != NULL);
HInnerAllocatedObject* allocation_memento = Add<HInnerAllocatedObject>(
- previous_object, previous_object_size);
+ previous_object, previous_object_size, HType::HeapObject());
AddStoreMapConstant(
allocation_memento, isolate()->factory()->allocation_memento_map());
Add<HStoreNamedField>(
// TODO(hpayer): Allocation site pretenuring support.
HInstruction* heap_number = Add<HAllocate>(heap_number_size,
- HType::Tagged(),
+ HType::HeapObject(),
NOT_TENURED,
HEAP_NUMBER_TYPE);
AddStoreMapConstant(heap_number, isolate()->factory()->heap_number_map());
ASSERT_EQ(num_field_maps, field_maps_.length());
// Determine field HType from field HeapType.
- if (field_type->Is(HeapType::Number())) {
- field_type_ = HType::HeapNumber();
- } else if (field_type->Is(HeapType::String())) {
- field_type_ = HType::String();
- } else if (field_type->Is(HeapType::Boolean())) {
- field_type_ = HType::Boolean();
- } else if (field_type->Is(HeapType::Array())) {
- field_type_ = HType::JSArray();
- } else if (field_type->Is(HeapType::Object())) {
- field_type_ = HType::JSObject();
- } else if (field_type->Is(HeapType::Null()) ||
- field_type->Is(HeapType::Undefined())) {
- field_type_ = HType::NonPrimitive();
- }
+ field_type_ = HType::FromType<HeapType>(field_type);
+ ASSERT(field_type_.IsHeapObject());
// Add dependency on the map that introduced the field.
Map::AddDependentCompilationInfo(
HValue* elements =
Add<HAllocate>(
Add<HConstant>(ExternalArray::kAlignedSize),
- HType::NonPrimitive(),
+ HType::HeapObject(),
NOT_TENURED,
external_array_map->instance_type());
Handle<Map> fixed_typed_array_map(
isolate()->heap()->MapForFixedTypedArray(array_type));
HValue* elements =
- Add<HAllocate>(total_size, HType::NonPrimitive(),
+ Add<HAllocate>(total_size, HType::HeapObject(),
NOT_TENURED, fixed_typed_array_map->instance_type());
AddStoreMapConstant(elements, fixed_typed_array_map);
InstanceType instance_type = boilerplate_object->HasFastDoubleElements()
? FIXED_DOUBLE_ARRAY_TYPE : FIXED_ARRAY_TYPE;
object_elements = Add<HAllocate>(
- object_elements_size, HType::NonPrimitive(),
+ object_elements_size, HType::HeapObject(),
pretenure_flag, instance_type, site_context->current());
}
BuildInitElementsInObjectHeader(boilerplate_object, object, object_elements);
Register temp = ToRegister(instr->temp());
SmiCheck check_needed =
- instr->hydrogen()->value()->IsHeapObject()
+ instr->hydrogen()->value()->type().IsHeapObject()
? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
Condition true_cond = EmitIsString(
Register input = ToRegister(instr->value());
Register temp = ToRegister(instr->temp());
- if (!instr->hydrogen()->value()->IsHeapObject()) {
+ if (!instr->hydrogen()->value()->type().IsHeapObject()) {
STATIC_ASSERT(kSmiTag == 0);
__ JumpIfSmi(input, instr->FalseLabel(chunk_));
}
Register input = ToRegister(instr->value());
Register temp = ToRegister(instr->temp());
- if (!instr->hydrogen()->value()->IsHeapObject()) {
+ if (!instr->hydrogen()->value()->type().IsHeapObject()) {
__ JumpIfSmi(input, instr->FalseLabel(chunk_));
}
__ mov(target, value);
if (instr->hydrogen()->NeedsWriteBarrier()) {
SmiCheck check_needed =
- instr->hydrogen()->value()->IsHeapObject()
+ instr->hydrogen()->value()->type().IsHeapObject()
? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
Register temp = ToRegister(instr->temp());
int offset = Context::SlotOffset(instr->slot_index());
Register value = ToRegister(instr->value());
ASSERT(!instr->key()->IsConstantOperand());
SmiCheck check_needed =
- instr->hydrogen()->value()->IsHeapObject()
+ instr->hydrogen()->value()->type().IsHeapObject()
? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
// Compute address of modified element and store it into key register.
__ lea(key, operand);
void LCodeGen::DoCheckNonSmi(LCheckNonSmi* instr) {
- if (!instr->hydrogen()->value()->IsHeapObject()) {
+ if (!instr->hydrogen()->value()->type().IsHeapObject()) {
LOperand* input = instr->value();
__ test(ToOperand(input), Immediate(kSmiTagMask));
DeoptimizeIf(zero, instr->environment());
LInstruction* LChunkBuilder::DoCheckHeapObject(HCheckHeapObject* instr) {
LOperand* value = UseAtStart(instr->value());
LInstruction* result = new(zone()) LCheckNonSmi(value);
- if (!instr->value()->IsHeapObject()) result = AssignEnvironment(result);
+ if (!instr->value()->type().IsHeapObject()) {
+ result = AssignEnvironment(result);
+ }
return result;
}
Register temp = ToRegister(instr->temp());
SmiCheck check_needed =
- instr->hydrogen()->value()->IsHeapObject()
+ instr->hydrogen()->value()->type().IsHeapObject()
? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
Condition true_cond = EmitIsString(
Register input = ToRegister(instr->value());
Register temp = ToRegister(instr->temp());
- if (!instr->hydrogen()->value()->IsHeapObject()) {
+ if (!instr->hydrogen()->value()->type().IsHeapObject()) {
__ JumpIfSmi(input, instr->FalseLabel(chunk_));
}
__ movp(temp, FieldOperand(input, HeapObject::kMapOffset));
void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) {
Register input = ToRegister(instr->value());
- if (!instr->hydrogen()->value()->IsHeapObject()) {
+ if (!instr->hydrogen()->value()->type().IsHeapObject()) {
__ JumpIfSmi(input, instr->FalseLabel(chunk_));
}
if (instr->hydrogen()->NeedsWriteBarrier()) {
SmiCheck check_needed =
- instr->hydrogen()->value()->IsHeapObject()
+ instr->hydrogen()->value()->type().IsHeapObject()
? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
int offset = Context::SlotOffset(instr->slot_index());
Register scratch = ToRegister(instr->temp());
ASSERT(instr->value()->IsRegister());
Register value = ToRegister(instr->value());
ASSERT(!key->IsConstantOperand());
- SmiCheck check_needed = hinstr->value()->IsHeapObject()
+ SmiCheck check_needed = hinstr->value()->type().IsHeapObject()
? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
// Compute address of modified element and store it into key register.
Register key_reg(ToRegister(key));
void LCodeGen::DoCheckNonSmi(LCheckNonSmi* instr) {
- if (!instr->hydrogen()->value()->IsHeapObject()) {
+ if (!instr->hydrogen()->value()->type().IsHeapObject()) {
LOperand* input = instr->value();
Condition cc = masm()->CheckSmi(ToRegister(input));
DeoptimizeIf(cc, instr->environment());
LInstruction* LChunkBuilder::DoCheckHeapObject(HCheckHeapObject* instr) {
LOperand* value = UseRegisterAtStart(instr->value());
LInstruction* result = new(zone()) LCheckNonSmi(value);
- if (!instr->value()->IsHeapObject()) result = AssignEnvironment(result);
+ if (!instr->value()->type().IsHeapObject()) {
+ result = AssignEnvironment(result);
+ }
return result;
}
'test-hashmap.cc',
'test-heap.cc',
'test-heap-profiler.cc',
+ 'test-hydrogen-types.cc',
'test-libplatform-task-queue.cc',
'test-libplatform-worker-thread.cc',
'test-list.cc',
# This tests only the type system, so there is no point in running several
# variants.
+ 'test-hydrogen-types/*': [PASS, NO_VARIANTS],
'test-types/*': [PASS, NO_VARIANTS],
# BUG(2999).
--- /dev/null
+// Copyright 2014 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.
+
+#include "hydrogen-types.h"
+
+#include "cctest.h"
+
+using namespace v8::internal;
+
+
+static const HType kTypes[] = {
+ #define DECLARE_TYPE(Name, mask) HType::Name(),
+ HTYPE_LIST(DECLARE_TYPE)
+ #undef DECLARE_TYPE
+};
+
+static const int kNumberOfTypes = sizeof(kTypes) / sizeof(kTypes[0]);
+
+
+TEST(HTypeDistinct) {
+ for (int i = 0; i < kNumberOfTypes; ++i) {
+ for (int j = 0; j < kNumberOfTypes; ++j) {
+ CHECK(i == j || !kTypes[i].Equals(kTypes[j]));
+ }
+ }
+}
+
+
+TEST(HTypeReflexivity) {
+ // Reflexivity of =
+ for (int i = 0; i < kNumberOfTypes; ++i) {
+ CHECK(kTypes[i].Equals(kTypes[i]));
+ }
+
+ // Reflexivity of <
+ for (int i = 0; i < kNumberOfTypes; ++i) {
+ CHECK(kTypes[i].IsSubtypeOf(kTypes[i]));
+ }
+}
+
+
+TEST(HTypeTransitivity) {
+ // Transitivity of =
+ for (int i = 0; i < kNumberOfTypes; ++i) {
+ for (int j = 0; j < kNumberOfTypes; ++j) {
+ for (int k = 0; k < kNumberOfTypes; ++k) {
+ HType ti = kTypes[i];
+ HType tj = kTypes[j];
+ HType tk = kTypes[k];
+ CHECK(!ti.Equals(tj) || !tj.Equals(tk) || ti.Equals(tk));
+ }
+ }
+ }
+
+ // Transitivity of <
+ for (int i = 0; i < kNumberOfTypes; ++i) {
+ for (int j = 0; j < kNumberOfTypes; ++j) {
+ for (int k = 0; k < kNumberOfTypes; ++k) {
+ HType ti = kTypes[i];
+ HType tj = kTypes[j];
+ HType tk = kTypes[k];
+ CHECK(!ti.IsSubtypeOf(tj) || !tj.IsSubtypeOf(tk) || ti.IsSubtypeOf(tk));
+ }
+ }
+ }
+}
+
+
+TEST(HTypeCombine) {
+ // T < T /\ T' and T' < T /\ T' for all T,T'
+ for (int i = 0; i < kNumberOfTypes; ++i) {
+ for (int j = 0; j < kNumberOfTypes; ++j) {
+ HType ti = kTypes[i];
+ HType tj = kTypes[j];
+ CHECK(ti.IsSubtypeOf(ti.Combine(tj)));
+ CHECK(tj.IsSubtypeOf(ti.Combine(tj)));
+ }
+ }
+}
+
+
+TEST(HTypeAny) {
+ // T < Any for all T
+ for (int i = 0; i < kNumberOfTypes; ++i) {
+ HType ti = kTypes[i];
+ CHECK(ti.IsAny());
+ }
+
+ // Any < T implies T = Any for all T
+ for (int i = 0; i < kNumberOfTypes; ++i) {
+ HType ti = kTypes[i];
+ CHECK(!HType::Any().IsSubtypeOf(ti) || HType::Any().Equals(ti));
+ }
+}
+
+
+TEST(HTypeTagged) {
+ // T < Tagged for all T \ {Any}
+ for (int i = 0; i < kNumberOfTypes; ++i) {
+ HType ti = kTypes[i];
+ CHECK(ti.IsTagged() || HType::Any().Equals(ti));
+ }
+
+ // Tagged < T implies T = Tagged or T = Any
+ for (int i = 0; i < kNumberOfTypes; ++i) {
+ HType ti = kTypes[i];
+ CHECK(!HType::Tagged().IsSubtypeOf(ti) ||
+ HType::Tagged().Equals(ti) ||
+ HType::Any().Equals(ti));
+ }
+}
+
+
+TEST(HTypeSmi) {
+ // T < Smi implies T = None or T = Smi for all T
+ for (int i = 0; i < kNumberOfTypes; ++i) {
+ HType ti = kTypes[i];
+ CHECK(!ti.IsSmi() ||
+ ti.Equals(HType::Smi()) ||
+ ti.Equals(HType::None()));
+ }
+}
+
+
+TEST(HTypeHeapObject) {
+ CHECK(!HType::TaggedPrimitive().IsHeapObject());
+ CHECK(!HType::TaggedNumber().IsHeapObject());
+ CHECK(!HType::Smi().IsHeapObject());
+ CHECK(HType::HeapObject().IsHeapObject());
+ CHECK(HType::HeapPrimitive().IsHeapObject());
+ CHECK(HType::Null().IsHeapObject());
+ CHECK(HType::HeapNumber().IsHeapObject());
+ CHECK(HType::String().IsHeapObject());
+ CHECK(HType::Boolean().IsHeapObject());
+ CHECK(HType::Undefined().IsHeapObject());
+ CHECK(HType::JSObject().IsHeapObject());
+ CHECK(HType::JSArray().IsHeapObject());
+}
+
+
+TEST(HTypePrimitive) {
+ CHECK(HType::TaggedNumber().IsTaggedPrimitive());
+ CHECK(HType::Smi().IsTaggedPrimitive());
+ CHECK(!HType::HeapObject().IsTaggedPrimitive());
+ CHECK(HType::HeapPrimitive().IsTaggedPrimitive());
+ CHECK(HType::Null().IsHeapPrimitive());
+ CHECK(HType::HeapNumber().IsHeapPrimitive());
+ CHECK(HType::String().IsHeapPrimitive());
+ CHECK(HType::Boolean().IsHeapPrimitive());
+ CHECK(HType::Undefined().IsHeapPrimitive());
+ CHECK(!HType::JSObject().IsTaggedPrimitive());
+ CHECK(!HType::JSArray().IsTaggedPrimitive());
+}
+
+
+TEST(HTypeJSObject) {
+ CHECK(HType::JSArray().IsJSObject());
+}
+
+
+TEST(HTypeNone) {
+ // None < T for all T
+ for (int i = 0; i < kNumberOfTypes; ++i) {
+ HType ti = kTypes[i];
+ CHECK(HType::None().IsSubtypeOf(ti));
+ }
+}
#include <vector>
#include "cctest.h"
+#include "hydrogen-types.h"
#include "types.h"
#include "utils/random-number-generator.h"
CheckEqual(type1, type3);
}
}
+
+ void HTypeFromType() {
+ for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) {
+ for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) {
+ TypeHandle type1 = *it1;
+ TypeHandle type2 = *it2;
+ HType htype1 = HType::FromType<Type>(type1);
+ HType htype2 = HType::FromType<Type>(type2);
+ CHECK(!type1->Is(type2) || htype1.IsSubtypeOf(htype2));
+ }
+ }
+ }
};
typedef Tests<Type, Type*, Zone, ZoneRep> ZoneTests;
ZoneTests().Convert<HeapType, Handle<HeapType>, Isolate, HeapRep>();
HeapTests().Convert<Type, Type*, Zone, ZoneRep>();
}
+
+
+TEST(HTypeFromType) {
+ CcTest::InitializeVM();
+ ZoneTests().HTypeFromType();
+ HeapTests().HTypeFromType();
+}
'../../src/hydrogen-sce.h',
'../../src/hydrogen-store-elimination.cc',
'../../src/hydrogen-store-elimination.h',
+ '../../src/hydrogen-types.cc',
+ '../../src/hydrogen-types.h',
'../../src/hydrogen-uint32-analysis.cc',
'../../src/hydrogen-uint32-analysis.h',
'../../src/i18n.cc',