From 35052bc2eadd5c7dc17ffa4fbfd435c14080c919 Mon Sep 17 00:00:00 2001 From: "mstarzinger@chromium.org" Date: Mon, 15 Jul 2013 15:12:16 +0000 Subject: [PATCH] Reland deprecation of HAllocateObject in favor of HAllocate. This essentially relands r14930 and r14935 with adaptions to the current code base. It models the instantiation of an implicit receiver for CallNew nodes in hydrogen using HAllocate together with generic stores instead of one specialized HAllocateObject instruction, hence creating a single choking point for inlined allocation in optimized code. R=hpayer@chromium.org Review URL: https://codereview.chromium.org/19207002 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@15673 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/arm/lithium-arm.cc | 8 ---- src/arm/lithium-arm.h | 16 -------- src/arm/lithium-codegen-arm.cc | 74 --------------------------------- src/arm/lithium-codegen-arm.h | 1 - src/flag-definitions.h | 3 ++ src/heap.cc | 10 +---- src/hydrogen-escape-analysis.cc | 2 +- src/hydrogen-instructions.cc | 5 --- src/hydrogen-instructions.h | 58 ++++++-------------------- src/hydrogen.cc | 72 ++++++++++++++++++++++++++++---- src/hydrogen.h | 1 - src/ia32/lithium-codegen-ia32.cc | 89 ---------------------------------------- src/ia32/lithium-codegen-ia32.h | 1 - src/ia32/lithium-ia32.cc | 9 ---- src/ia32/lithium-ia32.h | 16 -------- src/mips/lithium-codegen-mips.cc | 74 --------------------------------- src/mips/lithium-codegen-mips.h | 1 - src/mips/lithium-mips.cc | 8 ---- src/mips/lithium-mips.h | 16 -------- src/objects.h | 7 ++++ src/x64/lithium-codegen-x64.cc | 88 --------------------------------------- src/x64/lithium-codegen-x64.h | 1 - src/x64/lithium-x64.cc | 7 ---- src/x64/lithium-x64.h | 14 ------- test/cctest/test-heap.cc | 25 +++++++++++ 25 files changed, 114 insertions(+), 492 deletions(-) diff --git a/src/arm/lithium-arm.cc b/src/arm/lithium-arm.cc index 309f96a..d614bd0 100644 --- a/src/arm/lithium-arm.cc +++ b/src/arm/lithium-arm.cc @@ -2400,14 +2400,6 @@ LInstruction* LChunkBuilder::DoStringLength(HStringLength* instr) { } -LInstruction* LChunkBuilder::DoAllocateObject(HAllocateObject* instr) { - info()->MarkAsDeferredCalling(); - LAllocateObject* result = - new(zone()) LAllocateObject(TempRegister(), TempRegister()); - return AssignPointerMap(DefineAsRegister(result)); -} - - LInstruction* LChunkBuilder::DoAllocate(HAllocate* instr) { info()->MarkAsDeferredCalling(); LOperand* size = instr->size()->IsConstant() diff --git a/src/arm/lithium-arm.h b/src/arm/lithium-arm.h index b91288d..a628d5a 100644 --- a/src/arm/lithium-arm.h +++ b/src/arm/lithium-arm.h @@ -49,7 +49,6 @@ class LCodeGen; #define LITHIUM_CONCRETE_INSTRUCTION_LIST(V) \ V(AccessArgumentsAt) \ V(AddI) \ - V(AllocateObject) \ V(Allocate) \ V(ApplyArguments) \ V(ArgumentsElements) \ @@ -2463,21 +2462,6 @@ class LClampTToUint8: public LTemplateInstruction<1, 1, 1> { }; -class LAllocateObject: public LTemplateInstruction<1, 1, 2> { - public: - LAllocateObject(LOperand* temp, LOperand* temp2) { - temps_[0] = temp; - temps_[1] = temp2; - } - - LOperand* temp() { return temps_[0]; } - LOperand* temp2() { return temps_[1]; } - - DECLARE_CONCRETE_INSTRUCTION(AllocateObject, "allocate-object") - DECLARE_HYDROGEN_ACCESSOR(AllocateObject) -}; - - class LAllocate: public LTemplateInstruction<1, 2, 2> { public: LAllocate(LOperand* size, LOperand* temp1, LOperand* temp2) { diff --git a/src/arm/lithium-codegen-arm.cc b/src/arm/lithium-codegen-arm.cc index 241ecf8..bed1724 100644 --- a/src/arm/lithium-codegen-arm.cc +++ b/src/arm/lithium-codegen-arm.cc @@ -5314,80 +5314,6 @@ void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) { } -void LCodeGen::DoAllocateObject(LAllocateObject* instr) { - class DeferredAllocateObject: public LDeferredCode { - public: - DeferredAllocateObject(LCodeGen* codegen, LAllocateObject* instr) - : LDeferredCode(codegen), instr_(instr) { } - virtual void Generate() { codegen()->DoDeferredAllocateObject(instr_); } - virtual LInstruction* instr() { return instr_; } - private: - LAllocateObject* instr_; - }; - - DeferredAllocateObject* deferred = - new(zone()) DeferredAllocateObject(this, instr); - - Register result = ToRegister(instr->result()); - Register scratch = ToRegister(instr->temp()); - Register scratch2 = ToRegister(instr->temp2()); - Handle constructor = instr->hydrogen()->constructor(); - Handle initial_map = instr->hydrogen()->constructor_initial_map(); - int instance_size = initial_map->instance_size(); - ASSERT(initial_map->pre_allocated_property_fields() + - initial_map->unused_property_fields() - - initial_map->inobject_properties() == 0); - - __ Allocate(instance_size, result, scratch, scratch2, deferred->entry(), - TAG_OBJECT); - - __ bind(deferred->exit()); - if (FLAG_debug_code) { - Label is_in_new_space; - __ JumpIfInNewSpace(result, scratch, &is_in_new_space); - __ Abort("Allocated object is not in new-space"); - __ bind(&is_in_new_space); - } - - // Load the initial map. - Register map = scratch; - __ LoadHeapObject(map, constructor); - __ ldr(map, FieldMemOperand(map, JSFunction::kPrototypeOrInitialMapOffset)); - - // Initialize map and fields of the newly allocated object. - ASSERT(initial_map->instance_type() == JS_OBJECT_TYPE); - __ str(map, FieldMemOperand(result, JSObject::kMapOffset)); - __ LoadRoot(scratch, Heap::kEmptyFixedArrayRootIndex); - __ str(scratch, FieldMemOperand(result, JSObject::kElementsOffset)); - __ str(scratch, FieldMemOperand(result, JSObject::kPropertiesOffset)); - if (initial_map->inobject_properties() != 0) { - __ LoadRoot(scratch, Heap::kUndefinedValueRootIndex); - for (int i = 0; i < initial_map->inobject_properties(); i++) { - int property_offset = JSObject::kHeaderSize + i * kPointerSize; - __ str(scratch, FieldMemOperand(result, property_offset)); - } - } -} - - -void LCodeGen::DoDeferredAllocateObject(LAllocateObject* instr) { - Register result = ToRegister(instr->result()); - Handle initial_map = instr->hydrogen()->constructor_initial_map(); - int instance_size = initial_map->instance_size(); - - // TODO(3095996): Get rid of this. For now, we need to make the - // result register contain a valid pointer because it is already - // contained in the register pointer map. - __ mov(result, Operand::Zero()); - - PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters); - __ mov(r0, Operand(Smi::FromInt(instance_size))); - __ push(r0); - CallRuntimeFromDeferred(Runtime::kAllocateInNewSpace, 1, instr); - __ StoreToSafepointRegisterSlot(r0, result); -} - - void LCodeGen::DoAllocate(LAllocate* instr) { class DeferredAllocate: public LDeferredCode { public: diff --git a/src/arm/lithium-codegen-arm.h b/src/arm/lithium-codegen-arm.h index 075fb41..b0390ee 100644 --- a/src/arm/lithium-codegen-arm.h +++ b/src/arm/lithium-codegen-arm.h @@ -150,7 +150,6 @@ class LCodeGen BASE_EMBEDDED { void DoDeferredRandom(LRandom* instr); void DoDeferredStringCharCodeAt(LStringCharCodeAt* instr); void DoDeferredStringCharFromCode(LStringCharFromCode* instr); - void DoDeferredAllocateObject(LAllocateObject* instr); void DoDeferredAllocate(LAllocate* instr); void DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr, Label* map_check); diff --git a/src/flag-definitions.h b/src/flag-definitions.h index 6a2b151..50d9669 100644 --- a/src/flag-definitions.h +++ b/src/flag-definitions.h @@ -195,6 +195,9 @@ DEFINE_bool(clever_optimizations, true, "Optimize object size, Array shift, DOM strings and string +") DEFINE_bool(pretenuring, true, "allocate objects in old space") +// TODO(hpayer): We will remove this flag as soon as we have pretenuring +// support for specific allocation sites. +DEFINE_bool(pretenuring_call_new, false, "pretenure call new") DEFINE_bool(track_fields, true, "track fields with only smi values") DEFINE_bool(track_double_fields, true, "track fields with double values") DEFINE_bool(track_heap_object_fields, true, "track fields with heap values") diff --git a/src/heap.cc b/src/heap.cc index 0b2fe16..c4cc40c 100644 --- a/src/heap.cc +++ b/src/heap.cc @@ -4449,10 +4449,7 @@ MaybeObject* Heap::AllocateJSObjectFromMap(Map* map, PretenureFlag pretenure) { ASSERT(map->instance_type() != JS_BUILTINS_OBJECT_TYPE); // Allocate the backing storage for the properties. - int prop_size = - map->pre_allocated_property_fields() + - map->unused_property_fields() - - map->inobject_properties(); + int prop_size = map->InitialPropertiesLength(); ASSERT(prop_size >= 0); Object* properties; { MaybeObject* maybe_properties = AllocateFixedArray(prop_size, pretenure); @@ -4489,10 +4486,7 @@ MaybeObject* Heap::AllocateJSObjectFromMapWithAllocationSite(Map* map, ASSERT(map->instance_type() != JS_BUILTINS_OBJECT_TYPE); // Allocate the backing storage for the properties. - int prop_size = - map->pre_allocated_property_fields() + - map->unused_property_fields() - - map->inobject_properties(); + int prop_size = map->InitialPropertiesLength(); ASSERT(prop_size >= 0); Object* properties; { MaybeObject* maybe_properties = AllocateFixedArray(prop_size); diff --git a/src/hydrogen-escape-analysis.cc b/src/hydrogen-escape-analysis.cc index e852fb8..961bb94 100644 --- a/src/hydrogen-escape-analysis.cc +++ b/src/hydrogen-escape-analysis.cc @@ -55,7 +55,7 @@ void HEscapeAnalysisPhase::CollectCapturedValues() { HBasicBlock* block = graph()->blocks()->at(i); for (HInstructionIterator it(block); !it.Done(); it.Advance()) { HInstruction* instr = it.Current(); - if (instr->IsAllocate() || instr->IsAllocateObject()) { + if (instr->IsAllocate()) { CollectIfNoEscapingUses(instr); } } diff --git a/src/hydrogen-instructions.cc b/src/hydrogen-instructions.cc index 1e6073a..4475fc0 100644 --- a/src/hydrogen-instructions.cc +++ b/src/hydrogen-instructions.cc @@ -3173,11 +3173,6 @@ HType HStringCharFromCode::CalculateInferredType() { } -HType HAllocateObject::CalculateInferredType() { - return HType::JSObject(); -} - - HType HAllocate::CalculateInferredType() { return type_; } diff --git a/src/hydrogen-instructions.h b/src/hydrogen-instructions.h index cb2225d..27c517a 100644 --- a/src/hydrogen-instructions.h +++ b/src/hydrogen-instructions.h @@ -66,7 +66,6 @@ class LChunkBuilder; V(AccessArgumentsAt) \ V(Add) \ V(Allocate) \ - V(AllocateObject) \ V(ApplyArguments) \ V(ArgumentsElements) \ V(ArgumentsLength) \ @@ -4952,50 +4951,6 @@ class HLoadGlobalGeneric: public HTemplateInstruction<2> { }; -class HAllocateObject: public HTemplateInstruction<1> { - public: - HAllocateObject(HValue* context, Handle constructor) - : constructor_(constructor) { - SetOperandAt(0, context); - set_representation(Representation::Tagged()); - SetGVNFlag(kChangesNewSpacePromotion); - constructor_initial_map_ = constructor->has_initial_map() - ? Handle(constructor->initial_map()) - : Handle::null(); - // If slack tracking finished, the instance size and property counts - // remain unchanged so that we can allocate memory for the object. - ASSERT(!constructor->shared()->IsInobjectSlackTrackingInProgress()); - } - - // Maximum instance size for which allocations will be inlined. - static const int kMaxSize = 64 * kPointerSize; - - HValue* context() { return OperandAt(0); } - Handle constructor() { return constructor_; } - Handle constructor_initial_map() { return constructor_initial_map_; } - - virtual Representation RequiredInputRepresentation(int index) { - return Representation::Tagged(); - } - - virtual Handle GetMonomorphicJSObjectMap() { - ASSERT(!constructor_initial_map_.is_null()); - return 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 constructor_; - Handle constructor_initial_map_; -}; - - class HAllocate: public HTemplateInstruction<2> { public: enum Flags { @@ -5016,6 +4971,9 @@ class HAllocate: public HTemplateInstruction<2> { SetGVNFlag(kDependsOnNewSpacePromotion); } + // Maximum instance size for which allocations will be inlined. + static const int kMaxInlineSize = 64 * kPointerSize; + static Flags DefaultFlags() { return CAN_ALLOCATE_IN_NEW_SPACE; } @@ -5041,6 +4999,14 @@ class HAllocate: public HTemplateInstruction<2> { } } + virtual Handle GetMonomorphicJSObjectMap() { + return known_initial_map_; + } + + void set_known_initial_map(Handle known_initial_map) { + known_initial_map_ = known_initial_map; + } + virtual HType CalculateInferredType(); bool CanAllocateInNewSpace() const { @@ -5082,6 +5048,7 @@ class HAllocate: public HTemplateInstruction<2> { private: HType type_; Flags flags_; + Handle known_initial_map_; }; @@ -5132,7 +5099,6 @@ inline bool ReceiverObjectNeedsWriteBarrier(HValue* object, return false; } if (object != new_space_dominator) return true; - if (object->IsAllocateObject()) return false; if (object->IsAllocate()) { return !HAllocate::cast(object)->GuaranteedInNewSpace(); } diff --git a/src/hydrogen.cc b/src/hydrogen.cc index c6a2023..de7ba1d 100644 --- a/src/hydrogen.cc +++ b/src/hydrogen.cc @@ -7257,7 +7257,8 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) { static bool IsAllocationInlineable(Handle constructor) { return constructor->has_initial_map() && constructor->initial_map()->instance_type() == JS_OBJECT_TYPE && - constructor->initial_map()->instance_size() < HAllocateObject::kMaxSize; + constructor->initial_map()->instance_size() < HAllocate::kMaxInlineSize && + constructor->initial_map()->InitialPropertiesLength() == 0; } @@ -7267,6 +7268,7 @@ void HOptimizedGraphBuilder::VisitCallNew(CallNew* expr) { ASSERT(current_block()->HasPredecessor()); int argument_count = expr->arguments()->length() + 1; // Plus constructor. HValue* context = environment()->LookupContext(); + Factory* factory = isolate()->factory(); if (FLAG_inline_construct && expr->IsMonomorphic() && @@ -7285,19 +7287,73 @@ void HOptimizedGraphBuilder::VisitCallNew(CallNew* expr) { constructor->shared()->CompleteInobjectSlackTracking(); } - // Replace the constructor function with a newly allocated receiver. - HInstruction* receiver = Add(context, constructor); - // Index of the receiver from the top of the expression stack. + // Calculate instance size from initial map of constructor. + ASSERT(constructor->has_initial_map()); + Handle initial_map(constructor->initial_map()); + int instance_size = initial_map->instance_size(); + ASSERT(initial_map->InitialPropertiesLength() == 0); + + // Allocate an instance of the implicit receiver object. + HValue* size_in_bytes = Add(instance_size); + HAllocate::Flags flags = HAllocate::DefaultFlags(); + if (FLAG_pretenuring_call_new && + isolate()->heap()->ShouldGloballyPretenure()) { + flags = static_cast( + flags | HAllocate::CAN_ALLOCATE_IN_OLD_POINTER_SPACE); + } + HAllocate* receiver = + Add(context, size_in_bytes, HType::JSObject(), flags); + receiver->set_known_initial_map(initial_map); + + // Load the initial map from the constructor. + HValue* constructor_value = Add(constructor); + HValue* initial_map_value = + AddLoad(constructor_value, HObjectAccess::ForJSObjectOffset( + JSFunction::kPrototypeOrInitialMapOffset)); + + // Initialize map and fields of the newly allocated object. + { NoObservableSideEffectsScope no_effects(this); + ASSERT(initial_map->instance_type() == JS_OBJECT_TYPE); + AddStore(receiver, + HObjectAccess::ForJSObjectOffset(JSObject::kMapOffset), + initial_map_value); + HValue* empty_fixed_array = Add(factory->empty_fixed_array()); + AddStore(receiver, + HObjectAccess::ForJSObjectOffset(JSObject::kPropertiesOffset), + empty_fixed_array); + AddStore(receiver, + HObjectAccess::ForJSObjectOffset(JSObject::kElementsOffset), + empty_fixed_array); + if (initial_map->inobject_properties() != 0) { + HConstant* undefined = graph()->GetConstantUndefined(); + for (int i = 0; i < initial_map->inobject_properties(); i++) { + int property_offset = JSObject::kHeaderSize + i * kPointerSize; + AddStore(receiver, + HObjectAccess::ForJSObjectOffset(property_offset), + undefined); + } + } + } + + // Replace the constructor function with a newly allocated receiver using + // the index of the receiver from the top of the expression stack. const int receiver_index = argument_count - 1; ASSERT(environment()->ExpressionStackAt(receiver_index) == function); environment()->SetExpressionStackAt(receiver_index, receiver); if (TryInlineConstruct(expr, receiver)) return; - // TODO(mstarzinger): For now we remove the previous HAllocateObject and - // add HPushArgument for the arguments in case inlining failed. What we - // actually should do is emit HInvokeFunction on the constructor instead - // of using HCallNew as a fallback. + // TODO(mstarzinger): For now we remove the previous HAllocate and all + // corresponding instructions and instead add HPushArgument for the + // arguments in case inlining failed. What we actually should do is for + // inlining to try to build a subgraph without mutating the parent graph. + HInstruction* instr = current_block()->last(); + while (instr != initial_map_value) { + HInstruction* prev_instr = instr->previous(); + instr->DeleteAndReplaceWith(NULL); + instr = prev_instr; + } + initial_map_value->DeleteAndReplaceWith(NULL); receiver->DeleteAndReplaceWith(NULL); check->DeleteAndReplaceWith(NULL); environment()->SetExpressionStackAt(receiver_index, function); diff --git a/src/hydrogen.h b/src/hydrogen.h index 0a2ba9f..2b92dd2 100644 --- a/src/hydrogen.h +++ b/src/hydrogen.h @@ -67,7 +67,6 @@ class HBasicBlock: public ZoneObject { HInstruction* first() const { return first_; } HInstruction* last() const { return last_; } void set_last(HInstruction* instr) { last_ = instr; } - HInstruction* GetLastInstruction(); HControlInstruction* end() const { return end_; } HLoopInformation* loop_information() const { return loop_information_; } const ZoneList* predecessors() const { return &predecessors_; } diff --git a/src/ia32/lithium-codegen-ia32.cc b/src/ia32/lithium-codegen-ia32.cc index d9ee5bb..770cecb 100644 --- a/src/ia32/lithium-codegen-ia32.cc +++ b/src/ia32/lithium-codegen-ia32.cc @@ -6007,95 +6007,6 @@ void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) { } -void LCodeGen::DoAllocateObject(LAllocateObject* instr) { - class DeferredAllocateObject: public LDeferredCode { - public: - DeferredAllocateObject(LCodeGen* codegen, LAllocateObject* instr) - : LDeferredCode(codegen), instr_(instr) { } - virtual void Generate() { codegen()->DoDeferredAllocateObject(instr_); } - virtual LInstruction* instr() { return instr_; } - private: - LAllocateObject* instr_; - }; - - DeferredAllocateObject* deferred = - new(zone()) DeferredAllocateObject(this, instr); - - Register result = ToRegister(instr->result()); - Register scratch = ToRegister(instr->temp()); - Handle constructor = instr->hydrogen()->constructor(); - Handle initial_map = instr->hydrogen()->constructor_initial_map(); - int instance_size = initial_map->instance_size(); - ASSERT(initial_map->pre_allocated_property_fields() + - initial_map->unused_property_fields() - - initial_map->inobject_properties() == 0); - - __ Allocate(instance_size, result, no_reg, scratch, deferred->entry(), - TAG_OBJECT); - - __ bind(deferred->exit()); - if (FLAG_debug_code) { - Label is_in_new_space; - __ JumpIfInNewSpace(result, scratch, &is_in_new_space); - __ Abort("Allocated object is not in new-space"); - __ bind(&is_in_new_space); - } - - // Load the initial map. - Register map = scratch; - __ LoadHeapObject(scratch, constructor); - __ mov(map, FieldOperand(scratch, JSFunction::kPrototypeOrInitialMapOffset)); - - if (FLAG_debug_code) { - __ AssertNotSmi(map); - __ cmpb(FieldOperand(map, Map::kInstanceSizeOffset), - instance_size >> kPointerSizeLog2); - __ Assert(equal, "Unexpected instance size"); - __ cmpb(FieldOperand(map, Map::kPreAllocatedPropertyFieldsOffset), - initial_map->pre_allocated_property_fields()); - __ Assert(equal, "Unexpected pre-allocated property fields count"); - __ cmpb(FieldOperand(map, Map::kUnusedPropertyFieldsOffset), - initial_map->unused_property_fields()); - __ Assert(equal, "Unexpected unused property fields count"); - __ cmpb(FieldOperand(map, Map::kInObjectPropertiesOffset), - initial_map->inobject_properties()); - __ Assert(equal, "Unexpected in-object property fields count"); - } - - // Initialize map and fields of the newly allocated object. - ASSERT(initial_map->instance_type() == JS_OBJECT_TYPE); - __ mov(FieldOperand(result, JSObject::kMapOffset), map); - __ mov(scratch, factory()->empty_fixed_array()); - __ mov(FieldOperand(result, JSObject::kElementsOffset), scratch); - __ mov(FieldOperand(result, JSObject::kPropertiesOffset), scratch); - if (initial_map->inobject_properties() != 0) { - __ mov(scratch, factory()->undefined_value()); - for (int i = 0; i < initial_map->inobject_properties(); i++) { - int property_offset = JSObject::kHeaderSize + i * kPointerSize; - __ mov(FieldOperand(result, property_offset), scratch); - } - } -} - - -void LCodeGen::DoDeferredAllocateObject(LAllocateObject* instr) { - Register result = ToRegister(instr->result()); - Handle initial_map = instr->hydrogen()->constructor_initial_map(); - int instance_size = initial_map->instance_size(); - - // TODO(3095996): Get rid of this. For now, we need to make the - // result register contain a valid pointer because it is already - // contained in the register pointer map. - __ Set(result, Immediate(0)); - - PushSafepointRegistersScope scope(this); - __ push(Immediate(Smi::FromInt(instance_size))); - CallRuntimeFromDeferred( - Runtime::kAllocateInNewSpace, 1, instr, instr->context()); - __ StoreToSafepointRegisterSlot(result, eax); -} - - void LCodeGen::DoAllocate(LAllocate* instr) { class DeferredAllocate: public LDeferredCode { public: diff --git a/src/ia32/lithium-codegen-ia32.h b/src/ia32/lithium-codegen-ia32.h index 1cbe4fe..eb75225 100644 --- a/src/ia32/lithium-codegen-ia32.h +++ b/src/ia32/lithium-codegen-ia32.h @@ -163,7 +163,6 @@ class LCodeGen BASE_EMBEDDED { void DoDeferredRandom(LRandom* instr); void DoDeferredStringCharCodeAt(LStringCharCodeAt* instr); void DoDeferredStringCharFromCode(LStringCharFromCode* instr); - void DoDeferredAllocateObject(LAllocateObject* instr); void DoDeferredAllocate(LAllocate* instr); void DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr, Label* map_check); diff --git a/src/ia32/lithium-ia32.cc b/src/ia32/lithium-ia32.cc index cd4a957..24ee7bf 100644 --- a/src/ia32/lithium-ia32.cc +++ b/src/ia32/lithium-ia32.cc @@ -2510,15 +2510,6 @@ LInstruction* LChunkBuilder::DoStringLength(HStringLength* instr) { } -LInstruction* LChunkBuilder::DoAllocateObject(HAllocateObject* instr) { - info()->MarkAsDeferredCalling(); - LOperand* context = UseAny(instr->context()); - LOperand* temp = TempRegister(); - LAllocateObject* result = new(zone()) LAllocateObject(context, temp); - return AssignPointerMap(DefineAsRegister(result)); -} - - LInstruction* LChunkBuilder::DoAllocate(HAllocate* instr) { info()->MarkAsDeferredCalling(); LOperand* context = UseAny(instr->context()); diff --git a/src/ia32/lithium-ia32.h b/src/ia32/lithium-ia32.h index 56c9688..4dcc95a 100644 --- a/src/ia32/lithium-ia32.h +++ b/src/ia32/lithium-ia32.h @@ -44,7 +44,6 @@ class LCodeGen; V(AccessArgumentsAt) \ V(AddI) \ V(Allocate) \ - V(AllocateObject) \ V(ApplyArguments) \ V(ArgumentsElements) \ V(ArgumentsLength) \ @@ -2572,21 +2571,6 @@ class LCheckNonSmi: public LTemplateInstruction<0, 1, 0> { }; -class LAllocateObject: public LTemplateInstruction<1, 1, 1> { - public: - LAllocateObject(LOperand* context, LOperand* temp) { - inputs_[0] = context; - temps_[0] = temp; - } - - LOperand* context() { return inputs_[0]; } - LOperand* temp() { return temps_[0]; } - - DECLARE_CONCRETE_INSTRUCTION(AllocateObject, "allocate-object") - DECLARE_HYDROGEN_ACCESSOR(AllocateObject) -}; - - class LAllocate: public LTemplateInstruction<1, 2, 1> { public: LAllocate(LOperand* context, LOperand* size, LOperand* temp) { diff --git a/src/mips/lithium-codegen-mips.cc b/src/mips/lithium-codegen-mips.cc index deae97b..565c250 100644 --- a/src/mips/lithium-codegen-mips.cc +++ b/src/mips/lithium-codegen-mips.cc @@ -5272,80 +5272,6 @@ void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) { } -void LCodeGen::DoAllocateObject(LAllocateObject* instr) { - class DeferredAllocateObject: public LDeferredCode { - public: - DeferredAllocateObject(LCodeGen* codegen, LAllocateObject* instr) - : LDeferredCode(codegen), instr_(instr) { } - virtual void Generate() { codegen()->DoDeferredAllocateObject(instr_); } - virtual LInstruction* instr() { return instr_; } - private: - LAllocateObject* instr_; - }; - - DeferredAllocateObject* deferred = - new(zone()) DeferredAllocateObject(this, instr); - - Register result = ToRegister(instr->result()); - Register scratch = ToRegister(instr->temp()); - Register scratch2 = ToRegister(instr->temp2()); - Handle constructor = instr->hydrogen()->constructor(); - Handle initial_map = instr->hydrogen()->constructor_initial_map(); - int instance_size = initial_map->instance_size(); - ASSERT(initial_map->pre_allocated_property_fields() + - initial_map->unused_property_fields() - - initial_map->inobject_properties() == 0); - - __ Allocate(instance_size, result, scratch, scratch2, deferred->entry(), - TAG_OBJECT); - - __ bind(deferred->exit()); - if (FLAG_debug_code) { - Label is_in_new_space; - __ JumpIfInNewSpace(result, scratch, &is_in_new_space); - __ Abort("Allocated object is not in new-space"); - __ bind(&is_in_new_space); - } - - // Load the initial map. - Register map = scratch; - __ LoadHeapObject(map, constructor); - __ lw(map, FieldMemOperand(map, JSFunction::kPrototypeOrInitialMapOffset)); - - // Initialize map and fields of the newly allocated object. - ASSERT(initial_map->instance_type() == JS_OBJECT_TYPE); - __ sw(map, FieldMemOperand(result, JSObject::kMapOffset)); - __ LoadRoot(scratch, Heap::kEmptyFixedArrayRootIndex); - __ sw(scratch, FieldMemOperand(result, JSObject::kElementsOffset)); - __ sw(scratch, FieldMemOperand(result, JSObject::kPropertiesOffset)); - if (initial_map->inobject_properties() != 0) { - __ LoadRoot(scratch, Heap::kUndefinedValueRootIndex); - for (int i = 0; i < initial_map->inobject_properties(); i++) { - int property_offset = JSObject::kHeaderSize + i * kPointerSize; - __ sw(scratch, FieldMemOperand(result, property_offset)); - } - } -} - - -void LCodeGen::DoDeferredAllocateObject(LAllocateObject* instr) { - Register result = ToRegister(instr->result()); - Handle initial_map = instr->hydrogen()->constructor_initial_map(); - int instance_size = initial_map->instance_size(); - - // TODO(3095996): Get rid of this. For now, we need to make the - // result register contain a valid pointer because it is already - // contained in the register pointer map. - __ mov(result, zero_reg); - - PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters); - __ li(a0, Operand(Smi::FromInt(instance_size))); - __ push(a0); - CallRuntimeFromDeferred(Runtime::kAllocateInNewSpace, 1, instr); - __ StoreToSafepointRegisterSlot(v0, result); -} - - void LCodeGen::DoAllocate(LAllocate* instr) { class DeferredAllocate: public LDeferredCode { public: diff --git a/src/mips/lithium-codegen-mips.h b/src/mips/lithium-codegen-mips.h index 3d31ef1..1cba8cf 100644 --- a/src/mips/lithium-codegen-mips.h +++ b/src/mips/lithium-codegen-mips.h @@ -148,7 +148,6 @@ class LCodeGen BASE_EMBEDDED { void DoDeferredRandom(LRandom* instr); void DoDeferredStringCharCodeAt(LStringCharCodeAt* instr); void DoDeferredStringCharFromCode(LStringCharFromCode* instr); - void DoDeferredAllocateObject(LAllocateObject* instr); void DoDeferredAllocate(LAllocate* instr); void DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr, Label* map_check); diff --git a/src/mips/lithium-mips.cc b/src/mips/lithium-mips.cc index 9427262..06f99ed 100644 --- a/src/mips/lithium-mips.cc +++ b/src/mips/lithium-mips.cc @@ -2323,14 +2323,6 @@ LInstruction* LChunkBuilder::DoStringLength(HStringLength* instr) { } -LInstruction* LChunkBuilder::DoAllocateObject(HAllocateObject* instr) { - info()->MarkAsDeferredCalling(); - LAllocateObject* result = - new(zone()) LAllocateObject(TempRegister(), TempRegister()); - return AssignPointerMap(DefineAsRegister(result)); -} - - LInstruction* LChunkBuilder::DoAllocate(HAllocate* instr) { info()->MarkAsDeferredCalling(); LOperand* size = instr->size()->IsConstant() diff --git a/src/mips/lithium-mips.h b/src/mips/lithium-mips.h index 160d6e2..ace417c 100644 --- a/src/mips/lithium-mips.h +++ b/src/mips/lithium-mips.h @@ -49,7 +49,6 @@ class LCodeGen; #define LITHIUM_CONCRETE_INSTRUCTION_LIST(V) \ V(AccessArgumentsAt) \ V(AddI) \ - V(AllocateObject) \ V(Allocate) \ V(ApplyArguments) \ V(ArgumentsElements) \ @@ -2436,21 +2435,6 @@ class LClampTToUint8: public LTemplateInstruction<1, 1, 1> { }; -class LAllocateObject: public LTemplateInstruction<1, 1, 2> { - public: - LAllocateObject(LOperand* temp, LOperand* temp2) { - temps_[0] = temp; - temps_[1] = temp2; - } - - LOperand* temp() { return temps_[0]; } - LOperand* temp2() { return temps_[1]; } - - DECLARE_CONCRETE_INSTRUCTION(AllocateObject, "allocate-object") - DECLARE_HYDROGEN_ACCESSOR(AllocateObject) -}; - - class LAllocate: public LTemplateInstruction<1, 2, 2> { public: LAllocate(LOperand* size, LOperand* temp1, LOperand* temp2) { diff --git a/src/objects.h b/src/objects.h index bf04934..2cc232c 100644 --- a/src/objects.h +++ b/src/objects.h @@ -5505,6 +5505,13 @@ class Map: public HeapObject { int NumberOfDescribedProperties(DescriptorFlag which = OWN_DESCRIPTORS, PropertyAttributes filter = NONE); + // Returns the number of slots allocated for the initial properties + // backing storage for instances of this map. + int InitialPropertiesLength() { + return pre_allocated_property_fields() + unused_property_fields() - + inobject_properties(); + } + // Casting. static inline Map* cast(Object* obj); diff --git a/src/x64/lithium-codegen-x64.cc b/src/x64/lithium-codegen-x64.cc index 170474e..ab51b91 100644 --- a/src/x64/lithium-codegen-x64.cc +++ b/src/x64/lithium-codegen-x64.cc @@ -5032,94 +5032,6 @@ void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) { } -void LCodeGen::DoAllocateObject(LAllocateObject* instr) { - class DeferredAllocateObject: public LDeferredCode { - public: - DeferredAllocateObject(LCodeGen* codegen, LAllocateObject* instr) - : LDeferredCode(codegen), instr_(instr) { } - virtual void Generate() { codegen()->DoDeferredAllocateObject(instr_); } - virtual LInstruction* instr() { return instr_; } - private: - LAllocateObject* instr_; - }; - - DeferredAllocateObject* deferred = - new(zone()) DeferredAllocateObject(this, instr); - - Register result = ToRegister(instr->result()); - Register scratch = ToRegister(instr->temp()); - Handle constructor = instr->hydrogen()->constructor(); - Handle initial_map = instr->hydrogen()->constructor_initial_map(); - int instance_size = initial_map->instance_size(); - ASSERT(initial_map->pre_allocated_property_fields() + - initial_map->unused_property_fields() - - initial_map->inobject_properties() == 0); - - __ Allocate(instance_size, result, no_reg, scratch, deferred->entry(), - TAG_OBJECT); - - __ bind(deferred->exit()); - if (FLAG_debug_code) { - Label is_in_new_space; - __ JumpIfInNewSpace(result, scratch, &is_in_new_space); - __ Abort("Allocated object is not in new-space"); - __ bind(&is_in_new_space); - } - - // Load the initial map. - Register map = scratch; - __ LoadHeapObject(scratch, constructor); - __ movq(map, FieldOperand(scratch, JSFunction::kPrototypeOrInitialMapOffset)); - - if (FLAG_debug_code) { - __ AssertNotSmi(map); - __ cmpb(FieldOperand(map, Map::kInstanceSizeOffset), - Immediate(instance_size >> kPointerSizeLog2)); - __ Assert(equal, "Unexpected instance size"); - __ cmpb(FieldOperand(map, Map::kPreAllocatedPropertyFieldsOffset), - Immediate(initial_map->pre_allocated_property_fields())); - __ Assert(equal, "Unexpected pre-allocated property fields count"); - __ cmpb(FieldOperand(map, Map::kUnusedPropertyFieldsOffset), - Immediate(initial_map->unused_property_fields())); - __ Assert(equal, "Unexpected unused property fields count"); - __ cmpb(FieldOperand(map, Map::kInObjectPropertiesOffset), - Immediate(initial_map->inobject_properties())); - __ Assert(equal, "Unexpected in-object property fields count"); - } - - // Initialize map and fields of the newly allocated object. - ASSERT(initial_map->instance_type() == JS_OBJECT_TYPE); - __ movq(FieldOperand(result, JSObject::kMapOffset), map); - __ LoadRoot(scratch, Heap::kEmptyFixedArrayRootIndex); - __ movq(FieldOperand(result, JSObject::kElementsOffset), scratch); - __ movq(FieldOperand(result, JSObject::kPropertiesOffset), scratch); - if (initial_map->inobject_properties() != 0) { - __ LoadRoot(scratch, Heap::kUndefinedValueRootIndex); - for (int i = 0; i < initial_map->inobject_properties(); i++) { - int property_offset = JSObject::kHeaderSize + i * kPointerSize; - __ movq(FieldOperand(result, property_offset), scratch); - } - } -} - - -void LCodeGen::DoDeferredAllocateObject(LAllocateObject* instr) { - Register result = ToRegister(instr->result()); - Handle initial_map = instr->hydrogen()->constructor_initial_map(); - int instance_size = initial_map->instance_size(); - - // TODO(3095996): Get rid of this. For now, we need to make the - // result register contain a valid pointer because it is already - // contained in the register pointer map. - __ Set(result, 0); - - PushSafepointRegistersScope scope(this); - __ Push(Smi::FromInt(instance_size)); - CallRuntimeFromDeferred(Runtime::kAllocateInNewSpace, 1, instr); - __ StoreToSafepointRegisterSlot(result, rax); -} - - void LCodeGen::DoAllocate(LAllocate* instr) { class DeferredAllocate: public LDeferredCode { public: diff --git a/src/x64/lithium-codegen-x64.h b/src/x64/lithium-codegen-x64.h index c89ec1f..0a43096 100644 --- a/src/x64/lithium-codegen-x64.h +++ b/src/x64/lithium-codegen-x64.h @@ -127,7 +127,6 @@ class LCodeGen BASE_EMBEDDED { void DoDeferredRandom(LRandom* instr); void DoDeferredStringCharCodeAt(LStringCharCodeAt* instr); void DoDeferredStringCharFromCode(LStringCharFromCode* instr); - void DoDeferredAllocateObject(LAllocateObject* instr); void DoDeferredAllocate(LAllocate* instr); void DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr, Label* map_check); diff --git a/src/x64/lithium-x64.cc b/src/x64/lithium-x64.cc index 478e98a..945d002 100644 --- a/src/x64/lithium-x64.cc +++ b/src/x64/lithium-x64.cc @@ -2338,13 +2338,6 @@ LInstruction* LChunkBuilder::DoStringLength(HStringLength* instr) { } -LInstruction* LChunkBuilder::DoAllocateObject(HAllocateObject* instr) { - info()->MarkAsDeferredCalling(); - LAllocateObject* result = new(zone()) LAllocateObject(TempRegister()); - return AssignPointerMap(DefineAsRegister(result)); -} - - LInstruction* LChunkBuilder::DoAllocate(HAllocate* instr) { info()->MarkAsDeferredCalling(); LOperand* size = instr->size()->IsConstant() diff --git a/src/x64/lithium-x64.h b/src/x64/lithium-x64.h index b065c8c..62f65ae 100644 --- a/src/x64/lithium-x64.h +++ b/src/x64/lithium-x64.h @@ -50,7 +50,6 @@ class LCodeGen; V(AccessArgumentsAt) \ V(AddI) \ V(Allocate) \ - V(AllocateObject) \ V(ApplyArguments) \ V(ArgumentsElements) \ V(ArgumentsLength) \ @@ -2367,19 +2366,6 @@ class LCheckNonSmi: public LTemplateInstruction<0, 1, 0> { }; -class LAllocateObject: public LTemplateInstruction<1, 0, 1> { - public: - explicit LAllocateObject(LOperand* temp) { - temps_[0] = temp; - } - - LOperand* temp() { return temps_[0]; } - - DECLARE_CONCRETE_INSTRUCTION(AllocateObject, "allocate-object") - DECLARE_HYDROGEN_ACCESSOR(AllocateObject) -}; - - class LAllocate: public LTemplateInstruction<1, 1, 1> { public: LAllocate(LOperand* size, LOperand* temp) { diff --git a/test/cctest/test-heap.cc b/test/cctest/test-heap.cc index cc1e042..833f50f 100644 --- a/test/cctest/test-heap.cc +++ b/test/cctest/test-heap.cc @@ -2352,6 +2352,31 @@ TEST(OptimizedAllocationArrayLiterals) { } +TEST(OptimizedPretenuringCallNew) { + i::FLAG_allow_natives_syntax = true; + i::FLAG_pretenuring_call_new = true; + CcTest::InitializeVM(); + if (!i::V8::UseCrankshaft() || i::FLAG_always_opt) return; + if (i::FLAG_gc_global || i::FLAG_stress_compaction) return; + v8::HandleScope scope(CcTest::isolate()); + HEAP->SetNewSpaceHighPromotionModeActive(true); + + AlwaysAllocateScope always_allocate; + v8::Local res = CompileRun( + "function g() { this.a = 0; }" + "function f() {" + " return new g();" + "};" + "f(); f(); f();" + "%OptimizeFunctionOnNextCall(f);" + "f();"); + + Handle o = + v8::Utils::OpenHandle(*v8::Handle::Cast(res)); + CHECK(HEAP->InOldPointerSpace(*o)); +} + + static int CountMapTransitions(Map* map) { return map->transitions()->number_of_transitions(); } -- 2.7.4