Commit 7201bad9 authored by bmeurer's avatar bmeurer Committed by Commit bot

[turbofan] Properly deal with out-of-bounds fields in EscapeAnalysis.

Conflicting type feedback on Load/StoreICs can lead to out-of-bounds
field access, which is essentially dead code, but EscapeAnalysis was
confused about those. For now, mark the objects as escaping in these
cases, middle-term we want to deal better with this kind of compile-
time known dead code.

BUG=chromium:658185,v8:4586
R=jarin@chromium.org

Review-Url: https://codereview.chromium.org/2459273002
Cr-Commit-Position: refs/heads/master@{#40662}
parent b7aff1ff
...@@ -1399,7 +1399,20 @@ void EscapeAnalysis::ProcessLoadField(Node* node) { ...@@ -1399,7 +1399,20 @@ void EscapeAnalysis::ProcessLoadField(Node* node) {
if (VirtualObject* object = GetVirtualObject(state, from)) { if (VirtualObject* object = GetVirtualObject(state, from)) {
if (!object->IsTracked()) return; if (!object->IsTracked()) return;
int offset = OffsetForFieldAccess(node); int offset = OffsetForFieldAccess(node);
if (static_cast<size_t>(offset) >= object->field_count()) return; if (static_cast<size_t>(offset) >= object->field_count()) {
// We have a load from a field that is not inside the {object}. This
// can only happen with conflicting type feedback and for dead {node}s.
// For now, we just mark the {object} as escaping.
// TODO(turbofan): Consider introducing an Undefined or None operator
// that we can replace this load with, since we know it's dead code.
if (status_analysis_->SetEscaped(from)) {
TRACE(
"Setting #%d (%s) to escaped because load field #%d from "
"offset %d outside of object\n",
from->id(), from->op()->mnemonic(), node->id(), offset);
}
return;
}
Node* value = object->GetField(offset); Node* value = object->GetField(offset);
if (value) { if (value) {
value = ResolveReplacement(value); value = ResolveReplacement(value);
...@@ -1464,7 +1477,20 @@ void EscapeAnalysis::ProcessStoreField(Node* node) { ...@@ -1464,7 +1477,20 @@ void EscapeAnalysis::ProcessStoreField(Node* node) {
if (VirtualObject* object = GetVirtualObject(state, to)) { if (VirtualObject* object = GetVirtualObject(state, to)) {
if (!object->IsTracked()) return; if (!object->IsTracked()) return;
int offset = OffsetForFieldAccess(node); int offset = OffsetForFieldAccess(node);
if (static_cast<size_t>(offset) >= object->field_count()) return; if (static_cast<size_t>(offset) >= object->field_count()) {
// We have a store to a field that is not inside the {object}. This
// can only happen with conflicting type feedback and for dead {node}s.
// For now, we just mark the {object} as escaping.
// TODO(turbofan): Consider just eliminating the store in the reducer
// pass, as it's dead code anyways.
if (status_analysis_->SetEscaped(to)) {
TRACE(
"Setting #%d (%s) to escaped because store field #%d to "
"offset %d outside of object\n",
to->id(), to->op()->mnemonic(), node->id(), offset);
}
return;
}
Node* val = ResolveReplacement(NodeProperties::GetValueInput(node, 1)); Node* val = ResolveReplacement(NodeProperties::GetValueInput(node, 1));
// TODO(mstarzinger): The following is a workaround to not track some well // TODO(mstarzinger): The following is a workaround to not track some well
// known raw fields. We only ever store default initial values into these // known raw fields. We only ever store default initial values into these
......
// 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 --turbo-escape
var t = 0;
function foo() {
var o = {x:1};
var p = {y:2.5, x:0};
o = [];
for (var i = 0; i < 2; ++i) {
t = o.x;
o = p;
}
}
foo();
foo();
%OptimizeFunctionOnNextCall(foo);
foo();
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