Reviewers: Hannes Payer,
Message:
PTAL
Description:
Avoid dynamic initial map check when inlining call-new.
This improves check elimination and removes a load plus
a map check for every inlined call-new.
Please review this at https://codereview.chromium.org/293223002/
SVN Base: https://v8.googlecode.com/svn/branches/bleeding_edge
Affected files (+26, -21 lines):
M src/hydrogen.cc
M src/objects.h
M src/objects.cc
Index: src/hydrogen.cc
diff --git a/src/hydrogen.cc b/src/hydrogen.cc
index
5d78a4a2e33158d23e0a3d560251b1929ef40f67..5ae72194ae82449f0b36068792cb665df04f37bd
100644
--- a/src/hydrogen.cc
+++ b/src/hydrogen.cc
@@ -8610,25 +8610,16 @@ void HOptimizedGraphBuilder::VisitCallNew(CallNew*
expr) {
}
}
- HAllocate* receiver =
- BuildAllocate(size_in_bytes, HType::JSObject(), JS_OBJECT_TYPE,
- allocation_mode);
+ HAllocate* receiver = BuildAllocate(
+ size_in_bytes, HType::JSObject(), JS_OBJECT_TYPE, allocation_mode);
receiver->set_known_initial_map(initial_map);
- // Load the initial map from the constructor.
- HValue* constructor_value = Add<HConstant>(constructor);
- HValue* initial_map_value =
- Add<HLoadNamedField>(constructor_value, static_cast<HValue*>(NULL),
- HObjectAccess::ForMapAndOffset(
- handle(constructor->map()),
- JSFunction::kPrototypeOrInitialMapOffset));
-
// Initialize map and fields of the newly allocated object.
{ NoObservableSideEffectsScope no_effects(this);
ASSERT(initial_map->instance_type() == JS_OBJECT_TYPE);
Add<HStoreNamedField>(receiver,
HObjectAccess::ForMapAndOffset(initial_map,
JSObject::kMapOffset),
- initial_map_value);
+ Add<HConstant>(initial_map));
HValue* empty_fixed_array =
Add<HConstant>(factory->empty_fixed_array());
Add<HStoreNamedField>(receiver,
HObjectAccess::ForMapAndOffset(initial_map,
@@ -8655,21 +8646,25 @@ void HOptimizedGraphBuilder::VisitCallNew(CallNew*
expr) {
ASSERT(environment()->ExpressionStackAt(receiver_index) == function);
environment()->SetExpressionStackAt(receiver_index, receiver);
- if (TryInlineConstruct(expr, receiver)) return;
+ if (TryInlineConstruct(expr, receiver)) {
+ // Inlining worked, add a dependency on the initial map to make sure
that
+ // this code is deoptimized whenever the initial map of the
constructor
+ // changes.
+ Map::AddDependentCompilationInfo(
+ initial_map, DependentCode::kInitialMapChangedGroup, top_info());
+ return;
+ }
// TODO(mstarzinger): For now we remove the previous HAllocate and all
// corresponding instructions and instead add HPushArgument for the
// arguments in case inlining failed. What we actually should do is
for
// inlining to try to build a subgraph without mutating the parent
graph.
HInstruction* instr = current_block()->last();
- while (instr != initial_map_value) {
+ do {
HInstruction* prev_instr = instr->previous();
instr->DeleteAndReplaceWith(NULL);
instr = prev_instr;
- }
- initial_map_value->DeleteAndReplaceWith(NULL);
- receiver->DeleteAndReplaceWith(NULL);
- check->DeleteAndReplaceWith(NULL);
+ } while (instr != check);
environment()->SetExpressionStackAt(receiver_index, function);
HInstruction* call =
PreProcessCall(New<HCallNew>(function, argument_count));
Index: src/objects.cc
diff --git a/src/objects.cc b/src/objects.cc
index
352e5d6508d5465728352992d9a974e7bafeea16..744af1845a7b6b25bba80abcabff67b8d69f527f
100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -10210,6 +10210,8 @@ Handle<Object> CacheInitialJSArrayMaps(
void JSFunction::SetInstancePrototype(Handle<JSFunction> function,
Handle<Object> value) {
+ Isolate* isolate = function->GetIsolate();
+
ASSERT(value->IsJSReceiver());
// First some logic for the map of the prototype to make sure it is in
fast
@@ -10228,7 +10230,8 @@ void
JSFunction::SetInstancePrototype(Handle<JSFunction> function,
if (function->shared()->IsInobjectSlackTrackingInProgress()) {
function->shared()->CompleteInobjectSlackTracking();
}
- Handle<Map> new_map = Map::Copy(handle(function->initial_map()));
+ Handle<Map> initial_map(function->initial_map(), isolate);
+ Handle<Map> new_map = Map::Copy(initial_map);
new_map->set_prototype(*value);
// If the function is used as the global Array function, cache the
@@ -10237,17 +10240,21 @@ void
JSFunction::SetInstancePrototype(Handle<JSFunction> function,
Object* array_function =
native_context->get(Context::ARRAY_FUNCTION_INDEX);
if (array_function->IsJSFunction() &&
*function == JSFunction::cast(array_function)) {
- CacheInitialJSArrayMaps(handle(native_context), new_map);
+ CacheInitialJSArrayMaps(handle(native_context, isolate), new_map);
}
function->set_initial_map(*new_map);
+
+ // Deoptimize all code that embeds the previous initial map.
+ initial_map->dependent_code()->DeoptimizeDependentCodeGroup(
+ isolate, DependentCode::kInitialMapChangedGroup);
} else {
// Put the value in the initial map field until an initial map is
// needed. At that point, a new initial map is created and the
// prototype is put into the initial map where it belongs.
function->set_prototype_or_initial_map(*value);
}
- function->GetHeap()->ClearInstanceofCache();
+ isolate->heap()->ClearInstanceofCache();
}
Index: src/objects.h
diff --git a/src/objects.h b/src/objects.h
index
47fea39e4d9e7566646541c0cd8869ef743b3251..f472757311ab4ef6c819ddb749b331d3fddbfef7
100644
--- a/src/objects.h
+++ b/src/objects.h
@@ -5884,6 +5884,9 @@ class DependentCode: public FixedArray {
// Group of code that omit run-time type checks for the field(s)
introduced
// by this map.
kFieldTypeGroup,
+ // Group of code that omit run-time type checks for initial maps of
+ // constructors.
+ kInitialMapChangedGroup,
// Group of code that depends on tenuring information in
AllocationSites
// not being changed.
kAllocationSiteTenuringChangedGroup,
--
--
v8-dev mailing list
v8-dev@googlegroups.com
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 v8-dev+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.