Add a premonomorphic state to the call target cache.

From a CL by kasperl: https://codereview.chromium.org/162903004/

R=verwaest@chromium.org

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@19402 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 7f6dc1ff
...@@ -3192,6 +3192,8 @@ static void GenerateRecordCallTarget(MacroAssembler* masm) { ...@@ -3192,6 +3192,8 @@ static void GenerateRecordCallTarget(MacroAssembler* masm) {
masm->isolate()->heap()->undefined_value()); masm->isolate()->heap()->undefined_value());
ASSERT_EQ(*TypeFeedbackInfo::UninitializedSentinel(masm->isolate()), ASSERT_EQ(*TypeFeedbackInfo::UninitializedSentinel(masm->isolate()),
masm->isolate()->heap()->the_hole_value()); masm->isolate()->heap()->the_hole_value());
ASSERT_EQ(*TypeFeedbackInfo::PremonomorphicSentinel(masm->isolate()),
masm->isolate()->heap()->null_value());
// Load the cache state. // Load the cache state.
__ Add(x4, x2, Operand::UntagSmiAndScale(x3, kPointerSizeLog2)); __ Add(x4, x2, Operand::UntagSmiAndScale(x3, kPointerSizeLog2));
...@@ -3219,7 +3221,22 @@ static void GenerateRecordCallTarget(MacroAssembler* masm) { ...@@ -3219,7 +3221,22 @@ static void GenerateRecordCallTarget(MacroAssembler* masm) {
// A monomorphic miss (i.e, here the cache is not uninitialized) goes // A monomorphic miss (i.e, here the cache is not uninitialized) goes
// megamorphic. // megamorphic.
__ JumpIfRoot(x4, Heap::kTheHoleValueRootIndex, &initialize); Label not_uninitialized;
__ JumpIfNotRoot(x4, Heap::kTheHoleValueRootIndex, &not_uninitialized);
// PremonomorphicSentinel is an immortal immovable object (null) so no
// write-barrier is needed.
__ Add(x4, x2, Operand::UntagSmiAndScale(x3, kPointerSizeLog2));
__ LoadRoot(x10, Heap::kNullValueRootIndex);
__ Str(x10, FieldMemOperand(x4, FixedArray::kHeaderSize));
__ B(&done);
// If the cache isn't uninitialized, it is either premonomorphic or
// monomorphic. If it is premonomorphic, we initialize it thus making
// it monomorphic. Otherwise, we go megamorphic.
__ Bind(&not_uninitialized);
__ JumpIfRoot(x4, Heap::kNullValueRootIndex, &initialize);
// MegamorphicSentinel is an immortal immovable object (undefined) so no // MegamorphicSentinel is an immortal immovable object (undefined) so no
// write-barrier is needed. // write-barrier is needed.
__ Bind(&megamorphic); __ Bind(&megamorphic);
......
...@@ -3017,6 +3017,8 @@ static void GenerateRecordCallTarget(MacroAssembler* masm) { ...@@ -3017,6 +3017,8 @@ static void GenerateRecordCallTarget(MacroAssembler* masm) {
masm->isolate()->heap()->undefined_value()); masm->isolate()->heap()->undefined_value());
ASSERT_EQ(*TypeFeedbackInfo::UninitializedSentinel(masm->isolate()), ASSERT_EQ(*TypeFeedbackInfo::UninitializedSentinel(masm->isolate()),
masm->isolate()->heap()->the_hole_value()); masm->isolate()->heap()->the_hole_value());
ASSERT_EQ(*TypeFeedbackInfo::PremonomorphicSentinel(masm->isolate()),
masm->isolate()->heap()->null_value());
// Load the cache state into r4. // Load the cache state into r4.
__ add(r4, r2, Operand::PointerOffsetFromSmiKey(r3)); __ add(r4, r2, Operand::PointerOffsetFromSmiKey(r3));
...@@ -3043,10 +3045,26 @@ static void GenerateRecordCallTarget(MacroAssembler* masm) { ...@@ -3043,10 +3045,26 @@ static void GenerateRecordCallTarget(MacroAssembler* masm) {
__ bind(&miss); __ bind(&miss);
// A monomorphic miss (i.e, here the cache is not uninitialized) goes // A monomorphic miss (i.e, here the cache is not uninitialized or
// megamorphic. // pre-monomorphic) goes megamorphic.
Label not_uninitialized;
__ CompareRoot(r4, Heap::kTheHoleValueRootIndex); __ CompareRoot(r4, Heap::kTheHoleValueRootIndex);
__ b(ne, &not_uninitialized);
// PremonomorphicSentinel is an immortal immovable object (null) so no
// write-barrier is needed.
__ add(r4, r2, Operand::PointerOffsetFromSmiKey(r3));
__ LoadRoot(ip, Heap::kNullValueRootIndex);
__ str(ip, FieldMemOperand(r4, FixedArray::kHeaderSize));
__ jmp(&done);
// If the cache isn't uninitialized, it is either premonomorphic or
// monomorphic. If it is premonomorphic, we initialize it thus making
// it monomorphic. Otherwise, we go megamorphic.
__ bind(&not_uninitialized);
__ CompareRoot(r4, Heap::kNullValueRootIndex);
__ b(eq, &initialize); __ b(eq, &initialize);
// MegamorphicSentinel is an immortal immovable object (undefined) so no // MegamorphicSentinel is an immortal immovable object (undefined) so no
// write-barrier is needed. // write-barrier is needed.
__ bind(&megamorphic); __ bind(&megamorphic);
......
...@@ -2362,10 +2362,26 @@ static void GenerateRecordCallTarget(MacroAssembler* masm) { ...@@ -2362,10 +2362,26 @@ static void GenerateRecordCallTarget(MacroAssembler* masm) {
__ bind(&miss); __ bind(&miss);
// A monomorphic miss (i.e, here the cache is not uninitialized) goes // A monomorphic miss (i.e, here the cache is not uninitialized or
// megamorphic. // pre-monomorphic) goes megamorphic.
Label not_uninitialized;
__ cmp(ecx, Immediate(TypeFeedbackInfo::UninitializedSentinel(isolate))); __ cmp(ecx, Immediate(TypeFeedbackInfo::UninitializedSentinel(isolate)));
__ j(not_equal, &not_uninitialized);
// PremonomorphicSentinel is an immortal immovable object (null) so no
// write-barrier is needed.
__ mov(FieldOperand(ebx, edx, times_half_pointer_size,
FixedArray::kHeaderSize),
Immediate(TypeFeedbackInfo::PremonomorphicSentinel(isolate)));
__ jmp(&done, Label::kFar);
// If the cache isn't uninitialized, it is either premonomorphic or
// monomorphic. If it is premonomorphic, we initialize it thus making
// it monomorphic. Otherwise, we go megamorphic.
__ bind(&not_uninitialized);
__ cmp(ecx, Immediate(TypeFeedbackInfo::PremonomorphicSentinel(isolate)));
__ j(equal, &initialize); __ j(equal, &initialize);
// MegamorphicSentinel is an immortal immovable object (undefined) so no // MegamorphicSentinel is an immortal immovable object (undefined) so no
// write-barrier is needed. // write-barrier is needed.
__ bind(&megamorphic); __ bind(&megamorphic);
......
...@@ -6532,6 +6532,11 @@ Handle<Object> TypeFeedbackInfo::UninitializedSentinel(Isolate* isolate) { ...@@ -6532,6 +6532,11 @@ Handle<Object> TypeFeedbackInfo::UninitializedSentinel(Isolate* isolate) {
} }
Handle<Object> TypeFeedbackInfo::PremonomorphicSentinel(Isolate* isolate) {
return isolate->factory()->null_value();
}
Handle<Object> TypeFeedbackInfo::MegamorphicSentinel(Isolate* isolate) { Handle<Object> TypeFeedbackInfo::MegamorphicSentinel(Isolate* isolate) {
return isolate->factory()->undefined_value(); return isolate->factory()->undefined_value();
} }
......
...@@ -8176,6 +8176,9 @@ class TypeFeedbackInfo: public Struct { ...@@ -8176,6 +8176,9 @@ class TypeFeedbackInfo: public Struct {
// The object that indicates an uninitialized cache. // The object that indicates an uninitialized cache.
static inline Handle<Object> UninitializedSentinel(Isolate* isolate); static inline Handle<Object> UninitializedSentinel(Isolate* isolate);
// The object that indicates a cache in pre-monomorphic state.
static inline Handle<Object> PremonomorphicSentinel(Isolate* isolate);
// The object that indicates a megamorphic state. // The object that indicates a megamorphic state.
static inline Handle<Object> MegamorphicSentinel(Isolate* isolate); static inline Handle<Object> MegamorphicSentinel(Isolate* isolate);
......
...@@ -14762,6 +14762,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConstructor) { ...@@ -14762,6 +14762,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConstructor) {
Handle<AllocationSite> site; Handle<AllocationSite> site;
if (!type_info.is_null() && if (!type_info.is_null() &&
*type_info != isolate->heap()->null_value() &&
*type_info != isolate->heap()->undefined_value()) { *type_info != isolate->heap()->undefined_value()) {
site = Handle<AllocationSite>::cast(type_info); site = Handle<AllocationSite>::cast(type_info);
ASSERT(!site->SitePointsToLiteral()); ASSERT(!site->SitePointsToLiteral());
......
...@@ -2201,10 +2201,25 @@ static void GenerateRecordCallTarget(MacroAssembler* masm) { ...@@ -2201,10 +2201,25 @@ static void GenerateRecordCallTarget(MacroAssembler* masm) {
__ bind(&miss); __ bind(&miss);
// A monomorphic miss (i.e, here the cache is not uninitialized) goes // A monomorphic miss (i.e, here the cache is not uninitialized or
// megamorphic. // pre-monomorphic) goes megamorphic.
Label not_uninitialized;
__ Cmp(rcx, TypeFeedbackInfo::UninitializedSentinel(isolate)); __ Cmp(rcx, TypeFeedbackInfo::UninitializedSentinel(isolate));
__ j(not_equal, &not_uninitialized);
// PremonomorphicSentinel is an immortal immovable object (null) so no
// write-barrier is needed.
__ Move(FieldOperand(rbx, rdx, times_pointer_size, FixedArray::kHeaderSize),
TypeFeedbackInfo::PremonomorphicSentinel(isolate));
__ jmp(&done);
// If the cache isn't uninitialized, it is either premonomorphic or
// monomorphic. If it is premonomorphic, we initialize it thus making
// it monomorphic. Otherwise, we go megamorphic.
__ bind(&not_uninitialized);
__ Cmp(rcx, TypeFeedbackInfo::PremonomorphicSentinel(isolate));
__ j(equal, &initialize); __ j(equal, &initialize);
// MegamorphicSentinel is an immortal immovable object (undefined) so no // MegamorphicSentinel is an immortal immovable object (undefined) so no
// write-barrier is needed. // write-barrier is needed.
__ bind(&megamorphic); __ bind(&megamorphic);
......
...@@ -2848,7 +2848,9 @@ TEST(IncrementalMarkingClearsTypeFeedbackInfo) { ...@@ -2848,7 +2848,9 @@ TEST(IncrementalMarkingClearsTypeFeedbackInfo) {
// originating from two different native contexts. // originating from two different native contexts.
CcTest::global()->Set(v8_str("fun1"), fun1); CcTest::global()->Set(v8_str("fun1"), fun1);
CcTest::global()->Set(v8_str("fun2"), fun2); CcTest::global()->Set(v8_str("fun2"), fun2);
CompileRun("function f(a, b) { a(); b(); } f(fun1, fun2);"); CompileRun("function f(a, b) { a(); b(); }"
"f(fun1, fun2);" // Run twice to skip premonomorphic state.
"f(fun1, fun2)");
Handle<JSFunction> f = Handle<JSFunction> f =
v8::Utils::OpenHandle( v8::Utils::OpenHandle(
......
...@@ -128,6 +128,7 @@ if (support_smi_only_arrays) { ...@@ -128,6 +128,7 @@ if (support_smi_only_arrays) {
} }
// Case: [1,2,3] as allocation site // Case: [1,2,3] as allocation site
get_standard_literal(); // Skip premonomorphic state.
obj = fastliteralcase(get_standard_literal(), 1); obj = fastliteralcase(get_standard_literal(), 1);
assertKind(elements_kind.fast_smi_only, obj); assertKind(elements_kind.fast_smi_only, obj);
obj = fastliteralcase(get_standard_literal(), 1.5); obj = fastliteralcase(get_standard_literal(), 1.5);
...@@ -169,6 +170,7 @@ if (support_smi_only_arrays) { ...@@ -169,6 +170,7 @@ if (support_smi_only_arrays) {
return literal; return literal;
} }
fastliteralcase_smifast(1); // Skip premonomorphic state.
obj = fastliteralcase_smifast(1); obj = fastliteralcase_smifast(1);
assertKind(elements_kind.fast_smi_only, obj); assertKind(elements_kind.fast_smi_only, obj);
obj = fastliteralcase_smifast("carter"); obj = fastliteralcase_smifast("carter");
...@@ -183,6 +185,7 @@ if (support_smi_only_arrays) { ...@@ -183,6 +185,7 @@ if (support_smi_only_arrays) {
return literal; return literal;
} }
fastliteralcase_smiholey(5, 1); // Skip premonomorphic state.
obj = fastliteralcase_smiholey(5, 1); obj = fastliteralcase_smiholey(5, 1);
assertKind(elements_kind.fast_smi_only, obj); assertKind(elements_kind.fast_smi_only, obj);
assertHoley(obj); assertHoley(obj);
...@@ -197,6 +200,7 @@ if (support_smi_only_arrays) { ...@@ -197,6 +200,7 @@ if (support_smi_only_arrays) {
} }
// Case: new Array() as allocation site, smi->double // Case: new Array() as allocation site, smi->double
newarraycase_smidouble(1); // Skip premonomorphic state.
obj = newarraycase_smidouble(1); obj = newarraycase_smidouble(1);
assertKind(elements_kind.fast_smi_only, obj); assertKind(elements_kind.fast_smi_only, obj);
obj = newarraycase_smidouble(1.5); obj = newarraycase_smidouble(1.5);
...@@ -211,6 +215,7 @@ if (support_smi_only_arrays) { ...@@ -211,6 +215,7 @@ if (support_smi_only_arrays) {
} }
// Case: new Array() as allocation site, smi->fast // Case: new Array() as allocation site, smi->fast
newarraycase_smiobj(1); // Skip premonomorphic state.
obj = newarraycase_smiobj(1); obj = newarraycase_smiobj(1);
assertKind(elements_kind.fast_smi_only, obj); assertKind(elements_kind.fast_smi_only, obj);
obj = newarraycase_smiobj("gloria"); obj = newarraycase_smiobj("gloria");
...@@ -225,6 +230,7 @@ if (support_smi_only_arrays) { ...@@ -225,6 +230,7 @@ if (support_smi_only_arrays) {
} }
// Case: new Array(length) as allocation site // Case: new Array(length) as allocation site
newarraycase_length_smidouble(1); // Skip premonomorphic state.
obj = newarraycase_length_smidouble(1); obj = newarraycase_length_smidouble(1);
assertKind(elements_kind.fast_smi_only, obj); assertKind(elements_kind.fast_smi_only, obj);
obj = newarraycase_length_smidouble(1.5); obj = newarraycase_length_smidouble(1.5);
...@@ -248,6 +254,7 @@ if (support_smi_only_arrays) { ...@@ -248,6 +254,7 @@ if (support_smi_only_arrays) {
} }
// Case: new Array(<length>) as allocation site, smi->fast // Case: new Array(<length>) as allocation site, smi->fast
newarraycase_length_smiobj(1); // Skip premonomorphic state.
obj = newarraycase_length_smiobj(1); obj = newarraycase_length_smiobj(1);
assertKind(elements_kind.fast_smi_only, obj); assertKind(elements_kind.fast_smi_only, obj);
obj = newarraycase_length_smiobj("gloria"); obj = newarraycase_length_smiobj("gloria");
...@@ -261,6 +268,7 @@ if (support_smi_only_arrays) { ...@@ -261,6 +268,7 @@ if (support_smi_only_arrays) {
return a; return a;
} }
newarraycase_list_smidouble(1); // Skip premonomorphic state.
obj = newarraycase_list_smidouble(1); obj = newarraycase_list_smidouble(1);
assertKind(elements_kind.fast_smi_only, obj); assertKind(elements_kind.fast_smi_only, obj);
obj = newarraycase_list_smidouble(1.5); obj = newarraycase_list_smidouble(1.5);
...@@ -274,6 +282,7 @@ if (support_smi_only_arrays) { ...@@ -274,6 +282,7 @@ if (support_smi_only_arrays) {
return a; return a;
} }
newarraycase_list_smiobj(1); // Skip premonomorphic state.
obj = newarraycase_list_smiobj(1); obj = newarraycase_list_smiobj(1);
assertKind(elements_kind.fast_smi_only, obj); assertKind(elements_kind.fast_smi_only, obj);
obj = newarraycase_list_smiobj("coates"); obj = newarraycase_list_smiobj("coates");
...@@ -293,6 +302,7 @@ if (support_smi_only_arrays) { ...@@ -293,6 +302,7 @@ if (support_smi_only_arrays) {
return a; return a;
} }
foo(0); foo(1); // Skip premonomorphic state.
for (i = 0; i < 2; i++) { for (i = 0; i < 2; i++) {
a = foo(i); a = foo(i);
b = foo(i); b = foo(i);
...@@ -313,6 +323,7 @@ if (support_smi_only_arrays) { ...@@ -313,6 +323,7 @@ if (support_smi_only_arrays) {
return a; return a;
} }
newarraycase_onearg(5, 3.5); // Skip premonomorphic state.
obj = newarraycase_onearg(5, 3.5); obj = newarraycase_onearg(5, 3.5);
assertKind(elements_kind.fast_double, obj); assertKind(elements_kind.fast_double, obj);
obj = newarraycase_onearg(10, 5); obj = newarraycase_onearg(10, 5);
...@@ -388,6 +399,7 @@ if (support_smi_only_arrays) { ...@@ -388,6 +399,7 @@ if (support_smi_only_arrays) {
return literal; return literal;
} }
get_nested_literal(); // Skip premonomorphic state.
obj = get_nested_literal(); obj = get_nested_literal();
assertKind(elements_kind.fast, obj); assertKind(elements_kind.fast, obj);
obj[0][0] = 3.5; obj[0][0] = 3.5;
...@@ -403,6 +415,7 @@ if (support_smi_only_arrays) { ...@@ -403,6 +415,7 @@ if (support_smi_only_arrays) {
return literal; return literal;
} }
get_deep_nested_literal(); // Skip premonomorphic state.
obj = get_deep_nested_literal(); obj = get_deep_nested_literal();
assertKind(elements_kind.fast_smi_only, obj[1][0]); assertKind(elements_kind.fast_smi_only, obj[1][0]);
obj[0][0] = 3.5; obj[0][0] = 3.5;
...@@ -428,6 +441,7 @@ if (support_smi_only_arrays) { ...@@ -428,6 +441,7 @@ if (support_smi_only_arrays) {
return literal; return literal;
} }
get_object_literal(); // Skip premonomorphic state.
obj = get_object_literal(); obj = get_object_literal();
assertKind(elements_kind.fast_smi_only, obj.array); assertKind(elements_kind.fast_smi_only, obj.array);
obj.array[1] = 3.5; obj.array[1] = 3.5;
...@@ -443,6 +457,7 @@ if (support_smi_only_arrays) { ...@@ -443,6 +457,7 @@ if (support_smi_only_arrays) {
return literal; return literal;
} }
get_nested_object_literal(); // Skip premonomorphic state.
obj = get_nested_object_literal(); obj = get_nested_object_literal();
assertKind(elements_kind.fast, obj.array); assertKind(elements_kind.fast, obj.array);
assertKind(elements_kind.fast_smi_only, obj.array[1]); assertKind(elements_kind.fast_smi_only, obj.array[1]);
...@@ -462,6 +477,7 @@ if (support_smi_only_arrays) { ...@@ -462,6 +477,7 @@ if (support_smi_only_arrays) {
return literal; return literal;
} }
get_nested_literal(); // Skip premonomorphic state.
obj = get_nested_literal(); obj = get_nested_literal();
assertKind(elements_kind.fast, obj); assertKind(elements_kind.fast, obj);
obj[0][0] = 3.5; obj[0][0] = 3.5;
...@@ -477,6 +493,7 @@ if (support_smi_only_arrays) { ...@@ -477,6 +493,7 @@ if (support_smi_only_arrays) {
return literal; return literal;
} }
get_deep_nested_literal(); // Skip premonomorphic state.
obj = get_deep_nested_literal(); obj = get_deep_nested_literal();
assertKind(elements_kind.fast_smi_only, obj[1][0]); assertKind(elements_kind.fast_smi_only, obj[1][0]);
obj[0][0] = 3.5; obj[0][0] = 3.5;
......
...@@ -89,6 +89,7 @@ if (support_smi_only_arrays) { ...@@ -89,6 +89,7 @@ if (support_smi_only_arrays) {
return new t(len); return new t(len);
} }
bar(Array, 10); // Skip premonomorphic state.
a = bar(Array, 10); a = bar(Array, 10);
a[0] = 3.5; a[0] = 3.5;
b = bar(Array, 1); b = bar(Array, 1);
...@@ -108,6 +109,8 @@ if (support_smi_only_arrays) { ...@@ -108,6 +109,8 @@ if (support_smi_only_arrays) {
function bar0(t) { function bar0(t) {
return new t(); return new t();
} }
bar0(Array); // Skip premonomorphic state.
a = bar0(Array); a = bar0(Array);
a[0] = 3.5; a[0] = 3.5;
b = bar0(Array); b = bar0(Array);
...@@ -139,6 +142,8 @@ if (support_smi_only_arrays) { ...@@ -139,6 +142,8 @@ if (support_smi_only_arrays) {
function bar(len) { function bar(len) {
return new Array(len); return new Array(len);
} }
bar(10); // Skip premonomorphic state.
a = bar(10); a = bar(10);
a[0] = "a string"; a[0] = "a string";
a = bar(10); a = bar(10);
...@@ -190,6 +195,8 @@ if (support_smi_only_arrays) { ...@@ -190,6 +195,8 @@ if (support_smi_only_arrays) {
function bar() { function bar() {
return new Array(); return new Array();
} }
bar(); // Skip premonomorphic state.
a = bar(); a = bar();
bar(); bar();
%OptimizeFunctionOnNextCall(bar); %OptimizeFunctionOnNextCall(bar);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment