/* * 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.dex.code; import com.android.dx.rop.cst.Constant; import com.android.dx.rop.type.Type; import java.util.HashSet; /** * Container for all the pieces of a concrete method. Each instance * corresponds to a {@code code} structure in a {@code .dex} file. */ public final class DalvCode { /** * how much position info to preserve; one of the static * constants in {@link PositionList} */ private final int positionInfo; /** * {@code null-ok;} the instruction list, ready for final processing; * nulled out in {@link #finishProcessingIfNecessary} */ private OutputFinisher unprocessedInsns; /** * {@code non-null;} unprocessed catch table; * nulled out in {@link #finishProcessingIfNecessary} */ private CatchBuilder unprocessedCatches; /** * {@code null-ok;} catch table; set in * {@link #finishProcessingIfNecessary} */ private CatchTable catches; /** * {@code null-ok;} source positions list; set in * {@link #finishProcessingIfNecessary} */ private PositionList positions; /** * {@code null-ok;} local variable list; set in * {@link #finishProcessingIfNecessary} */ private LocalList locals; /** * {@code null-ok;} the processed instruction list; set in * {@link #finishProcessingIfNecessary} */ private DalvInsnList insns; /** * Constructs an instance. * * @param positionInfo how much position info to preserve; one of the * static constants in {@link PositionList} * @param unprocessedInsns {@code non-null;} the instruction list, ready * for final processing * @param unprocessedCatches {@code non-null;} unprocessed catch * (exception handler) table */ public DalvCode(int positionInfo, OutputFinisher unprocessedInsns, CatchBuilder unprocessedCatches) { if (unprocessedInsns == null) { throw new NullPointerException("unprocessedInsns == null"); } if (unprocessedCatches == null) { throw new NullPointerException("unprocessedCatches == null"); } this.positionInfo = positionInfo; this.unprocessedInsns = unprocessedInsns; this.unprocessedCatches = unprocessedCatches; this.catches = null; this.positions = null; this.locals = null; this.insns = null; } /** * Finish up processing of the method. */ private void finishProcessingIfNecessary() { if (insns != null) { return; } insns = unprocessedInsns.finishProcessingAndGetList(); positions = PositionList.make(insns, positionInfo); locals = LocalList.make(insns); catches = unprocessedCatches.build(); // Let them be gc'ed. unprocessedInsns = null; unprocessedCatches = null; } /** * Assign indices in all instructions that need them, using the * given callback to perform lookups. This must be called before * {@link #getInsns}. * * @param callback {@code non-null;} callback object */ public void assignIndices(AssignIndicesCallback callback) { unprocessedInsns.assignIndices(callback); } /** * Gets whether this instance has any position data to represent. * * @return {@code true} iff this instance has any position * data to represent */ public boolean hasPositions() { return (positionInfo != PositionList.NONE) && unprocessedInsns.hasAnyPositionInfo(); } /** * Gets whether this instance has any local variable data to represent. * * @return {@code true} iff this instance has any local variable * data to represent */ public boolean hasLocals() { return unprocessedInsns.hasAnyLocalInfo(); } /** * Gets whether this instance has any catches at all (either typed * or catch-all). * * @return whether this instance has any catches at all */ public boolean hasAnyCatches() { return unprocessedCatches.hasAnyCatches(); } /** * Gets the set of catch types handled anywhere in the code. * * @return {@code non-null;} the set of catch types */ public HashSet<Type> getCatchTypes() { return unprocessedCatches.getCatchTypes(); } /** * Gets the set of all constants referred to by instructions in * the code. * * @return {@code non-null;} the set of constants */ public HashSet<Constant> getInsnConstants() { return unprocessedInsns.getAllConstants(); } /** * Gets the list of instructions. * * @return {@code non-null;} the instruction list */ public DalvInsnList getInsns() { finishProcessingIfNecessary(); return insns; } /** * Gets the catch (exception handler) table. * * @return {@code non-null;} the catch table */ public CatchTable getCatches() { finishProcessingIfNecessary(); return catches; } /** * Gets the source positions list. * * @return {@code non-null;} the source positions list */ public PositionList getPositions() { finishProcessingIfNecessary(); return positions; } /** * Gets the source positions list. * * @return {@code non-null;} the source positions list */ public LocalList getLocals() { finishProcessingIfNecessary(); return locals; } /** * Class used as a callback for {@link #assignIndices}. */ public static interface AssignIndicesCallback { /** * Gets the index for the given constant. * * @param cst {@code non-null;} the constant * @return {@code >= -1;} the index or {@code -1} if the constant * shouldn't actually be reified with an index */ public int getIndex(Constant cst); } }