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:
parent
c1c10b452f
commit
67d9051bcd
@ -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;
|
||||
|
@ -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, ¬_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(¬_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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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());
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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_)) {
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -243,6 +243,8 @@ class Factory {
|
||||
|
||||
Handle<PropertyCell> NewPropertyCell(Handle<Object> value);
|
||||
|
||||
Handle<AllocationSite> NewAllocationSite();
|
||||
|
||||
Handle<Map> NewMap(
|
||||
InstanceType type,
|
||||
int instance_size,
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
46
src/heap.cc
46
src/heap.cc
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
19
src/heap.h
19
src/heap.h
@ -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();
|
||||
|
@ -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_;
|
||||
};
|
||||
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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, ¬_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(¬_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);
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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());
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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: ");
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
};
|
||||
|
@ -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);
|
||||
|
@ -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_))) {
|
||||
|
@ -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, ¬_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(¬_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);
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -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());
|
||||
|
Loading…
Reference in New Issue
Block a user