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
This commit is contained in:
mstarzinger@chromium.org 2013-07-15 15:12:16 +00:00
parent db76aa2717
commit 35052bc2ea
25 changed files with 114 additions and 492 deletions

View File

@ -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()

View File

@ -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) {

View File

@ -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<JSFunction> constructor = instr->hydrogen()->constructor();
Handle<Map> 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<Map> 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:

View File

@ -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);

View File

@ -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")

View File

@ -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);

View File

@ -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);
}
}

View File

@ -3173,11 +3173,6 @@ HType HStringCharFromCode::CalculateInferredType() {
}
HType HAllocateObject::CalculateInferredType() {
return HType::JSObject();
}
HType HAllocate::CalculateInferredType() {
return type_;
}

View File

@ -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<JSFunction> constructor)
: constructor_(constructor) {
SetOperandAt(0, context);
set_representation(Representation::Tagged());
SetGVNFlag(kChangesNewSpacePromotion);
constructor_initial_map_ = constructor->has_initial_map()
? Handle<Map>(constructor->initial_map())
: Handle<Map>::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<JSFunction> constructor() { return constructor_; }
Handle<Map> constructor_initial_map() { return constructor_initial_map_; }
virtual Representation RequiredInputRepresentation(int index) {
return Representation::Tagged();
}
virtual Handle<Map> 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<JSFunction> constructor_;
Handle<Map> 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<Map> GetMonomorphicJSObjectMap() {
return known_initial_map_;
}
void set_known_initial_map(Handle<Map> 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<Map> 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();
}

View File

@ -7257,7 +7257,8 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) {
static bool IsAllocationInlineable(Handle<JSFunction> 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<HAllocateObject>(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<Map> 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<HConstant>(instance_size);
HAllocate::Flags flags = HAllocate::DefaultFlags();
if (FLAG_pretenuring_call_new &&
isolate()->heap()->ShouldGloballyPretenure()) {
flags = static_cast<HAllocate::Flags>(
flags | HAllocate::CAN_ALLOCATE_IN_OLD_POINTER_SPACE);
}
HAllocate* receiver =
Add<HAllocate>(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<HConstant>(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<HConstant>(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);

View File

@ -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<HBasicBlock*>* predecessors() const { return &predecessors_; }

View File

@ -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<JSFunction> constructor = instr->hydrogen()->constructor();
Handle<Map> 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<Map> 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:

View File

@ -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);

View File

@ -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());

View File

@ -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) {

View File

@ -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<JSFunction> constructor = instr->hydrogen()->constructor();
Handle<Map> 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<Map> 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:

View File

@ -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);

View File

@ -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()

View File

@ -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) {

View File

@ -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);

View File

@ -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<JSFunction> constructor = instr->hydrogen()->constructor();
Handle<Map> 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<Map> 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:

View File

@ -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);

View File

@ -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()

View File

@ -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) {

View File

@ -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<v8::Value> res = CompileRun(
"function g() { this.a = 0; }"
"function f() {"
" return new g();"
"};"
"f(); f(); f();"
"%OptimizeFunctionOnNextCall(f);"
"f();");
Handle<JSObject> o =
v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(res));
CHECK(HEAP->InOldPointerSpace(*o));
}
static int CountMapTransitions(Map* map) {
return map->transitions()->number_of_transitions();
}