Reviewers: mvstanton,
Description:
Add a premonomorphic state to the call target cache.
This allows access to lazily initialized constructors and functions
fetched through the context chain to remain monomorphic.
(function() {
var fn = function() {
fn = function() { return 42; };
return fn();
}
for (var i = 0; i < 100; i++) {
fn();
}
})();
Please review this at https://codereview.chromium.org/162903004/
SVN Base: http://v8.googlecode.com/svn/branches/bleeding_edge/
Affected files (+71, -5 lines):
src/ia32/code-stubs-ia32.cc
src/objects-inl.h
src/objects.h
src/runtime.cc
src/x64/code-stubs-x64.cc
test/cctest/test-heap.cc
test/mjsunit/allocation-site-info.js
test/mjsunit/array-constructor-feedback.js
Index: src/ia32/code-stubs-ia32.cc
===================================================================
--- src/ia32/code-stubs-ia32.cc (revision 19345)
+++ src/ia32/code-stubs-ia32.cc (working copy)
@@ -2362,10 +2362,26 @@
__ bind(&miss);
- // A monomorphic miss (i.e, here the cache is not uninitialized) goes
- // megamorphic.
+ // A monomorphic miss (i.e, here the cache is not uninitialized or
+ // pre-monomorphic) goes megamorphic.
+ Label not_uninitialized;
__ cmp(ecx, Immediate(TypeFeedbackInfo::UninitializedSentinel(isolate)));
+ __ j(not_equal, ¬_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(¬_uninitialized);
+ __ cmp(ecx,
Immediate(TypeFeedbackInfo::PremonomorphicSentinel(isolate)));
__ j(equal, &initialize);
+
// MegamorphicSentinel is an immortal immovable object (undefined) so no
// write-barrier is needed.
__ bind(&megamorphic);
Index: src/objects-inl.h
===================================================================
--- src/objects-inl.h (revision 19345)
+++ src/objects-inl.h (working copy)
@@ -6542,6 +6542,11 @@
}
+Handle<Object> TypeFeedbackInfo::PremonomorphicSentinel(Isolate* isolate) {
+ return isolate->factory()->null_value();
+}
+
+
Handle<Object> TypeFeedbackInfo::MegamorphicSentinel(Isolate* isolate) {
return isolate->factory()->undefined_value();
}
Index: src/objects.h
===================================================================
--- src/objects.h (revision 19345)
+++ src/objects.h (working copy)
@@ -8180,6 +8180,9 @@
// The object that indicates an uninitialized cache.
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.
static inline Handle<Object> MegamorphicSentinel(Isolate* isolate);
Index: src/runtime.cc
===================================================================
--- src/runtime.cc (revision 19345)
+++ src/runtime.cc (working copy)
@@ -14762,6 +14762,7 @@
Handle<AllocationSite> site;
if (!type_info.is_null() &&
+ *type_info != isolate->heap()->null_value() &&
*type_info != isolate->heap()->undefined_value()) {
site = Handle<AllocationSite>::cast(type_info);
ASSERT(!site->SitePointsToLiteral());
Index: src/x64/code-stubs-x64.cc
===================================================================
--- src/x64/code-stubs-x64.cc (revision 19345)
+++ src/x64/code-stubs-x64.cc (working copy)
@@ -2201,10 +2201,25 @@
__ bind(&miss);
- // A monomorphic miss (i.e, here the cache is not uninitialized) goes
- // megamorphic.
+ // A monomorphic miss (i.e, here the cache is not uninitialized or
+ // pre-monomorphic) goes megamorphic.
+ Label not_uninitialized;
__ Cmp(rcx, TypeFeedbackInfo::UninitializedSentinel(isolate));
+ __ j(not_equal, ¬_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(¬_uninitialized);
+ __ Cmp(rcx, TypeFeedbackInfo::PremonomorphicSentinel(isolate));
__ j(equal, &initialize);
+
// MegamorphicSentinel is an immortal immovable object (undefined) so no
// write-barrier is needed.
__ bind(&megamorphic);
Index: test/cctest/test-heap.cc
===================================================================
--- test/cctest/test-heap.cc (revision 19345)
+++ test/cctest/test-heap.cc (working copy)
@@ -2848,7 +2848,9 @@
// originating from two different native contexts.
CcTest::global()->Set(v8_str("fun1"), fun1);
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 =
v8::Utils::OpenHandle(
Index: test/mjsunit/allocation-site-info.js
===================================================================
--- test/mjsunit/allocation-site-info.js (revision 19345)
+++ test/mjsunit/allocation-site-info.js (working copy)
@@ -128,6 +128,7 @@
}
// Case: [1,2,3] as allocation site
+ get_standard_literal(); // Skip premonomorphic state.
obj = fastliteralcase(get_standard_literal(), 1);
assertKind(elements_kind.fast_smi_only, obj);
obj = fastliteralcase(get_standard_literal(), 1.5);
@@ -169,6 +170,7 @@
return literal;
}
+ fastliteralcase_smifast(1); // Skip premonomorphic state.
obj = fastliteralcase_smifast(1);
assertKind(elements_kind.fast_smi_only, obj);
obj = fastliteralcase_smifast("carter");
@@ -183,6 +185,7 @@
return literal;
}
+ fastliteralcase_smiholey(5, 1); // Skip premonomorphic state.
obj = fastliteralcase_smiholey(5, 1);
assertKind(elements_kind.fast_smi_only, obj);
assertHoley(obj);
@@ -197,6 +200,7 @@
}
// Case: new Array() as allocation site, smi->double
+ newarraycase_smidouble(1); // Skip premonomorphic state.
obj = newarraycase_smidouble(1);
assertKind(elements_kind.fast_smi_only, obj);
obj = newarraycase_smidouble(1.5);
@@ -211,6 +215,7 @@
}
// Case: new Array() as allocation site, smi->fast
+ newarraycase_smiobj(1); // Skip premonomorphic state.
obj = newarraycase_smiobj(1);
assertKind(elements_kind.fast_smi_only, obj);
obj = newarraycase_smiobj("gloria");
@@ -225,6 +230,7 @@
}
// Case: new Array(length) as allocation site
+ newarraycase_length_smidouble(1); // Skip premonomorphic state.
obj = newarraycase_length_smidouble(1);
assertKind(elements_kind.fast_smi_only, obj);
obj = newarraycase_length_smidouble(1.5);
@@ -248,6 +254,7 @@
}
// Case: new Array(<length>) as allocation site, smi->fast
+ newarraycase_length_smiobj(1); // Skip premonomorphic state.
obj = newarraycase_length_smiobj(1);
assertKind(elements_kind.fast_smi_only, obj);
obj = newarraycase_length_smiobj("gloria");
@@ -261,6 +268,7 @@
return a;
}
+ newarraycase_list_smidouble(1); // Skip premonomorphic state.
obj = newarraycase_list_smidouble(1);
assertKind(elements_kind.fast_smi_only, obj);
obj = newarraycase_list_smidouble(1.5);
@@ -274,6 +282,7 @@
return a;
}
+ newarraycase_list_smiobj(1); // Skip premonomorphic state.
obj = newarraycase_list_smiobj(1);
assertKind(elements_kind.fast_smi_only, obj);
obj = newarraycase_list_smiobj("coates");
@@ -293,6 +302,7 @@
return a;
}
+ foo(0); foo(1); // Skip premonomorphic state.
for (i = 0; i < 2; i++) {
a = foo(i);
b = foo(i);
@@ -313,6 +323,7 @@
return a;
}
+ newarraycase_onearg(5, 3.5); // Skip premonomorphic state.
obj = newarraycase_onearg(5, 3.5);
assertKind(elements_kind.fast_double, obj);
obj = newarraycase_onearg(10, 5);
@@ -388,6 +399,7 @@
return literal;
}
+ get_nested_literal(); // Skip premonomorphic state.
obj = get_nested_literal();
assertKind(elements_kind.fast, obj);
obj[0][0] = 3.5;
@@ -403,6 +415,7 @@
return literal;
}
+ get_deep_nested_literal(); // Skip premonomorphic state.
obj = get_deep_nested_literal();
assertKind(elements_kind.fast_smi_only, obj[1][0]);
obj[0][0] = 3.5;
@@ -428,6 +441,7 @@
return literal;
}
+ get_object_literal(); // Skip premonomorphic state.
obj = get_object_literal();
assertKind(elements_kind.fast_smi_only, obj.array);
obj.array[1] = 3.5;
@@ -443,6 +457,7 @@
return literal;
}
+ get_nested_object_literal(); // Skip premonomorphic state.
obj = get_nested_object_literal();
assertKind(elements_kind.fast, obj.array);
assertKind(elements_kind.fast_smi_only, obj.array[1]);
@@ -462,6 +477,7 @@
return literal;
}
+ get_nested_literal(); // Skip premonomorphic state.
obj = get_nested_literal();
assertKind(elements_kind.fast, obj);
obj[0][0] = 3.5;
@@ -477,6 +493,7 @@
return literal;
}
+ get_deep_nested_literal(); // Skip premonomorphic state.
obj = get_deep_nested_literal();
assertKind(elements_kind.fast_smi_only, obj[1][0]);
obj[0][0] = 3.5;
Index: test/mjsunit/array-constructor-feedback.js
===================================================================
--- test/mjsunit/array-constructor-feedback.js (revision 19345)
+++ test/mjsunit/array-constructor-feedback.js (working copy)
@@ -89,6 +89,7 @@
return new t(len);
}
+ bar(Array, 10); // Skip premonomorphic state.
a = bar(Array, 10);
a[0] = 3.5;
b = bar(Array, 1);
@@ -108,6 +109,8 @@
function bar0(t) {
return new t();
}
+
+ bar0(Array); // Skip premonomorphic state.
a = bar0(Array);
a[0] = 3.5;
b = bar0(Array);
@@ -139,6 +142,8 @@
function bar(len) {
return new Array(len);
}
+
+ bar(10); // Skip premonomorphic state.
a = bar(10);
a[0] = "a string";
a = bar(10);
@@ -190,6 +195,8 @@
function bar() {
return new Array();
}
+
+ bar(); // Skip premonomorphic state.
a = bar();
bar();
%OptimizeFunctionOnNextCall(bar);
--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
---
You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/groups/opt_out.