Commit d949c646 authored by danno@chromium.org's avatar danno@chromium.org

Improve GVN handling of ElementTransitions.

BUG=
TEST=

Review URL: https://chromiumcodereview.appspot.com/9141016

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@10651 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent f833c403
......@@ -893,6 +893,13 @@ void HCheckInstanceType::GetCheckMaskAndTag(uint8_t* mask, uint8_t* tag) {
void HCheckMap::PrintDataTo(StringStream* stream) {
value()->PrintNameTo(stream);
stream->Add(" %p", *map());
if (mode() == REQUIRE_EXACT_MAP) {
stream->Add(" [EXACT]");
} else if (!has_element_transitions_) {
stream->Add(" [EXACT*]");
} else {
stream->Add(" [MATCH ELEMENTS]");
}
}
......
......@@ -186,6 +186,7 @@ class LChunkBuilder;
V(InobjectFields) \
V(BackingStoreFields) \
V(ElementsKind) \
V(ElementsPointer) \
V(ArrayElements) \
V(DoubleArrayElements) \
V(SpecializedArrayElements) \
......@@ -646,6 +647,18 @@ class HValue: public ZoneObject {
return gvn_flags_.ContainsAnyOf(AllObservableSideEffectsFlagSet());
}
GVNFlagSet DependsOnFlags() const {
GVNFlagSet result = gvn_flags_;
result.Intersect(AllDependsOnFlagSet());
return result;
}
GVNFlagSet SideEffectFlags() const {
GVNFlagSet result = gvn_flags_;
result.Intersect(AllSideEffectsFlagSet());
return result;
}
GVNFlagSet ChangesFlags() const {
GVNFlagSet result = gvn_flags_;
result.Intersect(AllChangesFlagSet());
......@@ -722,6 +735,15 @@ class HValue: public ZoneObject {
representation_ = r;
}
static GVNFlagSet AllDependsOnFlagSet() {
GVNFlagSet result;
// Create changes mask.
#define ADD_FLAG(type) result.Add(kDependsOn##type);
GVN_FLAG_LIST(ADD_FLAG)
#undef ADD_FLAG
return result;
}
static GVNFlagSet AllChangesFlagSet() {
GVNFlagSet result;
// Create changes mask.
......@@ -743,6 +765,8 @@ class HValue: public ZoneObject {
static GVNFlagSet AllObservableSideEffectsFlagSet() {
GVNFlagSet result = AllChangesFlagSet();
result.Remove(kChangesElementsKind);
result.Remove(kChangesElementsPointer);
result.Remove(kChangesMaps);
return result;
}
......@@ -1920,8 +1944,7 @@ class HLoadElements: public HUnaryOperation {
explicit HLoadElements(HValue* value) : HUnaryOperation(value) {
set_representation(Representation::Tagged());
SetFlag(kUseGVN);
SetGVNFlag(kDependsOnMaps);
SetGVNFlag(kDependsOnElementsKind);
SetGVNFlag(kDependsOnElementsPointer);
}
virtual Representation RequiredInputRepresentation(int index) {
......@@ -1972,6 +1995,11 @@ class HCheckMap: public HTemplateInstruction<2> {
set_representation(Representation::Tagged());
SetFlag(kUseGVN);
SetGVNFlag(kDependsOnMaps);
// If the map to check doesn't have the untransitioned elements, it must not
// be hoisted above TransitionElements instructions.
if (mode == REQUIRE_EXACT_MAP || !map->has_fast_smi_only_elements()) {
SetGVNFlag(kDependsOnElementsKind);
}
has_element_transitions_ =
map->LookupElementsTransitionMap(FAST_DOUBLE_ELEMENTS, NULL) != NULL ||
map->LookupElementsTransitionMap(FAST_ELEMENTS, NULL) != NULL;
......@@ -4135,7 +4163,17 @@ class HTransitionElementsKind: public HTemplateInstruction<1> {
transitioned_map_(transitioned_map) {
SetOperandAt(0, object);
SetFlag(kUseGVN);
SetGVNFlag(kDependsOnMaps);
SetGVNFlag(kChangesElementsKind);
if (original_map->has_fast_double_elements()) {
SetGVNFlag(kChangesElementsPointer);
SetGVNFlag(kDependsOnElementsPointer);
SetGVNFlag(kDependsOnDoubleArrayElements);
} else if (transitioned_map->has_fast_double_elements()) {
SetGVNFlag(kChangesElementsPointer);
SetGVNFlag(kDependsOnElementsPointer);
SetGVNFlag(kDependsOnArrayElements);
}
set_representation(Representation::Tagged());
}
......
This diff is collapsed.
......@@ -126,6 +126,7 @@ class HBasicBlock: public ZoneObject {
int PredecessorIndexOf(HBasicBlock* predecessor) const;
void AddSimulate(int ast_id) { AddInstruction(CreateSimulate(ast_id)); }
void AssignCommonDominator(HBasicBlock* other);
void AssignLoopSuccessorDominators();
void FinishExitWithDeoptimization(HDeoptimize::UseEnvironment has_uses) {
FinishExit(CreateDeoptimize(has_uses));
......@@ -149,6 +150,13 @@ class HBasicBlock: public ZoneObject {
bool IsDeoptimizing() const { return is_deoptimizing_; }
void MarkAsDeoptimizing() { is_deoptimizing_ = true; }
bool IsLoopSuccessorDominator() const {
return dominates_loop_successors_;
}
void MarkAsLoopSuccessorDominator() {
dominates_loop_successors_ = true;
}
inline Zone* zone();
#ifdef DEBUG
......@@ -182,6 +190,22 @@ class HBasicBlock: public ZoneObject {
HBasicBlock* parent_loop_header_;
bool is_inline_return_target_;
bool is_deoptimizing_;
bool dominates_loop_successors_;
};
class HPredecessorIterator BASE_EMBEDDED {
public:
explicit HPredecessorIterator(HBasicBlock* block)
: predecessor_list_(block->predecessors()), current_(0) { }
bool Done() { return current_ >= predecessor_list_->length(); }
HBasicBlock* Current() { return predecessor_list_->at(current_); }
void Advance() { current_++; }
private:
const ZoneList<HBasicBlock*>* predecessor_list_;
int current_;
};
......
......@@ -5511,7 +5511,7 @@ class PolymorphicCodeCacheHashTableKey : public HashTableKey {
for (int i = 0; i < maps_->length(); ++i) {
bool match_found = false;
for (int j = 0; j < other_maps.length(); ++j) {
if (maps_->at(i)->EquivalentTo(*other_maps.at(j))) {
if (*(maps_->at(i)) == *(other_maps.at(j))) {
match_found = true;
break;
}
......
......@@ -4696,12 +4696,6 @@ class Map: public HeapObject {
// The "shared" flags of both this map and |other| are ignored.
bool EquivalentToForNormalization(Map* other, PropertyNormalizationMode mode);
// Returns true if this map and |other| describe equivalent objects.
// The "shared" flags of both this map and |other| are ignored.
bool EquivalentTo(Map* other) {
return EquivalentToForNormalization(other, KEEP_INOBJECT_PROPERTIES);
}
// Returns the contents of this map's descriptor array for the given string.
// May return NULL. |safe_to_add_transition| is set to false and NULL
// is returned if adding transitions is not allowed.
......
// Copyright 2011 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Flags: --allow-natives-syntax --smi-only-arrays
// Ensure that ElementsKind transitions in various situations are hoisted (or
// not hoisted) correctly, don't change the semantics programs and don't trigger
// deopt through hoisting in important situations.
support_smi_only_arrays = %HasFastSmiOnlyElements(new Array(1,2,3,4,5,6));
if (support_smi_only_arrays) {
print("Tests include smi-only arrays.");
} else {
print("Tests do NOT include smi-only arrays.");
}
if (support_smi_only_arrays) {
// Make sure that a simple elements array transitions inside a loop before
// stores to an array gets hoisted in a way that doesn't generate a deopt in
// simple cases.}
function testDoubleConversion4(a) {
var object = new Object();
a[0] = 0;
var count = 3;
do {
a[0] = object;
} while (--count > 0);
}
testDoubleConversion4(new Array(5));
%OptimizeFunctionOnNextCall(testDoubleConversion4);
testDoubleConversion4(new Array(5));
testDoubleConversion4(new Array(5));
assertTrue(2 != %GetOptimizationStatus(testDoubleConversion4));
// Make sure that non-element related map checks that are not preceded by
// transitions in a loop still get hoisted in a way that doesn't generate a
// deopt in simple cases.
function testExactMapHoisting(a) {
var object = new Object();
a.foo = 0;
a[0] = 0;
a[1] = 1;
var count = 3;
do {
a.foo = object; // This map check should be hoistable
a[1] = object;
result = a.foo == object && a[1] == object;
} while (--count > 0);
}
testExactMapHoisting(new Array(5));
%OptimizeFunctionOnNextCall(testExactMapHoisting);
testExactMapHoisting(new Array(5));
testExactMapHoisting(new Array(5));
assertTrue(2 != %GetOptimizationStatus(testExactMapHoisting));
// Make sure that non-element related map checks do NOT get hoisted if they
// depend on an elements transition before them and it's not possible to hoist
// that transition.
function testExactMapHoisting2(a) {
var object = new Object();
a.foo = 0;
a[0] = 0;
a[1] = 1;
var count = 3;
do {
if (a.bar === undefined) {
a[1] = 2.5;
}
a.foo = object; // This map check should NOT be hoistable because it
// includes a check for the FAST_ELEMENTS map as well as
// the FAST_DOUBLE_ELEMENTS map, which depends on the
// double transition above in the if, which cannot be
// hoisted.
} while (--count > 0);
}
testExactMapHoisting2(new Array(5));
%OptimizeFunctionOnNextCall(testExactMapHoisting2);
testExactMapHoisting2(new Array(5));
testExactMapHoisting2(new Array(5));
assertTrue(2 != %GetOptimizationStatus(testExactMapHoisting2));
// Make sure that non-element related map checks do get hoisted if they use
// the transitioned map for the check and all transitions that they depend
// upon can hoisted, too.
function testExactMapHoisting3(a) {
var object = new Object();
a.foo = 0;
a[0] = 0;
a[1] = 1;
var count = 3;
do {
a[1] = 2.5;
a.foo = object; // This map check should be hoistable because all elements
// transitions in the loop can also be hoisted.
} while (--count > 0);
}
var add_transition = new Array(5);
add_transition.foo = 0;
add_transition[0] = new Object(); // For FAST_ELEMENT transition to be created
testExactMapHoisting3(new Array(5));
%OptimizeFunctionOnNextCall(testExactMapHoisting3);
testExactMapHoisting3(new Array(5));
testExactMapHoisting3(new Array(5));
assertTrue(2 != %GetOptimizationStatus(testExactMapHoisting3));
function testDominatingTransitionHoisting1(a) {
var object = new Object();
a[0] = 0;
var count = 3;
do {
if (a.baz != true) {
a[1] = 2.5;
}
a[0] = object;
} while (--count > 3);
}
testDominatingTransitionHoisting1(new Array(5));
%OptimizeFunctionOnNextCall(testDominatingTransitionHoisting1);
testDominatingTransitionHoisting1(new Array(5));
testDominatingTransitionHoisting1(new Array(5));
assertTrue(2 != %GetOptimizationStatus(testDominatingTransitionHoisting1));
function testHoistingWithSideEffect(a) {
var object = new Object();
a[0] = 0;
var count = 3;
do {
assertTrue(true);
a[0] = object;
} while (--count > 3);
}
testHoistingWithSideEffect(new Array(5));
%OptimizeFunctionOnNextCall(testHoistingWithSideEffect);
testHoistingWithSideEffect(new Array(5));
testHoistingWithSideEffect(new Array(5));
assertTrue(2 != %GetOptimizationStatus(testHoistingWithSideEffect));
}
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