| Index: src/compiler/liveness-analyzer.cc
|
| diff --git a/src/compiler/liveness-analyzer.cc b/src/compiler/liveness-analyzer.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..c219ff6f33cd610e27a48c40d3d33a3fc3f14246
|
| --- /dev/null
|
| +++ b/src/compiler/liveness-analyzer.cc
|
| @@ -0,0 +1,190 @@
|
| +// Copyright 2014 the V8 project authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "src/compiler/liveness-analyzer.h"
|
| +#include "src/compiler/js-graph.h"
|
| +#include "src/compiler/node.h"
|
| +#include "src/compiler/node-matchers.h"
|
| +
|
| +namespace v8 {
|
| +namespace internal {
|
| +namespace compiler {
|
| +
|
| +
|
| +LivenessAnalyzer::LivenessAnalyzer(size_t local_count, Zone* zone)
|
| + : zone_(zone), blocks_(zone), local_count_(local_count), queue_(zone) {}
|
| +
|
| +
|
| +void LivenessAnalyzer::Print(std::ostream& os) {
|
| + for (auto block : blocks_) {
|
| + block->Print(os);
|
| + os << std::endl;
|
| + }
|
| +}
|
| +
|
| +
|
| +LivenessAnalyzerBlock* LivenessAnalyzer::New() {
|
| + LivenessAnalyzerBlock* result =
|
| + new (zone()) LivenessAnalyzerBlock(blocks_.size(), local_count_, zone());
|
| + blocks_.push_back(result);
|
| + return result;
|
| +}
|
| +
|
| +
|
| +LivenessAnalyzerBlock* LivenessAnalyzer::New(
|
| + LivenessAnalyzerBlock* predecessor) {
|
| + LivenessAnalyzerBlock* result = New();
|
| + result->AddPredecessor(predecessor);
|
| + return result;
|
| +}
|
| +
|
| +
|
| +void LivenessAnalyzer::Queue(LivenessAnalyzerBlock* block) {
|
| + if (!block->IsQueued()) {
|
| + block->SetQueued();
|
| + queue_.push(block);
|
| + }
|
| +}
|
| +
|
| +
|
| +void LivenessAnalyzer::Run(FrameStateRelaxer* relaxer) {
|
| + // Put all blocks into the queue.
|
| + DCHECK(queue_.empty());
|
| + for (auto block : blocks_) {
|
| + Queue(block);
|
| + }
|
| +
|
| + // Compute the fix-point.
|
| + ZoneVector<bool> working_area(local_count_, false, zone_);
|
| + while (!queue_.empty()) {
|
| + LivenessAnalyzerBlock* block = queue_.front();
|
| + queue_.pop();
|
| + block->Process(&working_area, nullptr);
|
| +
|
| + for (auto i = block->pred_begin(); i != block->pred_end(); i++) {
|
| + if ((*i)->UpdateLive(&working_area)) {
|
| + Queue(*i);
|
| + }
|
| + }
|
| + }
|
| +
|
| + // Update the frame states according to the liveness.
|
| + for (auto block : blocks_) {
|
| + block->Process(&working_area, relaxer);
|
| + }
|
| +}
|
| +
|
| +
|
| +void LivenessAnalyzerBlock::Process(ZoneVector<bool>* result,
|
| + FrameStateRelaxer* relaxer) {
|
| + queued_ = false;
|
| +
|
| + // Copy the bitvector to the target bit vector.
|
| + *result = live_;
|
| +
|
| + for (auto i = entries_.rbegin(); i != entries_.rend(); i++) {
|
| + auto entry = *i;
|
| + switch (entry.kind()) {
|
| + case Entry::kLookup:
|
| + (*result)[entry.var()] = true;
|
| + break;
|
| + case Entry::kBind:
|
| + (*result)[entry.var()] = false;
|
| + break;
|
| + case Entry::kCheckpoint:
|
| + if (relaxer != nullptr) {
|
| + relaxer->RelaxFrameState(entry.node(), result);
|
| + }
|
| + break;
|
| + }
|
| + }
|
| +}
|
| +
|
| +
|
| +bool LivenessAnalyzerBlock::UpdateLive(ZoneVector<bool>* working_area) {
|
| + bool changed = false;
|
| + for (size_t i = 0; i < working_area->size(); i++) {
|
| + if ((*working_area)[i] && !live_[i]) {
|
| + // We can only make variables live during propagation.
|
| + live_[i] = true;
|
| + changed = true;
|
| + }
|
| + }
|
| + return changed;
|
| +}
|
| +
|
| +
|
| +void FrameStateRelaxer::RelaxFrameState(Node* frame_state,
|
| + ZoneVector<bool>* liveness) {
|
| + DCHECK_EQ(frame_state->opcode(), IrOpcode::kFrameState);
|
| + Node* locals_state = frame_state->InputAt(1);
|
| + DCHECK_EQ(locals_state->opcode(), IrOpcode::kStateValues);
|
| + int count = locals_state->InputCount();
|
| + DCHECK_EQ(count, static_cast<int>(liveness->size()));
|
| + for (int i = 0; i < count; i++) {
|
| + bool live = (*liveness)[i] || blacklist_[i];
|
| + if (!live || locals_state->InputAt(i) != replacement_node_) {
|
| + Node* new_values = RelaxStateValues(locals_state, liveness);
|
| + frame_state->ReplaceInput(1, new_values);
|
| + break;
|
| + }
|
| + }
|
| +}
|
| +
|
| +
|
| +Node* FrameStateRelaxer::RelaxStateValues(Node* values,
|
| + ZoneVector<bool>* liveness) {
|
| + int count = values->InputCount();
|
| + ZoneVector<Node*> inputs(count, nullptr, local_zone());
|
| + for (int i = 0; i < count; i++) {
|
| + bool live = (*liveness)[i] || blacklist_[i];
|
| + inputs[i] = live ? values->InputAt(i) : replacement_node_;
|
| + }
|
| + const Operator* op = js_graph()->common()->StateValues(count);
|
| + return js_graph()->graph()->NewNode(op, count,
|
| + count == 0 ? nullptr : &(inputs.front()));
|
| +}
|
| +
|
| +
|
| +void LivenessAnalyzerBlock::Print(std::ostream& os) {
|
| + os << "Block " << id();
|
| + bool first = true;
|
| + for (LivenessAnalyzerBlock* pred : predecessors_) {
|
| + if (!first) {
|
| + os << ", ";
|
| + } else {
|
| + os << "; predecessors: ";
|
| + first = false;
|
| + }
|
| + os << pred->id();
|
| + }
|
| + os << std::endl;
|
| +
|
| + for (auto entry : entries_) {
|
| + os << " ";
|
| + switch (entry.kind()) {
|
| + case Entry::kLookup:
|
| + os << "- Lookup " << entry.var() << std::endl;
|
| + break;
|
| + case Entry::kBind:
|
| + os << "- Bind " << entry.var() << std::endl;
|
| + break;
|
| + case Entry::kCheckpoint:
|
| + os << "- Checkpoint " << entry.node()->id() << std::endl;
|
| + break;
|
| + }
|
| + }
|
| +
|
| + if (live_.size() > 0) {
|
| + os << " Live set: ";
|
| + for (bool live : live_) {
|
| + os << (live ? "L" : ".");
|
| + }
|
| + os << std::endl;
|
| + }
|
| +}
|
| +
|
| +} // namespace compiler
|
| +} // namespace internal
|
| +} // namespace v8
|
|
|