blob: 9d99833a6ee1914d5206d18cddde1f809b42009d [file] [log] [blame]
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.dx.rop.code;
import com.android.dx.rop.type.TypeList;
import com.android.dx.util.Hex;
import com.android.dx.util.IntList;
import com.android.dx.util.LabeledItem;
/**
* Basic block of register-based instructions.
*/
public final class BasicBlock implements LabeledItem {
/** {@code >= 0;} target label for this block */
private final int label;
/** {@code non-null;} list of instructions in this block */
private final InsnList insns;
/**
* {@code non-null;} full list of successors that this block may
* branch to
*/
private final IntList successors;
/**
* {@code >= -1;} the primary / standard-flow / "default" successor, or
* {@code -1} if this block has no successors (that is, it
* exits the function/method)
*/
private final int primarySuccessor;
/**
* Constructs an instance. The predecessor set is set to {@code null}.
*
* @param label {@code >= 0;} target label for this block
* @param insns {@code non-null;} list of instructions in this block
* @param successors {@code non-null;} full list of successors that this
* block may branch to
* @param primarySuccessor {@code >= -1;} the primary / standard-flow /
* "default" successor, or {@code -1} if this block has no
* successors (that is, it exits the function/method or is an
* unconditional throw)
*/
public BasicBlock(int label, InsnList insns, IntList successors,
int primarySuccessor) {
if (label < 0) {
throw new IllegalArgumentException("label < 0");
}
try {
insns.throwIfMutable();
} catch (NullPointerException ex) {
// Elucidate exception.
throw new NullPointerException("insns == null");
}
int sz = insns.size();
if (sz == 0) {
throw new IllegalArgumentException("insns.size() == 0");
}
for (int i = sz - 2; i >= 0; i--) {
Rop one = insns.get(i).getOpcode();
if (one.getBranchingness() != Rop.BRANCH_NONE) {
throw new IllegalArgumentException("insns[" + i + "] is a " +
"branch or can throw");
}
}
Insn lastInsn = insns.get(sz - 1);
if (lastInsn.getOpcode().getBranchingness() == Rop.BRANCH_NONE) {
throw new IllegalArgumentException("insns does not end with " +
"a branch or throwing " +
"instruction");
}
try {
successors.throwIfMutable();
} catch (NullPointerException ex) {
// Elucidate exception.
throw new NullPointerException("successors == null");
}
if (primarySuccessor < -1) {
throw new IllegalArgumentException("primarySuccessor < -1");
}
if (primarySuccessor >= 0 && !successors.contains(primarySuccessor)) {
throw new IllegalArgumentException(
"primarySuccessor " + primarySuccessor + " not in successors " + successors);
}
this.label = label;
this.insns = insns;
this.successors = successors;
this.primarySuccessor = primarySuccessor;
}
/**
* {@inheritDoc}
*
* Instances of this class compare by identity. That is,
* {@code x.equals(y)} is only true if {@code x == y}.
*/
@Override
public boolean equals(Object other) {
return (this == other);
}
/**
* {@inheritDoc}
*
* Return the identity hashcode of this instance. This is proper,
* since instances of this class compare by identity (see {@link #equals}).
*/
@Override
public int hashCode() {
return System.identityHashCode(this);
}
/**
* Gets the target label of this block.
*
* @return {@code >= 0;} the label
*/
public int getLabel() {
return label;
}
/**
* Gets the list of instructions inside this block.
*
* @return {@code non-null;} the instruction list
*/
public InsnList getInsns() {
return insns;
}
/**
* Gets the list of successors that this block may branch to.
*
* @return {@code non-null;} the successors list
*/
public IntList getSuccessors() {
return successors;
}
/**
* Gets the primary successor of this block.
*
* @return {@code >= -1;} the primary successor, or {@code -1} if this
* block has no successors at all
*/
public int getPrimarySuccessor() {
return primarySuccessor;
}
/**
* Gets the secondary successor of this block. It is only valid to call
* this method on blocks that have exactly two successors.
*
* @return {@code >= 0;} the secondary successor
*/
public int getSecondarySuccessor() {
if (successors.size() != 2) {
throw new UnsupportedOperationException(
"block doesn't have exactly two successors");
}
int succ = successors.get(0);
if (succ == primarySuccessor) {
succ = successors.get(1);
}
return succ;
}
/**
* Gets the first instruction of this block. This is just a
* convenient shorthand for {@code getInsns().get(0)}.
*
* @return {@code non-null;} the first instruction
*/
public Insn getFirstInsn() {
return insns.get(0);
}
/**
* Gets the last instruction of this block. This is just a
* convenient shorthand for {@code getInsns().getLast()}.
*
* @return {@code non-null;} the last instruction
*/
public Insn getLastInsn() {
return insns.getLast();
}
/**
* Returns whether this block might throw an exception. This is
* just a convenient shorthand for {@code getLastInsn().canThrow()}.
*
* @return {@code true} iff this block might throw an
* exception
*/
public boolean canThrow() {
return insns.getLast().canThrow();
}
/**
* Returns whether this block has any associated exception handlers.
* This is just a shorthand for inspecting the last instruction in
* the block to see if it could throw, and if so, whether it in fact
* has any associated handlers.
*
* @return {@code true} iff this block has any associated
* exception handlers
*/
public boolean hasExceptionHandlers() {
Insn lastInsn = insns.getLast();
return lastInsn.getCatches().size() != 0;
}
/**
* Returns the exception handler types associated with this block,
* if any. This is just a shorthand for inspecting the last
* instruction in the block to see if it could throw, and if so,
* grabbing the catch list out of it. If not, this returns an
* empty list (not {@code null}).
*
* @return {@code non-null;} the exception handler types associated with
* this block
*/
public TypeList getExceptionHandlerTypes() {
Insn lastInsn = insns.getLast();
return lastInsn.getCatches();
}
/**
* Returns an instance that is identical to this one, except that
* the registers in each instruction are offset by the given
* amount.
*
* @param delta the amount to offset register numbers by
* @return {@code non-null;} an appropriately-constructed instance
*/
public BasicBlock withRegisterOffset(int delta) {
return new BasicBlock(label, insns.withRegisterOffset(delta),
successors, primarySuccessor);
}
public String toString() {
return '{' + Hex.u2(label) + '}';
}
/**
* BasicBlock visitor interface
*/
public interface Visitor {
/**
* Visits a basic block
* @param b block visited
*/
public void visitBlock (BasicBlock b);
}
}