OLD | NEW |
---|---|
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 5313 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
5324 class HObjectAccess { | 5324 class HObjectAccess { |
5325 public: | 5325 public: |
5326 inline bool IsInobject() const { | 5326 inline bool IsInobject() const { |
5327 return portion() != kBackingStore; | 5327 return portion() != kBackingStore; |
5328 } | 5328 } |
5329 | 5329 |
5330 inline int offset() const { | 5330 inline int offset() const { |
5331 return OffsetField::decode(value_); | 5331 return OffsetField::decode(value_); |
5332 } | 5332 } |
5333 | 5333 |
5334 inline Representation representation() const { | |
5335 return Representation::FromKind(RepresentationField::decode(value_)); | |
5336 } | |
5337 | |
5334 inline Handle<String> name() const { | 5338 inline Handle<String> name() const { |
5335 return name_; | 5339 return name_; |
5336 } | 5340 } |
5337 | 5341 |
5342 inline HObjectAccess WithRepresentation(Representation representation) { | |
danno
2013/07/16 11:51:58
Ouch. I really wish we didn't need this version. I
titzer
2013/07/23 15:04:10
Not really, because Representation::generalize() c
| |
5343 return HObjectAccess(portion(), offset(), representation, name()); | |
5344 } | |
5345 | |
5338 static HObjectAccess ForHeapNumberValue() { | 5346 static HObjectAccess ForHeapNumberValue() { |
5339 return HObjectAccess(kDouble, HeapNumber::kValueOffset); | 5347 return HObjectAccess( |
5348 kDouble, HeapNumber::kValueOffset, Representation::Double()); | |
5340 } | 5349 } |
5341 | 5350 |
5342 static HObjectAccess ForElementsPointer() { | 5351 static HObjectAccess ForElementsPointer() { |
5343 return HObjectAccess(kElementsPointer, JSObject::kElementsOffset); | 5352 return HObjectAccess(kElementsPointer, JSObject::kElementsOffset); |
5344 } | 5353 } |
5345 | 5354 |
5346 static HObjectAccess ForArrayLength() { | 5355 static HObjectAccess ForArrayLength(bool is_fast_elements = false) { |
danno
2013/07/16 11:51:58
Can you pass in the ElementsKind here? The boolean
titzer
2013/07/23 15:04:10
What would be the default elements kind? We have 3
danno
2013/07/23 16:15:43
I would prefer that you use ElementsKind and not h
| |
5347 return HObjectAccess(kArrayLengths, JSArray::kLengthOffset); | 5356 return HObjectAccess( |
5357 kArrayLengths, JSArray::kLengthOffset, | |
5358 is_fast_elements && FLAG_track_fields ? | |
5359 Representation::Smi() : Representation::Tagged()); | |
5348 } | 5360 } |
5349 | 5361 |
5350 static HObjectAccess ForAllocationSiteTransitionInfo() { | 5362 static HObjectAccess ForAllocationSiteTransitionInfo() { |
5351 return HObjectAccess(kInobject, AllocationSite::kTransitionInfoOffset); | 5363 return HObjectAccess(kInobject, AllocationSite::kTransitionInfoOffset); |
5352 } | 5364 } |
5353 | 5365 |
5354 static HObjectAccess ForFixedArrayLength() { | 5366 static HObjectAccess ForFixedArrayLength() { |
5355 return HObjectAccess(kArrayLengths, FixedArray::kLengthOffset); | 5367 return HObjectAccess( |
5368 kArrayLengths, FixedArray::kLengthOffset, | |
5369 FLAG_track_fields ? | |
5370 Representation::Smi() : Representation::Tagged()); | |
5356 } | 5371 } |
5357 | 5372 |
5358 static HObjectAccess ForPropertiesPointer() { | 5373 static HObjectAccess ForPropertiesPointer() { |
5359 return HObjectAccess(kInobject, JSObject::kPropertiesOffset); | 5374 return HObjectAccess(kInobject, JSObject::kPropertiesOffset); |
5360 } | 5375 } |
5361 | 5376 |
5362 static HObjectAccess ForPrototypeOrInitialMap() { | 5377 static HObjectAccess ForPrototypeOrInitialMap() { |
5363 return HObjectAccess(kInobject, JSFunction::kPrototypeOrInitialMapOffset); | 5378 return HObjectAccess(kInobject, JSFunction::kPrototypeOrInitialMapOffset); |
5364 } | 5379 } |
5365 | 5380 |
(...skipping 10 matching lines...) Expand all Loading... | |
5376 } | 5391 } |
5377 | 5392 |
5378 static HObjectAccess ForAllocationSiteInfoSite() { | 5393 static HObjectAccess ForAllocationSiteInfoSite() { |
5379 return HObjectAccess(kInobject, AllocationSiteInfo::kAllocationSiteOffset); | 5394 return HObjectAccess(kInobject, AllocationSiteInfo::kAllocationSiteOffset); |
5380 } | 5395 } |
5381 | 5396 |
5382 // Create an access to an offset in a fixed array header. | 5397 // Create an access to an offset in a fixed array header. |
5383 static HObjectAccess ForFixedArrayHeader(int offset); | 5398 static HObjectAccess ForFixedArrayHeader(int offset); |
5384 | 5399 |
5385 // Create an access to an in-object property in a JSObject. | 5400 // Create an access to an in-object property in a JSObject. |
5386 static HObjectAccess ForJSObjectOffset(int offset); | 5401 static HObjectAccess ForJSObjectOffset(int offset, |
5402 Representation representation = Representation::Tagged()); | |
5387 | 5403 |
5388 // Create an access to an in-object property in a JSArray. | 5404 // Create an access to an in-object property in a JSArray. |
5389 static HObjectAccess ForJSArrayOffset(int offset); | 5405 static HObjectAccess ForJSArrayOffset(int offset); |
5390 | 5406 |
5391 // Create an access to the backing store of an object. | 5407 // Create an access to the backing store of an object. |
5392 static HObjectAccess ForBackingStoreOffset(int offset); | 5408 static HObjectAccess ForBackingStoreOffset(int offset, |
5409 Representation representation = Representation::Tagged()); | |
5393 | 5410 |
5394 // Create an access to a resolved field (in-object or backing store). | 5411 // Create an access to a resolved field (in-object or backing store). |
5395 static HObjectAccess ForField(Handle<Map> map, | 5412 static HObjectAccess ForField(Handle<Map> map, |
5396 LookupResult *lookup, Handle<String> name = Handle<String>::null()); | 5413 LookupResult *lookup, Handle<String> name = Handle<String>::null()); |
5397 | 5414 |
5398 // Create an access for the payload of a Cell or JSGlobalPropertyCell. | 5415 // Create an access for the payload of a Cell or JSGlobalPropertyCell. |
5399 static HObjectAccess ForCellPayload(Isolate* isolate); | 5416 static HObjectAccess ForCellPayload(Isolate* isolate); |
5400 | 5417 |
5401 void PrintTo(StringStream* stream); | 5418 void PrintTo(StringStream* stream); |
5402 | 5419 |
5403 inline bool Equals(HObjectAccess that) const { | 5420 inline bool Equals(HObjectAccess that) const { |
5404 return value_ == that.value_; // portion and offset must match | 5421 return value_ == that.value_; // portion and offset must match |
5405 } | 5422 } |
5406 | 5423 |
5407 protected: | 5424 protected: |
5408 void SetGVNFlags(HValue *instr, bool is_store); | 5425 void SetGVNFlags(HValue *instr, bool is_store); |
5409 | 5426 |
5410 private: | 5427 private: |
5411 // internal use only; different parts of an object or array | 5428 // internal use only; different parts of an object or array |
5412 enum Portion { | 5429 enum Portion { |
5413 kMaps, // map of an object | 5430 kMaps, // map of an object |
5414 kArrayLengths, // the length of an array | 5431 kArrayLengths, // the length of an array |
5415 kElementsPointer, // elements pointer | 5432 kElementsPointer, // elements pointer |
5416 kBackingStore, // some field in the backing store | 5433 kBackingStore, // some field in the backing store |
5417 kDouble, // some double field | 5434 kDouble, // some double field |
5418 kInobject // some other in-object field | 5435 kInobject // some other in-object field |
5419 }; | 5436 }; |
5420 | 5437 |
5421 HObjectAccess(Portion portion, int offset, | 5438 HObjectAccess(Portion portion, int offset, |
5422 Handle<String> name = Handle<String>::null()) | 5439 Representation representation = Representation::Tagged(), |
5423 : value_(PortionField::encode(portion) | OffsetField::encode(offset)), | 5440 Handle<String> name = Handle<String>::null()) |
5441 : value_(PortionField::encode(portion) | | |
5442 RepresentationField::encode(representation.kind()) | | |
5443 OffsetField::encode(offset)), | |
5424 name_(name) { | 5444 name_(name) { |
5425 ASSERT(this->offset() == offset); // offset should decode correctly | 5445 // assert that the fields decode correctly |
5426 ASSERT(this->portion() == portion); // portion should decode correctly | 5446 ASSERT(this->offset() == offset); |
5447 ASSERT(this->portion() == portion); | |
5448 ASSERT(RepresentationField::decode(value_) == representation.kind()); | |
5427 } | 5449 } |
5428 | 5450 |
5429 class PortionField : public BitField<Portion, 0, 3> {}; | 5451 class PortionField : public BitField<Portion, 0, 3> {}; |
5430 class OffsetField : public BitField<int, 3, 29> {}; | 5452 class RepresentationField : public BitField<Representation::Kind, 3, 3> {}; |
5453 class OffsetField : public BitField<int, 6, 26> {}; | |
5431 | 5454 |
5432 uint32_t value_; // encodes both portion and offset | 5455 uint32_t value_; // encodes portion, representation, and offset |
5433 Handle<String> name_; | 5456 Handle<String> name_; |
5434 | 5457 |
5435 friend class HLoadNamedField; | 5458 friend class HLoadNamedField; |
5436 friend class HStoreNamedField; | 5459 friend class HStoreNamedField; |
5437 | 5460 |
5438 inline Portion portion() const { | 5461 inline Portion portion() const { |
5439 return PortionField::decode(value_); | 5462 return PortionField::decode(value_); |
5440 } | 5463 } |
5441 }; | 5464 }; |
5442 | 5465 |
5443 | 5466 |
5444 class HLoadNamedField: public HTemplateInstruction<2> { | 5467 class HLoadNamedField: public HTemplateInstruction<2> { |
5445 public: | 5468 public: |
5446 HLoadNamedField(HValue* object, | 5469 HLoadNamedField(HValue* object, |
5447 HObjectAccess access, | 5470 HObjectAccess access, |
5448 HValue* typecheck = NULL, | 5471 HValue* typecheck = NULL) |
5449 Representation field_representation | 5472 : access_(access) { |
5450 = Representation::Tagged()) | |
5451 : access_(access), | |
5452 field_representation_(field_representation) { | |
5453 ASSERT(object != NULL); | 5473 ASSERT(object != NULL); |
5454 SetOperandAt(0, object); | 5474 SetOperandAt(0, object); |
5455 SetOperandAt(1, typecheck != NULL ? typecheck : object); | 5475 SetOperandAt(1, typecheck != NULL ? typecheck : object); |
5456 | 5476 |
5457 if (FLAG_track_fields && field_representation.IsSmi()) { | 5477 Representation representation = access.representation(); |
5478 if (representation.IsSmi()) { | |
5458 set_type(HType::Smi()); | 5479 set_type(HType::Smi()); |
5459 set_representation(field_representation); | 5480 set_representation(representation); |
5460 } else if (FLAG_track_double_fields && field_representation.IsDouble()) { | 5481 } else if (representation.IsDouble()) { |
5461 set_representation(field_representation); | 5482 set_representation(representation); |
5462 } else if (FLAG_track_heap_object_fields && | 5483 } else if (FLAG_track_heap_object_fields && |
5463 field_representation.IsHeapObject()) { | 5484 representation.IsHeapObject()) { |
5464 set_type(HType::NonPrimitive()); | 5485 set_type(HType::NonPrimitive()); |
5465 set_representation(Representation::Tagged()); | 5486 set_representation(Representation::Tagged()); |
5466 } else { | 5487 } else { |
5467 set_representation(Representation::Tagged()); | 5488 set_representation(Representation::Tagged()); |
5468 } | 5489 } |
5469 access.SetGVNFlags(this, false); | 5490 access.SetGVNFlags(this, false); |
5470 } | 5491 } |
5471 | 5492 |
5472 HValue* object() { return OperandAt(0); } | 5493 HValue* object() { return OperandAt(0); } |
5473 HValue* typecheck() { | 5494 HValue* typecheck() { |
5474 ASSERT(HasTypeCheck()); | 5495 ASSERT(HasTypeCheck()); |
5475 return OperandAt(1); | 5496 return OperandAt(1); |
5476 } | 5497 } |
5477 | 5498 |
5478 bool HasTypeCheck() const { return OperandAt(0) != OperandAt(1); } | 5499 bool HasTypeCheck() const { return OperandAt(0) != OperandAt(1); } |
5479 HObjectAccess access() const { return access_; } | 5500 HObjectAccess access() const { return access_; } |
5480 Representation field_representation() const { return representation_; } | 5501 Representation field_representation() const { |
5502 return access_.representation(); | |
5503 } | |
5481 | 5504 |
5482 virtual bool HasEscapingOperandAt(int index) { return false; } | 5505 virtual bool HasEscapingOperandAt(int index) { return false; } |
5483 virtual Representation RequiredInputRepresentation(int index) { | 5506 virtual Representation RequiredInputRepresentation(int index) { |
5484 return Representation::Tagged(); | 5507 return Representation::Tagged(); |
5485 } | 5508 } |
5486 virtual void PrintDataTo(StringStream* stream); | 5509 virtual void PrintDataTo(StringStream* stream); |
5487 | 5510 |
5488 DECLARE_CONCRETE_INSTRUCTION(LoadNamedField) | 5511 DECLARE_CONCRETE_INSTRUCTION(LoadNamedField) |
5489 | 5512 |
5490 protected: | 5513 protected: |
5491 virtual bool DataEquals(HValue* other) { | 5514 virtual bool DataEquals(HValue* other) { |
5492 HLoadNamedField* b = HLoadNamedField::cast(other); | 5515 HLoadNamedField* b = HLoadNamedField::cast(other); |
5493 return access_.Equals(b->access_); | 5516 return access_.Equals(b->access_); |
5494 } | 5517 } |
5495 | 5518 |
5496 private: | 5519 private: |
5497 virtual bool IsDeletable() const { return true; } | 5520 virtual bool IsDeletable() const { return true; } |
5498 | 5521 |
5499 HObjectAccess access_; | 5522 HObjectAccess access_; |
5500 Representation field_representation_; | |
5501 }; | 5523 }; |
5502 | 5524 |
5503 | 5525 |
5504 class HLoadNamedFieldPolymorphic: public HTemplateInstruction<2> { | 5526 class HLoadNamedFieldPolymorphic: public HTemplateInstruction<2> { |
5505 public: | 5527 public: |
5506 HLoadNamedFieldPolymorphic(HValue* context, | 5528 HLoadNamedFieldPolymorphic(HValue* context, |
5507 HValue* object, | 5529 HValue* object, |
5508 SmallMapList* types, | 5530 SmallMapList* types, |
5509 Handle<String> name, | 5531 Handle<String> name, |
5510 Zone* zone); | 5532 Zone* zone); |
(...skipping 279 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
5790 virtual HValue* Canonicalize(); | 5812 virtual HValue* Canonicalize(); |
5791 | 5813 |
5792 DECLARE_CONCRETE_INSTRUCTION(LoadKeyedGeneric) | 5814 DECLARE_CONCRETE_INSTRUCTION(LoadKeyedGeneric) |
5793 }; | 5815 }; |
5794 | 5816 |
5795 | 5817 |
5796 class HStoreNamedField: public HTemplateInstruction<2> { | 5818 class HStoreNamedField: public HTemplateInstruction<2> { |
5797 public: | 5819 public: |
5798 HStoreNamedField(HValue* obj, | 5820 HStoreNamedField(HValue* obj, |
5799 HObjectAccess access, | 5821 HObjectAccess access, |
5800 HValue* val, | 5822 HValue* val) |
5801 Representation field_representation | |
5802 = Representation::Tagged()) | |
danno
2013/07/16 11:51:58
nit: start the first parameter "obj" on a new line
titzer
2013/07/23 15:04:10
Because I removed this parameter, the funky indent
| |
5803 : access_(access), | 5823 : access_(access), |
5804 field_representation_(field_representation), | |
5805 transition_(), | 5824 transition_(), |
5806 transition_unique_id_(), | 5825 transition_unique_id_(), |
5807 new_space_dominator_(NULL), | 5826 new_space_dominator_(NULL), |
5808 write_barrier_mode_(UPDATE_WRITE_BARRIER) { | 5827 write_barrier_mode_(UPDATE_WRITE_BARRIER) { |
5809 SetOperandAt(0, obj); | 5828 SetOperandAt(0, obj); |
5810 SetOperandAt(1, val); | 5829 SetOperandAt(1, val); |
5811 access.SetGVNFlags(this, true); | 5830 access.SetGVNFlags(this, true); |
5812 } | 5831 } |
5813 | 5832 |
5814 DECLARE_CONCRETE_INSTRUCTION(StoreNamedField) | 5833 DECLARE_CONCRETE_INSTRUCTION(StoreNamedField) |
5815 | 5834 |
5816 virtual bool HasEscapingOperandAt(int index) { return index == 1; } | 5835 virtual bool HasEscapingOperandAt(int index) { return index == 1; } |
5817 virtual Representation RequiredInputRepresentation(int index) { | 5836 virtual Representation RequiredInputRepresentation(int index) { |
5818 if (FLAG_track_double_fields && | 5837 if (index == 1 && field_representation().IsDouble()) { |
5819 index == 1 && field_representation_.IsDouble()) { | 5838 return field_representation(); |
5820 return field_representation_; | 5839 } else if (index == 1 && field_representation().IsSmi()) { |
5821 } else if (FLAG_track_fields && | 5840 return field_representation(); |
5822 index == 1 && field_representation_.IsSmi()) { | |
5823 return field_representation_; | |
5824 } | 5841 } |
5825 return Representation::Tagged(); | 5842 return Representation::Tagged(); |
5826 } | 5843 } |
5827 virtual void SetSideEffectDominator(GVNFlag side_effect, HValue* dominator) { | 5844 virtual void SetSideEffectDominator(GVNFlag side_effect, HValue* dominator) { |
5828 ASSERT(side_effect == kChangesNewSpacePromotion); | 5845 ASSERT(side_effect == kChangesNewSpacePromotion); |
5829 new_space_dominator_ = dominator; | 5846 new_space_dominator_ = dominator; |
5830 } | 5847 } |
5831 virtual void PrintDataTo(StringStream* stream); | 5848 virtual void PrintDataTo(StringStream* stream); |
5832 | 5849 |
5833 void SkipWriteBarrier() { write_barrier_mode_ = SKIP_WRITE_BARRIER; } | 5850 void SkipWriteBarrier() { write_barrier_mode_ = SKIP_WRITE_BARRIER; } |
(...skipping 10 matching lines...) Expand all Loading... | |
5844 void SetTransition(Handle<Map> map, CompilationInfo* info) { | 5861 void SetTransition(Handle<Map> map, CompilationInfo* info) { |
5845 ASSERT(transition_.is_null()); // Only set once. | 5862 ASSERT(transition_.is_null()); // Only set once. |
5846 if (map->CanBeDeprecated()) { | 5863 if (map->CanBeDeprecated()) { |
5847 map->AddDependentCompilationInfo(DependentCode::kTransitionGroup, info); | 5864 map->AddDependentCompilationInfo(DependentCode::kTransitionGroup, info); |
5848 } | 5865 } |
5849 transition_ = map; | 5866 transition_ = map; |
5850 } | 5867 } |
5851 HValue* new_space_dominator() const { return new_space_dominator_; } | 5868 HValue* new_space_dominator() const { return new_space_dominator_; } |
5852 | 5869 |
5853 bool NeedsWriteBarrier() { | 5870 bool NeedsWriteBarrier() { |
5854 ASSERT(!(FLAG_track_double_fields && field_representation_.IsDouble()) || | 5871 ASSERT(!(FLAG_track_double_fields && field_representation().IsDouble()) || |
5855 transition_.is_null()); | 5872 transition_.is_null()); |
5856 if (IsSkipWriteBarrier()) return false; | 5873 if (IsSkipWriteBarrier()) return false; |
5857 return (!FLAG_track_fields || !field_representation_.IsSmi()) && | 5874 if (field_representation().IsDouble()) return false; |
5858 // If there is a transition, a new storage object needs to be allocated. | 5875 if (field_representation().IsSmi()) return false; |
5859 !(FLAG_track_double_fields && field_representation_.IsDouble()) && | 5876 return StoringValueNeedsWriteBarrier(value()) && |
5860 StoringValueNeedsWriteBarrier(value()) && | |
5861 ReceiverObjectNeedsWriteBarrier(object(), new_space_dominator()); | 5877 ReceiverObjectNeedsWriteBarrier(object(), new_space_dominator()); |
5862 } | 5878 } |
5863 | 5879 |
5864 bool NeedsWriteBarrierForMap() { | 5880 bool NeedsWriteBarrierForMap() { |
5865 if (IsSkipWriteBarrier()) return false; | 5881 if (IsSkipWriteBarrier()) return false; |
5866 return ReceiverObjectNeedsWriteBarrier(object(), new_space_dominator()); | 5882 return ReceiverObjectNeedsWriteBarrier(object(), new_space_dominator()); |
5867 } | 5883 } |
5868 | 5884 |
5869 virtual void FinalizeUniqueValueId() { | 5885 virtual void FinalizeUniqueValueId() { |
5870 transition_unique_id_ = UniqueValueId(transition_); | 5886 transition_unique_id_ = UniqueValueId(transition_); |
5871 } | 5887 } |
5872 | 5888 |
5873 Representation field_representation() const { | 5889 Representation field_representation() const { |
5874 return field_representation_; | 5890 return access_.representation(); |
5875 } | 5891 } |
5876 | 5892 |
5877 private: | 5893 private: |
5878 HObjectAccess access_; | 5894 HObjectAccess access_; |
5879 Representation field_representation_; | |
5880 Handle<Map> transition_; | 5895 Handle<Map> transition_; |
5881 UniqueValueId transition_unique_id_; | 5896 UniqueValueId transition_unique_id_; |
5882 HValue* new_space_dominator_; | 5897 HValue* new_space_dominator_; |
5883 WriteBarrierMode write_barrier_mode_; | 5898 WriteBarrierMode write_barrier_mode_; |
5884 }; | 5899 }; |
5885 | 5900 |
5886 | 5901 |
5887 class HStoreNamedGeneric: public HTemplateInstruction<3> { | 5902 class HStoreNamedGeneric: public HTemplateInstruction<3> { |
5888 public: | 5903 public: |
5889 HStoreNamedGeneric(HValue* context, | 5904 HStoreNamedGeneric(HValue* context, |
(...skipping 820 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
6710 virtual bool IsDeletable() const { return true; } | 6725 virtual bool IsDeletable() const { return true; } |
6711 }; | 6726 }; |
6712 | 6727 |
6713 | 6728 |
6714 #undef DECLARE_INSTRUCTION | 6729 #undef DECLARE_INSTRUCTION |
6715 #undef DECLARE_CONCRETE_INSTRUCTION | 6730 #undef DECLARE_CONCRETE_INSTRUCTION |
6716 | 6731 |
6717 } } // namespace v8::internal | 6732 } } // namespace v8::internal |
6718 | 6733 |
6719 #endif // V8_HYDROGEN_INSTRUCTIONS_H_ | 6734 #endif // V8_HYDROGEN_INSTRUCTIONS_H_ |
OLD | NEW |