Commit 77130247 authored by bmeurer@chromium.org's avatar bmeurer@chromium.org

Handle HCheckInstanceType and HIsStringAndBranch in check elimination.

R=ishell@chromium.org

Committed: https://code.google.com/p/v8/source/detail?r=21593

Review URL: https://codereview.chromium.org/300423003

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@21606 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 97e55098
......@@ -104,6 +104,10 @@ class HCheckTable : public ZoneObject {
ReduceCompareObjectEqAndBranch(HCompareObjectEqAndBranch::cast(instr));
break;
}
case HValue::kIsStringAndBranch: {
ReduceIsStringAndBranch(HIsStringAndBranch::cast(instr));
break;
}
case HValue::kTransitionElementsKind: {
ReduceTransitionElementsKind(
HTransitionElementsKind::cast(instr));
......@@ -113,6 +117,10 @@ class HCheckTable : public ZoneObject {
ReduceCheckHeapObject(HCheckHeapObject::cast(instr));
break;
}
case HValue::kCheckInstanceType: {
ReduceCheckInstanceType(HCheckInstanceType::cast(instr));
break;
}
default: {
// If the instruction changes maps uncontrollably, drop everything.
if (instr->CheckChangesFlag(kOsrEntries)) {
......@@ -125,7 +133,7 @@ class HCheckTable : public ZoneObject {
}
}
// Improvements possible:
// - eliminate redundant HCheckSmi, HCheckInstanceType instructions
// - eliminate redundant HCheckSmi instructions
// - track which values have been HCheckHeapObject'd
}
......@@ -261,6 +269,28 @@ class HCheckTable : public ZoneObject {
ASSERT_NE(HCheckTableEntry::UNCHECKED_STABLE, re->state_);
}
learned = true;
} else if (end->IsIsStringAndBranch()) {
HIsStringAndBranch* cmp = HIsStringAndBranch::cast(end);
HValue* object = cmp->value()->ActualValue();
HCheckTableEntry* entry = copy->Find(object);
if (is_true_branch) {
// Learn on the true branch of if(IsString(x)).
if (entry == NULL) {
copy->Insert(object, NULL, string_maps(),
HCheckTableEntry::CHECKED);
} else {
EnsureChecked(entry, object, cmp);
entry->maps_ = entry->maps_->Intersect(string_maps(), zone);
ASSERT_NE(HCheckTableEntry::UNCHECKED_STABLE, entry->state_);
}
} else {
// Learn on the false branch of if(IsString(x)).
if (entry != NULL) {
EnsureChecked(entry, object, cmp);
entry->maps_ = entry->maps_->Subtract(string_maps(), zone);
ASSERT_NE(HCheckTableEntry::UNCHECKED_STABLE, entry->state_);
}
}
}
// Learning on false branches requires storing negative facts.
}
......@@ -415,6 +445,50 @@ class HCheckTable : public ZoneObject {
}
}
void ReduceCheckInstanceType(HCheckInstanceType* instr) {
HValue* value = instr->value()->ActualValue();
HCheckTableEntry* entry = Find(value);
if (entry == NULL) {
if (instr->check() == HCheckInstanceType::IS_STRING) {
Insert(value, NULL, string_maps(), HCheckTableEntry::CHECKED);
}
return;
}
UniqueSet<Map>* maps = new(zone()) UniqueSet<Map>(
entry->maps_->size(), zone());
for (int i = 0; i < entry->maps_->size(); ++i) {
InstanceType type;
Unique<Map> map = entry->maps_->at(i);
{
// This is safe, because maps don't move and their instance type does
// not change.
AllowHandleDereference allow_deref;
type = map.handle()->instance_type();
}
if (instr->is_interval_check()) {
InstanceType first_type, last_type;
instr->GetCheckInterval(&first_type, &last_type);
if (first_type <= type && type <= last_type) maps->Add(map, zone());
} else {
uint8_t mask, tag;
instr->GetCheckMaskAndTag(&mask, &tag);
if ((type & mask) == tag) maps->Add(map, zone());
}
}
if (maps->size() == entry->maps_->size()) {
TRACE(("Removing redundant CheckInstanceType #%d at B%d\n",
instr->id(), instr->block()->block_id()));
EnsureChecked(entry, value, instr);
instr->DeleteAndReplaceWith(value);
INC_STAT(removed_cit_);
} else if (maps->size() != 0) {
entry->maps_ = maps;
if (entry->state_ == HCheckTableEntry::UNCHECKED_STABLE) {
entry->state_ = HCheckTableEntry::CHECKED_STABLE;
}
}
}
void ReduceLoadNamedField(HLoadNamedField* instr) {
// Reduce a load of the map field when it is known to be a constant.
if (!instr->access().IsMap()) {
......@@ -528,6 +602,28 @@ class HCheckTable : public ZoneObject {
instr->block()->MarkSuccEdgeUnreachable(unreachable_succ);
}
void ReduceIsStringAndBranch(HIsStringAndBranch* instr) {
HValue* value = instr->value()->ActualValue();
HCheckTableEntry* entry = Find(value);
if (entry == NULL) return;
EnsureChecked(entry, value, instr);
int succ;
if (entry->maps_->IsSubset(string_maps())) {
TRACE(("Marking redundant IsStringAndBranch #%d at B%d as true\n",
instr->id(), instr->block()->block_id()));
succ = 0;
} else {
MapSet intersection = entry->maps_->Intersect(string_maps(), zone());
if (intersection->size() > 0) return;
TRACE(("Marking redundant IsStringAndBranch #%d at B%d as false\n",
instr->id(), instr->block()->block_id()));
succ = 1;
}
instr->set_known_successor_index(succ);
int unreachable_succ = 1 - succ;
instr->block()->MarkSuccEdgeUnreachable(unreachable_succ);
}
void ReduceTransitionElementsKind(HTransitionElementsKind* instr) {
HValue* object = instr->object()->ActualValue();
HCheckTableEntry* entry = Find(object);
......@@ -688,6 +784,7 @@ class HCheckTable : public ZoneObject {
}
Zone* zone() const { return phase_->zone(); }
MapSet string_maps() const { return phase_->string_maps(); }
friend class HCheckMapsEffects;
friend class HCheckEliminationPhase;
......@@ -794,6 +891,7 @@ void HCheckEliminationPhase::PrintStats() {
PRINT_STAT(redundant);
PRINT_STAT(removed);
PRINT_STAT(removed_cho);
PRINT_STAT(removed_cit);
PRINT_STAT(narrowed);
PRINT_STAT(loads);
PRINT_STAT(empty);
......
......@@ -16,11 +16,20 @@ namespace internal {
class HCheckEliminationPhase : public HPhase {
public:
explicit HCheckEliminationPhase(HGraph* graph)
: HPhase("H_Check Elimination", graph), aliasing_() {
: HPhase("H_Check Elimination", graph), aliasing_(),
string_maps_(kStringMapsSize, zone()) {
// Compute the set of string maps.
#define ADD_STRING_MAP(type, size, name, Name) \
string_maps_.Add(Unique<Map>::CreateImmovable( \
graph->isolate()->factory()->name##_map()), zone());
STRING_TYPE_LIST(ADD_STRING_MAP)
#undef ADD_STRING_MAP
ASSERT_EQ(kStringMapsSize, string_maps_.size());
#ifdef DEBUG
redundant_ = 0;
removed_ = 0;
removed_cho_ = 0;
removed_cit_ = 0;
narrowed_ = 0;
loads_ = 0;
empty_ = 0;
......@@ -35,13 +44,20 @@ class HCheckEliminationPhase : public HPhase {
friend class HCheckTable;
private:
const UniqueSet<Map>* string_maps() const { return &string_maps_; }
void PrintStats();
HAliasAnalyzer* aliasing_;
#define COUNT(type, size, name, Name) + 1
static const int kStringMapsSize = 0 STRING_TYPE_LIST(COUNT);
#undef COUNT
UniqueSet<Map> string_maps_;
#ifdef DEBUG
int redundant_;
int removed_;
int removed_cho_;
int removed_cit_;
int narrowed_;
int loads_;
int empty_;
......
......@@ -3256,11 +3256,27 @@ bool HIsObjectAndBranch::KnownSuccessorBlock(HBasicBlock** block) {
bool HIsStringAndBranch::KnownSuccessorBlock(HBasicBlock** block) {
if (known_successor_index() != kNoKnownSuccessorIndex) {
*block = SuccessorAt(known_successor_index());
return true;
}
if (FLAG_fold_constants && value()->IsConstant()) {
*block = HConstant::cast(value())->HasStringValue()
? FirstSuccessor() : SecondSuccessor();
return true;
}
if (value()->type().IsString()) {
*block = FirstSuccessor();
return true;
}
if (value()->type().IsSmi() ||
value()->type().IsNull() ||
value()->type().IsBoolean() ||
value()->type().IsUndefined() ||
value()->type().IsJSObject()) {
*block = SecondSuccessor();
return true;
}
*block = NULL;
return false;
}
......
......@@ -2909,6 +2909,8 @@ class HCheckInstanceType V8_FINAL : public HUnaryOperation {
void GetCheckInterval(InstanceType* first, InstanceType* last);
void GetCheckMaskAndTag(uint8_t* mask, uint8_t* tag);
Check check() const { return check_; }
DECLARE_CONCRETE_INSTRUCTION(CheckInstanceType)
protected:
......@@ -4425,6 +4427,12 @@ class HIsStringAndBranch V8_FINAL : public HUnaryControlInstruction {
virtual bool KnownSuccessorBlock(HBasicBlock** block) V8_OVERRIDE;
static const int kNoKnownSuccessorIndex = -1;
int known_successor_index() const { return known_successor_index_; }
void set_known_successor_index(int known_successor_index) {
known_successor_index_ = known_successor_index;
}
DECLARE_CONCRETE_INSTRUCTION(IsStringAndBranch)
protected:
......@@ -4434,7 +4442,10 @@ class HIsStringAndBranch V8_FINAL : public HUnaryControlInstruction {
HIsStringAndBranch(HValue* value,
HBasicBlock* true_target = NULL,
HBasicBlock* false_target = NULL)
: HUnaryControlInstruction(value, true_target, false_target) {}
: HUnaryControlInstruction(value, true_target, false_target),
known_successor_index_(kNoKnownSuccessorIndex) { }
int known_successor_index_;
};
......
......@@ -275,6 +275,26 @@ class UniqueSet V8_FINAL : public ZoneObject {
return out;
}
// Returns a new set representing all elements from this set which are not in
// that set. O(|this| * |that|).
UniqueSet<T>* Subtract(const UniqueSet<T>* that, Zone* zone) const {
if (that->size_ == 0) return this->Copy(zone);
UniqueSet<T>* out = new(zone) UniqueSet<T>(this->size_, zone);
int i = 0, j = 0;
while (i < this->size_) {
Unique<T> cand = this->array_[i];
if (!that->Contains(cand)) {
out->array_[j++] = cand;
}
i++;
}
out->size_ = j;
return out;
}
// Makes an exact copy of this set. O(|this|).
UniqueSet<T>* Copy(Zone* zone) const {
UniqueSet<T>* copy = new(zone) UniqueSet<T>(this->size_, zone);
......
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