| Index: src/compiler/escape-analysis.cc
|
| diff --git a/src/compiler/escape-analysis.cc b/src/compiler/escape-analysis.cc
|
| index 2cf96762a7226a3a3a837b817efc13af350d0be2..7d8b166fd9bbc5010b33b65f43213f890a9e730d 100644
|
| --- a/src/compiler/escape-analysis.cc
|
| +++ b/src/compiler/escape-analysis.cc
|
| @@ -24,7 +24,7 @@ namespace v8 {
|
| namespace internal {
|
| namespace compiler {
|
|
|
| -using Alias = EscapeStatusAnalysis::Alias;
|
| +using Alias = EscapeAnalysis::Alias;
|
|
|
| #ifdef DEBUG
|
| #define TRACE(...) \
|
| @@ -35,6 +35,90 @@ using Alias = EscapeStatusAnalysis::Alias;
|
| #define TRACE(...)
|
| #endif
|
|
|
| +// EscapeStatusAnalysis determines for each allocation whether it escapes.
|
| +class EscapeStatusAnalysis : public ZoneObject {
|
| + public:
|
| + enum Status {
|
| + kUnknown = 0u,
|
| + kTracked = 1u << 0,
|
| + kEscaped = 1u << 1,
|
| + kOnStack = 1u << 2,
|
| + kVisited = 1u << 3,
|
| + // A node is dangling, if it is a load of some kind, and does not have
|
| + // an effect successor.
|
| + kDanglingComputed = 1u << 4,
|
| + kDangling = 1u << 5,
|
| + // A node is is an effect branch point, if it has more than 2 non-dangling
|
| + // effect successors.
|
| + kBranchPointComputed = 1u << 6,
|
| + kBranchPoint = 1u << 7,
|
| + kInQueue = 1u << 8
|
| + };
|
| + typedef base::Flags<Status, uint16_t> StatusFlags;
|
| +
|
| + void RunStatusAnalysis();
|
| +
|
| + bool IsVirtual(Node* node);
|
| + bool IsEscaped(Node* node);
|
| + bool IsAllocation(Node* node);
|
| +
|
| + bool IsInQueue(NodeId id);
|
| + void SetInQueue(NodeId id, bool on_stack);
|
| +
|
| + void DebugPrint();
|
| +
|
| + EscapeStatusAnalysis(EscapeAnalysis* object_analysis, Graph* graph,
|
| + Zone* zone);
|
| + void EnqueueForStatusAnalysis(Node* node);
|
| + bool SetEscaped(Node* node);
|
| + bool IsEffectBranchPoint(Node* node);
|
| + bool IsDanglingEffectNode(Node* node);
|
| + void ResizeStatusVector();
|
| + size_t GetStatusVectorSize();
|
| + bool IsVirtual(NodeId id);
|
| +
|
| + Graph* graph() const { return graph_; }
|
| + void AssignAliases();
|
| + Alias GetAlias(NodeId id) const { return aliases_[id]; }
|
| + const ZoneVector<Alias>& GetAliasMap() const { return aliases_; }
|
| + Alias AliasCount() const { return next_free_alias_; }
|
| + static const Alias kNotReachable;
|
| + static const Alias kUntrackable;
|
| +
|
| + bool IsNotReachable(Node* node);
|
| +
|
| + private:
|
| + void Process(Node* node);
|
| + void ProcessAllocate(Node* node);
|
| + void ProcessFinishRegion(Node* node);
|
| + void ProcessStoreField(Node* node);
|
| + void ProcessStoreElement(Node* node);
|
| + bool CheckUsesForEscape(Node* node, bool phi_escaping = false) {
|
| + return CheckUsesForEscape(node, node, phi_escaping);
|
| + }
|
| + bool CheckUsesForEscape(Node* node, Node* rep, bool phi_escaping = false);
|
| + void RevisitUses(Node* node);
|
| + void RevisitInputs(Node* node);
|
| +
|
| + Alias NextAlias() { return next_free_alias_++; }
|
| +
|
| + bool HasEntry(Node* node);
|
| +
|
| + bool IsAllocationPhi(Node* node);
|
| +
|
| + ZoneVector<Node*> stack_;
|
| + EscapeAnalysis* object_analysis_;
|
| + Graph* const graph_;
|
| + ZoneVector<StatusFlags> status_;
|
| + Alias next_free_alias_;
|
| + ZoneVector<Node*> status_stack_;
|
| + ZoneVector<Alias> aliases_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(EscapeStatusAnalysis);
|
| +};
|
| +
|
| +DEFINE_OPERATORS_FOR_FLAGS(EscapeStatusAnalysis::StatusFlags)
|
| +
|
| const Alias EscapeStatusAnalysis::kNotReachable =
|
| std::numeric_limits<Alias>::max();
|
| const Alias EscapeStatusAnalysis::kUntrackable =
|
| @@ -475,14 +559,11 @@ EscapeStatusAnalysis::EscapeStatusAnalysis(EscapeAnalysis* object_analysis,
|
| : stack_(zone),
|
| object_analysis_(object_analysis),
|
| graph_(graph),
|
| - zone_(zone),
|
| status_(zone),
|
| next_free_alias_(0),
|
| status_stack_(zone),
|
| aliases_(zone) {}
|
|
|
| -EscapeStatusAnalysis::~EscapeStatusAnalysis() {}
|
| -
|
| bool EscapeStatusAnalysis::HasEntry(Node* node) {
|
| return status_[node->id()] & (kTracked | kEscaped);
|
| }
|
| @@ -761,8 +842,9 @@ void EscapeStatusAnalysis::DebugPrint() {
|
|
|
| EscapeAnalysis::EscapeAnalysis(Graph* graph, CommonOperatorBuilder* common,
|
| Zone* zone)
|
| - : status_analysis_(this, graph, zone),
|
| + : zone_(zone),
|
| common_(common),
|
| + status_analysis_(new (zone) EscapeStatusAnalysis(this, graph, zone)),
|
| virtual_states_(zone),
|
| replacements_(zone),
|
| cache_(nullptr) {}
|
| @@ -771,13 +853,13 @@ EscapeAnalysis::~EscapeAnalysis() {}
|
|
|
| void EscapeAnalysis::Run() {
|
| replacements_.resize(graph()->NodeCount());
|
| - status_analysis_.AssignAliases();
|
| - if (status_analysis_.AliasCount() > 0) {
|
| + status_analysis_->AssignAliases();
|
| + if (status_analysis_->AliasCount() > 0) {
|
| cache_ = new (zone()) MergeCache(zone());
|
| replacements_.resize(graph()->NodeCount());
|
| - status_analysis_.ResizeStatusVector();
|
| + status_analysis_->ResizeStatusVector();
|
| RunObjectAnalysis();
|
| - status_analysis_.RunStatusAnalysis();
|
| + status_analysis_->RunStatusAnalysis();
|
| }
|
| }
|
|
|
| @@ -855,11 +937,11 @@ void EscapeAnalysis::RunObjectAnalysis() {
|
| while (!queue.empty()) {
|
| Node* node = queue.back();
|
| queue.pop_back();
|
| - status_analysis_.SetInQueue(node->id(), false);
|
| + status_analysis_->SetInQueue(node->id(), false);
|
| if (Process(node)) {
|
| for (Edge edge : node->use_edges()) {
|
| Node* use = edge.from();
|
| - if (IsNotReachable(use)) {
|
| + if (status_analysis_->IsNotReachable(use)) {
|
| continue;
|
| }
|
| if (NodeProperties::IsEffectEdge(edge)) {
|
| @@ -867,14 +949,14 @@ void EscapeAnalysis::RunObjectAnalysis() {
|
| // We need DFS do avoid some duplication of VirtualStates and
|
| // VirtualObjects, and we want to delay phis to improve performance.
|
| if (use->opcode() == IrOpcode::kEffectPhi) {
|
| - if (!status_analysis_.IsInQueue(use->id())) {
|
| + if (!status_analysis_->IsInQueue(use->id())) {
|
| queue.push_front(use);
|
| }
|
| } else if ((use->opcode() != IrOpcode::kLoadField &&
|
| use->opcode() != IrOpcode::kLoadElement) ||
|
| - !IsDanglingEffectNode(use)) {
|
| - if (!status_analysis_.IsInQueue(use->id())) {
|
| - status_analysis_.SetInQueue(use->id(), true);
|
| + !status_analysis_->IsDanglingEffectNode(use)) {
|
| + if (!status_analysis_->IsInQueue(use->id())) {
|
| + status_analysis_->SetInQueue(use->id(), true);
|
| queue.push_back(use);
|
| }
|
| } else {
|
| @@ -1047,7 +1129,8 @@ void EscapeAnalysis::ForwardVirtualState(Node* node) {
|
| #ifdef DEBUG
|
| if (node->opcode() != IrOpcode::kLoadField &&
|
| node->opcode() != IrOpcode::kLoadElement &&
|
| - node->opcode() != IrOpcode::kLoad && IsDanglingEffectNode(node)) {
|
| + node->opcode() != IrOpcode::kLoad &&
|
| + status_analysis_->IsDanglingEffectNode(node)) {
|
| PrintF("Dangeling effect node: #%d (%s)\n", node->id(),
|
| node->op()->mnemonic());
|
| UNREACHABLE();
|
| @@ -1064,7 +1147,7 @@ void EscapeAnalysis::ForwardVirtualState(Node* node) {
|
| static_cast<void*>(virtual_states_[effect->id()]),
|
| effect->op()->mnemonic(), effect->id(), node->op()->mnemonic(),
|
| node->id());
|
| - if (IsEffectBranchPoint(effect) ||
|
| + if (status_analysis_->IsEffectBranchPoint(effect) ||
|
| OperatorProperties::GetFrameStateInputCount(node->op()) > 0) {
|
| virtual_states_[node->id()]->SetCopyRequired();
|
| TRACE(", effect input %s#%d is branch point", effect->op()->mnemonic(),
|
| @@ -1124,7 +1207,7 @@ bool EscapeAnalysis::ProcessEffectPhi(Node* node) {
|
| TRACE("Merge %s the node.\n", changed ? "changed" : "did not change");
|
|
|
| if (changed) {
|
| - status_analysis_.ResizeStatusVector();
|
| + status_analysis_->ResizeStatusVector();
|
| }
|
| return changed;
|
| }
|
| @@ -1221,21 +1304,21 @@ Node* EscapeAnalysis::GetReplacement(NodeId id) {
|
| }
|
|
|
| bool EscapeAnalysis::IsVirtual(Node* node) {
|
| - if (node->id() >= status_analysis_.GetStatusVectorSize()) {
|
| + if (node->id() >= status_analysis_->GetStatusVectorSize()) {
|
| return false;
|
| }
|
| - return status_analysis_.IsVirtual(node);
|
| + return status_analysis_->IsVirtual(node);
|
| }
|
|
|
| bool EscapeAnalysis::IsEscaped(Node* node) {
|
| - if (node->id() >= status_analysis_.GetStatusVectorSize()) {
|
| + if (node->id() >= status_analysis_->GetStatusVectorSize()) {
|
| return false;
|
| }
|
| - return status_analysis_.IsEscaped(node);
|
| + return status_analysis_->IsEscaped(node);
|
| }
|
|
|
| bool EscapeAnalysis::SetEscaped(Node* node) {
|
| - return status_analysis_.SetEscaped(node);
|
| + return status_analysis_->SetEscaped(node);
|
| }
|
|
|
| VirtualObject* EscapeAnalysis::GetVirtualObject(Node* at, NodeId id) {
|
| @@ -1271,7 +1354,7 @@ void EscapeAnalysis::ProcessLoadFromPhi(int offset, Node* from, Node* load,
|
| }
|
|
|
| cache_->LoadVirtualObjectsForFieldsFrom(state,
|
| - status_analysis_.GetAliasMap());
|
| + status_analysis_->GetAliasMap());
|
| if (cache_->objects().size() == cache_->fields().size()) {
|
| cache_->GetFields(offset);
|
| if (cache_->fields().size() == cache_->objects().size()) {
|
| @@ -1282,7 +1365,7 @@ void EscapeAnalysis::ProcessLoadFromPhi(int offset, Node* from, Node* load,
|
| Node* phi = graph()->NewNode(
|
| common()->Phi(MachineRepresentation::kTagged, value_input_count),
|
| value_input_count + 1, &cache_->fields().front());
|
| - status_analysis_.ResizeStatusVector();
|
| + status_analysis_->ResizeStatusVector();
|
| SetReplacement(load, phi);
|
| TRACE(" got phi created.\n");
|
| } else {
|
| @@ -1513,17 +1596,17 @@ void EscapeAnalysis::DebugPrint() {
|
|
|
| VirtualObject* EscapeAnalysis::GetVirtualObject(VirtualState* state,
|
| Node* node) {
|
| - if (node->id() >= status_analysis_.GetAliasMap().size()) return nullptr;
|
| + if (node->id() >= status_analysis_->GetAliasMap().size()) return nullptr;
|
| Alias alias = GetAlias(node->id());
|
| if (alias >= state->size()) return nullptr;
|
| return state->VirtualObjectFromAlias(alias);
|
| }
|
|
|
| bool EscapeAnalysis::ExistsVirtualAllocate() {
|
| - for (size_t id = 0; id < status_analysis_.GetAliasMap().size(); ++id) {
|
| + for (size_t id = 0; id < status_analysis_->GetAliasMap().size(); ++id) {
|
| Alias alias = GetAlias(static_cast<NodeId>(id));
|
| if (alias < EscapeStatusAnalysis::kUntrackable) {
|
| - if (status_analysis_.IsVirtual(static_cast<int>(id))) {
|
| + if (status_analysis_->IsVirtual(static_cast<int>(id))) {
|
| return true;
|
| }
|
| }
|
| @@ -1531,6 +1614,16 @@ bool EscapeAnalysis::ExistsVirtualAllocate() {
|
| return false;
|
| }
|
|
|
| +Alias EscapeAnalysis::GetAlias(NodeId id) const {
|
| + return status_analysis_->GetAlias(id);
|
| +}
|
| +
|
| +Alias EscapeAnalysis::AliasCount() const {
|
| + return status_analysis_->AliasCount();
|
| +}
|
| +
|
| +Graph* EscapeAnalysis::graph() const { return status_analysis_->graph(); }
|
| +
|
| } // namespace compiler
|
| } // namespace internal
|
| } // namespace v8
|
|
|