Deprecate HAllocateObject in favor of HAllocate.
This 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/15714005 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@14930 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
b10a3abdfe
commit
d7975dfdab
@ -2388,14 +2388,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()
|
||||
|
@ -49,7 +49,6 @@ class LCodeGen;
|
||||
#define LITHIUM_CONCRETE_INSTRUCTION_LIST(V) \
|
||||
V(AccessArgumentsAt) \
|
||||
V(AddI) \
|
||||
V(AllocateObject) \
|
||||
V(Allocate) \
|
||||
V(ApplyArguments) \
|
||||
V(ArgumentsElements) \
|
||||
@ -2457,21 +2456,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) {
|
||||
|
@ -5410,80 +5410,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:
|
||||
|
@ -157,7 +157,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);
|
||||
|
10
src/heap.cc
10
src/heap.cc
@ -4302,10 +4302,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);
|
||||
@ -4342,10 +4339,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);
|
||||
|
@ -3029,11 +3029,6 @@ HType HStringCharFromCode::CalculateInferredType() {
|
||||
}
|
||||
|
||||
|
||||
HType HAllocateObject::CalculateInferredType() {
|
||||
return HType::JSObject();
|
||||
}
|
||||
|
||||
|
||||
HType HAllocate::CalculateInferredType() {
|
||||
return type_;
|
||||
}
|
||||
|
@ -65,7 +65,6 @@ class LChunkBuilder;
|
||||
V(AccessArgumentsAt) \
|
||||
V(Add) \
|
||||
V(Allocate) \
|
||||
V(AllocateObject) \
|
||||
V(ApplyArguments) \
|
||||
V(ArgumentsElements) \
|
||||
V(ArgumentsLength) \
|
||||
@ -4808,48 +4807,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 {
|
||||
@ -4868,6 +4825,9 @@ class HAllocate: public HTemplateInstruction<2> {
|
||||
SetGVNFlag(kChangesNewSpacePromotion);
|
||||
}
|
||||
|
||||
// Maximum instance size for which allocations will be inlined.
|
||||
static const int kMaxInlineSize = 64 * kPointerSize;
|
||||
|
||||
static Flags DefaultFlags() {
|
||||
return CAN_ALLOCATE_IN_NEW_SPACE;
|
||||
}
|
||||
@ -4892,6 +4852,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 {
|
||||
@ -4926,6 +4894,7 @@ class HAllocate: public HTemplateInstruction<2> {
|
||||
private:
|
||||
HType type_;
|
||||
Flags flags_;
|
||||
Handle<Map> known_initial_map_;
|
||||
};
|
||||
|
||||
|
||||
@ -4969,7 +4938,6 @@ inline bool ReceiverObjectNeedsWriteBarrier(HValue* object,
|
||||
new_space_dominator);
|
||||
}
|
||||
if (object != new_space_dominator) return true;
|
||||
if (object->IsAllocateObject()) return false;
|
||||
if (object->IsAllocate()) {
|
||||
return !HAllocate::cast(object)->GuaranteedInNewSpace();
|
||||
}
|
||||
|
@ -8741,7 +8741,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;
|
||||
}
|
||||
|
||||
|
||||
@ -8751,6 +8752,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() &&
|
||||
@ -8770,20 +8772,76 @@ void HOptimizedGraphBuilder::VisitCallNew(CallNew* expr) {
|
||||
constructor->shared()->CompleteInobjectSlackTracking();
|
||||
}
|
||||
|
||||
// Replace the constructor function with a newly allocated receiver.
|
||||
HInstruction* receiver = new(zone()) 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 =
|
||||
AddInstruction(new(zone()) HConstant(instance_size,
|
||||
Representation::Integer32()));
|
||||
HInstruction* receiver =
|
||||
AddInstruction(new(zone()) HAllocate(context,
|
||||
size_in_bytes,
|
||||
HType::JSObject(),
|
||||
HAllocate::DefaultFlags()));
|
||||
HAllocate::cast(receiver)->set_known_initial_map(initial_map);
|
||||
|
||||
// Load the initial map from the constructor.
|
||||
HValue* constructor_value =
|
||||
AddInstruction(new(zone()) HConstant(constructor,
|
||||
Representation::Tagged()));
|
||||
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 =
|
||||
AddInstruction(new(zone()) HConstant(factory->empty_fixed_array(),
|
||||
Representation::Tagged()));
|
||||
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;
|
||||
AddInstruction(receiver);
|
||||
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);
|
||||
|
@ -66,7 +66,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_; }
|
||||
|
@ -5998,95 +5998,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:
|
||||
|
@ -159,7 +159,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);
|
||||
|
@ -2519,15 +2519,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());
|
||||
|
@ -44,7 +44,6 @@ class LCodeGen;
|
||||
V(AccessArgumentsAt) \
|
||||
V(AddI) \
|
||||
V(Allocate) \
|
||||
V(AllocateObject) \
|
||||
V(ApplyArguments) \
|
||||
V(ArgumentsElements) \
|
||||
V(ArgumentsLength) \
|
||||
@ -2552,21 +2551,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) {
|
||||
|
@ -5138,80 +5138,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:
|
||||
|
@ -151,7 +151,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);
|
||||
|
@ -2263,14 +2263,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()
|
||||
|
@ -49,7 +49,6 @@ class LCodeGen;
|
||||
#define LITHIUM_CONCRETE_INSTRUCTION_LIST(V) \
|
||||
V(AccessArgumentsAt) \
|
||||
V(AddI) \
|
||||
V(AllocateObject) \
|
||||
V(Allocate) \
|
||||
V(ApplyArguments) \
|
||||
V(ArgumentsElements) \
|
||||
@ -2398,21 +2397,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) {
|
||||
|
@ -5443,6 +5443,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);
|
||||
|
||||
|
@ -5088,94 +5088,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:
|
||||
|
@ -130,7 +130,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);
|
||||
|
@ -2328,13 +2328,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()
|
||||
|
@ -50,7 +50,6 @@ class LCodeGen;
|
||||
V(AccessArgumentsAt) \
|
||||
V(AddI) \
|
||||
V(Allocate) \
|
||||
V(AllocateObject) \
|
||||
V(ApplyArguments) \
|
||||
V(ArgumentsElements) \
|
||||
V(ArgumentsLength) \
|
||||
@ -2363,19 +2362,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) {
|
||||
|
Loading…
Reference in New Issue
Block a user