Create AllocationSite objects, pointed to by AllocationSiteInfo.

This creates a platform where we can do additional things with allocation sites,
other than just aid in reducing array transitions.

BUG=
R=hpayer@chromium.org

Review URL: https://codereview.chromium.org/15094018

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@15545 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
mvstanton@chromium.org 2013-07-08 10:02:16 +00:00
parent c1c10b452f
commit 67d9051bcd
34 changed files with 623 additions and 306 deletions

View File

@ -5403,7 +5403,7 @@ class Internals {
static const int kNodeIsIndependentShift = 4;
static const int kNodeIsPartiallyDependentShift = 5;
static const int kJSObjectType = 0xb0;
static const int kJSObjectType = 0xb1;
static const int kFirstNonstringType = 0x80;
static const int kOddballType = 0x83;
static const int kForeignType = 0x88;

View File

@ -60,6 +60,16 @@ void FastCloneShallowObjectStub::InitializeInterfaceDescriptor(
}
void CreateAllocationSiteStub::InitializeInterfaceDescriptor(
Isolate* isolate,
CodeStubInterfaceDescriptor* descriptor) {
static Register registers[] = { r2 };
descriptor->register_param_count_ = 1;
descriptor->register_params_ = registers;
descriptor->deoptimization_handler_ = NULL;
}
void KeyedLoadFastElementStub::InitializeInterfaceDescriptor(
Isolate* isolate,
CodeStubInterfaceDescriptor* descriptor) {
@ -2753,6 +2763,7 @@ void CodeStub::GenerateStubsAheadOfTime(Isolate* isolate) {
StubFailureTrampolineStub::GenerateAheadOfTime(isolate);
RecordWriteStub::GenerateFixedRegStubsAheadOfTime(isolate);
ArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate);
CreateAllocationSiteStub::GenerateAheadOfTime(isolate);
}
@ -4401,20 +4412,17 @@ static void GenerateRecordCallTarget(MacroAssembler* masm) {
// function without changing the state.
__ cmp(r3, r1);
__ b(eq, &done);
__ CompareRoot(r3, Heap::kUndefinedValueRootIndex);
__ b(eq, &done);
// Special handling of the Array() function, which caches not only the
// monomorphic Array function but the initial ElementsKind with special
// sentinels
__ JumpIfNotSmi(r3, &miss);
if (FLAG_debug_code) {
Handle<Object> terminal_kind_sentinel =
TypeFeedbackCells::MonomorphicArraySentinel(masm->isolate(),
LAST_FAST_ELEMENTS_KIND);
__ cmp(r3, Operand(terminal_kind_sentinel));
__ Assert(le, "Array function sentinel is not an ElementsKind");
}
// If we came here, we need to see if we are the array function.
// If we didn't have a matching function, and we didn't find the megamorph
// sentinel, then we have in the cell either some other function or an
// AllocationSite. Do a map check on the object in ecx.
Handle<Map> allocation_site_map(
masm->isolate()->heap()->allocation_site_map(),
masm->isolate());
__ ldr(r5, FieldMemOperand(r3, 0));
__ CompareRoot(r5, Heap::kAllocationSiteMapRootIndex);
__ b(ne, &miss);
// Make sure the function is the Array() function
__ LoadArrayFunction(r3);
@ -4443,14 +4451,22 @@ static void GenerateRecordCallTarget(MacroAssembler* masm) {
__ cmp(r1, r3);
__ b(ne, &not_array_function);
// The target function is the Array constructor, install a sentinel value in
// the constructor's type info cell that will track the initial ElementsKind
// that should be used for the array when its constructed.
Handle<Object> initial_kind_sentinel =
TypeFeedbackCells::MonomorphicArraySentinel(masm->isolate(),
GetInitialFastElementsKind());
__ mov(r3, Operand(initial_kind_sentinel));
__ str(r3, FieldMemOperand(r2, Cell::kValueOffset));
// The target function is the Array constructor,
// Create an AllocationSite if we don't already have it, store it in the cell
{
FrameScope scope(masm, StackFrame::INTERNAL);
__ push(r0);
__ push(r1);
__ push(r2);
CreateAllocationSiteStub create_stub;
__ CallStub(&create_stub);
__ pop(r2);
__ pop(r1);
__ pop(r0);
}
__ b(&done);
__ bind(&not_array_function);
@ -6934,10 +6950,6 @@ static void CreateArrayDispatchOneArgument(MacroAssembler* masm) {
ASSERT(FAST_DOUBLE_ELEMENTS == 4);
ASSERT(FAST_HOLEY_DOUBLE_ELEMENTS == 5);
Handle<Object> undefined_sentinel(
masm->isolate()->heap()->undefined_value(),
masm->isolate());
// is the low bit set? If so, we are holey and that is good.
__ tst(r3, Operand(1));
Label normal_sequence;
@ -6949,18 +6961,19 @@ static void CreateArrayDispatchOneArgument(MacroAssembler* masm) {
__ b(eq, &normal_sequence);
// We are going to create a holey array, but our kind is non-holey.
// Fix kind and retry
// Fix kind and retry (only if we have an allocation site in the cell).
__ add(r3, r3, Operand(1));
__ cmp(r2, Operand(undefined_sentinel));
__ CompareRoot(r2, Heap::kUndefinedValueRootIndex);
__ b(eq, &normal_sequence);
// The type cell may have gone megamorphic, don't overwrite if so
__ ldr(r5, FieldMemOperand(r2, kPointerSize));
__ JumpIfNotSmi(r5, &normal_sequence);
__ ldr(r5, FieldMemOperand(r2, Cell::kValueOffset));
__ ldr(r5, FieldMemOperand(r5, 0));
__ CompareRoot(r5, Heap::kAllocationSiteMapRootIndex);
__ b(ne, &normal_sequence);
// Save the resulting elements kind in type info
__ SmiTag(r3);
__ str(r3, FieldMemOperand(r2, kPointerSize));
__ ldr(r5, FieldMemOperand(r2, Cell::kValueOffset));
__ str(r3, FieldMemOperand(r5, AllocationSite::kPayloadOffset));
__ SmiUntag(r3);
__ bind(&normal_sequence);
@ -6989,7 +7002,7 @@ static void ArrayConstructorStubAheadOfTimeHelper(Isolate* isolate) {
ElementsKind kind = GetFastElementsKindFromSequenceIndex(i);
T stub(kind);
stub.GetCode(isolate)->set_is_pregenerated(true);
if (AllocationSiteInfo::GetMode(kind) != DONT_TRACK_ALLOCATION_SITE) {
if (AllocationSite::GetMode(kind) != DONT_TRACK_ALLOCATION_SITE) {
T stub1(kind, CONTEXT_CHECK_REQUIRED, DISABLE_ALLOCATION_SITES);
stub1.GetCode(isolate)->set_is_pregenerated(true);
}
@ -7030,10 +7043,6 @@ void ArrayConstructorStub::Generate(MacroAssembler* masm) {
// -- sp[0] : return address
// -- sp[4] : last argument
// -----------------------------------
Handle<Object> undefined_sentinel(
masm->isolate()->heap()->undefined_value(),
masm->isolate());
if (FLAG_debug_code) {
// The array construct code is only set for the global and natives
// builtin Array functions which always have maps.
@ -7049,7 +7058,7 @@ void ArrayConstructorStub::Generate(MacroAssembler* masm) {
// We should either have undefined in ebx or a valid cell
Label okay_here;
Handle<Map> cell_map = masm->isolate()->factory()->cell_map();
__ cmp(r2, Operand(undefined_sentinel));
__ CompareRoot(r2, Heap::kUndefinedValueRootIndex);
__ b(eq, &okay_here);
__ ldr(r3, FieldMemOperand(r2, 0));
__ cmp(r3, Operand(cell_map));
@ -7059,10 +7068,23 @@ void ArrayConstructorStub::Generate(MacroAssembler* masm) {
Label no_info, switch_ready;
// Get the elements kind and case on that.
__ cmp(r2, Operand(undefined_sentinel));
__ CompareRoot(r2, Heap::kUndefinedValueRootIndex);
__ b(eq, &no_info);
__ ldr(r3, FieldMemOperand(r2, Cell::kValueOffset));
__ JumpIfNotSmi(r3, &no_info);
// The type cell may have undefined in its value.
__ CompareRoot(r3, Heap::kUndefinedValueRootIndex);
__ b(eq, &no_info);
// We should have an allocation site object
if (FLAG_debug_code) {
__ push(r3);
__ ldr(r3, FieldMemOperand(r3, 0));
__ CompareRoot(r3, Heap::kAllocationSiteMapRootIndex);
__ Assert(eq, "Expected AllocationSite object in register edx");
}
__ ldr(r3, FieldMemOperand(r3, AllocationSite::kPayloadOffset));
__ SmiUntag(r3);
__ jmp(&switch_ready);
__ bind(&no_info);

View File

@ -1230,8 +1230,8 @@ void KeyedStoreIC::GenerateTransitionElementsSmiToDouble(MacroAssembler* masm) {
// Must return the modified receiver in r0.
if (!FLAG_trace_elements_transitions) {
Label fail;
AllocationSiteMode mode = AllocationSiteInfo::GetMode(FAST_SMI_ELEMENTS,
FAST_DOUBLE_ELEMENTS);
AllocationSiteMode mode = AllocationSite::GetMode(FAST_SMI_ELEMENTS,
FAST_DOUBLE_ELEMENTS);
ElementsTransitionGenerator::GenerateSmiToDouble(masm, mode, &fail);
__ mov(r0, r2);
__ Ret();
@ -1253,8 +1253,8 @@ void KeyedStoreIC::GenerateTransitionElementsDoubleToObject(
// Must return the modified receiver in r0.
if (!FLAG_trace_elements_transitions) {
Label fail;
AllocationSiteMode mode = AllocationSiteInfo::GetMode(FAST_DOUBLE_ELEMENTS,
FAST_ELEMENTS);
AllocationSiteMode mode = AllocationSite::GetMode(FAST_DOUBLE_ELEMENTS,
FAST_ELEMENTS);
ElementsTransitionGenerator::GenerateDoubleToObject(masm, mode, &fail);
__ mov(r0, r2);
__ Ret();
@ -1384,8 +1384,8 @@ static void KeyedStoreGenerateGenericHelper(
r4,
slow);
ASSERT(receiver_map.is(r3)); // Transition code expects map in r3
AllocationSiteMode mode = AllocationSiteInfo::GetMode(FAST_SMI_ELEMENTS,
FAST_DOUBLE_ELEMENTS);
AllocationSiteMode mode = AllocationSite::GetMode(FAST_SMI_ELEMENTS,
FAST_DOUBLE_ELEMENTS);
ElementsTransitionGenerator::GenerateSmiToDouble(masm, mode, slow);
__ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
__ jmp(&fast_double_without_map_check);
@ -1398,7 +1398,7 @@ static void KeyedStoreGenerateGenericHelper(
r4,
slow);
ASSERT(receiver_map.is(r3)); // Transition code expects map in r3
mode = AllocationSiteInfo::GetMode(FAST_SMI_ELEMENTS, FAST_ELEMENTS);
mode = AllocationSite::GetMode(FAST_SMI_ELEMENTS, FAST_ELEMENTS);
ElementsTransitionGenerator::GenerateMapChangeElementsTransition(masm, mode,
slow);
__ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
@ -1414,7 +1414,7 @@ static void KeyedStoreGenerateGenericHelper(
r4,
slow);
ASSERT(receiver_map.is(r3)); // Transition code expects map in r3
mode = AllocationSiteInfo::GetMode(FAST_DOUBLE_ELEMENTS, FAST_ELEMENTS);
mode = AllocationSite::GetMode(FAST_DOUBLE_ELEMENTS, FAST_ELEMENTS);
ElementsTransitionGenerator::GenerateDoubleToObject(masm, mode, slow);
__ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
__ jmp(&finish_object_store);

View File

@ -4142,7 +4142,7 @@ void LCodeGen::DoCallNewArray(LCallNewArray* instr) {
__ mov(r2, Operand(instr->hydrogen()->property_cell()));
ElementsKind kind = instr->hydrogen()->elements_kind();
AllocationSiteOverrideMode override_mode =
(AllocationSiteInfo::GetMode(kind) == TRACK_ALLOCATION_SITE)
(AllocationSite::GetMode(kind) == TRACK_ALLOCATION_SITE)
? DISABLE_ALLOCATION_SITES
: DONT_OVERRIDE;
ContextCheckMode context_mode = CONTEXT_CHECK_NOT_REQUIRED;

View File

@ -1728,11 +1728,11 @@ Handle<Code> CallStubCompiler::CompileArrayCodeCall(
GenerateLoadFunctionFromCell(cell, function, &miss);
}
Handle<Smi> kind(Smi::FromInt(GetInitialFastElementsKind()), isolate());
Handle<Cell> kind_feedback_cell =
isolate()->factory()->NewCell(kind);
Handle<AllocationSite> site = isolate()->factory()->NewAllocationSite();
site->set_payload(Smi::FromInt(GetInitialFastElementsKind()));
Handle<Cell> site_feedback_cell = isolate()->factory()->NewCell(site);
__ mov(r0, Operand(argc));
__ mov(r2, Operand(kind_feedback_cell));
__ mov(r2, Operand(site_feedback_cell));
__ mov(r1, Operand(function));
ArrayConstructorStub stub(isolate());

View File

@ -676,8 +676,9 @@ void CallNew::RecordTypeFeedback(TypeFeedbackOracle* oracle) {
target_ = oracle->GetCallNewTarget(this);
Object* value = allocation_info_cell_->value();
ASSERT(!value->IsTheHole());
if (value->IsSmi()) {
elements_kind_ = static_cast<ElementsKind>(Smi::cast(value)->value());
if (value->IsAllocationSite()) {
AllocationSite* site = AllocationSite::cast(value);
elements_kind_ = site->GetElementsKindPayload();
}
}
}

View File

@ -212,8 +212,9 @@ static MaybeObject* ArrayCodeGenericCommon(Arguments* args,
if (maybe_array->IsFailure()) return maybe_array;
AllocationSiteInfo* info = AllocationSiteInfo::FindForJSObject(array);
ElementsKind to_kind = array->GetElementsKind();
if (info != NULL && info->GetElementsKindPayload(&to_kind)) {
if (info != NULL && info->IsValid()) {
AllocationSite* site = info->GetAllocationSite();
ElementsKind to_kind = site->GetElementsKindPayload();
if (IsMoreGeneralElementsKindTransition(array->GetElementsKind(),
to_kind)) {
// We have advice that we should change the elements kind

View File

@ -315,16 +315,17 @@ HValue* CodeStubGraphBuilder<FastCloneShallowArrayStub>::BuildCodeStub() {
FastCloneShallowArrayStub::Mode mode = casted_stub()->mode();
int length = casted_stub()->length();
HInstruction* boilerplate =
HInstruction* allocation_site =
AddInstruction(new(zone) HLoadKeyed(GetParameter(0),
GetParameter(1),
NULL,
FAST_ELEMENTS));
IfBuilder checker(this);
checker.IfNot<HCompareObjectEqAndBranch, HValue*>(boilerplate, undefined);
checker.IfNot<HCompareObjectEqAndBranch, HValue*>(allocation_site, undefined);
checker.Then();
HObjectAccess access = HObjectAccess::ForAllocationSiteInfoSite();
HInstruction* boilerplate = AddLoad(allocation_site, access);
if (mode == FastCloneShallowArrayStub::CLONE_ANY_ELEMENTS) {
HValue* elements = AddLoadElements(boilerplate);
@ -333,6 +334,7 @@ HValue* CodeStubGraphBuilder<FastCloneShallowArrayStub>::BuildCodeStub() {
if_fixed_cow.Then();
environment()->Push(BuildCloneShallowArray(context(),
boilerplate,
allocation_site,
alloc_site_mode,
FAST_ELEMENTS,
0/*copy-on-write*/));
@ -343,12 +345,14 @@ HValue* CodeStubGraphBuilder<FastCloneShallowArrayStub>::BuildCodeStub() {
if_fixed.Then();
environment()->Push(BuildCloneShallowArray(context(),
boilerplate,
allocation_site,
alloc_site_mode,
FAST_ELEMENTS,
length));
if_fixed.Else();
environment()->Push(BuildCloneShallowArray(context(),
boilerplate,
allocation_site,
alloc_site_mode,
FAST_DOUBLE_ELEMENTS,
length));
@ -356,6 +360,7 @@ HValue* CodeStubGraphBuilder<FastCloneShallowArrayStub>::BuildCodeStub() {
ElementsKind elements_kind = casted_stub()->ComputeElementsKind();
environment()->Push(BuildCloneShallowArray(context(),
boilerplate,
allocation_site,
alloc_site_mode,
elements_kind,
length));
@ -421,6 +426,45 @@ Handle<Code> FastCloneShallowObjectStub::GenerateCode() {
}
template <>
HValue* CodeStubGraphBuilder<CreateAllocationSiteStub>::BuildCodeStub() {
Zone* zone = this->zone();
HValue* size = AddInstruction(new(zone) HConstant(AllocationSite::kSize));
HAllocate::Flags flags = HAllocate::DefaultFlags();
flags = static_cast<HAllocate::Flags>(
flags | HAllocate::CAN_ALLOCATE_IN_OLD_POINTER_SPACE);
HInstruction* object = AddInstruction(new(zone)
HAllocate(context(), size, HType::JSObject(), flags));
// Store the map
Handle<Map> allocation_site_map(isolate()->heap()->allocation_site_map(),
isolate());
AddStoreMapConstant(object, allocation_site_map);
// Store the payload (smi elements kind)
HValue* initial_elements_kind = AddInstruction(new(zone) HConstant(
GetInitialFastElementsKind()));
AddInstruction(new(zone) HStoreNamedField(object,
HObjectAccess::ForAllocationSitePayload(), initial_elements_kind));
// We use a hammer (SkipWriteBarrier()) to indicate that we know the input
// cell is really a Cell, and so no write barrier is needed.
// TODO(mvstanton): Add a debug_code check to verify the input cell is really
// a cell. (perhaps with a new instruction, HAssert).
HInstruction* cell = GetParameter(0);
HObjectAccess access = HObjectAccess::ForCellValue();
HStoreNamedField* store = AddStore(cell, access, object);
store->SkipWriteBarrier();
return cell;
}
Handle<Code> CreateAllocationSiteStub::GenerateCode() {
return DoGenerateCode(this);
}
template <>
HValue* CodeStubGraphBuilder<KeyedLoadFastElementStub>::BuildCodeStub() {
HInstruction* load = BuildUncheckedMonomorphicElementAccess(
@ -548,7 +592,10 @@ HValue* CodeStubGraphBuilderBase::BuildArrayConstructor(
}
HValue* property_cell = GetParameter(ArrayConstructorStubBase::kPropertyCell);
JSArrayBuilder array_builder(this, kind, property_cell, constructor,
// Walk through the property cell to the AllocationSite
HValue* alloc_site = AddInstruction(new(zone()) HLoadNamedField(property_cell,
HObjectAccess::ForCellValue()));
JSArrayBuilder array_builder(this, kind, alloc_site, constructor,
override_mode);
HValue* result = NULL;
switch (argument_class) {

View File

@ -663,6 +663,12 @@ void KeyedLoadDictionaryElementStub::Generate(MacroAssembler* masm) {
}
void CreateAllocationSiteStub::GenerateAheadOfTime(Isolate* isolate) {
CreateAllocationSiteStub stub;
stub.GetCode(isolate)->set_is_pregenerated(true);
}
void KeyedStoreElementStub::Generate(MacroAssembler* masm) {
switch (elements_kind_) {
case FAST_ELEMENTS:
@ -807,7 +813,7 @@ bool ToBooleanStub::Types::CanBeUndetectable() const {
void ElementsTransitionAndStoreStub::Generate(MacroAssembler* masm) {
Label fail;
AllocationSiteMode mode = AllocationSiteInfo::GetMode(from_, to_);
AllocationSiteMode mode = AllocationSite::GetMode(from_, to_);
ASSERT(!IsFastHoleyElementsKind(from_) || IsFastHoleyElementsKind(to_));
if (!FLAG_trace_elements_transitions) {
if (IsFastSmiOrObjectElementsKind(to_)) {

View File

@ -66,6 +66,7 @@ namespace internal {
V(FastNewBlockContext) \
V(FastCloneShallowArray) \
V(FastCloneShallowObject) \
V(CreateAllocationSite) \
V(ToBoolean) \
V(ToNumber) \
V(ArgumentsAccess) \
@ -738,6 +739,28 @@ class FastCloneShallowObjectStub : public HydrogenCodeStub {
};
class CreateAllocationSiteStub : public HydrogenCodeStub {
public:
explicit CreateAllocationSiteStub() { }
virtual Handle<Code> GenerateCode();
virtual bool IsPregenerated() { return true; }
static void GenerateAheadOfTime(Isolate* isolate);
virtual void InitializeInterfaceDescriptor(
Isolate* isolate,
CodeStubInterfaceDescriptor* descriptor);
private:
Major MajorKey() { return CreateAllocationSite; }
int NotMissMinorKey() { return 0; }
DISALLOW_COPY_AND_ASSIGN(CreateAllocationSiteStub);
};
class InstanceofStub: public PlatformCodeStub {
public:
enum Flags {
@ -1873,7 +1896,7 @@ class ArrayConstructorStubBase : public HydrogenCodeStub {
// if there is a difference between the global allocation site policy
// for an ElementsKind and the desired usage of the stub.
ASSERT(override_mode != DISABLE_ALLOCATION_SITES ||
AllocationSiteInfo::GetMode(kind) == TRACK_ALLOCATION_SITE);
AllocationSite::GetMode(kind) == TRACK_ALLOCATION_SITE);
bit_field_ = ElementsKindBits::encode(kind) |
AllocationSiteOverrideModeBits::encode(override_mode) |
ContextCheckModeBits::encode(context_mode);

View File

@ -519,6 +519,14 @@ Handle<PropertyCell> Factory::NewPropertyCell(Handle<Object> value) {
}
Handle<AllocationSite> Factory::NewAllocationSite() {
CALL_HEAP_FUNCTION(
isolate(),
isolate()->heap()->AllocateAllocationSite(),
AllocationSite);
}
Handle<Map> Factory::NewMap(InstanceType type,
int instance_size,
ElementsKind elements_kind) {

View File

@ -243,6 +243,8 @@ class Factory {
Handle<PropertyCell> NewPropertyCell(Handle<Object> value);
Handle<AllocationSite> NewAllocationSite();
Handle<Map> NewMap(
InstanceType type,
int instance_size,

View File

@ -495,10 +495,9 @@ void Heap::ScavengeObject(HeapObject** p, HeapObject* object) {
MaybeObject* Heap::AllocateEmptyJSArrayWithAllocationSite(
ElementsKind elements_kind,
Handle<Object> allocation_site_payload) {
Handle<AllocationSite> allocation_site) {
return AllocateJSArrayAndStorageWithAllocationSite(elements_kind, 0, 0,
allocation_site_payload,
DONT_INITIALIZE_ARRAY_ELEMENTS);
allocation_site, DONT_INITIALIZE_ARRAY_ELEMENTS);
}

View File

@ -2880,6 +2880,16 @@ MaybeObject* Heap::AllocateBox(Object* value, PretenureFlag pretenure) {
}
MaybeObject* Heap::AllocateAllocationSite() {
Object* result;
MaybeObject* maybe_result = Allocate(allocation_site_map(),
OLD_POINTER_SPACE);
if (!maybe_result->ToObject(&result)) return maybe_result;
AllocationSite::cast(result)->Initialize();
return result;
}
MaybeObject* Heap::CreateOddball(const char* to_string,
Object* to_number,
byte kind) {
@ -4186,7 +4196,7 @@ MaybeObject* Heap::CopyCode(Code* code, Vector<byte> reloc_info) {
MaybeObject* Heap::AllocateWithAllocationSite(Map* map, AllocationSpace space,
Handle<Object> allocation_site_info_payload) {
Handle<AllocationSite> allocation_site) {
ASSERT(gc_state_ == NOT_IN_GC);
ASSERT(map->instance_type() != MAP_TYPE);
// If allocation failures are disallowed, we may allocate in a different
@ -4202,7 +4212,7 @@ MaybeObject* Heap::AllocateWithAllocationSite(Map* map, AllocationSpace space,
AllocationSiteInfo* alloc_info = reinterpret_cast<AllocationSiteInfo*>(
reinterpret_cast<Address>(result) + map->instance_size());
alloc_info->set_map_no_write_barrier(allocation_site_info_map());
alloc_info->set_payload(*allocation_site_info_payload, SKIP_WRITE_BARRIER);
alloc_info->set_allocation_site(*allocation_site, SKIP_WRITE_BARRIER);
return result;
}
@ -4461,7 +4471,7 @@ MaybeObject* Heap::AllocateJSObjectFromMap(Map* map, PretenureFlag pretenure) {
MaybeObject* Heap::AllocateJSObjectFromMapWithAllocationSite(Map* map,
Handle<Object> allocation_site_info_payload) {
Handle<AllocationSite> allocation_site) {
// JSFunctions should be allocated using AllocateFunction to be
// properly initialized.
ASSERT(map->instance_type() != JS_FUNCTION_TYPE);
@ -4486,8 +4496,8 @@ MaybeObject* Heap::AllocateJSObjectFromMapWithAllocationSite(Map* map,
AllocationSpace space = NEW_SPACE;
if (map->instance_size() > Page::kMaxNonCodeHeapObjectSize) space = LO_SPACE;
Object* obj;
MaybeObject* maybe_obj = AllocateWithAllocationSite(map, space,
allocation_site_info_payload);
MaybeObject* maybe_obj =
AllocateWithAllocationSite(map, space, allocation_site);
if (!maybe_obj->To(&obj)) return maybe_obj;
// Initialize the JSObject.
@ -4523,7 +4533,7 @@ MaybeObject* Heap::AllocateJSObject(JSFunction* constructor,
MaybeObject* Heap::AllocateJSObjectWithAllocationSite(JSFunction* constructor,
Handle<Object> allocation_site_info_payload) {
Handle<AllocationSite> allocation_site) {
// Allocate the initial map if absent.
if (!constructor->has_initial_map()) {
Object* initial_map;
@ -4537,8 +4547,7 @@ MaybeObject* Heap::AllocateJSObjectWithAllocationSite(JSFunction* constructor,
// advice
Map* initial_map = constructor->initial_map();
Cell* cell = Cell::cast(*allocation_site_info_payload);
Smi* smi = Smi::cast(cell->value());
Smi* smi = Smi::cast(allocation_site->payload());
ElementsKind to_kind = static_cast<ElementsKind>(smi->value());
AllocationSiteMode mode = TRACK_ALLOCATION_SITE;
if (to_kind != initial_map->elements_kind()) {
@ -4546,13 +4555,13 @@ MaybeObject* Heap::AllocateJSObjectWithAllocationSite(JSFunction* constructor,
if (!maybe_new_map->To(&initial_map)) return maybe_new_map;
// Possibly alter the mode, since we found an updated elements kind
// in the type info cell.
mode = AllocationSiteInfo::GetMode(to_kind);
mode = AllocationSite::GetMode(to_kind);
}
MaybeObject* result;
if (mode == TRACK_ALLOCATION_SITE) {
result = AllocateJSObjectFromMapWithAllocationSite(initial_map,
allocation_site_info_payload);
allocation_site);
} else {
result = AllocateJSObjectFromMap(initial_map, NOT_TENURED);
}
@ -4647,10 +4656,10 @@ MaybeObject* Heap::AllocateJSArrayAndStorageWithAllocationSite(
ElementsKind elements_kind,
int length,
int capacity,
Handle<Object> allocation_site_payload,
Handle<AllocationSite> allocation_site,
ArrayStorageAllocationMode mode) {
MaybeObject* maybe_array = AllocateJSArrayWithAllocationSite(elements_kind,
allocation_site_payload);
allocation_site);
JSArray* array;
if (!maybe_array->To(&array)) return maybe_array;
return AllocateJSArrayStorage(array, length, capacity, mode);
@ -4899,7 +4908,9 @@ MaybeObject* Heap::CopyJSObject(JSObject* source) {
}
MaybeObject* Heap::CopyJSObjectWithAllocationSite(JSObject* source) {
MaybeObject* Heap::CopyJSObjectWithAllocationSite(
JSObject* source,
AllocationSite* site) {
// Never used to copy functions. If functions need to be copied we
// have to be careful to clear the literals array.
SLOW_ASSERT(!source->IsJSFunction());
@ -4949,7 +4960,7 @@ MaybeObject* Heap::CopyJSObjectWithAllocationSite(JSObject* source) {
AllocationSiteInfo* alloc_info;
if (maybe_alloc_info->To(&alloc_info)) {
alloc_info->set_map_no_write_barrier(allocation_site_info_map());
alloc_info->set_payload(source, SKIP_WRITE_BARRIER);
alloc_info->set_allocation_site(site, SKIP_WRITE_BARRIER);
}
}
} else {
@ -4971,7 +4982,7 @@ MaybeObject* Heap::CopyJSObjectWithAllocationSite(JSObject* source) {
AllocationSiteInfo* alloc_info = reinterpret_cast<AllocationSiteInfo*>(
reinterpret_cast<Address>(clone) + object_size);
alloc_info->set_map_no_write_barrier(allocation_site_info_map());
alloc_info->set_payload(source, SKIP_WRITE_BARRIER);
alloc_info->set_allocation_site(site, SKIP_WRITE_BARRIER);
}
SLOW_ASSERT(
@ -5388,7 +5399,7 @@ MaybeObject* Heap::AllocateJSArray(
MaybeObject* Heap::AllocateJSArrayWithAllocationSite(
ElementsKind elements_kind,
Handle<Object> allocation_site_info_payload) {
Handle<AllocationSite> allocation_site) {
Context* native_context = isolate()->context()->native_context();
JSFunction* array_function = native_context->array_function();
Map* map = array_function->initial_map();
@ -5400,8 +5411,7 @@ MaybeObject* Heap::AllocateJSArrayWithAllocationSite(
map = Map::cast(maybe_transitioned_map);
}
}
return AllocateJSObjectFromMapWithAllocationSite(map,
allocation_site_info_payload);
return AllocateJSObjectFromMapWithAllocationSite(map, allocation_site);
}

View File

@ -232,6 +232,7 @@ namespace internal {
V(last_index_string, "lastIndex") \
V(object_string, "object") \
V(payload_string, "payload") \
V(literals_string, "literals") \
V(prototype_string, "prototype") \
V(string_string, "string") \
V(String_string, "String") \
@ -658,7 +659,7 @@ class Heap {
MUST_USE_RESULT MaybeObject* AllocateJSObjectWithAllocationSite(
JSFunction* constructor,
Handle<Object> allocation_site_info_payload);
Handle<AllocationSite> allocation_site);
MUST_USE_RESULT MaybeObject* AllocateJSGeneratorObject(
JSFunction* function);
@ -677,7 +678,7 @@ class Heap {
inline MUST_USE_RESULT MaybeObject* AllocateEmptyJSArrayWithAllocationSite(
ElementsKind elements_kind,
Handle<Object> allocation_site_payload);
Handle<AllocationSite> allocation_site);
// Allocate a JSArray with a specified length but elements that are left
// uninitialized.
@ -692,7 +693,7 @@ class Heap {
ElementsKind elements_kind,
int length,
int capacity,
Handle<Object> allocation_site_payload,
Handle<AllocationSite> allocation_site,
ArrayStorageAllocationMode mode = DONT_INITIALIZE_ARRAY_ELEMENTS);
MUST_USE_RESULT MaybeObject* AllocateJSArrayStorage(
@ -719,7 +720,8 @@ class Heap {
// Returns failure if allocation failed.
MUST_USE_RESULT MaybeObject* CopyJSObject(JSObject* source);
MUST_USE_RESULT MaybeObject* CopyJSObjectWithAllocationSite(JSObject* source);
MUST_USE_RESULT MaybeObject* CopyJSObjectWithAllocationSite(
JSObject* source, AllocationSite* site);
// Allocates the function prototype.
// Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
@ -769,7 +771,7 @@ class Heap {
Map* map, PretenureFlag pretenure = NOT_TENURED);
MUST_USE_RESULT MaybeObject* AllocateJSObjectFromMapWithAllocationSite(
Map* map, Handle<Object> allocation_site_info_payload);
Map* map, Handle<AllocationSite> allocation_site);
// Allocates a heap object based on the map.
// Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
@ -778,7 +780,7 @@ class Heap {
MUST_USE_RESULT MaybeObject* Allocate(Map* map, AllocationSpace space);
MUST_USE_RESULT MaybeObject* AllocateWithAllocationSite(Map* map,
AllocationSpace space, Handle<Object> allocation_site_info_payload);
AllocationSpace space, Handle<AllocationSite> allocation_site);
// Allocates a JS Map in the heap.
// Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
@ -956,6 +958,9 @@ class Heap {
MUST_USE_RESULT MaybeObject* AllocateBox(Object* value,
PretenureFlag pretenure);
// Allocate a tenured AllocationSite. It's payload is null
MUST_USE_RESULT MaybeObject* AllocateAllocationSite();
// Allocates a fixed array initialized with undefined values
// Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
// failed.
@ -2159,7 +2164,7 @@ class Heap {
MUST_USE_RESULT MaybeObject* AllocateJSArrayWithAllocationSite(
ElementsKind elements_kind,
Handle<Object> allocation_site_info_payload);
Handle<AllocationSite> allocation_site);
// Allocate empty fixed array.
MUST_USE_RESULT MaybeObject* AllocateEmptyFixedArray();

View File

@ -5347,6 +5347,10 @@ class HObjectAccess {
return HObjectAccess(kArrayLengths, JSArray::kLengthOffset);
}
static HObjectAccess ForAllocationSitePayload() {
return HObjectAccess(kInobject, AllocationSite::kPayloadOffset);
}
static HObjectAccess ForFixedArrayLength() {
return HObjectAccess(kArrayLengths, FixedArray::kLengthOffset);
}
@ -5363,8 +5367,16 @@ class HObjectAccess {
return HObjectAccess(kMaps, JSObject::kMapOffset);
}
static HObjectAccess ForAllocationSitePayload() {
return HObjectAccess(kInobject, AllocationSiteInfo::kPayloadOffset);
static HObjectAccess ForPropertyCellValue() {
return HObjectAccess(kInobject, PropertyCell::kValueOffset);
}
static HObjectAccess ForCellValue() {
return HObjectAccess(kInobject, Cell::kValueOffset);
}
static HObjectAccess ForAllocationSiteInfoSite() {
return HObjectAccess(kInobject, AllocationSiteInfo::kAllocationSiteOffset);
}
// Create an access to an offset in a fixed array header.
@ -5792,7 +5804,8 @@ class HStoreNamedField: public HTemplateInstruction<2> {
field_representation_(field_representation),
transition_(),
transition_unique_id_(),
new_space_dominator_(NULL) {
new_space_dominator_(NULL),
write_barrier_mode_(UPDATE_WRITE_BARRIER) {
SetOperandAt(0, obj);
SetOperandAt(1, val);
access.SetGVNFlags(this, true);
@ -5817,6 +5830,11 @@ class HStoreNamedField: public HTemplateInstruction<2> {
}
virtual void PrintDataTo(StringStream* stream);
void SkipWriteBarrier() { write_barrier_mode_ = SKIP_WRITE_BARRIER; }
bool IsSkipWriteBarrier() const {
return write_barrier_mode_ == SKIP_WRITE_BARRIER;
}
HValue* object() { return OperandAt(0); }
HValue* value() { return OperandAt(1); }
@ -5835,6 +5853,7 @@ class HStoreNamedField: public HTemplateInstruction<2> {
bool NeedsWriteBarrier() {
ASSERT(!(FLAG_track_double_fields && field_representation_.IsDouble()) ||
transition_.is_null());
if (IsSkipWriteBarrier()) return false;
return (!FLAG_track_fields || !field_representation_.IsSmi()) &&
// If there is a transition, a new storage object needs to be allocated.
!(FLAG_track_double_fields && field_representation_.IsDouble()) &&
@ -5843,6 +5862,7 @@ class HStoreNamedField: public HTemplateInstruction<2> {
}
bool NeedsWriteBarrierForMap() {
if (IsSkipWriteBarrier()) return false;
return ReceiverObjectNeedsWriteBarrier(object(), new_space_dominator());
}
@ -5860,6 +5880,7 @@ class HStoreNamedField: public HTemplateInstruction<2> {
Handle<Map> transition_;
UniqueValueId transition_unique_id_;
HValue* new_space_dominator_;
WriteBarrierMode write_barrier_mode_;
};

View File

@ -1597,6 +1597,7 @@ void HGraphBuilder::BuildCopyElements(HValue* context,
HValue* HGraphBuilder::BuildCloneShallowArray(HContext* context,
HValue* boilerplate,
HValue* allocation_site,
AllocationSiteMode mode,
ElementsKind kind,
int length) {
@ -1633,7 +1634,7 @@ HValue* HGraphBuilder::BuildCloneShallowArray(HContext* context,
// Create an allocation site info if requested.
if (mode == TRACK_ALLOCATION_SITE) {
BuildCreateAllocationSiteInfo(object, JSArray::kSize, boilerplate);
BuildCreateAllocationSiteInfo(object, JSArray::kSize, allocation_site);
}
if (length > 0) {
@ -1740,14 +1741,16 @@ void HGraphBuilder::BuildCompareNil(
HValue* HGraphBuilder::BuildCreateAllocationSiteInfo(HValue* previous_object,
int previous_object_size,
HValue* payload) {
HInnerAllocatedObject* alloc_site = Add<HInnerAllocatedObject>(
HValue* alloc_site) {
ASSERT(alloc_site != NULL);
HInnerAllocatedObject* alloc_site_info = Add<HInnerAllocatedObject>(
previous_object, previous_object_size);
Handle<Map> alloc_site_map(isolate()->heap()->allocation_site_info_map());
AddStoreMapConstant(alloc_site, alloc_site_map);
HObjectAccess access = HObjectAccess::ForAllocationSitePayload();
AddStore(alloc_site, access, payload);
return alloc_site;
Handle<Map> alloc_site_info_map(
isolate()->heap()->allocation_site_info_map());
AddStoreMapConstant(alloc_site_info, alloc_site_info_map);
HObjectAccess access = HObjectAccess::ForAllocationSiteInfoSite();
AddStore(alloc_site_info, access, alloc_site);
return alloc_site_info;
}
@ -1780,7 +1783,7 @@ HGraphBuilder::JSArrayBuilder::JSArrayBuilder(HGraphBuilder* builder,
constructor_function_(constructor_function) {
mode_ = override_mode == DISABLE_ALLOCATION_SITES
? DONT_TRACK_ALLOCATION_SITE
: AllocationSiteInfo::GetMode(kind);
: AllocationSite::GetMode(kind);
}
@ -4524,6 +4527,7 @@ void HOptimizedGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) {
literal = BuildFastLiteral(context,
boilerplate_object,
original_boilerplate_object,
Handle<Object>::null(),
data_size,
pointer_size,
DONT_TRACK_ALLOCATION_SITE);
@ -4631,25 +4635,37 @@ void HOptimizedGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) {
HValue* context = environment()->LookupContext();
HInstruction* literal;
Handle<AllocationSite> site;
Handle<FixedArray> literals(environment()->closure()->literals(), isolate());
Handle<Object> raw_boilerplate(literals->get(expr->literal_index()),
isolate());
bool uninitialized = false;
if (raw_boilerplate->IsUndefined()) {
Handle<Object> literals_cell(literals->get(expr->literal_index()),
isolate());
Handle<Object> raw_boilerplate;
if (literals_cell->IsUndefined()) {
uninitialized = true;
raw_boilerplate = Runtime::CreateArrayLiteralBoilerplate(
isolate(), literals, expr->constant_elements());
if (raw_boilerplate.is_null()) {
return Bailout("array boilerplate creation failed");
}
literals->set(expr->literal_index(), *raw_boilerplate);
site = isolate()->factory()->NewAllocationSite();
site->set_payload(*raw_boilerplate);
literals->set(expr->literal_index(), *site);
if (JSObject::cast(*raw_boilerplate)->elements()->map() ==
isolate()->heap()->fixed_cow_array_map()) {
isolate()->counters()->cow_arrays_created_runtime()->Increment();
}
} else {
ASSERT(literals_cell->IsAllocationSite());
site = Handle<AllocationSite>::cast(literals_cell);
raw_boilerplate = Handle<Object>(site->payload(), isolate());
}
ASSERT(!raw_boilerplate.is_null());
ASSERT(site->IsLiteralSite());
Handle<JSObject> original_boilerplate_object =
Handle<JSObject>::cast(raw_boilerplate);
ElementsKind boilerplate_elements_kind =
@ -4658,7 +4674,7 @@ void HOptimizedGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) {
// TODO(mvstanton): This heuristic is only a temporary solution. In the
// end, we want to quit creating allocation site info after a certain number
// of GCs for a call site.
AllocationSiteMode mode = AllocationSiteInfo::GetMode(
AllocationSiteMode mode = AllocationSite::GetMode(
boilerplate_elements_kind);
// Check whether to use fast or slow deep-copying for boilerplate.
@ -4678,6 +4694,7 @@ void HOptimizedGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) {
literal = BuildFastLiteral(context,
boilerplate_object,
original_boilerplate_object,
site,
data_size,
pointer_size,
mode);
@ -8504,6 +8521,7 @@ HInstruction* HOptimizedGraphBuilder::BuildFastLiteral(
HValue* context,
Handle<JSObject> boilerplate_object,
Handle<JSObject> original_boilerplate_object,
Handle<Object> allocation_site,
int data_size,
int pointer_size,
AllocationSiteMode mode) {
@ -8541,8 +8559,9 @@ HInstruction* HOptimizedGraphBuilder::BuildFastLiteral(
int offset = 0;
int data_offset = 0;
BuildEmitDeepCopy(boilerplate_object, original_boilerplate_object, target,
&offset, data_target, &data_offset, mode);
BuildEmitDeepCopy(boilerplate_object, original_boilerplate_object,
allocation_site, target, &offset, data_target,
&data_offset, mode);
return target;
}
@ -8550,11 +8569,30 @@ HInstruction* HOptimizedGraphBuilder::BuildFastLiteral(
void HOptimizedGraphBuilder::BuildEmitDeepCopy(
Handle<JSObject> boilerplate_object,
Handle<JSObject> original_boilerplate_object,
Handle<Object> allocation_site_object,
HInstruction* target,
int* offset,
HInstruction* data_target,
int* data_offset,
AllocationSiteMode mode) {
Zone* zone = this->zone();
bool create_allocation_site_info = mode == TRACK_ALLOCATION_SITE &&
boilerplate_object->map()->CanTrackAllocationSite();
// If using allocation sites, then the payload on the site should already
// be filled in as a valid (boilerplate) array.
ASSERT(!create_allocation_site_info ||
AllocationSite::cast(*allocation_site_object)->IsLiteralSite());
HInstruction* allocation_site = NULL;
if (create_allocation_site_info) {
allocation_site = AddInstruction(new(zone) HConstant(
allocation_site_object, Representation::Tagged()));
}
// Only elements backing stores for non-COW arrays need to be copied.
Handle<FixedArrayBase> elements(boilerplate_object->elements());
Handle<FixedArrayBase> original_elements(
original_boilerplate_object->elements());
@ -8600,9 +8638,7 @@ void HOptimizedGraphBuilder::BuildEmitDeepCopy(
boilerplate_object->map()->CanTrackAllocationSite()) {
elements_offset += AllocationSiteInfo::kSize;
*offset += AllocationSiteInfo::kSize;
HInstruction* original_boilerplate =
Add<HConstant>(original_boilerplate_object);
BuildCreateAllocationSiteInfo(target, JSArray::kSize, original_boilerplate);
BuildCreateAllocationSiteInfo(target, JSArray::kSize, allocation_site);
}
}
@ -8700,9 +8736,10 @@ void HOptimizedGraphBuilder::BuildEmitInObjectProperties(
*offset);
AddStore(object_properties, access, value_instruction);
BuildEmitDeepCopy(value_object, original_value_object, target,
offset, data_target, data_offset, DONT_TRACK_ALLOCATION_SITE);
BuildEmitDeepCopy(value_object, original_value_object,
Handle<Object>::null(), target,
offset, data_target, data_offset,
DONT_TRACK_ALLOCATION_SITE);
} else {
Representation representation = details.representation();
HInstruction* value_instruction = Add<HConstant>(value);
@ -8809,8 +8846,10 @@ void HOptimizedGraphBuilder::BuildEmitFixedArray(
HInstruction* value_instruction = Add<HInnerAllocatedObject>(target,
*offset);
Add<HStoreKeyed>(object_elements, key_constant, value_instruction, kind);
BuildEmitDeepCopy(value_object, original_value_object, target,
offset, data_target, data_offset, DONT_TRACK_ALLOCATION_SITE);
BuildEmitDeepCopy(value_object, original_value_object,
Handle<Object>::null(), target,
offset, data_target, data_offset,
DONT_TRACK_ALLOCATION_SITE);
} else {
HInstruction* value_instruction =
Add<HLoadKeyed>(boilerplate_elements, key_constant,

View File

@ -1397,6 +1397,7 @@ class HGraphBuilder {
HValue* BuildCloneShallowArray(HContext* context,
HValue* boilerplate,
HValue* allocation_site,
AllocationSiteMode mode,
ElementsKind kind,
int length);
@ -1858,12 +1859,14 @@ class HOptimizedGraphBuilder: public HGraphBuilder, public AstVisitor {
HInstruction* BuildFastLiteral(HValue* context,
Handle<JSObject> boilerplate_object,
Handle<JSObject> original_boilerplate_object,
Handle<Object> allocation_site,
int data_size,
int pointer_size,
AllocationSiteMode mode);
void BuildEmitDeepCopy(Handle<JSObject> boilerplat_object,
Handle<JSObject> object,
Handle<Object> allocation_site,
HInstruction* target,
int* offset,
HInstruction* data_target,

View File

@ -65,6 +65,16 @@ void FastCloneShallowObjectStub::InitializeInterfaceDescriptor(
}
void CreateAllocationSiteStub::InitializeInterfaceDescriptor(
Isolate* isolate,
CodeStubInterfaceDescriptor* descriptor) {
static Register registers[] = { ebx };
descriptor->register_param_count_ = 1;
descriptor->register_params_ = registers;
descriptor->deoptimization_handler_ = NULL;
}
void KeyedLoadFastElementStub::InitializeInterfaceDescriptor(
Isolate* isolate,
CodeStubInterfaceDescriptor* descriptor) {
@ -4400,17 +4410,15 @@ static void GenerateRecordCallTarget(MacroAssembler* masm) {
__ cmp(ecx, Immediate(TypeFeedbackCells::MegamorphicSentinel(isolate)));
__ j(equal, &done);
// Special handling of the Array() function, which caches not only the
// monomorphic Array function but the initial ElementsKind with special
// sentinels
__ JumpIfNotSmi(ecx, &miss);
if (FLAG_debug_code) {
Handle<Object> terminal_kind_sentinel =
TypeFeedbackCells::MonomorphicArraySentinel(masm->isolate(),
LAST_FAST_ELEMENTS_KIND);
__ cmp(ecx, Immediate(terminal_kind_sentinel));
__ Assert(less_equal, "Array function sentinel is not an ElementsKind");
}
// If we came here, we need to see if we are the array function.
// If we didn't have a matching function, and we didn't find the megamorph
// sentinel, then we have in the cell either some other function or an
// AllocationSite. Do a map check on the object in ecx.
Handle<Map> allocation_site_map(
masm->isolate()->heap()->allocation_site_map(),
masm->isolate());
__ cmp(FieldOperand(ecx, 0), Immediate(allocation_site_map));
__ j(not_equal, &miss);
// Load the global or builtins object from the current context
__ LoadGlobalContext(ecx);
@ -4442,14 +4450,22 @@ static void GenerateRecordCallTarget(MacroAssembler* masm) {
Context::SlotOffset(Context::ARRAY_FUNCTION_INDEX)));
__ j(not_equal, &not_array_function);
// The target function is the Array constructor, install a sentinel value in
// the constructor's type info cell that will track the initial ElementsKind
// that should be used for the array when its constructed.
Handle<Object> initial_kind_sentinel =
TypeFeedbackCells::MonomorphicArraySentinel(isolate,
GetInitialFastElementsKind());
__ mov(FieldOperand(ebx, Cell::kValueOffset),
Immediate(initial_kind_sentinel));
// The target function is the Array constructor,
// Create an AllocationSite if we don't already have it, store it in the cell
{
FrameScope scope(masm, StackFrame::INTERNAL);
__ push(eax);
__ push(edi);
__ push(ebx);
CreateAllocationSiteStub create_stub;
__ CallStub(&create_stub);
__ pop(ebx);
__ pop(edi);
__ pop(eax);
}
__ jmp(&done);
__ bind(&not_array_function);
@ -4615,6 +4631,7 @@ void CodeStub::GenerateStubsAheadOfTime(Isolate* isolate) {
// It is important that the store buffer overflow stubs are generated first.
RecordWriteStub::GenerateFixedRegStubsAheadOfTime(isolate);
ArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate);
CreateAllocationSiteStub::GenerateAheadOfTime(isolate);
}
@ -7492,18 +7509,20 @@ static void CreateArrayDispatchOneArgument(MacroAssembler* masm) {
__ j(zero, &normal_sequence);
// We are going to create a holey array, but our kind is non-holey.
// Fix kind and retry
// Fix kind and retry (only if we have an allocation site in the cell).
__ inc(edx);
__ cmp(ebx, Immediate(undefined_sentinel));
__ j(equal, &normal_sequence);
// The type cell may have gone megamorphic, don't overwrite if so
__ mov(ecx, FieldOperand(ebx, kPointerSize));
__ JumpIfNotSmi(ecx, &normal_sequence);
__ mov(ecx, FieldOperand(ebx, Cell::kValueOffset));
Handle<Map> allocation_site_map(
masm->isolate()->heap()->allocation_site_map(),
masm->isolate());
__ cmp(FieldOperand(ecx, 0), Immediate(allocation_site_map));
__ j(not_equal, &normal_sequence);
// Save the resulting elements kind in type info
__ SmiTag(edx);
__ mov(FieldOperand(ebx, kPointerSize), edx);
__ mov(FieldOperand(ecx, AllocationSite::kPayloadOffset), edx);
__ SmiUntag(edx);
__ bind(&normal_sequence);
@ -7532,7 +7551,7 @@ static void ArrayConstructorStubAheadOfTimeHelper(Isolate* isolate) {
ElementsKind kind = GetFastElementsKindFromSequenceIndex(i);
T stub(kind);
stub.GetCode(isolate)->set_is_pregenerated(true);
if (AllocationSiteInfo::GetMode(kind) != DONT_TRACK_ALLOCATION_SITE) {
if (AllocationSite::GetMode(kind) != DONT_TRACK_ALLOCATION_SITE) {
T stub1(kind, CONTEXT_CHECK_REQUIRED, DISABLE_ALLOCATION_SITES);
stub1.GetCode(isolate)->set_is_pregenerated(true);
}
@ -7604,7 +7623,20 @@ void ArrayConstructorStub::Generate(MacroAssembler* masm) {
__ cmp(ebx, Immediate(undefined_sentinel));
__ j(equal, &no_info);
__ mov(edx, FieldOperand(ebx, Cell::kValueOffset));
__ JumpIfNotSmi(edx, &no_info);
// The type cell may have undefined in its value.
__ cmp(edx, Immediate(undefined_sentinel));
__ j(equal, &no_info);
// We should have an allocation site object
if (FLAG_debug_code) {
__ cmp(FieldOperand(edx, 0),
Immediate(Handle<Map>(
masm->isolate()->heap()->allocation_site_map())));
__ Assert(equal, "Expected AllocationSite object in register edx");
}
__ mov(edx, FieldOperand(edx, AllocationSite::kPayloadOffset));
__ SmiUntag(edx);
__ jmp(&switch_ready);
__ bind(&no_info);

View File

@ -798,8 +798,8 @@ static void KeyedStoreGenerateGenericHelper(
ebx,
edi,
slow);
AllocationSiteMode mode = AllocationSiteInfo::GetMode(FAST_SMI_ELEMENTS,
FAST_DOUBLE_ELEMENTS);
AllocationSiteMode mode = AllocationSite::GetMode(FAST_SMI_ELEMENTS,
FAST_DOUBLE_ELEMENTS);
ElementsTransitionGenerator::GenerateSmiToDouble(masm, mode, slow);
__ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
__ jmp(&fast_double_without_map_check);
@ -811,7 +811,7 @@ static void KeyedStoreGenerateGenericHelper(
ebx,
edi,
slow);
mode = AllocationSiteInfo::GetMode(FAST_SMI_ELEMENTS, FAST_ELEMENTS);
mode = AllocationSite::GetMode(FAST_SMI_ELEMENTS, FAST_ELEMENTS);
ElementsTransitionGenerator::GenerateMapChangeElementsTransition(masm, mode,
slow);
__ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
@ -827,7 +827,7 @@ static void KeyedStoreGenerateGenericHelper(
ebx,
edi,
slow);
mode = AllocationSiteInfo::GetMode(FAST_DOUBLE_ELEMENTS, FAST_ELEMENTS);
mode = AllocationSite::GetMode(FAST_DOUBLE_ELEMENTS, FAST_ELEMENTS);
ElementsTransitionGenerator::GenerateDoubleToObject(masm, mode, slow);
__ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
__ jmp(&finish_object_store);
@ -1598,8 +1598,8 @@ void KeyedStoreIC::GenerateTransitionElementsSmiToDouble(MacroAssembler* masm) {
// Must return the modified receiver in eax.
if (!FLAG_trace_elements_transitions) {
Label fail;
AllocationSiteMode mode = AllocationSiteInfo::GetMode(FAST_SMI_ELEMENTS,
FAST_DOUBLE_ELEMENTS);
AllocationSiteMode mode = AllocationSite::GetMode(FAST_SMI_ELEMENTS,
FAST_DOUBLE_ELEMENTS);
ElementsTransitionGenerator::GenerateSmiToDouble(masm, mode, &fail);
__ mov(eax, edx);
__ Ret();
@ -1626,8 +1626,8 @@ void KeyedStoreIC::GenerateTransitionElementsDoubleToObject(
// Must return the modified receiver in eax.
if (!FLAG_trace_elements_transitions) {
Label fail;
AllocationSiteMode mode = AllocationSiteInfo::GetMode(FAST_DOUBLE_ELEMENTS,
FAST_ELEMENTS);
AllocationSiteMode mode = AllocationSite::GetMode(FAST_DOUBLE_ELEMENTS,
FAST_ELEMENTS);
ElementsTransitionGenerator::GenerateDoubleToObject(masm, mode, &fail);
__ mov(eax, edx);
__ Ret();

View File

@ -4198,7 +4198,7 @@ void LCodeGen::DoCallNewArray(LCallNewArray* instr) {
__ mov(ebx, instr->hydrogen()->property_cell());
ElementsKind kind = instr->hydrogen()->elements_kind();
AllocationSiteOverrideMode override_mode =
(AllocationSiteInfo::GetMode(kind) == TRACK_ALLOCATION_SITE)
(AllocationSite::GetMode(kind) == TRACK_ALLOCATION_SITE)
? DISABLE_ALLOCATION_SITES
: DONT_OVERRIDE;
ContextCheckMode context_mode = CONTEXT_CHECK_NOT_REQUIRED;

View File

@ -350,7 +350,6 @@ void LCallNewArray::PrintDataTo(StringStream* stream) {
stream->Add(" ");
constructor()->PrintTo(stream);
stream->Add(" #%d / ", arity());
ASSERT(hydrogen()->property_cell()->value()->IsSmi());
ElementsKind kind = hydrogen()->elements_kind();
stream->Add(" (%s) ", ElementsKindToString(kind));
}

View File

@ -1724,11 +1724,11 @@ Handle<Code> CallStubCompiler::CompileArrayCodeCall(
GenerateLoadFunctionFromCell(cell, function, &miss);
}
Handle<Smi> kind(Smi::FromInt(GetInitialFastElementsKind()), isolate());
Handle<Cell> kind_feedback_cell =
isolate()->factory()->NewCell(kind);
Handle<AllocationSite> site = isolate()->factory()->NewAllocationSite();
site->set_payload(Smi::FromInt(GetInitialFastElementsKind()));
Handle<Cell> site_feedback_cell = isolate()->factory()->NewCell(site);
__ mov(eax, Immediate(argc));
__ mov(ebx, kind_feedback_cell);
__ mov(ebx, site_feedback_cell);
__ mov(edi, function);
ArrayConstructorStub stub(isolate());

View File

@ -914,10 +914,15 @@ void TypeSwitchInfo::TypeSwitchInfoVerify() {
}
void AllocationSite::AllocationSiteVerify() {
CHECK(IsAllocationSite());
}
void AllocationSiteInfo::AllocationSiteInfoVerify() {
CHECK(IsAllocationSiteInfo());
VerifyHeapPointer(payload());
CHECK(payload()->IsObject());
VerifyHeapPointer(allocation_site());
CHECK(!IsValid() || GetAllocationSite()->IsAllocationSite());
}

View File

@ -1311,7 +1311,7 @@ bool JSObject::ShouldTrackAllocationInfo() {
return true;
}
return AllocationSiteInfo::GetMode(GetElementsKind()) ==
return AllocationSite::GetMode(GetElementsKind()) ==
TRACK_ALLOCATION_SITE;
}
return false;
@ -1320,7 +1320,7 @@ bool JSObject::ShouldTrackAllocationInfo() {
// Heuristic: We only need to create allocation site info if the boilerplate
// elements kind is the initial elements kind.
AllocationSiteMode AllocationSiteInfo::GetMode(
AllocationSiteMode AllocationSite::GetMode(
ElementsKind boilerplate_elements_kind) {
if (FLAG_track_allocation_sites &&
IsFastSmiElementsKind(boilerplate_elements_kind)) {
@ -1331,8 +1331,8 @@ AllocationSiteMode AllocationSiteInfo::GetMode(
}
AllocationSiteMode AllocationSiteInfo::GetMode(ElementsKind from,
ElementsKind to) {
AllocationSiteMode AllocationSite::GetMode(ElementsKind from,
ElementsKind to) {
if (FLAG_track_allocation_sites &&
IsFastSmiElementsKind(from) &&
(IsFastObjectElementsKind(to) || IsFastDoubleElementsKind(to))) {
@ -4448,7 +4448,8 @@ ACCESSORS(SignatureInfo, args, Object, kArgsOffset)
ACCESSORS(TypeSwitchInfo, types, Object, kTypesOffset)
ACCESSORS(AllocationSiteInfo, payload, Object, kPayloadOffset)
ACCESSORS(AllocationSite, payload, Object, kPayloadOffset)
ACCESSORS(AllocationSiteInfo, allocation_site, Object, kAllocationSiteOffset)
ACCESSORS(Script, source, Object, kSourceOffset)
ACCESSORS(Script, name, Object, kNameOffset)

View File

@ -1117,8 +1117,8 @@ void TypeSwitchInfo::TypeSwitchInfoPrint(FILE* out) {
}
void AllocationSiteInfo::AllocationSiteInfoPrint(FILE* out) {
HeapObject::PrintHeader(out, "AllocationSiteInfo");
void AllocationSite::AllocationSitePrint(FILE* out) {
HeapObject::PrintHeader(out, "AllocationSite");
PrintF(out, " - payload: ");
if (payload()->IsCell()) {
Cell* cell = Cell::cast(payload());
@ -1144,6 +1144,17 @@ void AllocationSiteInfo::AllocationSiteInfoPrint(FILE* out) {
}
void AllocationSiteInfo::AllocationSiteInfoPrint(FILE* out) {
HeapObject::PrintHeader(out, "AllocationSiteInfo");
PrintF(out, " - allocation site: ");
if (IsValid()) {
GetAllocationSite()->Print();
} else {
PrintF(out, "<invalid>\n");
}
}
void Script::ScriptPrint(FILE* out) {
HeapObject::PrintHeader(out, "Script");
PrintF(out, "\n - source: ");

View File

@ -8865,21 +8865,6 @@ AllocationSiteInfo* AllocationSiteInfo::FindForJSObject(JSObject* object) {
}
bool AllocationSiteInfo::GetElementsKindPayload(ElementsKind* kind) {
ASSERT(kind != NULL);
if (payload()->IsCell()) {
Cell* cell = Cell::cast(payload());
Object* cell_contents = cell->value();
if (cell_contents->IsSmi()) {
*kind = static_cast<ElementsKind>(
Smi::cast(cell_contents)->value());
return true;
}
}
return false;
}
uint32_t StringHasher::MakeArrayIndexHash(uint32_t value, int length) {
// For array indexes mix the length into the hash as an array index could
// be zero.
@ -10269,7 +10254,11 @@ void Code::ClearTypeFeedbackCells(Heap* heap) {
TypeFeedbackInfo::cast(raw_info)->type_feedback_cells();
for (int i = 0; i < type_feedback_cells->CellCount(); i++) {
Cell* cell = type_feedback_cells->GetCell(i);
cell->set_value(TypeFeedbackCells::RawUninitializedSentinel(heap));
// Don't clear AllocationSites
Object* value = cell->value();
if (value == NULL || !value->IsAllocationSite()) {
cell->set_value(TypeFeedbackCells::RawUninitializedSentinel(heap));
}
}
}
}
@ -11734,7 +11723,7 @@ MaybeObject* JSObject::SetFastElement(uint32_t index,
? FAST_HOLEY_DOUBLE_ELEMENTS
: FAST_DOUBLE_ELEMENTS;
MaybeObject* maybe_failure = UpdateAllocationSiteInfo(to_kind);
MaybeObject* maybe_failure = UpdateAllocationSite(to_kind);
if (maybe_failure->IsFailure()) return maybe_failure;
MaybeObject* maybe =
@ -11751,7 +11740,7 @@ MaybeObject* JSObject::SetFastElement(uint32_t index,
? FAST_HOLEY_ELEMENTS
: FAST_ELEMENTS;
MaybeObject* maybe_failure = UpdateAllocationSiteInfo(kind);
MaybeObject* maybe_failure = UpdateAllocationSite(kind);
if (maybe_failure->IsFailure()) return maybe_failure;
MaybeObject* maybe_new_map = GetElementsTransitionMap(GetIsolate(),
@ -12314,28 +12303,30 @@ Handle<Object> JSObject::TransitionElementsKind(Handle<JSObject> object,
}
MaybeObject* JSObject::UpdateAllocationSiteInfo(ElementsKind to_kind) {
MaybeObject* JSObject::UpdateAllocationSite(ElementsKind to_kind) {
if (!FLAG_track_allocation_sites || !IsJSArray()) {
return this;
}
AllocationSiteInfo* info = AllocationSiteInfo::FindForJSObject(this);
if (info == NULL) {
if (info == NULL || !info->IsValid()) {
return this;
}
if (info->payload()->IsJSArray()) {
JSArray* payload = JSArray::cast(info->payload());
// Walk through to the Allocation Site
AllocationSite* site = info->GetAllocationSite();
if (site->IsLiteralSite()) {
JSArray* payload = JSArray::cast(site->payload());
ElementsKind kind = payload->GetElementsKind();
if (AllocationSiteInfo::GetMode(kind, to_kind) == TRACK_ALLOCATION_SITE) {
if (AllocationSite::GetMode(kind, to_kind) == TRACK_ALLOCATION_SITE) {
// If the array is huge, it's not likely to be defined in a local
// function, so we shouldn't make new instances of it very often.
uint32_t length = 0;
CHECK(payload->length()->ToArrayIndex(&length));
if (length <= AllocationSiteInfo::kMaximumArrayBytesToPretransition) {
if (length <= AllocationSite::kMaximumArrayBytesToPretransition) {
if (FLAG_trace_track_allocation_sites) {
PrintF(
"AllocationSiteInfo: JSArray %p boilerplate updated %s->%s\n",
"AllocationSite: JSArray %p boilerplate updated %s->%s\n",
reinterpret_cast<void*>(this),
ElementsKindToString(kind),
ElementsKindToString(to_kind));
@ -12343,21 +12334,16 @@ MaybeObject* JSObject::UpdateAllocationSiteInfo(ElementsKind to_kind) {
return payload->TransitionElementsKind(to_kind);
}
}
} else if (info->payload()->IsCell()) {
Cell* cell = Cell::cast(info->payload());
Object* cell_contents = cell->value();
if (cell_contents->IsSmi()) {
ElementsKind kind = static_cast<ElementsKind>(
Smi::cast(cell_contents)->value());
if (AllocationSiteInfo::GetMode(kind, to_kind) == TRACK_ALLOCATION_SITE) {
if (FLAG_trace_track_allocation_sites) {
PrintF("AllocationSiteInfo: JSArray %p info updated %s->%s\n",
reinterpret_cast<void*>(this),
ElementsKindToString(kind),
ElementsKindToString(to_kind));
}
cell->set_value(Smi::FromInt(to_kind));
} else {
ElementsKind kind = site->GetElementsKindPayload();
if (AllocationSite::GetMode(kind, to_kind) == TRACK_ALLOCATION_SITE) {
if (FLAG_trace_track_allocation_sites) {
PrintF("AllocationSite: JSArray %p site updated %s->%s\n",
reinterpret_cast<void*>(this),
ElementsKindToString(kind),
ElementsKindToString(to_kind));
}
site->set_payload(Smi::FromInt(to_kind));
}
}
return this;
@ -12374,7 +12360,7 @@ MaybeObject* JSObject::TransitionElementsKind(ElementsKind to_kind) {
if (from_kind == to_kind) return this;
MaybeObject* maybe_failure = UpdateAllocationSiteInfo(to_kind);
MaybeObject* maybe_failure = UpdateAllocationSite(to_kind);
if (maybe_failure->IsFailure()) return maybe_failure;
Isolate* isolate = GetIsolate();

View File

@ -387,6 +387,7 @@ const int kStubMinorKeyBits = kBitsPerInt - kSmiTagSize - kStubMajorKeyBits;
V(SIGNATURE_INFO_TYPE) \
V(TYPE_SWITCH_INFO_TYPE) \
V(ALLOCATION_SITE_INFO_TYPE) \
V(ALLOCATION_SITE_TYPE) \
V(SCRIPT_TYPE) \
V(CODE_CACHE_TYPE) \
V(POLYMORPHIC_CODE_CACHE_TYPE) \
@ -550,6 +551,7 @@ const int kStubMinorKeyBits = kBitsPerInt - kSmiTagSize - kStubMajorKeyBits;
V(SIGNATURE_INFO, SignatureInfo, signature_info) \
V(TYPE_SWITCH_INFO, TypeSwitchInfo, type_switch_info) \
V(SCRIPT, Script, script) \
V(ALLOCATION_SITE, AllocationSite, allocation_site) \
V(ALLOCATION_SITE_INFO, AllocationSiteInfo, allocation_site_info) \
V(CODE_CACHE, CodeCache, code_cache) \
V(POLYMORPHIC_CODE_CACHE, PolymorphicCodeCache, polymorphic_code_cache) \
@ -709,6 +711,7 @@ enum InstanceType {
OBJECT_TEMPLATE_INFO_TYPE,
SIGNATURE_INFO_TYPE,
TYPE_SWITCH_INFO_TYPE,
ALLOCATION_SITE_TYPE,
ALLOCATION_SITE_INFO_TYPE,
SCRIPT_TYPE,
CODE_CACHE_TYPE,
@ -2210,8 +2213,7 @@ class JSObject: public JSReceiver {
ElementsKind to_kind);
MUST_USE_RESULT MaybeObject* TransitionElementsKind(ElementsKind to_kind);
MUST_USE_RESULT MaybeObject* UpdateAllocationSiteInfo(
ElementsKind to_kind);
MUST_USE_RESULT MaybeObject* UpdateAllocationSite(ElementsKind to_kind);
// Replaces an existing transition with a transition to a map with a FIELD.
MUST_USE_RESULT MaybeObject* ConvertTransitionToMapTransition(
@ -7461,26 +7463,68 @@ enum AllocationSiteMode {
};
class AllocationSiteInfo: public Struct {
class AllocationSite: public Struct {
public:
static const int kPayloadOffset = HeapObject::kHeaderSize;
static const int kSize = kPayloadOffset + kPointerSize;
static const uint32_t kMaximumArrayBytesToPretransition = 8 * 1024;
// TODO(mvstanton): rename payload to transition_info.
DECL_ACCESSORS(payload, Object)
static inline AllocationSiteInfo* cast(Object* obj);
void Initialize() {
SetElementsKindPayload(GetInitialFastElementsKind());
}
ElementsKind GetElementsKindPayload() {
ASSERT(!IsLiteralSite());
return static_cast<ElementsKind>(Smi::cast(payload())->value());
}
void SetElementsKindPayload(ElementsKind kind) {
set_payload(Smi::FromInt(static_cast<int>(kind)));
}
bool IsLiteralSite() {
// If the payload is a smi, then it represents an ElementsKind
// for a constructed array. Otherwise, it must be a boilerplate
// for an array literal
return payload()->IsJSArray();
}
DECLARE_PRINTER(AllocationSite)
DECLARE_VERIFIER(AllocationSite)
static inline AllocationSite* cast(Object* obj);
static inline AllocationSiteMode GetMode(
ElementsKind boilerplate_elements_kind);
static inline AllocationSiteMode GetMode(ElementsKind from, ElementsKind to);
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(AllocationSite);
};
class AllocationSiteInfo: public Struct {
public:
static const int kAllocationSiteOffset = HeapObject::kHeaderSize;
static const int kSize = kAllocationSiteOffset + kPointerSize;
DECL_ACCESSORS(allocation_site, Object)
bool IsValid() { return allocation_site()->IsAllocationSite(); }
AllocationSite* GetAllocationSite() {
ASSERT(IsValid());
return AllocationSite::cast(allocation_site());
}
DECLARE_PRINTER(AllocationSiteInfo)
DECLARE_VERIFIER(AllocationSiteInfo)
// Returns NULL if no AllocationSiteInfo is available for object.
static AllocationSiteInfo* FindForJSObject(JSObject* object);
static inline AllocationSiteMode GetMode(
ElementsKind boilerplate_elements_kind);
static inline AllocationSiteMode GetMode(ElementsKind from, ElementsKind to);
static inline AllocationSiteInfo* cast(Object* obj);
static const int kPayloadOffset = HeapObject::kHeaderSize;
static const int kSize = kPayloadOffset + kPointerSize;
static const uint32_t kMaximumArrayBytesToPretransition = 8 * 1024;
bool GetElementsKindPayload(ElementsKind* kind);
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(AllocationSiteInfo);
};

View File

@ -501,6 +501,30 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteralShallow) {
}
static Handle<AllocationSite> GetLiteralAllocationSite(
Isolate* isolate,
Handle<FixedArray> literals,
int literals_index,
Handle<FixedArray> elements) {
// Check if boilerplate exists. If not, create it first.
Handle<Object> literal_site(literals->get(literals_index), isolate);
Handle<AllocationSite> site;
if (*literal_site == isolate->heap()->undefined_value()) {
ASSERT(*elements != isolate->heap()->empty_fixed_array());
Handle<Object> boilerplate =
Runtime::CreateArrayLiteralBoilerplate(isolate, literals, elements);
if (boilerplate.is_null()) return site;
site = isolate->factory()->NewAllocationSite();
site->set_payload(*boilerplate);
literals->set(literals_index, *site);
} else {
site = Handle<AllocationSite>::cast(literal_site);
}
return site;
}
RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteral) {
HandleScope scope(isolate);
ASSERT(args.length() == 3);
@ -508,17 +532,12 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteral) {
CONVERT_SMI_ARG_CHECKED(literals_index, 1);
CONVERT_ARG_HANDLE_CHECKED(FixedArray, elements, 2);
// Check if boilerplate exists. If not, create it first.
Handle<Object> boilerplate(literals->get(literals_index), isolate);
if (*boilerplate == isolate->heap()->undefined_value()) {
ASSERT(*elements != isolate->heap()->empty_fixed_array());
boilerplate =
Runtime::CreateArrayLiteralBoilerplate(isolate, literals, elements);
RETURN_IF_EMPTY_HANDLE(isolate, boilerplate);
// Update the functions literal and return the boilerplate.
literals->set(literals_index, *boilerplate);
}
return JSObject::cast(*boilerplate)->DeepCopy(isolate);
Handle<AllocationSite> site = GetLiteralAllocationSite(isolate, literals,
literals_index, elements);
RETURN_IF_EMPTY_HANDLE(isolate, site);
JSObject* boilerplate = JSObject::cast(site->payload());
return boilerplate->DeepCopy(isolate);
}
@ -529,29 +548,24 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralShallow) {
CONVERT_SMI_ARG_CHECKED(literals_index, 1);
CONVERT_ARG_HANDLE_CHECKED(FixedArray, elements, 2);
// Check if boilerplate exists. If not, create it first.
Handle<Object> boilerplate(literals->get(literals_index), isolate);
if (*boilerplate == isolate->heap()->undefined_value()) {
ASSERT(*elements != isolate->heap()->empty_fixed_array());
boilerplate =
Runtime::CreateArrayLiteralBoilerplate(isolate, literals, elements);
RETURN_IF_EMPTY_HANDLE(isolate, boilerplate);
// Update the functions literal and return the boilerplate.
literals->set(literals_index, *boilerplate);
}
if (JSObject::cast(*boilerplate)->elements()->map() ==
Handle<AllocationSite> site = GetLiteralAllocationSite(isolate, literals,
literals_index, elements);
RETURN_IF_EMPTY_HANDLE(isolate, site);
JSObject* boilerplate = JSObject::cast(site->payload());
if (boilerplate->elements()->map() ==
isolate->heap()->fixed_cow_array_map()) {
isolate->counters()->cow_arrays_created_runtime()->Increment();
}
JSObject* boilerplate_object = JSObject::cast(*boilerplate);
AllocationSiteMode mode = AllocationSiteInfo::GetMode(
boilerplate_object->GetElementsKind());
AllocationSiteMode mode = AllocationSite::GetMode(
boilerplate->GetElementsKind());
if (mode == TRACK_ALLOCATION_SITE) {
return isolate->heap()->CopyJSObjectWithAllocationSite(boilerplate_object);
return isolate->heap()->CopyJSObjectWithAllocationSite(
boilerplate, *site);
}
return isolate->heap()->CopyJSObject(boilerplate_object);
return isolate->heap()->CopyJSObject(boilerplate);
}
@ -5203,8 +5217,15 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreArrayLiteralElement) {
CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 3);
CONVERT_SMI_ARG_CHECKED(literal_index, 4);
Object* raw_boilerplate_object = literals->get(literal_index);
Handle<JSArray> boilerplate_object(JSArray::cast(raw_boilerplate_object));
Object* raw_literal_cell = literals->get(literal_index);
JSArray* boilerplate = NULL;
if (raw_literal_cell->IsAllocationSite()) {
AllocationSite* site = AllocationSite::cast(raw_literal_cell);
boilerplate = JSArray::cast(site->payload());
} else {
boilerplate = JSArray::cast(raw_literal_cell);
}
Handle<JSArray> boilerplate_object(boilerplate);
ElementsKind elements_kind = object->GetElementsKind();
ASSERT(IsFastElementsKind(elements_kind));
// Smis should never trigger transitions.
@ -13818,19 +13839,21 @@ static MaybeObject* ArrayConstructorCommon(Isolate* isolate,
MaybeObject* maybe_array;
if (!type_info.is_null() &&
*type_info != isolate->heap()->undefined_value() &&
Cell::cast(*type_info)->value()->IsSmi() &&
Cell::cast(*type_info)->value()->IsAllocationSite() &&
can_use_type_feedback) {
Cell* cell = Cell::cast(*type_info);
Smi* smi = Smi::cast(cell->value());
ElementsKind to_kind = static_cast<ElementsKind>(smi->value());
Handle<Cell> cell = Handle<Cell>::cast(type_info);
Handle<AllocationSite> site = Handle<AllocationSite>(
AllocationSite::cast(cell->value()), isolate);
ASSERT(!site->IsLiteralSite());
ElementsKind to_kind = site->GetElementsKindPayload();
if (holey && !IsFastHoleyElementsKind(to_kind)) {
to_kind = GetHoleyElementsKind(to_kind);
// Update the allocation site info to reflect the advice alteration.
cell->set_value(Smi::FromInt(to_kind));
site->SetElementsKindPayload(to_kind);
}
maybe_array = isolate->heap()->AllocateJSObjectWithAllocationSite(
*constructor, type_info);
*constructor, site);
if (!maybe_array->To(&array)) return maybe_array;
} else {
maybe_array = isolate->heap()->AllocateJSObject(*constructor);

View File

@ -186,13 +186,14 @@ bool TypeFeedbackOracle::StoreIsPolymorphic(TypeFeedbackId ast_id) {
bool TypeFeedbackOracle::CallIsMonomorphic(Call* expr) {
Handle<Object> value = GetInfo(expr->CallFeedbackId());
return value->IsMap() || value->IsSmi() || value->IsJSFunction();
return value->IsMap() || value->IsAllocationSite() || value->IsJSFunction() ||
value->IsSmi();
}
bool TypeFeedbackOracle::CallNewIsMonomorphic(CallNew* expr) {
Handle<Object> info = GetInfo(expr->CallNewFeedbackId());
return info->IsSmi() || info->IsJSFunction();
return info->IsAllocationSite() || info->IsJSFunction();
}
@ -302,9 +303,7 @@ CheckType TypeFeedbackOracle::GetCallCheckType(Call* expr) {
Handle<JSFunction> TypeFeedbackOracle::GetCallTarget(Call* expr) {
Handle<Object> info = GetInfo(expr->CallFeedbackId());
if (info->IsSmi()) {
ASSERT(static_cast<ElementsKind>(Smi::cast(*info)->value()) <=
LAST_FAST_ELEMENTS_KIND);
if (info->IsAllocationSite()) {
return Handle<JSFunction>(isolate_->global_context()->array_function());
} else {
return Handle<JSFunction>::cast(info);
@ -314,9 +313,7 @@ Handle<JSFunction> TypeFeedbackOracle::GetCallTarget(Call* expr) {
Handle<JSFunction> TypeFeedbackOracle::GetCallNewTarget(CallNew* expr) {
Handle<Object> info = GetInfo(expr->CallNewFeedbackId());
if (info->IsSmi()) {
ASSERT(static_cast<ElementsKind>(Smi::cast(*info)->value()) <=
LAST_FAST_ELEMENTS_KIND);
if (info->IsAllocationSite()) {
return Handle<JSFunction>(isolate_->global_context()->array_function());
} else {
return Handle<JSFunction>::cast(info);
@ -675,6 +672,7 @@ void TypeFeedbackOracle::ProcessTypeFeedbackCells(Handle<Code> code) {
Cell* cell = cache->GetCell(i);
Object* value = cell->value();
if (value->IsSmi() ||
value->IsAllocationSite() ||
(value->IsJSFunction() &&
!CanRetainOtherContext(JSFunction::cast(value),
*native_context_))) {

View File

@ -61,6 +61,16 @@ void FastCloneShallowObjectStub::InitializeInterfaceDescriptor(
}
void CreateAllocationSiteStub::InitializeInterfaceDescriptor(
Isolate* isolate,
CodeStubInterfaceDescriptor* descriptor) {
static Register registers[] = { rbx };
descriptor->register_param_count_ = 1;
descriptor->register_params_ = registers;
descriptor->deoptimization_handler_ = NULL;
}
void KeyedLoadFastElementStub::InitializeInterfaceDescriptor(
Isolate* isolate,
CodeStubInterfaceDescriptor* descriptor) {
@ -3505,17 +3515,15 @@ static void GenerateRecordCallTarget(MacroAssembler* masm) {
__ Cmp(rcx, TypeFeedbackCells::MegamorphicSentinel(isolate));
__ j(equal, &done);
// Special handling of the Array() function, which caches not only the
// monomorphic Array function but the initial ElementsKind with special
// sentinels
__ JumpIfNotSmi(rcx, &miss);
if (FLAG_debug_code) {
Handle<Object> terminal_kind_sentinel =
TypeFeedbackCells::MonomorphicArraySentinel(masm->isolate(),
LAST_FAST_ELEMENTS_KIND);
__ Cmp(rcx, terminal_kind_sentinel);
__ Assert(less_equal, "Array function sentinel is not an ElementsKind");
}
// If we came here, we need to see if we are the array function.
// If we didn't have a matching function, and we didn't find the megamorph
// sentinel, then we have in the cell either some other function or an
// AllocationSite. Do a map check on the object in rcx.
Handle<Map> allocation_site_map(
masm->isolate()->heap()->allocation_site_map(),
masm->isolate());
__ Cmp(FieldOperand(rcx, 0), allocation_site_map);
__ j(not_equal, &miss);
// Make sure the function is the Array() function
__ LoadArrayFunction(rcx);
@ -3534,7 +3542,7 @@ static void GenerateRecordCallTarget(MacroAssembler* masm) {
__ bind(&megamorphic);
__ Move(FieldOperand(rbx, Cell::kValueOffset),
TypeFeedbackCells::MegamorphicSentinel(isolate));
__ jmp(&done, Label::kNear);
__ jmp(&done);
// An uninitialized cache is patched with the function or sentinel to
// indicate the ElementsKind if function is the Array constructor.
@ -3544,14 +3552,22 @@ static void GenerateRecordCallTarget(MacroAssembler* masm) {
__ cmpq(rdi, rcx);
__ j(not_equal, &not_array_function);
// The target function is the Array constructor, install a sentinel value in
// the constructor's type info cell that will track the initial ElementsKind
// that should be used for the array when its constructed.
Handle<Object> initial_kind_sentinel =
TypeFeedbackCells::MonomorphicArraySentinel(isolate,
GetInitialFastElementsKind());
__ Move(FieldOperand(rbx, Cell::kValueOffset),
initial_kind_sentinel);
// The target function is the Array constructor,
// Create an AllocationSite if we don't already have it, store it in the cell
{
FrameScope scope(masm, StackFrame::INTERNAL);
__ push(rax);
__ push(rdi);
__ push(rbx);
CreateAllocationSiteStub create_stub;
__ CallStub(&create_stub);
__ pop(rbx);
__ pop(rdi);
__ pop(rax);
}
__ jmp(&done);
__ bind(&not_array_function);
@ -3721,6 +3737,7 @@ void CodeStub::GenerateStubsAheadOfTime(Isolate* isolate) {
// It is important that the store buffer overflow stubs are generated first.
RecordWriteStub::GenerateFixedRegStubsAheadOfTime(isolate);
ArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate);
CreateAllocationSiteStub::GenerateAheadOfTime(isolate);
}
@ -6536,18 +6553,20 @@ static void CreateArrayDispatchOneArgument(MacroAssembler* masm) {
__ j(zero, &normal_sequence);
// We are going to create a holey array, but our kind is non-holey.
// Fix kind and retry
// Fix kind and retry (only if we have an allocation site in the cell).
__ incl(rdx);
__ Cmp(rbx, undefined_sentinel);
__ j(equal, &normal_sequence);
// The type cell may have gone megamorphic, don't overwrite if so
__ movq(rcx, FieldOperand(rbx, kPointerSize));
__ JumpIfNotSmi(rcx, &normal_sequence);
__ movq(rcx, FieldOperand(rbx, Cell::kValueOffset));
Handle<Map> allocation_site_map(
masm->isolate()->heap()->allocation_site_map(),
masm->isolate());
__ Cmp(FieldOperand(rcx, 0), allocation_site_map);
__ j(not_equal, &normal_sequence);
// Save the resulting elements kind in type info
__ Integer32ToSmi(rdx, rdx);
__ movq(FieldOperand(rbx, kPointerSize), rdx);
__ movq(FieldOperand(rcx, AllocationSite::kPayloadOffset), rdx);
__ SmiToInteger32(rdx, rdx);
__ bind(&normal_sequence);
@ -6576,7 +6595,7 @@ static void ArrayConstructorStubAheadOfTimeHelper(Isolate* isolate) {
ElementsKind kind = GetFastElementsKindFromSequenceIndex(i);
T stub(kind);
stub.GetCode(isolate)->set_is_pregenerated(true);
if (AllocationSiteInfo::GetMode(kind) != DONT_TRACK_ALLOCATION_SITE) {
if (AllocationSite::GetMode(kind) != DONT_TRACK_ALLOCATION_SITE) {
T stub1(kind, CONTEXT_CHECK_REQUIRED, DISABLE_ALLOCATION_SITES);
stub1.GetCode(isolate)->set_is_pregenerated(true);
}
@ -6649,7 +6668,19 @@ void ArrayConstructorStub::Generate(MacroAssembler* masm) {
__ Cmp(rbx, undefined_sentinel);
__ j(equal, &no_info);
__ movq(rdx, FieldOperand(rbx, Cell::kValueOffset));
__ JumpIfNotSmi(rdx, &no_info);
// The type cell may have undefined in its value.
__ Cmp(rdx, undefined_sentinel);
__ j(equal, &no_info);
// We should have an allocation site object
if (FLAG_debug_code) {
__ Cmp(FieldOperand(rdx, 0),
Handle<Map>(masm->isolate()->heap()->allocation_site_map()));
__ Assert(equal, "Expected AllocationSite object in register rdx");
}
__ movq(rdx, FieldOperand(rdx, AllocationSite::kPayloadOffset));
__ SmiToInteger32(rdx, rdx);
__ jmp(&switch_ready);
__ bind(&no_info);

View File

@ -673,8 +673,8 @@ static void KeyedStoreGenerateGenericHelper(
rbx,
rdi,
slow);
AllocationSiteMode mode = AllocationSiteInfo::GetMode(FAST_SMI_ELEMENTS,
FAST_DOUBLE_ELEMENTS);
AllocationSiteMode mode = AllocationSite::GetMode(FAST_SMI_ELEMENTS,
FAST_DOUBLE_ELEMENTS);
ElementsTransitionGenerator::GenerateSmiToDouble(masm, mode, slow);
__ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset));
__ jmp(&fast_double_without_map_check);
@ -686,7 +686,7 @@ static void KeyedStoreGenerateGenericHelper(
rbx,
rdi,
slow);
mode = AllocationSiteInfo::GetMode(FAST_SMI_ELEMENTS, FAST_ELEMENTS);
mode = AllocationSite::GetMode(FAST_SMI_ELEMENTS, FAST_ELEMENTS);
ElementsTransitionGenerator::GenerateMapChangeElementsTransition(masm, mode,
slow);
__ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset));
@ -702,7 +702,7 @@ static void KeyedStoreGenerateGenericHelper(
rbx,
rdi,
slow);
mode = AllocationSiteInfo::GetMode(FAST_DOUBLE_ELEMENTS, FAST_ELEMENTS);
mode = AllocationSite::GetMode(FAST_DOUBLE_ELEMENTS, FAST_ELEMENTS);
ElementsTransitionGenerator::GenerateDoubleToObject(masm, mode, slow);
__ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset));
__ jmp(&finish_object_store);
@ -1618,8 +1618,8 @@ void KeyedStoreIC::GenerateTransitionElementsSmiToDouble(MacroAssembler* masm) {
// Must return the modified receiver in eax.
if (!FLAG_trace_elements_transitions) {
Label fail;
AllocationSiteMode mode = AllocationSiteInfo::GetMode(FAST_SMI_ELEMENTS,
FAST_DOUBLE_ELEMENTS);
AllocationSiteMode mode = AllocationSite::GetMode(FAST_SMI_ELEMENTS,
FAST_DOUBLE_ELEMENTS);
ElementsTransitionGenerator::GenerateSmiToDouble(masm, mode, &fail);
__ movq(rax, rdx);
__ Ret();
@ -1643,8 +1643,8 @@ void KeyedStoreIC::GenerateTransitionElementsDoubleToObject(
// Must return the modified receiver in eax.
if (!FLAG_trace_elements_transitions) {
Label fail;
AllocationSiteMode mode = AllocationSiteInfo::GetMode(FAST_DOUBLE_ELEMENTS,
FAST_ELEMENTS);
AllocationSiteMode mode = AllocationSite::GetMode(FAST_DOUBLE_ELEMENTS,
FAST_ELEMENTS);
ElementsTransitionGenerator::GenerateDoubleToObject(masm, mode, &fail);
__ movq(rax, rdx);
__ Ret();

View File

@ -3890,7 +3890,7 @@ void LCodeGen::DoCallNewArray(LCallNewArray* instr) {
__ Move(rbx, instr->hydrogen()->property_cell());
ElementsKind kind = instr->hydrogen()->elements_kind();
AllocationSiteOverrideMode override_mode =
(AllocationSiteInfo::GetMode(kind) == TRACK_ALLOCATION_SITE)
(AllocationSite::GetMode(kind) == TRACK_ALLOCATION_SITE)
? DISABLE_ALLOCATION_SITES
: DONT_OVERRIDE;
ContextCheckMode context_mode = CONTEXT_CHECK_NOT_REQUIRED;

View File

@ -1641,11 +1641,11 @@ Handle<Code> CallStubCompiler::CompileArrayCodeCall(
GenerateLoadFunctionFromCell(cell, function, &miss);
}
Handle<Smi> kind(Smi::FromInt(GetInitialFastElementsKind()), isolate());
Handle<Cell> kind_feedback_cell =
isolate()->factory()->NewCell(kind);
Handle<AllocationSite> site = isolate()->factory()->NewAllocationSite();
site->set_payload(Smi::FromInt(GetInitialFastElementsKind()));
Handle<Cell> site_feedback_cell = isolate()->factory()->NewCell(site);
__ movq(rax, Immediate(argc));
__ Move(rbx, kind_feedback_cell);
__ Move(rbx, site_feedback_cell);
__ Move(rdi, function);
ArrayConstructorStub stub(isolate());