[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:
parent
4d0768dc4b
commit
1c7bdc7f6f
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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(
|
||||
|
@ -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.
|
||||
|
21
test/mjsunit/regress/regress-crbug-616709.js
Normal file
21
test/mjsunit/regress/regress-crbug-616709.js
Normal 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);
|
Loading…
Reference in New Issue
Block a user