From e9357a5e7795f7436b633ba24babcc5d574bd3af Mon Sep 17 00:00:00 2001 From: "bmeurer@chromium.org" Date: Thu, 29 May 2014 04:13:50 +0000 Subject: [PATCH] Refactor HType to get rid of various hacks. - 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 --- src/arm/lithium-arm.cc | 4 +- src/arm/lithium-codegen-arm.cc | 12 +-- src/arm64/lithium-arm64.cc | 4 +- src/arm64/lithium-codegen-arm64.cc | 12 +-- src/code-stubs-hydrogen.cc | 2 +- src/hydrogen-instructions.cc | 52 ++------- src/hydrogen-instructions.h | 210 ++++++++++--------------------------- src/hydrogen-types.cc | 67 ++++++++++++ src/hydrogen-types.h | 87 +++++++++++++++ src/hydrogen.cc | 40 +++---- src/ia32/lithium-codegen-ia32.cc | 12 +-- src/ia32/lithium-ia32.cc | 4 +- src/x64/lithium-codegen-x64.cc | 12 +-- src/x64/lithium-x64.cc | 4 +- test/cctest/cctest.gyp | 1 + test/cctest/cctest.status | 1 + test/cctest/test-hydrogen-types.cc | 168 +++++++++++++++++++++++++++++ test/cctest/test-types.cc | 20 ++++ tools/gyp/v8.gyp | 2 + 19 files changed, 460 insertions(+), 254 deletions(-) create mode 100644 src/hydrogen-types.cc create mode 100644 src/hydrogen-types.h create mode 100644 test/cctest/test-hydrogen-types.cc diff --git a/src/arm/lithium-arm.cc b/src/arm/lithium-arm.cc index 8a52f7b..1525565 100644 --- a/src/arm/lithium-arm.cc +++ b/src/arm/lithium-arm.cc @@ -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; } diff --git a/src/arm/lithium-codegen-arm.cc b/src/arm/lithium-codegen-arm.cc index 5f249c2..b342bf4 100644 --- a/src/arm/lithium-codegen-arm.cc +++ b/src/arm/lithium-codegen-arm.cc @@ -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()); diff --git a/src/arm64/lithium-arm64.cc b/src/arm64/lithium-arm64.cc index f434e46..d365dcf 100644 --- a/src/arm64/lithium-arm64.cc +++ b/src/arm64/lithium-arm64.cc @@ -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; } diff --git a/src/arm64/lithium-codegen-arm64.cc b/src/arm64/lithium-codegen-arm64.cc index 8ffbbc5..ef492a6 100644 --- a/src/arm64/lithium-codegen-arm64.cc +++ b/src/arm64/lithium-codegen-arm64.cc @@ -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()); diff --git a/src/code-stubs-hydrogen.cc b/src/code-stubs-hydrogen.cc index 46d8551..29f650d 100644 --- a/src/code-stubs-hydrogen.cc +++ b/src/code-stubs-hydrogen.cc @@ -1420,7 +1420,7 @@ HValue* CodeStubGraphBuilder::BuildCodeStub() { // Allocate the context in new space. HAllocate* function_context = Add( Add(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, diff --git a/src/hydrogen-instructions.cc b/src/hydrogen-instructions.cc index ef9f6d4..ce1e9db 100644 --- a/src/hydrogen-instructions.cc +++ b/src/hydrogen-instructions.cc @@ -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 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, Representation r) - : HTemplateInstruction<0>(HType::TypeFromValue(object)), + : HTemplateInstruction<0>(HType::FromValue(object)), object_(Unique::CreateUninitialized(object)), object_map_(Handle::null()), has_stable_map_value_(false), @@ -2757,7 +2717,7 @@ HConstant::HConstant(Unique 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(Handle::null())), object_map_(Handle::null()), has_stable_map_value_(false), diff --git a/src/hydrogen-instructions.h b/src/hydrogen-instructions.h index 74faf55..908faa8 100644 --- a/src/hydrogen-instructions.h +++ b/src/hydrogen-instructions.h @@ -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_ & 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 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* maps() const { return maps_; } void set_maps(const UniqueSet* maps) { maps_ = maps; } @@ -2881,7 +2772,7 @@ class HCheckMaps V8_FINAL : public HTemplateInstruction<2> { private: HCheckMaps(HValue* value, const UniqueSet* 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* 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(Handle::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(Handle::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 index 0000000..2d83e1b --- /dev/null +++ b/src/hydrogen-types.cc @@ -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 +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); + + +// static +template +HType HType::FromType(Handle type); + + +// static +HType HType::FromValue(Handle 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 index 0000000..c34c278 --- /dev/null +++ b/src/hydrogen-types.h @@ -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 + +#include "base/macros.h" + +namespace v8 { +namespace internal { + +// Forward declarations. +template 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_ & 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 + static HType FromType(typename T::TypeHandle type) V8_WARN_UNUSED_RESULT; + static HType FromValue(Handle 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_ diff --git a/src/hydrogen.cc b/src/hydrogen.cc index c1cb28f..3b77c73 100644 --- a/src/hydrogen.cc +++ b/src/hydrogen.cc @@ -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( - result, Add(JSRegExpResult::kSize)); + result, Add(JSRegExpResult::kSize), HType::HeapObject()); // Initialize the JSRegExpResult header. HValue* global_object = Add( @@ -2293,7 +2293,7 @@ HValue* HGraphBuilder::BuildAllocateElements(ElementsKind kind, HValue* total_size = AddUncasted(mul, header_size); total_size->ClearFlag(HValue::kCanOverflow); - return Add(total_size, HType::NonPrimitive(), NOT_TENURED, + return Add(total_size, HType::HeapObject(), NOT_TENURED, instance_type); } @@ -2352,7 +2352,7 @@ HInnerAllocatedObject* HGraphBuilder::BuildJSArrayHeader(HValue* array, } HInnerAllocatedObject* elements = Add( - array, Add(elements_location)); + array, Add(elements_location), HType::HeapObject()); Add(array, HObjectAccess::ForElementsPointer(), elements); return elements; } @@ -2641,7 +2641,7 @@ HValue* HGraphBuilder::BuildCloneShallowArrayCommon( if (extra_size != NULL) { HValue* elements = Add(object, - Add(array_size)); + Add(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( - previous_object, previous_object_size); + previous_object, previous_object_size, HType::HeapObject()); AddStoreMapConstant( allocation_memento, isolate()->factory()->allocation_memento_map()); Add( @@ -5485,7 +5485,7 @@ HInstruction* HOptimizedGraphBuilder::BuildStoreNamedField( // TODO(hpayer): Allocation site pretenuring support. HInstruction* heap_number = Add(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(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( Add(ExternalArray::kAlignedSize), - HType::NonPrimitive(), + HType::HeapObject(), NOT_TENURED, external_array_map->instance_type()); @@ -8853,7 +8841,7 @@ HValue* HOptimizedGraphBuilder::BuildAllocateFixedTypedArray( Handle fixed_typed_array_map( isolate()->heap()->MapForFixedTypedArray(array_type)); HValue* elements = - Add(total_size, HType::NonPrimitive(), + Add(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( - object_elements_size, HType::NonPrimitive(), + object_elements_size, HType::HeapObject(), pretenure_flag, instance_type, site_context->current()); } BuildInitElementsInObjectHeader(boilerplate_object, object, object_elements); diff --git a/src/ia32/lithium-codegen-ia32.cc b/src/ia32/lithium-codegen-ia32.cc index 525944a..c2d602b 100644 --- a/src/ia32/lithium-codegen-ia32.cc +++ b/src/ia32/lithium-codegen-ia32.cc @@ -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()); diff --git a/src/ia32/lithium-ia32.cc b/src/ia32/lithium-ia32.cc index 7e587c1..9565a08 100644 --- a/src/ia32/lithium-ia32.cc +++ b/src/ia32/lithium-ia32.cc @@ -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; } diff --git a/src/x64/lithium-codegen-x64.cc b/src/x64/lithium-codegen-x64.cc index 879fbb8..2cfda62 100644 --- a/src/x64/lithium-codegen-x64.cc +++ b/src/x64/lithium-codegen-x64.cc @@ -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()); diff --git a/src/x64/lithium-x64.cc b/src/x64/lithium-x64.cc index e1b9e5f..3989db2 100644 --- a/src/x64/lithium-x64.cc +++ b/src/x64/lithium-x64.cc @@ -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; } diff --git a/test/cctest/cctest.gyp b/test/cctest/cctest.gyp index 5ca8b25..c775a1f 100644 --- a/test/cctest/cctest.gyp +++ b/test/cctest/cctest.gyp @@ -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', diff --git a/test/cctest/cctest.status b/test/cctest/cctest.status index 087b833..3179364 100644 --- a/test/cctest/cctest.status +++ b/test/cctest/cctest.status @@ -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 index 0000000..1d333c6 --- /dev/null +++ b/test/cctest/test-hydrogen-types.cc @@ -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)); + } +} diff --git a/test/cctest/test-types.cc b/test/cctest/test-types.cc index 21e3df8..41863bc 100644 --- a/test/cctest/test-types.cc +++ b/test/cctest/test-types.cc @@ -28,6 +28,7 @@ #include #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(type1); + HType htype2 = HType::FromType(type2); + CHECK(!type1->Is(type2) || htype1.IsSubtypeOf(htype2)); + } + } + } }; typedef Tests ZoneTests; @@ -1920,3 +1933,10 @@ TEST(Convert) { ZoneTests().Convert, Isolate, HeapRep>(); HeapTests().Convert(); } + + +TEST(HTypeFromType) { + CcTest::InitializeVM(); + ZoneTests().HTypeFromType(); + HeapTests().HTypeFromType(); +} diff --git a/tools/gyp/v8.gyp b/tools/gyp/v8.gyp index 5681f19..803022e 100644 --- a/tools/gyp/v8.gyp +++ b/tools/gyp/v8.gyp @@ -421,6 +421,8 @@ '../../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', -- 2.7.4