| Index: pkg/compiler/lib/src/ssa/variable_allocator.dart
|
| diff --git a/pkg/compiler/lib/src/ssa/variable_allocator.dart b/pkg/compiler/lib/src/ssa/variable_allocator.dart
|
| deleted file mode 100644
|
| index bd95f58b00f2735768f5dfbd517aa42d437fde5e..0000000000000000000000000000000000000000
|
| --- a/pkg/compiler/lib/src/ssa/variable_allocator.dart
|
| +++ /dev/null
|
| @@ -1,716 +0,0 @@
|
| -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
|
| -// for details. All rights reserved. Use of this source code is governed by a
|
| -// BSD-style license that can be found in the LICENSE file.
|
| -
|
| -part of ssa;
|
| -
|
| -/**
|
| - * The [LiveRange] class covers a range where an instruction is live.
|
| - */
|
| -class LiveRange {
|
| - final int start;
|
| - // [end] is not final because it can be updated due to loops.
|
| - int end;
|
| - LiveRange(this.start, this.end) {
|
| - assert(start <= end);
|
| - }
|
| -
|
| - String toString() => '[$start $end[';
|
| -}
|
| -
|
| -/**
|
| - * The [LiveInterval] class contains the list of ranges where an
|
| - * instruction is live.
|
| - */
|
| -class LiveInterval {
|
| - /**
|
| - * The id where the instruction is defined.
|
| - */
|
| - int start;
|
| - final List<LiveRange> ranges;
|
| - LiveInterval() : ranges = <LiveRange>[];
|
| -
|
| - // We want [HCheck] instructions to have the same name as the
|
| - // instruction it checks, so both instructions should share the same
|
| - // live ranges.
|
| - LiveInterval.forCheck(this.start, LiveInterval checkedInterval)
|
| - : ranges = checkedInterval.ranges;
|
| -
|
| - /**
|
| - * Update all ranges that are contained in [from, to[ to
|
| - * die at [to].
|
| - */
|
| - void loopUpdate(int from, int to) {
|
| - for (LiveRange range in ranges) {
|
| - if (from <= range.start && range.end < to) {
|
| - range.end = to;
|
| - }
|
| - }
|
| - }
|
| -
|
| - /**
|
| - * Add a new range to this interval.
|
| - */
|
| - void add(LiveRange interval) {
|
| - ranges.add(interval);
|
| - }
|
| -
|
| - /**
|
| - * Returns true if one of the ranges of this interval dies at [at].
|
| - */
|
| - bool diesAt(int at) {
|
| - for (LiveRange range in ranges) {
|
| - if (range.end == at) return true;
|
| - }
|
| - return false;
|
| - }
|
| -
|
| - String toString() {
|
| - List<String> res = new List<String>();
|
| - for (final interval in ranges) res.add(interval.toString());
|
| - return '(${res.join(", ")})';
|
| - }
|
| -}
|
| -
|
| -/**
|
| - * The [LiveEnvironment] class contains the liveIn set of a basic
|
| - * block. A liveIn set of a block contains the instructions that are
|
| - * live when entering that block.
|
| - */
|
| -class LiveEnvironment {
|
| - /**
|
| - * The instruction id where the basic block starts. See
|
| - * [SsaLiveIntervalBuilder.instructionId].
|
| - */
|
| - int startId;
|
| -
|
| - /**
|
| - * The instruction id where the basic block ends.
|
| - */
|
| - final int endId;
|
| -
|
| - /**
|
| - * Loop markers that will be updated once the loop header is
|
| - * visited. The liveIn set of the loop header will be merged into this
|
| - * environment. [loopMarkers] is a mapping from block header to the
|
| - * end instruction id of the loop exit block.
|
| - */
|
| - final Map<HBasicBlock, int> loopMarkers;
|
| -
|
| - /**
|
| - * The instructions that are live in this basic block. The values of
|
| - * the map contain the instruction ids where the instructions die.
|
| - * It will be used when adding a range to the live interval of an
|
| - * instruction.
|
| - */
|
| - final Map<HInstruction, int> liveInstructions;
|
| -
|
| - /**
|
| - * Map containing the live intervals of instructions.
|
| - */
|
| - final Map<HInstruction, LiveInterval> liveIntervals;
|
| -
|
| - LiveEnvironment(this.liveIntervals, this.endId)
|
| - : liveInstructions = new Map<HInstruction, int>(),
|
| - loopMarkers = new Map<HBasicBlock, int>();
|
| -
|
| - /**
|
| - * Remove an instruction from the liveIn set. This method also
|
| - * updates the live interval of [instruction] to contain the new
|
| - * range: [id, / id contained in [liveInstructions] /].
|
| - */
|
| - void remove(HInstruction instruction, int id) {
|
| - LiveInterval interval = liveIntervals.putIfAbsent(
|
| - instruction, () => new LiveInterval());
|
| - int lastId = liveInstructions[instruction];
|
| - // If [lastId] is null, then this instruction is not being used.
|
| - interval.add(new LiveRange(id, lastId == null ? id : lastId));
|
| - // The instruction is defined at [id].
|
| - interval.start = id;
|
| - liveInstructions.remove(instruction);
|
| - }
|
| -
|
| - /**
|
| - * Add [instruction] to the liveIn set. If the instruction is not
|
| - * already in the set, we save the id where it dies.
|
| - */
|
| - void add(HInstruction instruction, int userId) {
|
| - // Note that we are visiting the graph in post-dominator order, so
|
| - // the first time we see a variable is when it dies.
|
| - liveInstructions.putIfAbsent(instruction, () => userId);
|
| - }
|
| -
|
| - /**
|
| - * Merge this environment with [other]. Update the end id of
|
| - * instructions in case they are different between this and [other].
|
| - */
|
| - void mergeWith(LiveEnvironment other) {
|
| - other.liveInstructions.forEach((HInstruction instruction, int existingId) {
|
| - // If both environments have the same instruction id of where
|
| - // [instruction] dies, there is no need to update the live
|
| - // interval of [instruction]. For example the if block and the
|
| - // else block have the same end id for an instruction that is
|
| - // being used in the join block and defined before the if/else.
|
| - if (existingId == endId) return;
|
| - LiveInterval range = liveIntervals.putIfAbsent(
|
| - instruction, () => new LiveInterval());
|
| - range.add(new LiveRange(other.startId, existingId));
|
| - liveInstructions[instruction] = endId;
|
| - });
|
| - other.loopMarkers.forEach((k, v) { loopMarkers[k] = v; });
|
| - }
|
| -
|
| - void addLoopMarker(HBasicBlock header, int id) {
|
| - assert(!loopMarkers.containsKey(header));
|
| - loopMarkers[header] = id;
|
| - }
|
| -
|
| - void removeLoopMarker(HBasicBlock header) {
|
| - assert(loopMarkers.containsKey(header));
|
| - loopMarkers.remove(header);
|
| - }
|
| -
|
| - bool get isEmpty => liveInstructions.isEmpty && loopMarkers.isEmpty;
|
| - bool contains(HInstruction instruction) =>
|
| - liveInstructions.containsKey(instruction);
|
| - String toString() => liveInstructions.toString();
|
| -}
|
| -
|
| -/**
|
| - * Builds the live intervals of each instruction. The algorithm visits
|
| - * the graph post-dominator tree to find the last uses of an
|
| - * instruction, and computes the liveIns of each basic block.
|
| - */
|
| -class SsaLiveIntervalBuilder extends HBaseVisitor {
|
| - final Compiler compiler;
|
| - final Set<HInstruction> generateAtUseSite;
|
| - final Set<HInstruction> controlFlowOperators;
|
| -
|
| - /**
|
| - * A counter to assign start and end ids to live ranges. The initial
|
| - * value is not relevant. Note that instructionId goes downward to ease
|
| - * reasoning about live ranges (the first instruction of a graph has
|
| - * the lowest id).
|
| - */
|
| - int instructionId = 0;
|
| -
|
| - /**
|
| - * The liveIns of basic blocks.
|
| - */
|
| - final Map<HBasicBlock, LiveEnvironment> liveInstructions;
|
| -
|
| - /**
|
| - * The live intervals of instructions.
|
| - */
|
| - final Map<HInstruction, LiveInterval> liveIntervals;
|
| -
|
| - SsaLiveIntervalBuilder(
|
| - this.compiler, this.generateAtUseSite, this.controlFlowOperators)
|
| - : liveInstructions = new Map<HBasicBlock, LiveEnvironment>(),
|
| - liveIntervals = new Map<HInstruction, LiveInterval>();
|
| -
|
| - void visitGraph(HGraph graph) {
|
| - visitPostDominatorTree(graph);
|
| - if (!liveInstructions[graph.entry].isEmpty) {
|
| - compiler.internalError(CURRENT_ELEMENT_SPANNABLE, 'LiveIntervalBuilder.');
|
| - }
|
| - }
|
| -
|
| - void markInputsAsLiveInEnvironment(HInstruction instruction,
|
| - LiveEnvironment environment) {
|
| - for (int i = 0, len = instruction.inputs.length; i < len; i++) {
|
| - markAsLiveInEnvironment(instruction.inputs[i], environment);
|
| - }
|
| - }
|
| -
|
| - // Returns the non-HCheck instruction, or the last [HCheck] in the
|
| - // check chain that is not generate at use site.
|
| - //
|
| - // For example:
|
| - //
|
| - // t1 = GeneratedAtUseSite instruction
|
| - // t2 = check(t1)
|
| - // t3 = check(t2)
|
| - // t4 = use(t3)
|
| - // t5 = use(t3)
|
| - // t6 = use(t2)
|
| - //
|
| - // The t1 is generate-at-use site, and the live-range must thus be on t2 and
|
| - // not on the checked instruction t1.
|
| - // When looking for the checkedInstructionOrNonGenerateAtUseSite of t3 we must
|
| - // return t2.
|
| - HInstruction checkedInstructionOrNonGenerateAtUseSite(HCheck check) {
|
| - var checked = check.checkedInput;
|
| - while (checked is HCheck) {
|
| - HInstruction next = checked.checkedInput;
|
| - if (generateAtUseSite.contains(next)) break;
|
| - checked = next;
|
| - }
|
| - return checked;
|
| - }
|
| -
|
| - void markAsLiveInEnvironment(HInstruction instruction,
|
| - LiveEnvironment environment) {
|
| - if (generateAtUseSite.contains(instruction)) {
|
| - markInputsAsLiveInEnvironment(instruction, environment);
|
| - } else {
|
| - environment.add(instruction, instructionId);
|
| - // Special case the HCheck instruction to mark the actual
|
| - // checked instruction live. The checked instruction and the
|
| - // [HCheck] will share the same live ranges.
|
| - if (instruction is HCheck) {
|
| - HCheck check = instruction;
|
| - HInstruction checked = checkedInstructionOrNonGenerateAtUseSite(check);
|
| - if (!generateAtUseSite.contains(checked)) {
|
| - environment.add(checked, instructionId);
|
| - }
|
| - }
|
| - }
|
| - }
|
| -
|
| - void removeFromEnvironment(HInstruction instruction,
|
| - LiveEnvironment environment) {
|
| - environment.remove(instruction, instructionId);
|
| - // Special case the HCheck instruction to have the same live
|
| - // interval as the instruction it is checking.
|
| - if (instruction is HCheck) {
|
| - HCheck check = instruction;
|
| - HInstruction checked = checkedInstructionOrNonGenerateAtUseSite(check);
|
| - if (!generateAtUseSite.contains(checked)) {
|
| - liveIntervals.putIfAbsent(checked, () => new LiveInterval());
|
| - // Unconditionally force the live ranges of the HCheck to
|
| - // be the live ranges of the instruction it is checking.
|
| - liveIntervals[instruction] =
|
| - new LiveInterval.forCheck(instructionId, liveIntervals[checked]);
|
| - }
|
| - }
|
| - }
|
| -
|
| - void visitBasicBlock(HBasicBlock block) {
|
| - LiveEnvironment environment =
|
| - new LiveEnvironment(liveIntervals, instructionId);
|
| -
|
| - // If the control flow instruction in this block will actually be
|
| - // inlined in the codegen in the join block, we need to make
|
| - // whatever is used by that control flow instruction as live in
|
| - // the join block.
|
| - if (controlFlowOperators.contains(block.last)) {
|
| - HIf ifInstruction = block.last;
|
| - HBasicBlock joinBlock = ifInstruction.joinBlock;
|
| - if (generateAtUseSite.contains(joinBlock.phis.first)) {
|
| - markInputsAsLiveInEnvironment(
|
| - ifInstruction, liveInstructions[joinBlock]);
|
| - }
|
| - }
|
| -
|
| - // Add to the environment the liveIn of its successor, as well as
|
| - // the inputs of the phis of the successor that flow from this block.
|
| - for (int i = 0; i < block.successors.length; i++) {
|
| - HBasicBlock successor = block.successors[i];
|
| - LiveEnvironment successorEnv = liveInstructions[successor];
|
| - if (successorEnv != null) {
|
| - environment.mergeWith(successorEnv);
|
| - } else {
|
| - environment.addLoopMarker(successor, instructionId);
|
| - }
|
| -
|
| - int index = successor.predecessors.indexOf(block);
|
| - for (HPhi phi = successor.phis.first; phi != null; phi = phi.next) {
|
| - markAsLiveInEnvironment(phi.inputs[index], environment);
|
| - }
|
| - }
|
| -
|
| - // Iterate over all instructions to remove an instruction from the
|
| - // environment and add its inputs.
|
| - HInstruction instruction = block.last;
|
| - while (instruction != null) {
|
| - if (!generateAtUseSite.contains(instruction)) {
|
| - removeFromEnvironment(instruction, environment);
|
| - markInputsAsLiveInEnvironment(instruction, environment);
|
| - }
|
| - instructionId--;
|
| - instruction = instruction.previous;
|
| - }
|
| -
|
| - // We just remove the phis from the environment. The inputs of the
|
| - // phis will be put in the environment of the predecessors.
|
| - for (HPhi phi = block.phis.first; phi != null; phi = phi.next) {
|
| - if (!generateAtUseSite.contains(phi)) {
|
| - environment.remove(phi, instructionId);
|
| - }
|
| - }
|
| -
|
| - // Save the liveInstructions of that block.
|
| - environment.startId = instructionId + 1;
|
| - liveInstructions[block] = environment;
|
| -
|
| - // If the block is a loop header, we can remove the loop marker,
|
| - // because it will just recompute the loop phis.
|
| - // We also check if this loop header has any back edges. If not,
|
| - // we know there is no loop marker for it.
|
| - if (block.isLoopHeader() && block.predecessors.length > 1) {
|
| - updateLoopMarker(block);
|
| - }
|
| - }
|
| -
|
| - void updateLoopMarker(HBasicBlock header) {
|
| - LiveEnvironment env = liveInstructions[header];
|
| - int lastId = env.loopMarkers[header];
|
| - // Update all instructions that are liveIns in [header] to have a
|
| - // range that covers the loop.
|
| - env.liveInstructions.forEach((HInstruction instruction, int id) {
|
| - LiveInterval range = env.liveIntervals.putIfAbsent(
|
| - instruction, () => new LiveInterval());
|
| - range.loopUpdate(env.startId, lastId);
|
| - env.liveInstructions[instruction] = lastId;
|
| - });
|
| -
|
| - env.removeLoopMarker(header);
|
| -
|
| - // Update all liveIns set to contain the liveIns of [header].
|
| - liveInstructions.forEach((HBasicBlock block, LiveEnvironment other) {
|
| - if (other.loopMarkers.containsKey(header)) {
|
| - env.liveInstructions.forEach((HInstruction instruction, int id) {
|
| - other.liveInstructions[instruction] = id;
|
| - });
|
| - other.removeLoopMarker(header);
|
| - env.loopMarkers.forEach((k, v) { other.loopMarkers[k] = v; });
|
| - }
|
| - });
|
| - }
|
| -}
|
| -
|
| -/**
|
| - * Represents a copy from one instruction to another. The codegen
|
| - * also uses this class to represent a copy from one variable to
|
| - * another.
|
| - */
|
| -class Copy {
|
| - final source;
|
| - final destination;
|
| - Copy(this.source, this.destination);
|
| - String toString() => '$destination <- $source';
|
| -}
|
| -
|
| -/**
|
| - * A copy handler contains the copies that a basic block needs to do
|
| - * after executing all its instructions.
|
| - */
|
| -class CopyHandler {
|
| - /**
|
| - * The copies from an instruction to a phi of the successor.
|
| - */
|
| - final List<Copy> copies;
|
| -
|
| - /**
|
| - * Assignments from an instruction that does not need a name (e.g. a
|
| - * constant) to the phi of a successor.
|
| - */
|
| - final List<Copy> assignments;
|
| -
|
| - CopyHandler()
|
| - : copies = new List<Copy>(),
|
| - assignments = new List<Copy>();
|
| -
|
| - void addCopy(HInstruction source, HInstruction destination) {
|
| - copies.add(new Copy(source, destination));
|
| - }
|
| -
|
| - void addAssignment(HInstruction source, HInstruction destination) {
|
| - assignments.add(new Copy(source, destination));
|
| - }
|
| -
|
| - String toString() => 'Copies: $copies, assignments: $assignments';
|
| - bool get isEmpty => copies.isEmpty && assignments.isEmpty;
|
| -}
|
| -
|
| -/**
|
| - * Contains the mapping between instructions and their names for code
|
| - * generation, as well as the [CopyHandler] for each basic block.
|
| - */
|
| -class VariableNames {
|
| - final Map<HInstruction, String> ownName;
|
| - final Map<HBasicBlock, CopyHandler> copyHandlers;
|
| -
|
| - // Used to control heuristic that determines how local variables are declared.
|
| - final Set<String> allUsedNames;
|
| - /**
|
| - * Name that is used as a temporary to break cycles in
|
| - * parallel copies. We make sure this name is not being used
|
| - * anywhere by reserving it when we allocate names for instructions.
|
| - */
|
| - final String swapTemp;
|
| -
|
| - String getSwapTemp() {
|
| - allUsedNames.add(swapTemp);
|
| - return swapTemp;
|
| - }
|
| -
|
| - VariableNames()
|
| - : ownName = new Map<HInstruction, String>(),
|
| - copyHandlers = new Map<HBasicBlock, CopyHandler>(),
|
| - allUsedNames = new Set<String>(),
|
| - swapTemp = 't0';
|
| -
|
| - int get numberOfVariables => allUsedNames.length;
|
| -
|
| - String getName(HInstruction instruction) {
|
| - return ownName[instruction];
|
| - }
|
| -
|
| - CopyHandler getCopyHandler(HBasicBlock block) {
|
| - return copyHandlers[block];
|
| - }
|
| -
|
| - void addNameUsed(String name) {
|
| - allUsedNames.add(name);
|
| - }
|
| -
|
| - bool hasName(HInstruction instruction) => ownName.containsKey(instruction);
|
| -
|
| - void addCopy(HBasicBlock block, HInstruction source, HPhi destination) {
|
| - CopyHandler handler =
|
| - copyHandlers.putIfAbsent(block, () => new CopyHandler());
|
| - handler.addCopy(source, destination);
|
| - }
|
| -
|
| - void addAssignment(HBasicBlock block, HInstruction source, HPhi destination) {
|
| - CopyHandler handler =
|
| - copyHandlers.putIfAbsent(block, () => new CopyHandler());
|
| - handler.addAssignment(source, destination);
|
| - }
|
| -}
|
| -
|
| -/**
|
| - * Allocates variable names for instructions, making sure they don't collide.
|
| - */
|
| -class VariableNamer {
|
| - final VariableNames names;
|
| - final Compiler compiler;
|
| - final Set<String> usedNames;
|
| - final List<String> freeTemporaryNames;
|
| - int temporaryIndex = 0;
|
| - static final RegExp regexp = new RegExp('t[0-9]+');
|
| -
|
| - VariableNamer(LiveEnvironment environment,
|
| - this.names,
|
| - this.compiler)
|
| - : usedNames = new Set<String>(),
|
| - freeTemporaryNames = new List<String>() {
|
| - // [VariableNames.swapTemp] is used when there is a cycle in a copy handler.
|
| - // Therefore we make sure no one uses it.
|
| - usedNames.add(names.swapTemp);
|
| -
|
| - // All liveIns instructions must have a name at this point, so we
|
| - // add them to the list of used names.
|
| - environment.liveInstructions.forEach((HInstruction instruction, int index) {
|
| - String name = names.getName(instruction);
|
| - if (name != null) {
|
| - usedNames.add(name);
|
| - names.addNameUsed(name);
|
| - }
|
| - });
|
| - }
|
| -
|
| - String allocateWithHint(String originalName) {
|
| - int i = 0;
|
| - JavaScriptBackend backend = compiler.backend;
|
| - String name = backend.namer.safeVariableName(originalName);
|
| - while (usedNames.contains(name)) {
|
| - name = backend.namer.safeVariableName('$originalName${i++}');
|
| - }
|
| - return name;
|
| - }
|
| -
|
| - String allocateTemporary() {
|
| - while (!freeTemporaryNames.isEmpty) {
|
| - String name = freeTemporaryNames.removeLast();
|
| - if (!usedNames.contains(name)) return name;
|
| - }
|
| - String name = 't${temporaryIndex++}';
|
| - while (usedNames.contains(name)) name = 't${temporaryIndex++}';
|
| - return name;
|
| - }
|
| -
|
| - HPhi firstPhiUserWithElement(HInstruction instruction) {
|
| - for (HInstruction user in instruction.usedBy) {
|
| - if (user is HPhi && user.sourceElement != null) {
|
| - return user;
|
| - }
|
| - }
|
| - return null;
|
| - }
|
| -
|
| - String allocateName(HInstruction instruction) {
|
| - String name;
|
| - if (instruction is HCheck) {
|
| - // Special case this instruction to use the name of its
|
| - // input if it has one.
|
| - var temp = instruction;
|
| - do {
|
| - temp = temp.checkedInput;
|
| - name = names.ownName[temp];
|
| - } while (name == null && temp is HCheck);
|
| - if (name != null) return addAllocatedName(instruction, name);
|
| - }
|
| -
|
| - if (instruction.sourceElement != null) {
|
| - name = allocateWithHint(instruction.sourceElement.name);
|
| - } else {
|
| - // We could not find an element for the instruction. If the
|
| - // instruction is used by a phi, try to use the name of the phi.
|
| - // Otherwise, just allocate a temporary name.
|
| - HPhi phi = firstPhiUserWithElement(instruction);
|
| - if (phi != null) {
|
| - name = allocateWithHint(phi.sourceElement.name);
|
| - } else {
|
| - name = allocateTemporary();
|
| - }
|
| - }
|
| - return addAllocatedName(instruction, name);
|
| - }
|
| -
|
| - String addAllocatedName(HInstruction instruction, String name) {
|
| - usedNames.add(name);
|
| - names.addNameUsed(name);
|
| - names.ownName[instruction] = name;
|
| - return name;
|
| - }
|
| -
|
| - /**
|
| - * Frees [instruction]'s name so it can be used for other instructions.
|
| - */
|
| - void freeName(HInstruction instruction) {
|
| - String ownName = names.ownName[instruction];
|
| - if (ownName != null) {
|
| - // We check if we have already looked for temporary names
|
| - // because if we haven't, chances are the temporary we allocate
|
| - // in this block can match a phi with the same name in the
|
| - // successor block.
|
| - if (temporaryIndex != 0 && regexp.hasMatch(ownName)) {
|
| - freeTemporaryNames.add(ownName);
|
| - }
|
| - usedNames.remove(ownName);
|
| - }
|
| - }
|
| -}
|
| -
|
| -/**
|
| - * Visits all blocks in the graph, sets names to instructions, and
|
| - * creates the [CopyHandler] for each block. This class needs to have
|
| - * the liveIns set as well as all the live intervals of instructions.
|
| - * It visits the graph in dominator order, so that at each entry of a
|
| - * block, the instructions in its liveIns set have names.
|
| - *
|
| - * When visiting a block, it goes through all instructions. For each
|
| - * instruction, it frees the names of the inputs that die at that
|
| - * instruction, and allocates a name to the instruction. For each phi,
|
| - * it adds a copy to the CopyHandler of the corresponding predecessor.
|
| - */
|
| -class SsaVariableAllocator extends HBaseVisitor {
|
| -
|
| - final Compiler compiler;
|
| - final Map<HBasicBlock, LiveEnvironment> liveInstructions;
|
| - final Map<HInstruction, LiveInterval> liveIntervals;
|
| - final Set<HInstruction> generateAtUseSite;
|
| -
|
| - final VariableNames names;
|
| -
|
| - SsaVariableAllocator(this.compiler,
|
| - this.liveInstructions,
|
| - this.liveIntervals,
|
| - this.generateAtUseSite)
|
| - : this.names = new VariableNames();
|
| -
|
| - void visitGraph(HGraph graph) {
|
| - visitDominatorTree(graph);
|
| - }
|
| -
|
| - void visitBasicBlock(HBasicBlock block) {
|
| - VariableNamer namer = new VariableNamer(
|
| - liveInstructions[block], names, compiler);
|
| -
|
| - block.forEachPhi((HPhi phi) {
|
| - handlePhi(phi, namer);
|
| - });
|
| -
|
| - block.forEachInstruction((HInstruction instruction) {
|
| - handleInstruction(instruction, namer);
|
| - });
|
| - }
|
| -
|
| - /**
|
| - * Returns whether [instruction] needs a name. Instructions that
|
| - * have no users or that are generated at use site do not need a name.
|
| - */
|
| - bool needsName(instruction) {
|
| - if (instruction is HThis) return false;
|
| - if (instruction is HParameterValue) return true;
|
| - if (instruction.usedBy.isEmpty) return false;
|
| - if (generateAtUseSite.contains(instruction)) return false;
|
| - return !instruction.nonCheck().isCodeMotionInvariant();
|
| - }
|
| -
|
| - /**
|
| - * Returns whether [instruction] dies at the instruction [at].
|
| - */
|
| - bool diesAt(HInstruction instruction, HInstruction at) {
|
| - LiveInterval atInterval = liveIntervals[at];
|
| - LiveInterval instructionInterval = liveIntervals[instruction];
|
| - int start = atInterval.start;
|
| - return instructionInterval.diesAt(start);
|
| - }
|
| -
|
| - void freeUsedNamesAt(HInstruction instruction,
|
| - HInstruction at,
|
| - VariableNamer namer) {
|
| - if (needsName(instruction)) {
|
| - if (diesAt(instruction, at)) {
|
| - namer.freeName(instruction);
|
| - }
|
| - } else if (generateAtUseSite.contains(instruction)) {
|
| - // If the instruction is generated at use site, then all its
|
| - // inputs may also die at [at].
|
| - for (int i = 0, len = instruction.inputs.length; i < len; i++) {
|
| - HInstruction input = instruction.inputs[i];
|
| - freeUsedNamesAt(input, at, namer);
|
| - }
|
| - }
|
| - }
|
| -
|
| - void handleInstruction(HInstruction instruction, VariableNamer namer) {
|
| - if (generateAtUseSite.contains(instruction)) {
|
| - assert(!liveIntervals.containsKey(instruction));
|
| - return;
|
| - }
|
| -
|
| - for (int i = 0, len = instruction.inputs.length; i < len; i++) {
|
| - HInstruction input = instruction.inputs[i];
|
| - freeUsedNamesAt(input, instruction, namer);
|
| - }
|
| -
|
| - if (needsName(instruction)) {
|
| - namer.allocateName(instruction);
|
| - }
|
| - }
|
| -
|
| - void handlePhi(HPhi phi, VariableNamer namer) {
|
| - if (!needsName(phi)) return;
|
| -
|
| - for (int i = 0; i < phi.inputs.length; i++) {
|
| - HInstruction input = phi.inputs[i];
|
| - HBasicBlock predecessor = phi.block.predecessors[i];
|
| - // A [HTypeKnown] instruction never has a name, but its checked
|
| - // input might, therefore we need to do a copy instead of an
|
| - // assignment.
|
| - while (input is HTypeKnown) input = input.inputs[0];
|
| - if (!needsName(input)) {
|
| - names.addAssignment(predecessor, input, phi);
|
| - } else {
|
| - names.addCopy(predecessor, input, phi);
|
| - }
|
| - }
|
| -
|
| - namer.allocateName(phi);
|
| - }
|
| -}
|
|
|