| Index: src/hydrogen-load-elimination.cc
|
| diff --git a/src/hydrogen-load-elimination.cc b/src/hydrogen-load-elimination.cc
|
| index f2e993b18dea2305884acd01274f85edab887260..f84eac046b5d88297ba9d75eda72c57e356037af 100644
|
| --- a/src/hydrogen-load-elimination.cc
|
| +++ b/src/hydrogen-load-elimination.cc
|
| @@ -76,7 +76,9 @@ class HLoadEliminationTable : public ZoneObject {
|
| FieldOf(l->access()),
|
| l->object()->ActualValue()->id()));
|
| HValue* result = load(l);
|
| - if (result != instr) {
|
| + if (result != instr &&
|
| + result->type().Equals(instr->type()) &&
|
| + result->representation().Equals(instr->representation())) {
|
| // The load can be replaced with a previous load or a value.
|
| TRACE((" replace L%d -> v%d\n", instr->id(), result->id()));
|
| instr->DeleteAndReplaceWith(result);
|
| @@ -98,26 +100,33 @@ class HLoadEliminationTable : public ZoneObject {
|
| }
|
| break;
|
| }
|
| + case HValue::kTransitionElementsKind: {
|
| + HTransitionElementsKind* t = HTransitionElementsKind::cast(instr);
|
| + HValue* object = t->object()->ActualValue();
|
| + KillFieldInternal(object, FieldOf(JSArray::kElementsOffset), NULL);
|
| + KillFieldInternal(object, FieldOf(JSObject::kMapOffset), NULL);
|
| + break;
|
| + }
|
| default: {
|
| - if (instr->CheckGVNFlag(kChangesInobjectFields)) {
|
| + if (instr->CheckChangesFlag(kInobjectFields)) {
|
| TRACE((" kill-all i%d\n", instr->id()));
|
| Kill();
|
| break;
|
| }
|
| - if (instr->CheckGVNFlag(kChangesMaps)) {
|
| + if (instr->CheckChangesFlag(kMaps)) {
|
| TRACE((" kill-maps i%d\n", instr->id()));
|
| KillOffset(JSObject::kMapOffset);
|
| }
|
| - if (instr->CheckGVNFlag(kChangesElementsKind)) {
|
| + if (instr->CheckChangesFlag(kElementsKind)) {
|
| TRACE((" kill-elements-kind i%d\n", instr->id()));
|
| KillOffset(JSObject::kMapOffset);
|
| KillOffset(JSObject::kElementsOffset);
|
| }
|
| - if (instr->CheckGVNFlag(kChangesElementsPointer)) {
|
| + if (instr->CheckChangesFlag(kElementsPointer)) {
|
| TRACE((" kill-elements i%d\n", instr->id()));
|
| KillOffset(JSObject::kElementsOffset);
|
| }
|
| - if (instr->CheckGVNFlag(kChangesOsrEntries)) {
|
| + if (instr->CheckChangesFlag(kOsrEntries)) {
|
| TRACE((" kill-osr i%d\n", instr->id()));
|
| Kill();
|
| }
|
| @@ -132,8 +141,34 @@ class HLoadEliminationTable : public ZoneObject {
|
| return this;
|
| }
|
|
|
| - // Support for global analysis with HFlowEngine: Copy state to sucessor block.
|
| - HLoadEliminationTable* Copy(HBasicBlock* succ, Zone* zone) {
|
| + // Support for global analysis with HFlowEngine: Merge given state with
|
| + // the other incoming state.
|
| + static HLoadEliminationTable* Merge(HLoadEliminationTable* succ_state,
|
| + HBasicBlock* succ_block,
|
| + HLoadEliminationTable* pred_state,
|
| + HBasicBlock* pred_block,
|
| + Zone* zone) {
|
| + ASSERT(pred_state != NULL);
|
| + if (succ_state == NULL) {
|
| + return pred_state->Copy(succ_block, pred_block, zone);
|
| + } else {
|
| + return succ_state->Merge(succ_block, pred_state, pred_block, zone);
|
| + }
|
| + }
|
| +
|
| + // Support for global analysis with HFlowEngine: Given state merged with all
|
| + // the other incoming states, prepare it for use.
|
| + static HLoadEliminationTable* Finish(HLoadEliminationTable* state,
|
| + HBasicBlock* block,
|
| + Zone* zone) {
|
| + ASSERT(state != NULL);
|
| + return state;
|
| + }
|
| +
|
| + private:
|
| + // Copy state to successor block.
|
| + HLoadEliminationTable* Copy(HBasicBlock* succ, HBasicBlock* from_block,
|
| + Zone* zone) {
|
| HLoadEliminationTable* copy =
|
| new(zone) HLoadEliminationTable(zone, aliasing_);
|
| copy->EnsureFields(fields_.length());
|
| @@ -147,10 +182,9 @@ class HLoadEliminationTable : public ZoneObject {
|
| return copy;
|
| }
|
|
|
| - // Support for global analysis with HFlowEngine: Merge this state with
|
| - // the other incoming state.
|
| - HLoadEliminationTable* Merge(HBasicBlock* succ,
|
| - HLoadEliminationTable* that, Zone* zone) {
|
| + // Merge this state with the other incoming state.
|
| + HLoadEliminationTable* Merge(HBasicBlock* succ, HLoadEliminationTable* that,
|
| + HBasicBlock* that_block, Zone* zone) {
|
| if (that->fields_.length() < fields_.length()) {
|
| // Drop fields not in the other table.
|
| fields_.Rewind(that->fields_.length());
|
| @@ -176,6 +210,10 @@ class HLoadEliminationTable : public ZoneObject {
|
| approx = approx->next_;
|
| }
|
| }
|
| + if (FLAG_trace_load_elimination) {
|
| + TRACE((" merge-to B%d\n", succ->block_id()));
|
| + Print();
|
| + }
|
| return this;
|
| }
|
|
|
| @@ -187,6 +225,10 @@ class HLoadEliminationTable : public ZoneObject {
|
| // load or store for this object and field exists, return the new value with
|
| // which the load should be replaced. Otherwise, return {instr}.
|
| HValue* load(HLoadNamedField* instr) {
|
| + // There must be no loads from non observable in-object properties.
|
| + ASSERT(!instr->access().IsInobject() ||
|
| + instr->access().existing_inobject_property());
|
| +
|
| int field = FieldOf(instr->access());
|
| if (field < 0) return instr;
|
|
|
| @@ -197,9 +239,12 @@ class HLoadEliminationTable : public ZoneObject {
|
| // Load is not redundant. Fill out a new entry.
|
| approx->last_value_ = instr;
|
| return instr;
|
| - } else {
|
| + } else if (approx->last_value_->block()->EqualToOrDominates(
|
| + instr->block())) {
|
| // Eliminate the load. Reuse previously stored value or load instruction.
|
| return approx->last_value_;
|
| + } else {
|
| + return instr;
|
| }
|
| }
|
|
|
| @@ -208,6 +253,12 @@ class HLoadEliminationTable : public ZoneObject {
|
| // the stored values are the same), return NULL indicating that this store
|
| // instruction is redundant. Otherwise, return {instr}.
|
| HValue* store(HStoreNamedField* instr) {
|
| + if (instr->access().IsInobject() &&
|
| + !instr->access().existing_inobject_property()) {
|
| + TRACE((" skipping non existing property initialization store\n"));
|
| + return instr;
|
| + }
|
| +
|
| int field = FieldOf(instr->access());
|
| if (field < 0) return KillIfMisaligned(instr);
|
|
|
| @@ -411,11 +462,7 @@ class HLoadEliminationTable : public ZoneObject {
|
| class HLoadEliminationEffects : public ZoneObject {
|
| public:
|
| explicit HLoadEliminationEffects(Zone* zone)
|
| - : zone_(zone),
|
| - maps_stored_(false),
|
| - fields_stored_(false),
|
| - elements_stored_(false),
|
| - stores_(5, zone) { }
|
| + : zone_(zone), stores_(5, zone) { }
|
|
|
| inline bool Disabled() {
|
| return false; // Effects are _not_ disabled.
|
| @@ -423,37 +470,25 @@ class HLoadEliminationEffects : public ZoneObject {
|
|
|
| // Process a possibly side-effecting instruction.
|
| void Process(HInstruction* instr, Zone* zone) {
|
| - switch (instr->opcode()) {
|
| - case HValue::kStoreNamedField: {
|
| - stores_.Add(HStoreNamedField::cast(instr), zone_);
|
| - break;
|
| - }
|
| - case HValue::kOsrEntry: {
|
| - // Kill everything. Loads must not be hoisted past the OSR entry.
|
| - maps_stored_ = true;
|
| - fields_stored_ = true;
|
| - elements_stored_ = true;
|
| - }
|
| - default: {
|
| - fields_stored_ |= instr->CheckGVNFlag(kChangesInobjectFields);
|
| - maps_stored_ |= instr->CheckGVNFlag(kChangesMaps);
|
| - maps_stored_ |= instr->CheckGVNFlag(kChangesElementsKind);
|
| - elements_stored_ |= instr->CheckGVNFlag(kChangesElementsKind);
|
| - elements_stored_ |= instr->CheckGVNFlag(kChangesElementsPointer);
|
| - }
|
| + if (instr->IsStoreNamedField()) {
|
| + stores_.Add(HStoreNamedField::cast(instr), zone_);
|
| + } else {
|
| + flags_.Add(instr->ChangesFlags());
|
| }
|
| }
|
|
|
| // Apply these effects to the given load elimination table.
|
| void Apply(HLoadEliminationTable* table) {
|
| - if (fields_stored_) {
|
| + // Loads must not be hoisted past the OSR entry, therefore we kill
|
| + // everything if we see an OSR entry.
|
| + if (flags_.Contains(kInobjectFields) || flags_.Contains(kOsrEntries)) {
|
| table->Kill();
|
| return;
|
| }
|
| - if (maps_stored_) {
|
| + if (flags_.Contains(kElementsKind) || flags_.Contains(kMaps)) {
|
| table->KillOffset(JSObject::kMapOffset);
|
| }
|
| - if (elements_stored_) {
|
| + if (flags_.Contains(kElementsKind) || flags_.Contains(kElementsPointer)) {
|
| table->KillOffset(JSObject::kElementsOffset);
|
| }
|
|
|
| @@ -465,9 +500,7 @@ class HLoadEliminationEffects : public ZoneObject {
|
|
|
| // Union these effects with the other effects.
|
| void Union(HLoadEliminationEffects* that, Zone* zone) {
|
| - maps_stored_ |= that->maps_stored_;
|
| - fields_stored_ |= that->fields_stored_;
|
| - elements_stored_ |= that->elements_stored_;
|
| + flags_.Add(that->flags_);
|
| for (int i = 0; i < that->stores_.length(); i++) {
|
| stores_.Add(that->stores_[i], zone);
|
| }
|
| @@ -475,9 +508,7 @@ class HLoadEliminationEffects : public ZoneObject {
|
|
|
| private:
|
| Zone* zone_;
|
| - bool maps_stored_ : 1;
|
| - bool fields_stored_ : 1;
|
| - bool elements_stored_ : 1;
|
| + GVNFlagSet flags_;
|
| ZoneList<HStoreNamedField*> stores_;
|
| };
|
|
|
|
|