[turbofan] Properly handle dictionary maps in the prototype chain.

Dictionary prototypes don't have stable maps, but still don't matter for
element access. Generalized the JSNativeContextSpecialization a bit to
handle everything that Crankshaft can handle in this regard.

R=jarin@chromium.org
BUG=chromium:616709

Review-Url: https://codereview.chromium.org/2067423003
Cr-Commit-Position: refs/heads/master@{#37019}
This commit is contained in:
bmeurer 2016-06-15 22:24:33 -07:00 committed by Commit bot
parent 4d0768dc4b
commit 1c7bdc7f6f
5 changed files with 60 additions and 31 deletions

View File

@ -124,20 +124,6 @@ void CompilationDependencies::AssumeMapStable(Handle<Map> map) {
}
void CompilationDependencies::AssumePrototypeMapsStable(
Handle<Map> map, MaybeHandle<JSReceiver> prototype) {
for (PrototypeIterator i(map); !i.IsAtEnd(); i.Advance()) {
Handle<JSReceiver> const current =
PrototypeIterator::GetCurrent<JSReceiver>(i);
AssumeMapStable(handle(current->map()));
Handle<JSReceiver> last;
if (prototype.ToHandle(&last) && last.is_identical_to(current)) {
break;
}
}
}
void CompilationDependencies::AssumeTransitionStable(
Handle<AllocationSite> site) {
// Do nothing if the object doesn't have any useful element transitions left.

View File

@ -32,9 +32,6 @@ class CompilationDependencies {
Insert(DependentCode::kFieldTypeGroup, map);
}
void AssumeMapStable(Handle<Map> map);
void AssumePrototypeMapsStable(
Handle<Map> map,
MaybeHandle<JSReceiver> prototype = MaybeHandle<JSReceiver>());
void AssumeMapNotDeprecated(Handle<Map> map);
void AssumePropertyCell(Handle<PropertyCell> cell) {
Insert(DependentCode::kPropertyCellChangedGroup, cell);

View File

@ -225,7 +225,8 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess(
// Determine actual holder and perform prototype chain checks.
Handle<JSObject> holder;
if (access_info.holder().ToHandle(&holder)) {
AssumePrototypesStable(receiver_type, native_context, holder);
this_effect = CheckPrototypeMaps(receiver_type, native_context, holder,
this_effect, this_control);
}
// Generate the actual property access.
@ -668,7 +669,8 @@ Reduction JSNativeContextSpecialization::ReduceElementAccess(
// not compatible with (monomorphic) keyed stores.
Handle<JSObject> holder;
if (access_info.holder().ToHandle(&holder)) {
AssumePrototypesStable(receiver_type, native_context, holder);
this_effect = CheckPrototypeMaps(receiver_type, native_context, holder,
this_effect, this_control);
}
// TODO(bmeurer): We currently specialize based on elements kind. We should
@ -753,8 +755,9 @@ Reduction JSNativeContextSpecialization::ReduceElementAccess(
if (receiver_type->NowIs(initial_holey_array_type) &&
isolate()->IsFastArrayConstructorPrototypeChainIntact()) {
// Add a code dependency on the array protector cell.
AssumePrototypesStable(receiver_type, native_context,
isolate()->initial_object_prototype());
this_effect = CheckPrototypeMaps(
receiver_type, native_context,
isolate()->initial_object_prototype(), this_effect, this_control);
dependencies()->AssumePropertyCell(factory()->array_protector());
// Turn the hole into undefined.
mode = CheckTaggedHoleMode::kConvertHoleToUndefined;
@ -772,8 +775,9 @@ Reduction JSNativeContextSpecialization::ReduceElementAccess(
if (receiver_type->NowIs(initial_holey_array_type) &&
isolate()->IsFastArrayConstructorPrototypeChainIntact()) {
// Add a code dependency on the array protector cell.
AssumePrototypesStable(receiver_type, native_context,
isolate()->initial_object_prototype());
this_effect = CheckPrototypeMaps(
receiver_type, native_context,
isolate()->initial_object_prototype(), this_effect, this_control);
dependencies()->AssumePropertyCell(factory()->array_protector());
// Return the signaling NaN hole directly if all uses are truncating.
mode = CheckFloat64HoleMode::kAllowReturnHole;
@ -956,10 +960,9 @@ Reduction JSNativeContextSpecialization::ReduceJSStoreProperty(Node* node) {
p.language_mode(), store_mode);
}
void JSNativeContextSpecialization::AssumePrototypesStable(
Node* JSNativeContextSpecialization::CheckPrototypeMaps(
Type* receiver_type, Handle<Context> native_context,
Handle<JSObject> holder) {
Handle<JSObject> holder, Node* effect, Node* control) {
// Determine actual holder and perform prototype chain checks.
for (auto i = receiver_type->Classes(); !i.Done(); i.Advance()) {
Handle<Map> map = i.Current();
@ -970,8 +973,28 @@ void JSNativeContextSpecialization::AssumePrototypesStable(
.ToHandle(&constructor)) {
map = handle(constructor->initial_map(), isolate());
}
dependencies()->AssumePrototypeMapsStable(map, holder);
for (PrototypeIterator j(map); !j.IsAtEnd(); j.Advance()) {
Handle<JSReceiver> const current =
PrototypeIterator::GetCurrent<JSReceiver>(j);
Handle<Map> current_map(current->map(), isolate());
if (current_map->is_stable()) {
dependencies()->AssumeMapStable(current_map);
} else {
// TODO(bmeurer): Introduce a dedicated CheckMaps operator.
Node* prototype = jsgraph()->HeapConstant(current);
Node* prototype_map = effect =
graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
prototype, effect, control);
Node* check = graph()->NewNode(
simplified()->ReferenceEqual(Type::Internal()), prototype_map,
jsgraph()->HeapConstant(current_map));
effect =
graph()->NewNode(simplified()->CheckIf(), check, effect, control);
}
if (holder.is_identical_to(current)) break;
}
}
return effect;
}
bool JSNativeContextSpecialization::ExtractReceiverMaps(

View File

@ -80,10 +80,12 @@ class JSNativeContextSpecialization final : public AdvancedReducer {
Reduction ReduceSoftDeoptimize(Node* node);
// Adds stability dependencies on all prototypes of every class in
// {receiver_type} up to (and including) the {holder}.
void AssumePrototypesStable(Type* receiver_type,
Handle<Context> native_context,
Handle<JSObject> holder);
// {receiver_type} up to (and including) the {holder} if the maps
// are stable, otherwise falls back to inserting runtime map checks
// on the prototypes.
Node* CheckPrototypeMaps(Type* receiver_type, Handle<Context> native_context,
Handle<JSObject> holder, Node* effect,
Node* control);
// Extract receiver maps from {nexus} and filter based on {receiver} if
// possible.

View File

@ -0,0 +1,21 @@
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --allow-natives-syntax
// Make the Object prototype have dictionary properties.
for (var i = 0; i < 2000; i++) {
Object.prototype['X'+i] = true;
}
function boom(a1) {
return a1[0];
}
var a = new Array(1);
a[0] = 0.1;
boom(a);
boom(a);
%OptimizeFunctionOnNextCall(boom);
boom(a);