| Index: src/hydrogen-instructions.h
|
| diff --git a/src/hydrogen-instructions.h b/src/hydrogen-instructions.h
|
| index 3aa15e375a78aee6cbb4b31395cb1a87957ebe54..eea429e6f2b11ea2d506d448e7bf39871886d472 100644
|
| --- a/src/hydrogen-instructions.h
|
| +++ b/src/hydrogen-instructions.h
|
| @@ -64,6 +64,7 @@ class LChunkBuilder;
|
| V(AbnormalExit) \
|
| V(AccessArgumentsAt) \
|
| V(Add) \
|
| + V(Allocate) \
|
| V(AllocateObject) \
|
| V(ApplyArguments) \
|
| V(ArgumentsElements) \
|
| @@ -179,6 +180,7 @@ class LChunkBuilder;
|
| V(Throw) \
|
| V(ToFastProperties) \
|
| V(TransitionElementsKind) \
|
| + V(TrapAllocationMemento) \
|
| V(Typeof) \
|
| V(TypeofIsAndBranch) \
|
| V(UnaryMathOperation) \
|
| @@ -4160,6 +4162,106 @@ class HLoadGlobalGeneric: public HTemplateInstruction<2> {
|
| };
|
|
|
|
|
| +class HAllocateObject: public HTemplateInstruction<1> {
|
| + public:
|
| + HAllocateObject(HValue* context, Handle<JSFunction> constructor)
|
| + : constructor_(constructor) {
|
| + SetOperandAt(0, context);
|
| + set_representation(Representation::Tagged());
|
| + SetGVNFlag(kChangesNewSpacePromotion);
|
| + }
|
| +
|
| + // Maximum instance size for which allocations will be inlined.
|
| + static const int kMaxSize = 64 * kPointerSize;
|
| +
|
| + HValue* context() { return OperandAt(0); }
|
| + Handle<JSFunction> constructor() { return constructor_; }
|
| +
|
| + virtual Representation RequiredInputRepresentation(int index) {
|
| + return Representation::Tagged();
|
| + }
|
| + virtual Handle<Map> GetMonomorphicJSObjectMap() {
|
| + ASSERT(constructor()->has_initial_map());
|
| + return Handle<Map>(constructor()->initial_map());
|
| + }
|
| + virtual HType CalculateInferredType();
|
| +
|
| + DECLARE_CONCRETE_INSTRUCTION(AllocateObject)
|
| +
|
| + private:
|
| + // TODO(svenpanne) Might be safe, but leave it out until we know for sure.
|
| + // virtual bool IsDeletable() const { return true; }
|
| +
|
| + Handle<JSFunction> constructor_;
|
| +};
|
| +
|
| +
|
| +class HAllocate: public HTemplateInstruction<2> {
|
| + public:
|
| + enum Flags {
|
| + CAN_ALLOCATE_IN_NEW_SPACE = 1 << 0,
|
| + CAN_ALLOCATE_IN_OLD_DATA_SPACE = 1 << 1,
|
| + CAN_ALLOCATE_IN_OLD_POINTER_SPACE = 1 << 2,
|
| + ALLOCATE_DOUBLE_ALIGNED = 1 << 3
|
| + };
|
| +
|
| + HAllocate(HValue* context, HValue* size, HType type, Flags flags)
|
| + : type_(type),
|
| + flags_(flags) {
|
| + ASSERT((flags & CAN_ALLOCATE_IN_OLD_DATA_SPACE) == 0); // unimplemented
|
| + ASSERT((flags & CAN_ALLOCATE_IN_OLD_POINTER_SPACE) == 0); // unimplemented
|
| + SetOperandAt(0, context);
|
| + SetOperandAt(1, size);
|
| + set_representation(Representation::Tagged());
|
| + SetGVNFlag(kChangesNewSpacePromotion);
|
| + }
|
| +
|
| + HValue* context() { return OperandAt(0); }
|
| + HValue* size() { return OperandAt(1); }
|
| +
|
| + virtual Representation RequiredInputRepresentation(int index) {
|
| + if (index == 0) {
|
| + return Representation::Tagged();
|
| + } else {
|
| + return Representation::Integer32();
|
| + }
|
| + }
|
| +
|
| + virtual HType CalculateInferredType();
|
| +
|
| + bool CanAllocateInNewSpace() const {
|
| + return (flags_ & CAN_ALLOCATE_IN_NEW_SPACE) != 0;
|
| + }
|
| +
|
| + bool CanAllocateInOldDataSpace() const {
|
| + return (flags_ & CAN_ALLOCATE_IN_OLD_DATA_SPACE) != 0;
|
| + }
|
| +
|
| + bool CanAllocateInOldPointerSpace() const {
|
| + return (flags_ & CAN_ALLOCATE_IN_OLD_POINTER_SPACE) != 0;
|
| + }
|
| +
|
| + bool CanAllocateInOldSpace() const {
|
| + return CanAllocateInOldDataSpace() ||
|
| + CanAllocateInOldPointerSpace();
|
| + }
|
| +
|
| + bool GuaranteedInNewSpace() const {
|
| + return CanAllocateInNewSpace() && !CanAllocateInOldSpace();
|
| + }
|
| +
|
| + bool MustAllocateDoubleAligned() const {
|
| + return (flags_ & ALLOCATE_DOUBLE_ALIGNED) != 0;
|
| + }
|
| +
|
| + DECLARE_CONCRETE_INSTRUCTION(Allocate)
|
| +
|
| + private:
|
| + HType type_;
|
| + Flags flags_;
|
| +};
|
| +
|
| +
|
| inline bool StoringValueNeedsWriteBarrier(HValue* value) {
|
| return !value->type().IsBoolean()
|
| && !value->type().IsSmi()
|
| @@ -4169,8 +4271,13 @@ inline bool StoringValueNeedsWriteBarrier(HValue* value) {
|
|
|
| inline bool ReceiverObjectNeedsWriteBarrier(HValue* object,
|
| HValue* new_space_dominator) {
|
| - return (!object->IsAllocateObject() && !object->IsFastLiteral()) ||
|
| - (object != new_space_dominator);
|
| + if (object != new_space_dominator) return true;
|
| + if (object->IsFastLiteral()) return false;
|
| + if (object->IsAllocateObject()) return false;
|
| + if (object->IsAllocate()) {
|
| + return !HAllocate::cast(object)->GuaranteedInNewSpace();
|
| + }
|
| + return true;
|
| }
|
|
|
|
|
| @@ -4502,15 +4609,23 @@ class ArrayInstructionInterface {
|
| };
|
|
|
|
|
| +enum LoadKeyedHoleMode {
|
| + NEVER_RETURN_HOLE,
|
| + ALLOW_RETURN_HOLE
|
| +};
|
| +
|
| +
|
| class HLoadKeyed
|
| : public HTemplateInstruction<3>, public ArrayInstructionInterface {
|
| public:
|
| HLoadKeyed(HValue* obj,
|
| HValue* key,
|
| HValue* dependency,
|
| - ElementsKind elements_kind)
|
| + ElementsKind elements_kind,
|
| + LoadKeyedHoleMode mode = NEVER_RETURN_HOLE)
|
| : bit_field_(0) {
|
| - bit_field_ = ElementsKindField::encode(elements_kind);
|
| + bit_field_ = ElementsKindField::encode(elements_kind) |
|
| + HoleModeField::encode(mode);
|
|
|
| SetOperandAt(0, obj);
|
| SetOperandAt(1, key);
|
| @@ -4523,8 +4638,7 @@ class HLoadKeyed
|
| IsFastDoubleElementsKind(elements_kind));
|
|
|
| if (IsFastSmiOrObjectElementsKind(elements_kind)) {
|
| - if (IsFastSmiElementsKind(elements_kind) &&
|
| - IsFastPackedElementsKind(elements_kind)) {
|
| + if (IsFastSmiElementsKind(elements_kind)) {
|
| set_type(HType::Smi());
|
| }
|
|
|
| @@ -4573,6 +4687,9 @@ class HLoadKeyed
|
| ElementsKind elements_kind() const {
|
| return ElementsKindField::decode(bit_field_);
|
| }
|
| + LoadKeyedHoleMode hole_mode() const {
|
| + return HoleModeField::decode(bit_field_);
|
| + }
|
|
|
| virtual Representation RequiredInputRepresentation(int index) {
|
| // kind_fast: tagged[int32] (none)
|
| @@ -4595,6 +4712,7 @@ class HLoadKeyed
|
|
|
| virtual void PrintDataTo(StringStream* stream);
|
|
|
| + bool UsesMustHandleHole() const;
|
| bool RequiresHoleCheck() const;
|
|
|
| virtual Range* InferRange(Zone* zone);
|
| @@ -4619,11 +4737,13 @@ class HLoadKeyed
|
| // Establish some checks around our packed fields
|
| enum LoadKeyedBits {
|
| kBitsForElementsKind = 5,
|
| - kBitsForIndexOffset = 26,
|
| + kBitsForHoleMode = 1,
|
| + kBitsForIndexOffset = 25,
|
| kBitsForIsDehoisted = 1,
|
|
|
| kStartElementsKind = 0,
|
| - kStartIndexOffset = kStartElementsKind + kBitsForElementsKind,
|
| + kStartHoleMode = kStartElementsKind + kBitsForElementsKind,
|
| + kStartIndexOffset = kStartHoleMode + kBitsForHoleMode,
|
| kStartIsDehoisted = kStartIndexOffset + kBitsForIndexOffset
|
| };
|
|
|
| @@ -4633,6 +4753,9 @@ class HLoadKeyed
|
| class ElementsKindField:
|
| public BitField<ElementsKind, kStartElementsKind, kBitsForElementsKind>
|
| {}; // NOLINT
|
| + class HoleModeField:
|
| + public BitField<LoadKeyedHoleMode, kStartHoleMode, kBitsForHoleMode>
|
| + {}; // NOLINT
|
| class IndexOffsetField:
|
| public BitField<uint32_t, kStartIndexOffset, kBitsForIndexOffset>
|
| {}; // NOLINT
|
| @@ -4771,11 +4894,18 @@ class HStoreKeyed
|
| public:
|
| HStoreKeyed(HValue* obj, HValue* key, HValue* val,
|
| ElementsKind elements_kind)
|
| - : elements_kind_(elements_kind), index_offset_(0), is_dehoisted_(false) {
|
| + : elements_kind_(elements_kind),
|
| + index_offset_(0),
|
| + is_dehoisted_(false),
|
| + new_space_dominator_(NULL) {
|
| SetOperandAt(0, obj);
|
| SetOperandAt(1, key);
|
| SetOperandAt(2, val);
|
|
|
| + if (IsFastObjectElementsKind(elements_kind)) {
|
| + SetFlag(kTrackSideEffectDominators);
|
| + SetGVNFlag(kDependsOnNewSpacePromotion);
|
| + }
|
| if (is_external()) {
|
| SetGVNFlag(kChangesSpecializedArrayElements);
|
| } else if (IsFastDoubleElementsKind(elements_kind)) {
|
| @@ -4843,11 +4973,19 @@ class HStoreKeyed
|
| bool IsDehoisted() { return is_dehoisted_; }
|
| void SetDehoisted(bool is_dehoisted) { is_dehoisted_ = is_dehoisted; }
|
|
|
| + virtual void SetSideEffectDominator(GVNFlag side_effect, HValue* dominator) {
|
| + ASSERT(side_effect == kChangesNewSpacePromotion);
|
| + new_space_dominator_ = dominator;
|
| + }
|
| +
|
| + HValue* new_space_dominator() const { return new_space_dominator_; }
|
| +
|
| bool NeedsWriteBarrier() {
|
| if (value_is_smi()) {
|
| return false;
|
| } else {
|
| - return StoringValueNeedsWriteBarrier(value());
|
| + return StoringValueNeedsWriteBarrier(value()) &&
|
| + ReceiverObjectNeedsWriteBarrier(elements(), new_space_dominator());
|
| }
|
| }
|
|
|
| @@ -4861,6 +4999,7 @@ class HStoreKeyed
|
| ElementsKind elements_kind_;
|
| uint32_t index_offset_;
|
| bool is_dehoisted_;
|
| + HValue* new_space_dominator_;
|
| };
|
|
|
|
|
| @@ -4899,9 +5038,10 @@ class HStoreKeyedGeneric: public HTemplateInstruction<4> {
|
| };
|
|
|
|
|
| -class HTransitionElementsKind: public HTemplateInstruction<1> {
|
| +class HTransitionElementsKind: public HTemplateInstruction<2> {
|
| public:
|
| - HTransitionElementsKind(HValue* object,
|
| + HTransitionElementsKind(HValue* context,
|
| + HValue* object,
|
| Handle<Map> original_map,
|
| Handle<Map> transitioned_map)
|
| : original_map_(original_map),
|
| @@ -4909,6 +5049,7 @@ class HTransitionElementsKind: public HTemplateInstruction<1> {
|
| from_kind_(original_map->elements_kind()),
|
| to_kind_(transitioned_map->elements_kind()) {
|
| SetOperandAt(0, object);
|
| + SetOperandAt(1, context);
|
| SetFlag(kUseGVN);
|
| SetGVNFlag(kChangesElementsKind);
|
| if (original_map->has_fast_double_elements()) {
|
| @@ -4927,6 +5068,7 @@ class HTransitionElementsKind: public HTemplateInstruction<1> {
|
| }
|
|
|
| HValue* object() { return OperandAt(0); }
|
| + HValue* context() { return OperandAt(1); }
|
| Handle<Map> original_map() { return original_map_; }
|
| Handle<Map> transitioned_map() { return transitioned_map_; }
|
| ElementsKind from_kind() { return from_kind_; }
|
| @@ -5079,40 +5221,6 @@ class HStringLength: public HUnaryOperation {
|
| };
|
|
|
|
|
| -class HAllocateObject: public HTemplateInstruction<1> {
|
| - public:
|
| - HAllocateObject(HValue* context, Handle<JSFunction> constructor)
|
| - : constructor_(constructor) {
|
| - SetOperandAt(0, context);
|
| - set_representation(Representation::Tagged());
|
| - SetGVNFlag(kChangesNewSpacePromotion);
|
| - }
|
| -
|
| - // Maximum instance size for which allocations will be inlined.
|
| - static const int kMaxSize = 64 * kPointerSize;
|
| -
|
| - HValue* context() { return OperandAt(0); }
|
| - Handle<JSFunction> constructor() { return constructor_; }
|
| -
|
| - virtual Representation RequiredInputRepresentation(int index) {
|
| - return Representation::Tagged();
|
| - }
|
| - virtual Handle<Map> GetMonomorphicJSObjectMap() {
|
| - ASSERT(constructor()->has_initial_map());
|
| - return Handle<Map>(constructor()->initial_map());
|
| - }
|
| - virtual HType CalculateInferredType();
|
| -
|
| - DECLARE_CONCRETE_INSTRUCTION(AllocateObject)
|
| -
|
| - private:
|
| - // TODO(svenpanne) Might be safe, but leave it out until we know for sure.
|
| - // virtual bool IsDeletable() const { return true; }
|
| -
|
| - Handle<JSFunction> constructor_;
|
| -};
|
| -
|
| -
|
| template <int V>
|
| class HMaterializedLiteral: public HTemplateInstruction<V> {
|
| public:
|
| @@ -5346,6 +5454,22 @@ class HTypeof: public HTemplateInstruction<2> {
|
| };
|
|
|
|
|
| +class HTrapAllocationMemento : public HTemplateInstruction<1> {
|
| + public:
|
| + explicit HTrapAllocationMemento(HValue* obj) {
|
| + SetOperandAt(0, obj);
|
| + }
|
| +
|
| + virtual Representation RequiredInputRepresentation(int index) {
|
| + return Representation::Tagged();
|
| + }
|
| +
|
| + HValue* object() { return OperandAt(0); }
|
| +
|
| + DECLARE_CONCRETE_INSTRUCTION(TrapAllocationMemento)
|
| +};
|
| +
|
| +
|
| class HToFastProperties: public HUnaryOperation {
|
| public:
|
| explicit HToFastProperties(HValue* value) : HUnaryOperation(value) {
|
|
|