diff options
Diffstat (limited to 'src/compiler/escape-analysis.cc')
-rw-r--r-- | src/compiler/escape-analysis.cc | 99 |
1 files changed, 83 insertions, 16 deletions
diff --git a/src/compiler/escape-analysis.cc b/src/compiler/escape-analysis.cc index 02180459..255e74ea 100644 --- a/src/compiler/escape-analysis.cc +++ b/src/compiler/escape-analysis.cc @@ -12,6 +12,7 @@ #include "src/compiler/common-operator.h" #include "src/compiler/graph-reducer.h" #include "src/compiler/js-operator.h" +#include "src/compiler/linkage.h" #include "src/compiler/node-matchers.h" #include "src/compiler/node-properties.h" #include "src/compiler/node.h" @@ -201,7 +202,7 @@ class VirtualObject : public ZoneObject { } bool UpdateFrom(const VirtualObject& other); bool MergeFrom(MergeCache* cache, Node* at, Graph* graph, - CommonOperatorBuilder* common); + CommonOperatorBuilder* common, bool initialMerge); void SetObjectState(Node* node) { object_state_ = node; } Node* GetObjectState() const { return object_state_; } bool IsCopyRequired() const { return status_ & kCopyRequired; } @@ -252,10 +253,14 @@ bool VirtualObject::UpdateFrom(const VirtualObject& other) { class VirtualState : public ZoneObject { public: VirtualState(Node* owner, Zone* zone, size_t size) - : info_(size, nullptr, zone), owner_(owner) {} + : info_(size, nullptr, zone), + initialized_(static_cast<int>(size), zone), + owner_(owner) {} VirtualState(Node* owner, const VirtualState& state) : info_(state.info_.size(), nullptr, state.info_.get_allocator().zone()), + initialized_(state.initialized_.length(), + state.info_.get_allocator().zone()), owner_(owner) { for (size_t i = 0; i < info_.size(); ++i) { if (state.info_[i]) { @@ -280,6 +285,7 @@ class VirtualState : public ZoneObject { private: ZoneVector<VirtualObject*> info_; + BitVector initialized_; Node* owner_; DISALLOW_COPY_AND_ASSIGN(VirtualState); @@ -375,6 +381,7 @@ VirtualObject* VirtualState::VirtualObjectFromAlias(size_t alias) { void VirtualState::SetVirtualObject(Alias alias, VirtualObject* obj) { info_[alias] = obj; + if (obj) initialized_.Add(alias); } bool VirtualState::UpdateFrom(VirtualState* from, Zone* zone) { @@ -431,7 +438,6 @@ bool IsEquivalentPhi(Node* phi, ZoneVector<Node*>& inputs) { } return true; } - } // namespace bool VirtualObject::MergeFields(size_t i, Node* at, MergeCache* cache, @@ -440,12 +446,21 @@ bool VirtualObject::MergeFields(size_t i, Node* at, MergeCache* cache, int value_input_count = static_cast<int>(cache->fields().size()); Node* rep = GetField(i); if (!rep || !IsCreatedPhi(i)) { + Type* phi_type = Type::None(); + for (Node* input : cache->fields()) { + CHECK_NOT_NULL(input); + CHECK(!input->IsDead()); + Type* input_type = NodeProperties::GetType(input); + phi_type = Type::Union(phi_type, input_type, graph->zone()); + } Node* control = NodeProperties::GetControlInput(at); cache->fields().push_back(control); Node* phi = graph->NewNode( common->Phi(MachineRepresentation::kTagged, value_input_count), value_input_count + 1, &cache->fields().front()); + NodeProperties::SetType(phi, phi_type); SetField(i, phi, true); + #ifdef DEBUG if (FLAG_trace_turbo_escape) { PrintF(" Creating Phi #%d as merge of", phi->id()); @@ -471,12 +486,15 @@ bool VirtualObject::MergeFields(size_t i, Node* at, MergeCache* cache, } bool VirtualObject::MergeFrom(MergeCache* cache, Node* at, Graph* graph, - CommonOperatorBuilder* common) { + CommonOperatorBuilder* common, + bool initialMerge) { DCHECK(at->opcode() == IrOpcode::kEffectPhi || at->opcode() == IrOpcode::kPhi); bool changed = false; for (size_t i = 0; i < field_count(); ++i) { - if (Node* field = cache->GetFields(i)) { + if (!initialMerge && GetField(i) == nullptr) continue; + Node* field = cache->GetFields(i); + if (field && !IsCreatedPhi(i)) { changed = changed || GetField(i) != field; SetField(i, field); TRACE(" Field %zu agree on rep #%d\n", i, field->id()); @@ -516,8 +534,11 @@ bool VirtualState::MergeFrom(MergeCache* cache, Zone* zone, Graph* graph, fields = std::min(obj->field_count(), fields); } } - if (cache->objects().size() == cache->states().size()) { + if (cache->objects().size() == cache->states().size() && + (mergeObject || !initialized_.Contains(alias))) { + bool initialMerge = false; if (!mergeObject) { + initialMerge = true; VirtualObject* obj = new (zone) VirtualObject(cache->objects().front()->id(), this, zone, fields, cache->objects().front()->IsInitialized()); @@ -542,7 +563,9 @@ bool VirtualState::MergeFrom(MergeCache* cache, Zone* zone, Graph* graph, PrintF("\n"); } #endif // DEBUG - changed = mergeObject->MergeFrom(cache, at, graph, common) || changed; + changed = + mergeObject->MergeFrom(cache, at, graph, common, initialMerge) || + changed; } else { if (mergeObject) { TRACE(" Alias %d, virtual object removed\n", alias); @@ -671,6 +694,15 @@ void EscapeStatusAnalysis::Process(Node* node) { RevisitInputs(rep); RevisitUses(rep); } + } else { + Node* from = NodeProperties::GetValueInput(node, 0); + from = object_analysis_->ResolveReplacement(from); + if (SetEscaped(from)) { + TRACE("Setting #%d (%s) to escaped because of unresolved load #%i\n", + from->id(), from->op()->mnemonic(), node->id()); + RevisitInputs(from); + RevisitUses(from); + } } RevisitUses(node); break; @@ -795,6 +827,7 @@ bool EscapeStatusAnalysis::CheckUsesForEscape(Node* uses, Node* rep, case IrOpcode::kSelect: // TODO(mstarzinger): The following list of operators will eventually be // handled by the EscapeAnalysisReducer (similar to ObjectIsSmi). + case IrOpcode::kConvertTaggedHoleToUndefined: case IrOpcode::kStringEqual: case IrOpcode::kStringLessThan: case IrOpcode::kStringLessThanOrEqual: @@ -802,8 +835,11 @@ bool EscapeStatusAnalysis::CheckUsesForEscape(Node* uses, Node* rep, case IrOpcode::kPlainPrimitiveToNumber: case IrOpcode::kPlainPrimitiveToWord32: case IrOpcode::kPlainPrimitiveToFloat64: + case IrOpcode::kStringCharAt: case IrOpcode::kStringCharCodeAt: - case IrOpcode::kObjectIsCallable: + case IrOpcode::kStringIndexOf: + case IrOpcode::kObjectIsDetectableCallable: + case IrOpcode::kObjectIsNonCallable: case IrOpcode::kObjectIsNumber: case IrOpcode::kObjectIsReceiver: case IrOpcode::kObjectIsString: @@ -819,9 +855,9 @@ bool EscapeStatusAnalysis::CheckUsesForEscape(Node* uses, Node* rep, if (use->op()->EffectInputCount() == 0 && uses->op()->EffectInputCount() > 0 && !IrOpcode::IsJsOpcode(use->opcode())) { - TRACE("Encountered unaccounted use by #%d (%s)\n", use->id(), - use->op()->mnemonic()); - UNREACHABLE(); + V8_Fatal(__FILE__, __LINE__, + "Encountered unaccounted use by #%d (%s)\n", use->id(), + use->op()->mnemonic()); } if (SetEscaped(rep)) { TRACE("Setting #%d (%s) to escaped because of use by #%d (%s)\n", @@ -842,6 +878,7 @@ void EscapeStatusAnalysis::ProcessFinishRegion(Node* node) { } if (CheckUsesForEscape(node, true)) { RevisitInputs(node); + RevisitUses(node); } } @@ -863,11 +900,15 @@ EscapeAnalysis::EscapeAnalysis(Graph* graph, CommonOperatorBuilder* common, virtual_states_(zone), replacements_(zone), cycle_detection_(zone), - cache_(nullptr) {} + cache_(nullptr) { + // Type slot_not_analyzed_ manually. + double v = OpParameter<double>(slot_not_analyzed_); + NodeProperties::SetType(slot_not_analyzed_, Type::Range(v, v, zone)); +} EscapeAnalysis::~EscapeAnalysis() {} -void EscapeAnalysis::Run() { +bool EscapeAnalysis::Run() { replacements_.resize(graph()->NodeCount()); status_analysis_->AssignAliases(); if (status_analysis_->AliasCount() > 0) { @@ -876,6 +917,9 @@ void EscapeAnalysis::Run() { status_analysis_->ResizeStatusVector(); RunObjectAnalysis(); status_analysis_->RunStatusAnalysis(); + return true; + } else { + return false; } } @@ -966,6 +1010,7 @@ void EscapeAnalysis::RunObjectAnalysis() { // VirtualObjects, and we want to delay phis to improve performance. if (use->opcode() == IrOpcode::kEffectPhi) { if (!status_analysis_->IsInQueue(use->id())) { + status_analysis_->SetInQueue(use->id(), true); queue.push_front(use); } } else if ((use->opcode() != IrOpcode::kLoadField && @@ -1044,6 +1089,19 @@ bool EscapeStatusAnalysis::IsEffectBranchPoint(Node* node) { return false; } +namespace { + +bool HasFrameStateInput(const Operator* op) { + if (op->opcode() == IrOpcode::kCall || op->opcode() == IrOpcode::kTailCall) { + const CallDescriptor* d = CallDescriptorOf(op); + return d->NeedsFrameState(); + } else { + return OperatorProperties::HasFrameStateInput(op); + } +} + +} // namespace + bool EscapeAnalysis::Process(Node* node) { switch (node->opcode()) { case IrOpcode::kAllocate: @@ -1080,6 +1138,9 @@ bool EscapeAnalysis::Process(Node* node) { ProcessAllocationUsers(node); break; } + if (HasFrameStateInput(node->op())) { + virtual_states_[node->id()]->SetCopyRequired(); + } return true; } @@ -1173,8 +1234,7 @@ void EscapeAnalysis::ForwardVirtualState(Node* node) { static_cast<void*>(virtual_states_[effect->id()]), effect->op()->mnemonic(), effect->id(), node->op()->mnemonic(), node->id()); - if (status_analysis_->IsEffectBranchPoint(effect) || - OperatorProperties::HasFrameStateInput(node->op())) { + if (status_analysis_->IsEffectBranchPoint(effect)) { virtual_states_[node->id()]->SetCopyRequired(); TRACE(", effect input %s#%d is branch point", effect->op()->mnemonic(), effect->id()); @@ -1393,10 +1453,16 @@ void EscapeAnalysis::ProcessLoadFromPhi(int offset, Node* from, Node* load, Node* rep = replacement(load); if (!rep || !IsEquivalentPhi(rep, cache_->fields())) { int value_input_count = static_cast<int>(cache_->fields().size()); + Type* phi_type = Type::None(); + for (Node* input : cache_->fields()) { + Type* input_type = NodeProperties::GetType(input); + phi_type = Type::Union(phi_type, input_type, graph()->zone()); + } cache_->fields().push_back(NodeProperties::GetControlInput(from)); Node* phi = graph()->NewNode( common()->Phi(MachineRepresentation::kTagged, value_input_count), value_input_count + 1, &cache_->fields().front()); + NodeProperties::SetType(phi, phi_type); status_analysis_->ResizeStatusVector(); SetReplacement(load, phi); TRACE(" got phi created.\n"); @@ -1583,13 +1649,14 @@ Node* EscapeAnalysis::GetOrCreateObjectState(Node* effect, Node* node) { cache_->fields().clear(); for (size_t i = 0; i < vobj->field_count(); ++i) { if (Node* field = vobj->GetField(i)) { - cache_->fields().push_back(field); + cache_->fields().push_back(ResolveReplacement(field)); } } int input_count = static_cast<int>(cache_->fields().size()); Node* new_object_state = graph()->NewNode(common()->ObjectState(input_count), input_count, &cache_->fields().front()); + NodeProperties::SetType(new_object_state, Type::OtherInternal()); vobj->SetObjectState(new_object_state); TRACE( "Creating object state #%d for vobj %p (from node #%d) at effect " |