Refactor HType to get rid of various hacks.
authorbmeurer@chromium.org <bmeurer@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 29 May 2014 04:13:50 +0000 (04:13 +0000)
committerbmeurer@chromium.org <bmeurer@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 29 May 2014 04:13:50 +0000 (04:13 +0000)
- Move HType to it's own file.
- Add HType::HeapObject and some other useful types.
- Get rid of the broken and useless HType::NonPrimitive.
- Introduce HType::FromType() to convert from HeapType to HType.
- Also add unit tests for HType.
- Fix types in Crankshaft.

R=rossberg@chromium.org

Review URL: https://codereview.chromium.org/300893003

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@21578 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

19 files changed:
src/arm/lithium-arm.cc
src/arm/lithium-codegen-arm.cc
src/arm64/lithium-arm64.cc
src/arm64/lithium-codegen-arm64.cc
src/code-stubs-hydrogen.cc
src/hydrogen-instructions.cc
src/hydrogen-instructions.h
src/hydrogen-types.cc [new file with mode: 0644]
src/hydrogen-types.h [new file with mode: 0644]
src/hydrogen.cc
src/ia32/lithium-codegen-ia32.cc
src/ia32/lithium-ia32.cc
src/x64/lithium-codegen-x64.cc
src/x64/lithium-x64.cc
test/cctest/cctest.gyp
test/cctest/cctest.status
test/cctest/test-hydrogen-types.cc [new file with mode: 0644]
test/cctest/test-types.cc
tools/gyp/v8.gyp

index 8a52f7b..1525565 100644 (file)
@@ -1979,7 +1979,9 @@ LInstruction* LChunkBuilder::DoChange(HChange* instr) {
 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;
 }
 
index 5f249c2..b342bf4 100644 (file)
@@ -2528,7 +2528,7 @@ void LCodeGen::DoIsStringAndBranch(LIsStringAndBranch* instr) {
   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);
@@ -2548,7 +2548,7 @@ void LCodeGen::DoIsUndetectableAndBranch(LIsUndetectableAndBranch* instr) {
   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));
@@ -2617,7 +2617,7 @@ void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) {
   Register scratch = scratch0();
   Register input = ToRegister(instr->value());
 
-  if (!instr->hydrogen()->value()->IsHeapObject()) {
+  if (!instr->hydrogen()->value()->type().IsHeapObject()) {
     __ JumpIfSmi(input, instr->FalseLabel(chunk_));
   }
 
@@ -3019,7 +3019,7 @@ void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) {
   __ 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(),
@@ -4325,7 +4325,7 @@ void LCodeGen::DoStoreKeyedFixedArray(LStoreKeyed* instr) {
 
   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));
@@ -5022,7 +5022,7 @@ void LCodeGen::DoCheckSmi(LCheckSmi* instr) {
 
 
 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());
index f434e46..d365dcf 100644 (file)
@@ -1216,7 +1216,9 @@ LInstruction* LChunkBuilder::DoCheckMaps(HCheckMaps* instr) {
 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;
 }
 
index 8ffbbc5..ef492a6 100644 (file)
@@ -2186,7 +2186,7 @@ void LCodeGen::DoCheckMaps(LCheckMaps* instr) {
 
 
 void LCodeGen::DoCheckNonSmi(LCheckNonSmi* instr) {
-  if (!instr->hydrogen()->value()->IsHeapObject()) {
+  if (!instr->hydrogen()->value()->type().IsHeapObject()) {
     DeoptimizeIfSmi(ToRegister(instr->value()), instr->environment());
   }
 }
@@ -2989,7 +2989,7 @@ void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) {
   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()));
@@ -3243,7 +3243,7 @@ void LCodeGen::DoIsStringAndBranch(LIsStringAndBranch* instr) {
   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);
@@ -3263,7 +3263,7 @@ void LCodeGen::DoIsUndetectableAndBranch(LIsUndetectableAndBranch* instr) {
   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));
@@ -5090,7 +5090,7 @@ void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) {
   __ 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(),
@@ -5284,7 +5284,7 @@ void LCodeGen::DoStoreKeyedFixed(LStoreKeyedFixed* instr) {
     // 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());
index 46d8551..29f650d 100644 (file)
@@ -1420,7 +1420,7 @@ HValue* CodeStubGraphBuilder<FastNewContextStub>::BuildCodeStub() {
   // 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,
index ef9f6d4..ce1e9db 100644 (file)
@@ -308,48 +308,6 @@ bool Range::MulAndCheckOverflow(const Representation& r, Range* other) {
 }
 
 
-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();
 }
@@ -1638,7 +1596,9 @@ HValue* HUnaryMathOperation::Canonicalize() {
 
 
 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();
   }
 
@@ -2698,7 +2658,7 @@ static bool IsInteger32(double 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),
@@ -2757,7 +2717,7 @@ HConstant::HConstant(Unique<Object> object,
     is_undetectable_(is_undetectable),
     instance_type_(instance_type) {
   ASSERT(!object.handle().is_null());
-  ASSERT(!type.IsTaggedNumber());
+  ASSERT(!type.IsTaggedNumber() || type.IsNone());
   Initialize(r);
 }
 
@@ -2815,7 +2775,7 @@ HConstant::HConstant(double double_value,
 
 
 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),
index 74faf55..908faa8 100644 (file)
@@ -12,6 +12,7 @@
 #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"
@@ -282,124 +283,6 @@ class Range V8_FINAL : public ZoneObject {
 };
 
 
-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)
@@ -727,10 +610,6 @@ class HValue : public ZoneObject {
     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...).
@@ -933,13 +812,13 @@ class HValue : public ZoneObject {
   // 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() {
@@ -955,6 +834,12 @@ class HValue : public ZoneObject {
     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();
   }
@@ -2839,10 +2724,16 @@ class HCheckMaps V8_FINAL : public HTemplateInstruction<2> {
   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; }
@@ -2881,7 +2772,7 @@ class HCheckMaps V8_FINAL : public HTemplateInstruction<2> {
 
  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());
@@ -2895,7 +2786,7 @@ class HCheckMaps V8_FINAL : public HTemplateInstruction<2> {
   }
 
   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());
@@ -2999,6 +2890,17 @@ class HCheckInstanceType V8_FINAL : public HUnaryOperation {
     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; }
@@ -3022,7 +2924,7 @@ class HCheckInstanceType V8_FINAL : public HUnaryOperation {
   const char* GetCheckName();
 
   HCheckInstanceType(HValue* value, Check check)
-      : HUnaryOperation(value), check_(check) {
+      : HUnaryOperation(value, HType::HeapObject()), check_(check) {
     set_representation(Representation::Tagged());
     SetFlag(kUseGVN);
   }
@@ -3069,6 +2971,11 @@ class HCheckHeapObject V8_FINAL : public HUnaryOperation {
     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
@@ -3083,8 +2990,7 @@ class HCheckHeapObject V8_FINAL : public HUnaryOperation {
   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);
   }
@@ -3566,7 +3472,7 @@ class HConstant V8_FINAL : public HTemplateInstruction<0> {
                                           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));
   }
 
@@ -3576,7 +3482,7 @@ class HConstant V8_FINAL : public HTemplateInstruction<0> {
                                          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));
   }
 
@@ -4187,7 +4093,7 @@ class HBoundsCheckBaseIndexInformation V8_FINAL
 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);
@@ -5140,7 +5046,7 @@ class HBitwise V8_FINAL : public HBitwiseBinaryOperation {
            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
@@ -5719,7 +5625,7 @@ class HInnerAllocatedObject V8_FINAL : public HTemplateInstruction<2> {
                                     HValue* context,
                                     HValue* value,
                                     HValue* offset,
-                                    HType type = HType::Tagged()) {
+                                    HType type) {
     return new(zone) HInnerAllocatedObject(value, offset, type);
   }
 
@@ -5737,20 +5643,21 @@ class HInnerAllocatedObject V8_FINAL : public HTemplateInstruction<2> {
  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());
 }
 
@@ -6371,9 +6278,7 @@ class HLoadNamedField V8_FINAL : public HTemplateInstruction<2> {
                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());
@@ -6395,9 +6300,7 @@ class HLoadNamedField V8_FINAL : public HTemplateInstruction<2> {
     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);
@@ -6813,7 +6716,7 @@ class HStoreNamedField V8_FINAL : public HTemplateInstruction<3> {
 
   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;
   }
 
@@ -7673,11 +7576,12 @@ class HCheckMapValue V8_FINAL : public HTemplateInstruction<2> {
   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;
 
@@ -7691,8 +7595,8 @@ class HCheckMapValue V8_FINAL : public HTemplateInstruction<2> {
   }
 
  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());
diff --git a/src/hydrogen-types.cc b/src/hydrogen-types.cc
new file mode 100644 (file)
index 0000000..2d83e1b
--- /dev/null
@@ -0,0 +1,67 @@
+// 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
diff --git a/src/hydrogen-types.h b/src/hydrogen-types.h
new file mode 100644 (file)
index 0000000..c34c278
--- /dev/null
@@ -0,0 +1,87 @@
+// 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_
index c1cb28f..3b77c73 100644 (file)
@@ -701,11 +701,11 @@ HConstant* HGraph::GetConstant##Name() {                                       \
 }
 
 
-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
@@ -1553,7 +1553,7 @@ HValue* HGraphBuilder::BuildRegExpConstructResult(HValue* length,
 
   // 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>(
@@ -2293,7 +2293,7 @@ HValue* HGraphBuilder::BuildAllocateElements(ElementsKind kind,
   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);
 }
 
@@ -2352,7 +2352,7 @@ HInnerAllocatedObject* HGraphBuilder::BuildJSArrayHeader(HValue* array,
   }
 
   HInnerAllocatedObject* elements = Add<HInnerAllocatedObject>(
-      array, Add<HConstant>(elements_location));
+      array, Add<HConstant>(elements_location), HType::HeapObject());
   Add<HStoreNamedField>(array, HObjectAccess::ForElementsPointer(), elements);
   return elements;
 }
@@ -2641,7 +2641,7 @@ HValue* HGraphBuilder::BuildCloneShallowArrayCommon(
 
   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;
   }
 
@@ -2799,7 +2799,7 @@ void HGraphBuilder::BuildCreateAllocationMemento(
     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>(
@@ -5485,7 +5485,7 @@ HInstruction* HOptimizedGraphBuilder::BuildStoreNamedField(
 
       // 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());
@@ -5673,20 +5673,8 @@ void HOptimizedGraphBuilder::PropertyAccessInfo::LoadFieldMaps(
   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(
@@ -8796,7 +8784,7 @@ HValue* HOptimizedGraphBuilder::BuildAllocateExternalElements(
   HValue* elements =
       Add<HAllocate>(
           Add<HConstant>(ExternalArray::kAlignedSize),
-          HType::NonPrimitive(),
+          HType::HeapObject(),
           NOT_TENURED,
           external_array_map->instance_type());
 
@@ -8853,7 +8841,7 @@ HValue* HOptimizedGraphBuilder::BuildAllocateFixedTypedArray(
   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);
 
@@ -10286,7 +10274,7 @@ HInstruction* HOptimizedGraphBuilder::BuildFastLiteral(
     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);
index 525944a..c2d602b 100644 (file)
@@ -2398,7 +2398,7 @@ void LCodeGen::DoIsStringAndBranch(LIsStringAndBranch* instr) {
   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(
@@ -2420,7 +2420,7 @@ void LCodeGen::DoIsUndetectableAndBranch(LIsUndetectableAndBranch* instr) {
   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_));
   }
@@ -2488,7 +2488,7 @@ void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) {
   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_));
   }
 
@@ -2894,7 +2894,7 @@ void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) {
   __ 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());
@@ -4210,7 +4210,7 @@ void LCodeGen::DoStoreKeyedFixedArray(LStoreKeyed* instr) {
     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);
@@ -4861,7 +4861,7 @@ void LCodeGen::DoCheckSmi(LCheckSmi* instr) {
 
 
 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());
index 7e587c1..9565a08 100644 (file)
@@ -1976,7 +1976,9 @@ LInstruction* LChunkBuilder::DoChange(HChange* instr) {
 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;
 }
 
index 879fbb8..2cfda62 100644 (file)
@@ -2414,7 +2414,7 @@ void LCodeGen::DoIsStringAndBranch(LIsStringAndBranch* instr) {
   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(
@@ -2441,7 +2441,7 @@ void LCodeGen::DoIsUndetectableAndBranch(LIsUndetectableAndBranch* instr) {
   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));
@@ -2488,7 +2488,7 @@ static Condition BranchCondition(HHasInstanceTypeAndBranch* instr) {
 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_));
   }
 
@@ -2877,7 +2877,7 @@ void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) {
 
   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());
@@ -4305,7 +4305,7 @@ void LCodeGen::DoStoreKeyedFixedArray(LStoreKeyed* instr) {
     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));
@@ -4909,7 +4909,7 @@ void LCodeGen::DoCheckSmi(LCheckSmi* instr) {
 
 
 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());
index e1b9e5f..3989db2 100644 (file)
@@ -1918,7 +1918,9 @@ LInstruction* LChunkBuilder::DoChange(HChange* instr) {
 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;
 }
 
index 5ca8b25..c775a1f 100644 (file)
@@ -83,6 +83,7 @@
         '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',
index 087b833..3179364 100644 (file)
@@ -67,6 +67,7 @@
 
   # 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).
diff --git a/test/cctest/test-hydrogen-types.cc b/test/cctest/test-hydrogen-types.cc
new file mode 100644 (file)
index 0000000..1d333c6
--- /dev/null
@@ -0,0 +1,168 @@
+// 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));
+  }
+}
index 21e3df8..41863bc 100644 (file)
@@ -28,6 +28,7 @@
 #include <vector>
 
 #include "cctest.h"
+#include "hydrogen-types.h"
 #include "types.h"
 #include "utils/random-number-generator.h"
 
@@ -1776,6 +1777,18 @@ struct Tests : Rep {
       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;
@@ -1920,3 +1933,10 @@ TEST(Convert) {
   ZoneTests().Convert<HeapType, Handle<HeapType>, Isolate, HeapRep>();
   HeapTests().Convert<Type, Type*, Zone, ZoneRep>();
 }
+
+
+TEST(HTypeFromType) {
+  CcTest::InitializeVM();
+  ZoneTests().HTypeFromType();
+  HeapTests().HTypeFromType();
+}
index 5681f19..803022e 100644 (file)
         '../../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',