Commit a56bbe92 authored by bmeurer@chromium.org's avatar bmeurer@chromium.org

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.

R=hpayer@chromium.org

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

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@21458 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 4b9c0305
......@@ -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));
......
......@@ -10212,6 +10212,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
......@@ -10230,7 +10232,8 @@ void JSFunction::SetInstancePrototype(Handle<JSFunction> function,
if (function->IsInobjectSlackTrackingInProgress()) {
function->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
......@@ -10239,17 +10242,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();
}
......
......@@ -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,
......
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