Revision: 13330
Author: [email protected]
Date: Tue Jan 8 01:03:16 2013
Log: Adapt Danno's Track Allocation Info idea to fast literals. When
allocating a literal array,
we store an AllocationSiteInfo object right after the JSArray, with a
pointer to the
boilerplate object. Later, if the array transitions we check for the
continued existence
of the temporary AllocationSiteInfo object (has no roots). If found, we'll
use it to
transition the boilerplate array as well.
Danno's original changeset: https://codereview.chromium.org/10615002/
Review URL: https://codereview.chromium.org/11663005
http://code.google.com/p/v8/source/detail?r=13330
Modified:
/branches/bleeding_edge/include/v8.h
/branches/bleeding_edge/src/arm/code-stubs-arm.cc
/branches/bleeding_edge/src/arm/codegen-arm.cc
/branches/bleeding_edge/src/arm/full-codegen-arm.cc
/branches/bleeding_edge/src/arm/macro-assembler-arm.cc
/branches/bleeding_edge/src/arm/macro-assembler-arm.h
/branches/bleeding_edge/src/code-stubs.h
/branches/bleeding_edge/src/flag-definitions.h
/branches/bleeding_edge/src/ia32/code-stubs-ia32.cc
/branches/bleeding_edge/src/ia32/codegen-ia32.cc
/branches/bleeding_edge/src/ia32/full-codegen-ia32.cc
/branches/bleeding_edge/src/ia32/macro-assembler-ia32.cc
/branches/bleeding_edge/src/ia32/macro-assembler-ia32.h
/branches/bleeding_edge/src/objects-debug.cc
/branches/bleeding_edge/src/objects-inl.h
/branches/bleeding_edge/src/objects-printer.cc
/branches/bleeding_edge/src/objects.cc
/branches/bleeding_edge/src/objects.h
/branches/bleeding_edge/src/x64/code-stubs-x64.cc
/branches/bleeding_edge/src/x64/codegen-x64.cc
/branches/bleeding_edge/src/x64/full-codegen-x64.cc
/branches/bleeding_edge/src/x64/macro-assembler-x64.cc
/branches/bleeding_edge/src/x64/macro-assembler-x64.h
/branches/bleeding_edge/test/mjsunit/array-natives-elements.js
/branches/bleeding_edge/test/mjsunit/elements-kind.js
=======================================
--- /branches/bleeding_edge/include/v8.h Wed Dec 19 02:28:36 2012
+++ /branches/bleeding_edge/include/v8.h Tue Jan 8 01:03:16 2013
@@ -4191,7 +4191,7 @@
static const int kFalseValueRootIndex = 9;
static const int kEmptySymbolRootIndex = 119;
- static const int kJSObjectType = 0xaa;
+ static const int kJSObjectType = 0xab;
static const int kFirstNonstringType = 0x80;
static const int kOddballType = 0x82;
static const int kForeignType = 0x85;
=======================================
--- /branches/bleeding_edge/src/arm/code-stubs-arm.cc Mon Jan 7 02:06:11
2013
+++ /branches/bleeding_edge/src/arm/code-stubs-arm.cc Tue Jan 8 01:03:16
2013
@@ -344,6 +344,7 @@
MacroAssembler* masm,
int length,
FastCloneShallowArrayStub::Mode mode,
+ AllocationSiteInfoMode allocation_site_info_mode,
Label* fail) {
// Registers on entry:
//
@@ -357,7 +358,12 @@
? FixedDoubleArray::SizeFor(length)
: FixedArray::SizeFor(length);
}
- int size = JSArray::kSize + elements_size;
+ int size = JSArray::kSize;
+ int allocation_info_start = size;
+ if (allocation_site_info_mode == TRACK_ALLOCATION_SITE_INFO) {
+ size += AllocationSiteInfo::kSize;
+ }
+ size += elements_size;
// Allocate both the JS array and the elements array in one big
// allocation. This avoids multiple limit checks.
@@ -367,6 +373,13 @@
}
__ AllocateInNewSpace(size, r0, r1, r2, fail, flags);
+ if (allocation_site_info_mode == TRACK_ALLOCATION_SITE_INFO) {
+ __ mov(r2, Operand(Handle<Map>(masm->isolate()->heap()->
+ allocation_site_info_map())));
+ __ str(r2, FieldMemOperand(r0, allocation_info_start));
+ __ str(r3, FieldMemOperand(r0, allocation_info_start + kPointerSize));
+ }
+
// Copy the JS array part.
for (int i = 0; i < JSArray::kSize; i += kPointerSize) {
if ((i != JSArray::kElementsOffset) || (length == 0)) {
@@ -379,7 +392,11 @@
// Get hold of the elements array of the boilerplate and setup the
// elements pointer in the resulting object.
__ ldr(r3, FieldMemOperand(r3, JSArray::kElementsOffset));
- __ add(r2, r0, Operand(JSArray::kSize));
+ if (allocation_site_info_mode == TRACK_ALLOCATION_SITE_INFO) {
+ __ add(r2, r0, Operand(JSArray::kSize + AllocationSiteInfo::kSize));
+ } else {
+ __ add(r2, r0, Operand(JSArray::kSize));
+ }
__ str(r2, FieldMemOperand(r0, JSArray::kElementsOffset));
// Copy the elements array.
@@ -406,6 +423,13 @@
__ b(eq, &slow_case);
FastCloneShallowArrayStub::Mode mode = mode_;
+ AllocationSiteInfoMode allocation_site_info_mode =
+ DONT_TRACK_ALLOCATION_SITE_INFO;
+ if (mode == CLONE_ANY_ELEMENTS_WITH_ALLOCATION_SITE_INFO) {
+ mode = CLONE_ANY_ELEMENTS;
+ allocation_site_info_mode = TRACK_ALLOCATION_SITE_INFO;
+ }
+
if (mode == CLONE_ANY_ELEMENTS) {
Label double_elements, check_fast_elements;
__ ldr(r0, FieldMemOperand(r3, JSArray::kElementsOffset));
@@ -413,7 +437,9 @@
__ CompareRoot(r0, Heap::kFixedCOWArrayMapRootIndex);
__ b(ne, &check_fast_elements);
GenerateFastCloneShallowArrayCommon(masm, 0,
- COPY_ON_WRITE_ELEMENTS,
&slow_case);
+ COPY_ON_WRITE_ELEMENTS,
+ allocation_site_info_mode,
+ &slow_case);
// Return and remove the on-stack parameters.
__ add(sp, sp, Operand(3 * kPointerSize));
__ Ret();
@@ -422,7 +448,9 @@
__ CompareRoot(r0, Heap::kFixedArrayMapRootIndex);
__ b(ne, &double_elements);
GenerateFastCloneShallowArrayCommon(masm, length_,
- CLONE_ELEMENTS, &slow_case);
+ CLONE_ELEMENTS,
+ allocation_site_info_mode,
+ &slow_case);
// Return and remove the on-stack parameters.
__ add(sp, sp, Operand(3 * kPointerSize));
__ Ret();
@@ -454,7 +482,8 @@
__ pop(r3);
}
- GenerateFastCloneShallowArrayCommon(masm, length_, mode, &slow_case);
+ GenerateFastCloneShallowArrayCommon(masm, length_, mode,
+ allocation_site_info_mode,
&slow_case);
// Return and remove the on-stack parameters.
__ add(sp, sp, Operand(3 * kPointerSize));
=======================================
--- /branches/bleeding_edge/src/arm/codegen-arm.cc Fri Dec 28 03:09:16 2012
+++ /branches/bleeding_edge/src/arm/codegen-arm.cc Tue Jan 8 01:03:16 2013
@@ -179,6 +179,10 @@
Label loop, entry, convert_hole, gc_required, only_change_map, done;
bool vfp2_supported = CpuFeatures::IsSupported(VFP2);
+ if (FLAG_track_allocation_sites) {
+ masm->TestJSArrayForAllocationSiteInfo(r2, r4, fail);
+ }
+
// Check for empty arrays, which only require a map transition and no
changes
// to the backing store.
__ ldr(r4, FieldMemOperand(r2, JSObject::kElementsOffset));
=======================================
--- /branches/bleeding_edge/src/arm/full-codegen-arm.cc Mon Jan 7 01:43:12
2013
+++ /branches/bleeding_edge/src/arm/full-codegen-arm.cc Tue Jan 8 01:03:16
2013
@@ -1733,6 +1733,15 @@
FastCloneShallowArrayStub::Mode mode = has_fast_elements
? FastCloneShallowArrayStub::CLONE_ELEMENTS
: FastCloneShallowArrayStub::CLONE_ANY_ELEMENTS;
+
+ // Tracking allocation info allows us to pre-transition later if it
makes
+ // sense.
+ if (mode == FastCloneShallowArrayStub::CLONE_ANY_ELEMENTS &&
+ FLAG_track_allocation_sites) {
+ mode = FastCloneShallowArrayStub::
+ CLONE_ANY_ELEMENTS_WITH_ALLOCATION_SITE_INFO;
+ }
+
FastCloneShallowArrayStub stub(mode, length);
__ CallStub(&stub);
}
=======================================
--- /branches/bleeding_edge/src/arm/macro-assembler-arm.cc Mon Jan 7
01:43:12 2013
+++ /branches/bleeding_edge/src/arm/macro-assembler-arm.cc Tue Jan 8
01:03:16 2013
@@ -3881,6 +3881,29 @@
cmp(r2, null_value);
b(ne, &next);
}
+
+
+void MacroAssembler::TestJSArrayForAllocationSiteInfo(
+ Register receiver_reg,
+ Register scratch_reg,
+ Label* allocation_info_present) {
+ Label no_info_available;
+ ExternalReference new_space_start =
+ ExternalReference::new_space_start(isolate());
+ ExternalReference new_space_allocation_top =
+ ExternalReference::new_space_allocation_top_address(isolate());
+ ldr(scratch_reg, FieldMemOperand(receiver_reg,
+ JSArray::kSize +
AllocationSiteInfo::kSize));
+ cmp(scratch_reg, Operand(new_space_start));
+ b(lt, &no_info_available);
+ cmp(scratch_reg, Operand(new_space_allocation_top));
+ b(hs, &no_info_available);
+ ldr(scratch_reg, MemOperand(scratch_reg, 0));
+ cmp(scratch_reg,
+ Operand(Handle<Map>(isolate()->heap()->allocation_site_info_map())));
+ b(eq, allocation_info_present);
+ bind(&no_info_available);
+}
#ifdef DEBUG
=======================================
--- /branches/bleeding_edge/src/arm/macro-assembler-arm.h Fri Dec 28
07:14:44 2012
+++ /branches/bleeding_edge/src/arm/macro-assembler-arm.h Tue Jan 8
01:03:16 2013
@@ -1309,6 +1309,16 @@
// in r0. Assumes that any other register can be used as a scratch.
void CheckEnumCache(Register null_value, Label* call_runtime);
+ // AllocationSiteInfo support. Arrays may have an associated
+ // AllocationSiteInfo object that can be checked for in order to
pretransition
+ // to another type.
+ // On entry, receiver_reg should point to the array object.
+ // scratch_reg gets clobbered.
+ // If allocation info is present, jump to allocation_info_present
+ void TestJSArrayForAllocationSiteInfo(Register receiver_reg,
+ Register scratch_reg,
+ Label* allocation_info_present);
+
private:
void CallCFunctionHelper(Register function,
int num_reg_arguments,
=======================================
--- /branches/bleeding_edge/src/code-stubs.h Mon Jan 7 02:06:11 2013
+++ /branches/bleeding_edge/src/code-stubs.h Tue Jan 8 01:03:16 2013
@@ -422,14 +422,17 @@
public:
// Maximum length of copied elements array.
static const int kMaximumClonedLength = 8;
-
enum Mode {
CLONE_ELEMENTS,
CLONE_DOUBLE_ELEMENTS,
COPY_ON_WRITE_ELEMENTS,
- CLONE_ANY_ELEMENTS
+ CLONE_ANY_ELEMENTS,
+ CLONE_ANY_ELEMENTS_WITH_ALLOCATION_SITE_INFO,
+ LAST_CLONE_MODE = CLONE_ANY_ELEMENTS_WITH_ALLOCATION_SITE_INFO
};
+ static const int kFastCloneModeCount = LAST_CLONE_MODE + 1;
+
FastCloneShallowArrayStub(Mode mode, int length)
: mode_(mode),
length_((mode == COPY_ON_WRITE_ELEMENTS) ? 0 : length) {
@@ -445,8 +448,8 @@
Major MajorKey() { return FastCloneShallowArray; }
int MinorKey() {
- ASSERT(mode_ == 0 || mode_ == 1 || mode_ == 2 || mode_ == 3);
- return length_ * 4 + mode_;
+ ASSERT(mode_ >= 0 && mode_ <= LAST_CLONE_MODE);
+ return length_ * kFastCloneModeCount + mode_;
}
};
=======================================
--- /branches/bleeding_edge/src/flag-definitions.h Fri Dec 28 05:34:15 2012
+++ /branches/bleeding_edge/src/flag-definitions.h Tue Jan 8 01:03:16 2013
@@ -209,7 +209,8 @@
"perform array index dehoisting")
DEFINE_bool(dead_code_elimination, true, "use dead code elimination")
DEFINE_bool(trace_dead_code_elimination, false, "trace dead code
elimination")
-
+DEFINE_bool(track_allocation_sites, true,
+ "Use allocation site info to reduce transitions")
DEFINE_bool(trace_osr, false, "trace on-stack replacement")
DEFINE_int(stress_runs, 0, "number of stress runs")
DEFINE_bool(optimize_closures, true, "optimize closures")
=======================================
--- /branches/bleeding_edge/src/ia32/code-stubs-ia32.cc Mon Jan 7 02:06:11
2013
+++ /branches/bleeding_edge/src/ia32/code-stubs-ia32.cc Tue Jan 8 01:03:16
2013
@@ -323,6 +323,7 @@
MacroAssembler* masm,
int length,
FastCloneShallowArrayStub::Mode mode,
+ AllocationSiteInfoMode allocation_site_info_mode,
Label* fail) {
// Registers on entry:
//
@@ -336,7 +337,12 @@
? FixedDoubleArray::SizeFor(length)
: FixedArray::SizeFor(length);
}
- int size = JSArray::kSize + elements_size;
+ int size = JSArray::kSize;
+ int allocation_info_start = size;
+ if (allocation_site_info_mode == TRACK_ALLOCATION_SITE_INFO) {
+ size += AllocationSiteInfo::kSize;
+ }
+ size += elements_size;
// Allocate both the JS array and the elements array in one big
// allocation. This avoids multiple limit checks.
@@ -346,6 +352,13 @@
}
__ AllocateInNewSpace(size, eax, ebx, edx, fail, flags);
+ if (allocation_site_info_mode == TRACK_ALLOCATION_SITE_INFO) {
+ __ mov(FieldOperand(eax, allocation_info_start),
+ Immediate(Handle<Map>(masm->isolate()->heap()->
+ allocation_site_info_map())));
+ __ mov(FieldOperand(eax, allocation_info_start + kPointerSize), ecx);
+ }
+
// Copy the JS array part.
for (int i = 0; i < JSArray::kSize; i += kPointerSize) {
if ((i != JSArray::kElementsOffset) || (length == 0)) {
@@ -358,7 +371,11 @@
// Get hold of the elements array of the boilerplate and setup the
// elements pointer in the resulting object.
__ mov(ecx, FieldOperand(ecx, JSArray::kElementsOffset));
- __ lea(edx, Operand(eax, JSArray::kSize));
+ if (allocation_site_info_mode == TRACK_ALLOCATION_SITE_INFO) {
+ __ lea(edx, Operand(eax, JSArray::kSize +
AllocationSiteInfo::kSize));
+ } else {
+ __ lea(edx, Operand(eax, JSArray::kSize));
+ }
__ mov(FieldOperand(eax, JSArray::kElementsOffset), edx);
// Copy the elements array.
@@ -408,20 +425,31 @@
FastCloneShallowArrayStub::Mode mode = mode_;
// ecx is boilerplate object.
+ AllocationSiteInfoMode allocation_site_info_mode =
+ DONT_TRACK_ALLOCATION_SITE_INFO;
+ if (mode == CLONE_ANY_ELEMENTS_WITH_ALLOCATION_SITE_INFO) {
+ mode = CLONE_ANY_ELEMENTS;
+ allocation_site_info_mode = TRACK_ALLOCATION_SITE_INFO;
+ }
+
if (mode == CLONE_ANY_ELEMENTS) {
Label double_elements, check_fast_elements;
__ mov(ebx, FieldOperand(ecx, JSArray::kElementsOffset));
__ CheckMap(ebx, factory->fixed_cow_array_map(),
&check_fast_elements, DONT_DO_SMI_CHECK);
GenerateFastCloneShallowArrayCommon(masm, 0,
- COPY_ON_WRITE_ELEMENTS,
&slow_case);
+ COPY_ON_WRITE_ELEMENTS,
+ allocation_site_info_mode,
+ &slow_case);
__ ret(3 * kPointerSize);
__ bind(&check_fast_elements);
__ CheckMap(ebx, factory->fixed_array_map(),
&double_elements, DONT_DO_SMI_CHECK);
GenerateFastCloneShallowArrayCommon(masm, length_,
- CLONE_ELEMENTS, &slow_case);
+ CLONE_ELEMENTS,
+ allocation_site_info_mode,
+ &slow_case);
__ ret(3 * kPointerSize);
__ bind(&double_elements);
@@ -450,7 +478,8 @@
__ pop(ecx);
}
- GenerateFastCloneShallowArrayCommon(masm, length_, mode, &slow_case);
+ GenerateFastCloneShallowArrayCommon(masm, length_, mode,
+ allocation_site_info_mode,
&slow_case);
// Return and remove the on-stack parameters.
__ ret(3 * kPointerSize);
=======================================
--- /branches/bleeding_edge/src/ia32/codegen-ia32.cc Fri Jan 4 02:56:24
2013
+++ /branches/bleeding_edge/src/ia32/codegen-ia32.cc Tue Jan 8 01:03:16
2013
@@ -388,6 +388,7 @@
#define __ ACCESS_MASM(masm)
+
void ElementsTransitionGenerator::GenerateMapChangeElementsTransition(
MacroAssembler* masm) {
// ----------- S t a t e -------------
@@ -420,6 +421,10 @@
// -----------------------------------
Label loop, entry, convert_hole, gc_required, only_change_map;
+ if (FLAG_track_allocation_sites) {
+ masm->TestJSArrayForAllocationSiteInfo(edx, edi, fail);
+ }
+
// Check for empty arrays, which only require a map transition and no
changes
// to the backing store.
__ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
=======================================
--- /branches/bleeding_edge/src/ia32/full-codegen-ia32.cc Tue Dec 18
04:00:50 2012
+++ /branches/bleeding_edge/src/ia32/full-codegen-ia32.cc Tue Jan 8
01:03:16 2013
@@ -1678,6 +1678,15 @@
FastCloneShallowArrayStub::Mode mode = has_constant_fast_elements
? FastCloneShallowArrayStub::CLONE_ELEMENTS
: FastCloneShallowArrayStub::CLONE_ANY_ELEMENTS;
+
+ // Tracking allocation info allows us to pre-transition later if it
makes
+ // sense.
+ if (mode == FastCloneShallowArrayStub::CLONE_ANY_ELEMENTS &&
+ FLAG_track_allocation_sites) {
+ mode = FastCloneShallowArrayStub::
+ CLONE_ANY_ELEMENTS_WITH_ALLOCATION_SITE_INFO;
+ }
+
FastCloneShallowArrayStub stub(mode, length);
__ CallStub(&stub);
}
=======================================
--- /branches/bleeding_edge/src/ia32/macro-assembler-ia32.cc Fri Jan 4
02:56:24 2013
+++ /branches/bleeding_edge/src/ia32/macro-assembler-ia32.cc Tue Jan 8
01:03:16 2013
@@ -3050,6 +3050,30 @@
cmp(ecx, isolate()->factory()->null_value());
j(not_equal, &next);
}
+
+
+void MacroAssembler::TestJSArrayForAllocationSiteInfo(
+ Register receiver_reg,
+ Register scratch_reg,
+ Label* allocation_info_present) {
+ Label no_info_available;
+ ExternalReference new_space_start =
+ ExternalReference::new_space_start(isolate());
+ ExternalReference new_space_allocation_top =
+ ExternalReference::new_space_allocation_top_address(isolate());
+
+ lea(scratch_reg, Operand(receiver_reg,
+ JSArray::kSize + AllocationSiteInfo::kSize));
+ cmp(scratch_reg, Immediate(new_space_start));
+ j(less, &no_info_available);
+ cmp(scratch_reg, Operand::StaticVariable(new_space_allocation_top));
+ j(greater_equal, &no_info_available);
+ cmp(MemOperand(scratch_reg, 0),
+
Immediate(Handle<Map>(isolate()->heap()->allocation_site_info_map())));
+ j(equal, allocation_info_present);
+ bind(&no_info_available);
+}
+
} } // namespace v8::internal
=======================================
--- /branches/bleeding_edge/src/ia32/macro-assembler-ia32.h Fri Dec 28
03:09:16 2012
+++ /branches/bleeding_edge/src/ia32/macro-assembler-ia32.h Tue Jan 8
01:03:16 2013
@@ -859,6 +859,16 @@
// in eax. Assumes that any other register can be used as a scratch.
void CheckEnumCache(Label* call_runtime);
+ // AllocationSiteInfo support. Arrays may have an associated
+ // AllocationSiteInfo object that can be checked for in order to
pretransition
+ // to another type.
+ // On entry, receiver_reg should point to the array object.
+ // scratch_reg gets clobbered.
+ // If allocation info is present, jump to allocation_info_present
+ void TestJSArrayForAllocationSiteInfo(Register receiver_reg,
+ Register scratch_reg,
+ Label* allocation_info_present);
+
private:
bool generating_stub_;
bool allow_stub_calls_;
=======================================
--- /branches/bleeding_edge/src/objects-debug.cc Fri Dec 14 06:19:18 2012
+++ /branches/bleeding_edge/src/objects-debug.cc Tue Jan 8 01:03:16 2013
@@ -772,6 +772,13 @@
CHECK(IsTypeSwitchInfo());
VerifyPointer(types());
}
+
+
+void AllocationSiteInfo::AllocationSiteInfoVerify() {
+ CHECK(IsAllocationSiteInfo());
+ VerifyHeapPointer(payload());
+ CHECK(payload()->IsObject());
+}
void Script::ScriptVerify() {
=======================================
--- /branches/bleeding_edge/src/objects-inl.h Mon Jan 7 07:02:56 2013
+++ /branches/bleeding_edge/src/objects-inl.h Tue Jan 8 01:03:16 2013
@@ -4064,6 +4064,8 @@
ACCESSORS(TypeSwitchInfo, types, Object, kTypesOffset)
+ACCESSORS(AllocationSiteInfo, payload, Object, kPayloadOffset)
+
ACCESSORS(Script, source, Object, kSourceOffset)
ACCESSORS(Script, name, Object, kNameOffset)
ACCESSORS(Script, id, Object, kIdOffset)
=======================================
--- /branches/bleeding_edge/src/objects-printer.cc Wed Nov 28 07:11:38 2012
+++ /branches/bleeding_edge/src/objects-printer.cc Tue Jan 8 01:03:16 2013
@@ -1000,6 +1000,22 @@
PrintF(out, "\n - types: ");
types()->ShortPrint(out);
}
+
+
+void AllocationSiteInfo::AllocationSiteInfoPrint(FILE* out) {
+ HeapObject::PrintHeader(out, "AllocationSiteInfo");
+ PrintF(out, " - payload: ");
+ if (payload()->IsJSArray()) {
+ PrintF(out, "Array literal ");
+ payload()->ShortPrint(out);
+ PrintF(out, "\n");
+ return;
+ }
+
+ PrintF(out, "unknown payload ");
+ payload()->ShortPrint(out);
+ PrintF(out, "\n");
+}
void Script::ScriptPrint(FILE* out) {
=======================================
--- /branches/bleeding_edge/src/objects.cc Mon Jan 7 07:36:26 2013
+++ /branches/bleeding_edge/src/objects.cc Tue Jan 8 01:03:16 2013
@@ -7481,6 +7481,31 @@
}
return this;
}
+
+
+AllocationSiteInfo* AllocationSiteInfo::FindForJSObject(JSObject* object) {
+ // Currently, AllocationSiteInfo objects are only allocated immediately
+ // after JSArrays in NewSpace, and detecting whether a JSArray has one
+ // involves carefully checking the object immediately after the JSArray
+ // (if there is one) to see if it's an AllocationSiteInfo.
+ if (FLAG_track_allocation_sites &&
object->GetHeap()->InNewSpace(object)) {
+ Address ptr_end = (reinterpret_cast<Address>(object) - kHeapObjectTag)
+
+ object->Size();
+ if ((ptr_end + AllocationSiteInfo::kSize) <=
+ object->GetHeap()->NewSpaceTop()) {
+ // There is room in newspace for allocation info. Do we have some?
+ Map** possible_allocation_site_info_map =
+ reinterpret_cast<Map**>(ptr_end);
+ if (*possible_allocation_site_info_map ==
+ object->GetHeap()->allocation_site_info_map()) {
+ AllocationSiteInfo* info = AllocationSiteInfo::cast(
+ reinterpret_cast<Object*>(ptr_end + 1));
+ return info;
+ }
+ }
+ }
+ return NULL;
+}
uint32_t StringHasher::MakeArrayIndexHash(uint32_t value, int length) {
@@ -9830,6 +9855,14 @@
}
// Convert to fast double elements if appropriate.
if (HasFastSmiElements() && !value->IsSmi() && value->IsNumber()) {
+ // Consider fixing the boilerplate as well if we have one.
+ ElementsKind to_kind = IsHoleyElementsKind(elements_kind)
+ ? FAST_HOLEY_DOUBLE_ELEMENTS
+ : FAST_DOUBLE_ELEMENTS;
+
+ MaybeObject* trans = PossiblyTransitionArrayBoilerplate(to_kind);
+ if (trans != NULL && trans->IsFailure()) return trans;
+
MaybeObject* maybe =
SetFastDoubleElementsCapacityAndLength(new_capacity, array_length);
if (maybe->IsFailure()) return maybe;
@@ -10369,6 +10402,24 @@
object->TransitionElementsKind(to_kind),
Object);
}
+
+
+MaybeObject* JSObject::PossiblyTransitionArrayBoilerplate(
+ ElementsKind to_kind) {
+ ASSERT(IsJSArray());
+ MaybeObject* ret = NULL;
+ AllocationSiteInfo* info = AllocationSiteInfo::FindForJSObject(this);
+ if (info != NULL) {
+ JSObject* payload = JSObject::cast(info->payload());
+ if (payload->GetElementsKind() != to_kind) {
+ if (IsMoreGeneralElementsKindTransition(payload->GetElementsKind(),
+ to_kind)) {
+ ret = payload->TransitionElementsKind(to_kind);
+ }
+ }
+ }
+ return ret;
+}
MaybeObject* JSObject::TransitionElementsKind(ElementsKind to_kind) {
@@ -10381,6 +10432,9 @@
if (from_kind == to_kind) return this;
+ MaybeObject* trans = PossiblyTransitionArrayBoilerplate(to_kind);
+ if (trans != NULL && trans->IsFailure()) return trans;
+
Isolate* isolate = GetIsolate();
if (elements() == isolate->heap()->empty_fixed_array() ||
(IsFastSmiOrObjectElementsKind(from_kind) &&
=======================================
--- /branches/bleeding_edge/src/objects.h Thu Jan 3 01:18:01 2013
+++ /branches/bleeding_edge/src/objects.h Tue Jan 8 01:03:16 2013
@@ -291,6 +291,7 @@
V(OBJECT_TEMPLATE_INFO_TYPE)
\
V(SIGNATURE_INFO_TYPE)
\
V(TYPE_SWITCH_INFO_TYPE)
\
+
V(ALLOCATION_SITE_INFO_TYPE)
\
V(SCRIPT_TYPE)
\
V(CODE_CACHE_TYPE)
\
V(POLYMORPHIC_CODE_CACHE_TYPE)
\
@@ -444,6 +445,7 @@
V(SIGNATURE_INFO, SignatureInfo,
signature_info) \
V(TYPE_SWITCH_INFO, TypeSwitchInfo,
type_switch_info) \
V(SCRIPT, Script,
script) \
+ V(ALLOCATION_SITE_INFO, AllocationSiteInfo,
allocation_site_info) \
V(CODE_CACHE, CodeCache,
code_cache) \
V(POLYMORPHIC_CODE_CACHE, PolymorphicCodeCache,
polymorphic_code_cache) \
V(TYPE_FEEDBACK_INFO, TypeFeedbackInfo,
type_feedback_info) \
@@ -606,6 +608,7 @@
OBJECT_TEMPLATE_INFO_TYPE,
SIGNATURE_INFO_TYPE,
TYPE_SWITCH_INFO_TYPE,
+ ALLOCATION_SITE_INFO_TYPE,
SCRIPT_TYPE,
CODE_CACHE_TYPE,
POLYMORPHIC_CODE_CACHE_TYPE,
@@ -2012,6 +2015,8 @@
ElementsKind to_kind);
MUST_USE_RESULT MaybeObject* TransitionElementsKind(ElementsKind
to_kind);
+ MUST_USE_RESULT MaybeObject* PossiblyTransitionArrayBoilerplate(
+ ElementsKind to_kind);
// Replaces an existing transition with a transition to a map with a
FIELD.
MUST_USE_RESULT MaybeObject* ConvertTransitionToMapTransition(
@@ -6897,6 +6902,32 @@
};
+enum AllocationSiteInfoMode {
+ DONT_TRACK_ALLOCATION_SITE_INFO,
+ TRACK_ALLOCATION_SITE_INFO
+};
+
+
+class AllocationSiteInfo: public Struct {
+ public:
+ DECL_ACCESSORS(payload, Object)
+
+ static inline AllocationSiteInfo* cast(Object* obj);
+
+ DECLARE_PRINTER(AllocationSiteInfo)
+ DECLARE_VERIFIER(AllocationSiteInfo)
+
+ // Returns NULL if no AllocationSiteInfo is available for object.
+ static AllocationSiteInfo* FindForJSObject(JSObject* object);
+
+ static const int kPayloadOffset = HeapObject::kHeaderSize;
+ static const int kSize = kPayloadOffset + kPointerSize;
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(AllocationSiteInfo);
+};
+
+
// Representation of a slow alias as part of a non-strict arguments
objects.
// For fast aliases (if HasNonStrictArgumentsElements()):
// - the parameter map contains an index into the context
=======================================
--- /branches/bleeding_edge/src/x64/code-stubs-x64.cc Mon Jan 7 02:06:11
2013
+++ /branches/bleeding_edge/src/x64/code-stubs-x64.cc Tue Jan 8 01:03:16
2013
@@ -316,6 +316,7 @@
MacroAssembler* masm,
int length,
FastCloneShallowArrayStub::Mode mode,
+ AllocationSiteInfoMode allocation_site_info_mode,
Label* fail) {
// Registers on entry:
//
@@ -329,7 +330,12 @@
? FixedDoubleArray::SizeFor(length)
: FixedArray::SizeFor(length);
}
- int size = JSArray::kSize + elements_size;
+ int size = JSArray::kSize;
+ int allocation_info_start = size;
+ if (allocation_site_info_mode == TRACK_ALLOCATION_SITE_INFO) {
+ size += AllocationSiteInfo::kSize;
+ }
+ size += elements_size;
// Allocate both the JS array and the elements array in one big
// allocation. This avoids multiple limit checks.
@@ -339,6 +345,12 @@
}
__ AllocateInNewSpace(size, rax, rbx, rdx, fail, flags);
+ if (allocation_site_info_mode == TRACK_ALLOCATION_SITE_INFO) {
+ __ LoadRoot(kScratchRegister, Heap::kAllocationSiteInfoMapRootIndex);
+ __ movq(FieldOperand(rax, allocation_info_start), kScratchRegister);
+ __ movq(FieldOperand(rax, allocation_info_start + kPointerSize), rcx);
+ }
+
// Copy the JS array part.
for (int i = 0; i < JSArray::kSize; i += kPointerSize) {
if ((i != JSArray::kElementsOffset) || (length == 0)) {
@@ -351,7 +363,11 @@
// Get hold of the elements array of the boilerplate and setup the
// elements pointer in the resulting object.
__ movq(rcx, FieldOperand(rcx, JSArray::kElementsOffset));
- __ lea(rdx, Operand(rax, JSArray::kSize));
+ if (allocation_site_info_mode == TRACK_ALLOCATION_SITE_INFO) {
+ __ lea(rdx, Operand(rax, JSArray::kSize +
AllocationSiteInfo::kSize));
+ } else {
+ __ lea(rdx, Operand(rax, JSArray::kSize));
+ }
__ movq(FieldOperand(rax, JSArray::kElementsOffset), rdx);
// Copy the elements array.
@@ -398,6 +414,13 @@
FastCloneShallowArrayStub::Mode mode = mode_;
// rcx is boilerplate object.
Factory* factory = masm->isolate()->factory();
+ AllocationSiteInfoMode allocation_site_info_mode =
+ DONT_TRACK_ALLOCATION_SITE_INFO;
+ if (mode == CLONE_ANY_ELEMENTS_WITH_ALLOCATION_SITE_INFO) {
+ mode = CLONE_ANY_ELEMENTS;
+ allocation_site_info_mode = TRACK_ALLOCATION_SITE_INFO;
+ }
+
if (mode == CLONE_ANY_ELEMENTS) {
Label double_elements, check_fast_elements;
__ movq(rbx, FieldOperand(rcx, JSArray::kElementsOffset));
@@ -405,7 +428,9 @@
factory->fixed_cow_array_map());
__ j(not_equal, &check_fast_elements);
GenerateFastCloneShallowArrayCommon(masm, 0,
- COPY_ON_WRITE_ELEMENTS,
&slow_case);
+ COPY_ON_WRITE_ELEMENTS,
+ allocation_site_info_mode,
+ &slow_case);
__ ret(3 * kPointerSize);
__ bind(&check_fast_elements);
@@ -413,7 +438,9 @@
factory->fixed_array_map());
__ j(not_equal, &double_elements);
GenerateFastCloneShallowArrayCommon(masm, length_,
- CLONE_ELEMENTS, &slow_case);
+ CLONE_ELEMENTS,
+ allocation_site_info_mode,
+ &slow_case);
__ ret(3 * kPointerSize);
__ bind(&double_elements);
@@ -443,7 +470,8 @@
__ pop(rcx);
}
- GenerateFastCloneShallowArrayCommon(masm, length_, mode, &slow_case);
+ GenerateFastCloneShallowArrayCommon(masm, length_, mode,
+ allocation_site_info_mode,
&slow_case);
__ ret(3 * kPointerSize);
__ bind(&slow_case);
=======================================
--- /branches/bleeding_edge/src/x64/codegen-x64.cc Thu Jan 3 06:20:08 2013
+++ /branches/bleeding_edge/src/x64/codegen-x64.cc Tue Jan 8 01:03:16 2013
@@ -283,6 +283,10 @@
// The fail label is not actually used since we do not allocate.
Label allocated, new_backing_store, only_change_map, done;
+ if (FLAG_track_allocation_sites) {
+ masm->TestJSArrayForAllocationSiteInfo(rdx, rdi, fail);
+ }
+
// Check for empty arrays, which only require a map transition and no
changes
// to the backing store.
__ movq(r8, FieldOperand(rdx, JSObject::kElementsOffset));
=======================================
--- /branches/bleeding_edge/src/x64/full-codegen-x64.cc Thu Jan 3 06:20:08
2013
+++ /branches/bleeding_edge/src/x64/full-codegen-x64.cc Tue Jan 8 01:03:16
2013
@@ -1703,6 +1703,15 @@
FastCloneShallowArrayStub::Mode mode = has_constant_fast_elements
? FastCloneShallowArrayStub::CLONE_ELEMENTS
: FastCloneShallowArrayStub::CLONE_ANY_ELEMENTS;
+
+ // Tracking allocation info allows us to pre-transition later if it
makes
+ // sense.
+ if (mode == FastCloneShallowArrayStub::CLONE_ANY_ELEMENTS &&
+ FLAG_track_allocation_sites) {
+ mode = FastCloneShallowArrayStub::
+ CLONE_ANY_ELEMENTS_WITH_ALLOCATION_SITE_INFO;
+ }
+
FastCloneShallowArrayStub stub(mode, length);
__ CallStub(&stub);
}
=======================================
--- /branches/bleeding_edge/src/x64/macro-assembler-x64.cc Thu Jan 3
06:20:08 2013
+++ /branches/bleeding_edge/src/x64/macro-assembler-x64.cc Tue Jan 8
01:03:16 2013
@@ -4608,6 +4608,29 @@
cmpq(rcx, null_value);
j(not_equal, &next);
}
+
+void MacroAssembler::TestJSArrayForAllocationSiteInfo(
+ Register receiver_reg,
+ Register scratch_reg,
+ Label* allocation_info_present) {
+ Label no_info_available;
+ ExternalReference new_space_start =
+ ExternalReference::new_space_start(isolate());
+ ExternalReference new_space_allocation_top =
+ ExternalReference::new_space_allocation_top_address(isolate());
+
+ lea(scratch_reg, Operand(receiver_reg,
+ JSArray::kSize + AllocationSiteInfo::kSize));
+ movq(kScratchRegister, new_space_start);
+ cmpq(scratch_reg, kScratchRegister);
+ j(less, &no_info_available);
+ cmpq(scratch_reg, ExternalOperand(new_space_allocation_top));
+ j(greater_equal, &no_info_available);
+ CompareRoot(MemOperand(scratch_reg, 0),
+ Heap::kAllocationSiteInfoMapRootIndex);
+ j(equal, allocation_info_present);
+ bind(&no_info_available);
+}
} } // namespace v8::internal
=======================================
--- /branches/bleeding_edge/src/x64/macro-assembler-x64.h Thu Jan 3
06:20:08 2013
+++ /branches/bleeding_edge/src/x64/macro-assembler-x64.h Tue Jan 8
01:03:16 2013
@@ -1315,6 +1315,16 @@
void CheckEnumCache(Register null_value,
Label* call_runtime);
+ // AllocationSiteInfo support. Arrays may have an associated
+ // AllocationSiteInfo object that can be checked for in order to
pretransition
+ // to another type.
+ // On entry, receiver_reg should point to the array object.
+ // scratch_reg gets clobbered.
+ // If allocation info is present, jump to allocation_info_present
+ void TestJSArrayForAllocationSiteInfo(Register receiver_reg,
+ Register scratch_reg,
+ Label* allocation_info_present);
+
private:
// Order general registers are pushed by Pushad.
// rax, rcx, rdx, rbx, rsi, rdi, r8, r9, r11, r14, r15.
=======================================
--- /branches/bleeding_edge/test/mjsunit/array-natives-elements.js Mon Nov
26 06:29:21 2012
+++ /branches/bleeding_edge/test/mjsunit/array-natives-elements.js Tue Jan
8 01:03:16 2013
@@ -57,17 +57,27 @@
// Push
var a0 = [1, 2, 3];
- assertTrue(%HasFastSmiElements(a0));
- a0.push(4);
- assertTrue(%HasFastSmiElements(a0));
- a0.push(1.3);
- assertTrue(%HasFastDoubleElements(a0));
- a0.push(1.5);
- assertTrue(%HasFastDoubleElements(a0));
- a0.push({});
- assertTrue(%HasFastObjectElements(a0));
- a0.push({});
- assertTrue(%HasFastObjectElements(a0));
+ if (%HasFastSmiElements(a0)) {
+ assertTrue(%HasFastSmiElements(a0));
+ a0.push(4);
+ assertTrue(%HasFastSmiElements(a0));
+ a0.push(1.3);
+ assertTrue(%HasFastDoubleElements(a0));
+ a0.push(1.5);
+ assertTrue(%HasFastDoubleElements(a0));
+ a0.push({});
+ assertTrue(%HasFastObjectElements(a0));
+ a0.push({});
+ assertTrue(%HasFastObjectElements(a0));
+ } else {
+ assertTrue(%HasFastObjectElements(a0));
+ a0.push(4);
+ a0.push(1.3);
+ a0.push(1.5);
+ a0.push({});
+ a0.push({});
+ assertTrue(%HasFastObjectElements(a0));
+ }
assertEquals([1,2,3,4,1.3,1.5,{},{}], a0);
// Concat
=======================================
--- /branches/bleeding_edge/test/mjsunit/elements-kind.js Thu Nov 15
04:19:14 2012
+++ /branches/bleeding_edge/test/mjsunit/elements-kind.js Tue Jan 8
01:03:16 2013
@@ -26,6 +26,7 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Flags: --allow-natives-syntax --smi-only-arrays --expose-gc
+// Flags: --notrack_allocation_sites
// Test element kind of objects.
// Since --smi-only-arrays affects builtins, its default setting at compile
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev