Immediately "optimize as prototype" when setting as prototype of a function.

This saves space since OptimizeAsPrototype detaches from the transition tree, reclaiming intermediate maps. On gmail this corresponds to roughly 20% of all maps.

BUG=

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

Cr-Commit-Position: refs/heads/master@{#26772}
This commit is contained in:
verwaest 2015-02-20 04:23:54 -08:00 committed by Commit bot
parent f4bd25da69
commit fade797d02

View File

@ -10033,6 +10033,41 @@ void SharedFunctionInfo::TrimOptimizedCodeMap(int shrink_by) {
} }
static void GetMinInobjectSlack(Map* map, void* data) {
int slack = map->unused_property_fields();
if (*reinterpret_cast<int*>(data) > slack) {
*reinterpret_cast<int*>(data) = slack;
}
}
static void ShrinkInstanceSize(Map* map, void* data) {
int slack = *reinterpret_cast<int*>(data);
map->set_inobject_properties(map->inobject_properties() - slack);
map->set_unused_property_fields(map->unused_property_fields() - slack);
map->set_instance_size(map->instance_size() - slack * kPointerSize);
// Visitor id might depend on the instance size, recalculate it.
map->set_visitor_id(StaticVisitorBase::GetVisitorId(map));
}
void JSFunction::CompleteInobjectSlackTracking() {
DCHECK(has_initial_map());
Map* map = initial_map();
DCHECK(map->counter() >= Map::kSlackTrackingCounterEnd - 1);
map->set_counter(Map::kRetainingCounterStart);
int slack = map->unused_property_fields();
map->TraverseTransitionTree(&GetMinInobjectSlack, &slack);
if (slack != 0) {
// Resize the initial map and all maps in its transition tree.
map->TraverseTransitionTree(&ShrinkInstanceSize, &slack);
}
}
void JSObject::OptimizeAsPrototype(Handle<JSObject> object, void JSObject::OptimizeAsPrototype(Handle<JSObject> object,
PrototypeOptimizationMode mode) { PrototypeOptimizationMode mode) {
if (object->IsGlobalObject()) return; if (object->IsGlobalObject()) return;
@ -10224,6 +10259,11 @@ void JSFunction::SetInstancePrototype(Handle<JSFunction> function,
// needed. At that point, a new initial map is created and the // needed. At that point, a new initial map is created and the
// prototype is put into the initial map where it belongs. // prototype is put into the initial map where it belongs.
function->set_prototype_or_initial_map(*value); function->set_prototype_or_initial_map(*value);
if (value->IsJSObject()) {
// Optimize as prototype to detach it from its transition tree.
JSObject::OptimizeAsPrototype(Handle<JSObject>::cast(value),
FAST_PROTOTYPE);
}
} }
isolate->heap()->ClearInstanceofCache(); isolate->heap()->ClearInstanceofCache();
} }
@ -10766,41 +10806,6 @@ void SharedFunctionInfo::ResetForNewContext(int new_ic_age) {
} }
static void GetMinInobjectSlack(Map* map, void* data) {
int slack = map->unused_property_fields();
if (*reinterpret_cast<int*>(data) > slack) {
*reinterpret_cast<int*>(data) = slack;
}
}
static void ShrinkInstanceSize(Map* map, void* data) {
int slack = *reinterpret_cast<int*>(data);
map->set_inobject_properties(map->inobject_properties() - slack);
map->set_unused_property_fields(map->unused_property_fields() - slack);
map->set_instance_size(map->instance_size() - slack * kPointerSize);
// Visitor id might depend on the instance size, recalculate it.
map->set_visitor_id(StaticVisitorBase::GetVisitorId(map));
}
void JSFunction::CompleteInobjectSlackTracking() {
DCHECK(has_initial_map());
Map* map = initial_map();
DCHECK(map->counter() >= Map::kSlackTrackingCounterEnd - 1);
map->set_counter(Map::kRetainingCounterStart);
int slack = map->unused_property_fields();
map->TraverseTransitionTree(&GetMinInobjectSlack, &slack);
if (slack != 0) {
// Resize the initial map and all maps in its transition tree.
map->TraverseTransitionTree(&ShrinkInstanceSize, &slack);
}
}
int SharedFunctionInfo::SearchOptimizedCodeMap(Context* native_context, int SharedFunctionInfo::SearchOptimizedCodeMap(Context* native_context,
BailoutId osr_ast_id) { BailoutId osr_ast_id) {
DisallowHeapAllocation no_gc; DisallowHeapAllocation no_gc;