Incorrect handling of HTransitionElementsKind in hydrogen check elimination phase fixed.
BUG=chromium:460917 LOG=Y Review URL: https://codereview.chromium.org/1000893003 Cr-Commit-Position: refs/heads/master@{#27154}
This commit is contained in:
parent
44c8c1bcfe
commit
0902b5f4df
@ -628,14 +628,23 @@ class HCheckTable : public ZoneObject {
|
||||
HValue* object = instr->object()->ActualValue();
|
||||
HCheckTableEntry* entry = Find(object);
|
||||
// Can only learn more about an object that already has a known set of maps.
|
||||
if (entry == NULL) return;
|
||||
if (entry == NULL) {
|
||||
Kill(object);
|
||||
return;
|
||||
}
|
||||
EnsureChecked(entry, object, instr);
|
||||
if (entry->maps_->Contains(instr->original_map())) {
|
||||
// If the object has the original map, it will be transitioned.
|
||||
UniqueSet<Map>* maps = entry->maps_->Copy(zone());
|
||||
maps->Remove(instr->original_map());
|
||||
maps->Add(instr->transitioned_map(), zone());
|
||||
entry->maps_ = maps;
|
||||
HCheckTableEntry::State state =
|
||||
(entry->state_ == HCheckTableEntry::CHECKED_STABLE &&
|
||||
instr->map_is_stable())
|
||||
? HCheckTableEntry::CHECKED_STABLE
|
||||
: HCheckTableEntry::CHECKED;
|
||||
Kill(object);
|
||||
Insert(object, NULL, maps, state);
|
||||
} else {
|
||||
// Object does not have the given map, thus the transition is redundant.
|
||||
instr->DeleteAndReplaceWith(object);
|
||||
|
@ -7297,8 +7297,13 @@ class HTransitionElementsKind FINAL : public HTemplateInstruction<2> {
|
||||
HValue* context() const { return OperandAt(1); }
|
||||
Unique<Map> original_map() const { return original_map_; }
|
||||
Unique<Map> transitioned_map() const { return transitioned_map_; }
|
||||
ElementsKind from_kind() const { return from_kind_; }
|
||||
ElementsKind to_kind() const { return to_kind_; }
|
||||
ElementsKind from_kind() const {
|
||||
return FromElementsKindField::decode(bit_field_);
|
||||
}
|
||||
ElementsKind to_kind() const {
|
||||
return ToElementsKindField::decode(bit_field_);
|
||||
}
|
||||
bool map_is_stable() const { return MapIsStableField::decode(bit_field_); }
|
||||
|
||||
std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
|
||||
|
||||
@ -7314,29 +7319,33 @@ class HTransitionElementsKind FINAL : public HTemplateInstruction<2> {
|
||||
int RedefinedOperandIndex() OVERRIDE { return 0; }
|
||||
|
||||
private:
|
||||
HTransitionElementsKind(HValue* context,
|
||||
HValue* object,
|
||||
HTransitionElementsKind(HValue* context, HValue* object,
|
||||
Handle<Map> original_map,
|
||||
Handle<Map> transitioned_map)
|
||||
: original_map_(Unique<Map>(original_map)),
|
||||
transitioned_map_(Unique<Map>(transitioned_map)),
|
||||
from_kind_(original_map->elements_kind()),
|
||||
to_kind_(transitioned_map->elements_kind()) {
|
||||
bit_field_(
|
||||
FromElementsKindField::encode(original_map->elements_kind()) |
|
||||
ToElementsKindField::encode(transitioned_map->elements_kind()) |
|
||||
MapIsStableField::encode(transitioned_map->is_stable())) {
|
||||
SetOperandAt(0, object);
|
||||
SetOperandAt(1, context);
|
||||
SetFlag(kUseGVN);
|
||||
SetChangesFlag(kElementsKind);
|
||||
if (!IsSimpleMapChangeTransition(from_kind_, to_kind_)) {
|
||||
if (!IsSimpleMapChangeTransition(from_kind(), to_kind())) {
|
||||
SetChangesFlag(kElementsPointer);
|
||||
SetChangesFlag(kNewSpacePromotion);
|
||||
}
|
||||
set_representation(Representation::Tagged());
|
||||
}
|
||||
|
||||
class FromElementsKindField : public BitField<ElementsKind, 0, 5> {};
|
||||
class ToElementsKindField : public BitField<ElementsKind, 5, 5> {};
|
||||
class MapIsStableField : public BitField<bool, 10, 1> {};
|
||||
|
||||
Unique<Map> original_map_;
|
||||
Unique<Map> transitioned_map_;
|
||||
ElementsKind from_kind_;
|
||||
ElementsKind to_kind_;
|
||||
uint32_t bit_field_;
|
||||
};
|
||||
|
||||
|
||||
|
35
test/mjsunit/regress/regress-460917.js
Normal file
35
test/mjsunit/regress/regress-460917.js
Normal file
@ -0,0 +1,35 @@
|
||||
// Copyright 2015 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
|
||||
|
||||
function boom(a1, a2) {
|
||||
// Do something with a2 that needs a map check (for DOUBLE_ELEMENTS).
|
||||
var s = a2[0];
|
||||
// Emit a load that transitions a1 to FAST_ELEMENTS.
|
||||
var t = a1[0];
|
||||
// Emit a store to a2 that assumes DOUBLE_ELEMENTS.
|
||||
// The map check is considered redundant and will be eliminated.
|
||||
a2[0] = 0.3;
|
||||
}
|
||||
|
||||
// Prepare type feedback for the "t = a1[0]" load: fast elements.
|
||||
var fast_elem = new Array(1);
|
||||
fast_elem[0] = "tagged";
|
||||
boom(fast_elem, [1]);
|
||||
|
||||
// Prepare type feedback for the "a2[0] = 0.3" store: double elements.
|
||||
var double_elem = new Array(1);
|
||||
double_elem[0] = 0.1;
|
||||
boom(double_elem, double_elem);
|
||||
|
||||
// Reset |double_elem| and go have a party.
|
||||
double_elem = new Array(10);
|
||||
double_elem[0] = 0.1;
|
||||
|
||||
%OptimizeFunctionOnNextCall(boom);
|
||||
boom(double_elem, double_elem);
|
||||
|
||||
assertEquals(0.3, double_elem[0]);
|
||||
assertEquals(undefined, double_elem[1]);
|
Loading…
Reference in New Issue
Block a user