1/* 2 * Copyright (C) 2007 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.dx.dex.code; 18 19import com.android.dx.rop.cst.Constant; 20import com.android.dx.rop.type.Type; 21 22import java.util.HashSet; 23 24/** 25 * Container for all the pieces of a concrete method. Each instance 26 * corresponds to a {@code code} structure in a {@code .dex} file. 27 */ 28public final class DalvCode { 29 /** 30 * how much position info to preserve; one of the static 31 * constants in {@link PositionList} 32 */ 33 private final int positionInfo; 34 35 /** 36 * {@code null-ok;} the instruction list, ready for final processing; 37 * nulled out in {@link #finishProcessingIfNecessary} 38 */ 39 private OutputFinisher unprocessedInsns; 40 41 /** 42 * {@code non-null;} unprocessed catch table; 43 * nulled out in {@link #finishProcessingIfNecessary} 44 */ 45 private CatchBuilder unprocessedCatches; 46 47 /** 48 * {@code null-ok;} catch table; set in 49 * {@link #finishProcessingIfNecessary} 50 */ 51 private CatchTable catches; 52 53 /** 54 * {@code null-ok;} source positions list; set in 55 * {@link #finishProcessingIfNecessary} 56 */ 57 private PositionList positions; 58 59 /** 60 * {@code null-ok;} local variable list; set in 61 * {@link #finishProcessingIfNecessary} 62 */ 63 private LocalList locals; 64 65 /** 66 * {@code null-ok;} the processed instruction list; set in 67 * {@link #finishProcessingIfNecessary} 68 */ 69 private DalvInsnList insns; 70 71 /** 72 * Constructs an instance. 73 * 74 * @param positionInfo how much position info to preserve; one of the 75 * static constants in {@link PositionList} 76 * @param unprocessedInsns {@code non-null;} the instruction list, ready 77 * for final processing 78 * @param unprocessedCatches {@code non-null;} unprocessed catch 79 * (exception handler) table 80 */ 81 public DalvCode(int positionInfo, OutputFinisher unprocessedInsns, 82 CatchBuilder unprocessedCatches) { 83 if (unprocessedInsns == null) { 84 throw new NullPointerException("unprocessedInsns == null"); 85 } 86 87 if (unprocessedCatches == null) { 88 throw new NullPointerException("unprocessedCatches == null"); 89 } 90 91 this.positionInfo = positionInfo; 92 this.unprocessedInsns = unprocessedInsns; 93 this.unprocessedCatches = unprocessedCatches; 94 this.catches = null; 95 this.positions = null; 96 this.locals = null; 97 this.insns = null; 98 } 99 100 /** 101 * Finish up processing of the method. 102 */ 103 private void finishProcessingIfNecessary() { 104 if (insns != null) { 105 return; 106 } 107 108 insns = unprocessedInsns.finishProcessingAndGetList(); 109 positions = PositionList.make(insns, positionInfo); 110 locals = LocalList.make(insns); 111 catches = unprocessedCatches.build(); 112 113 // Let them be gc'ed. 114 unprocessedInsns = null; 115 unprocessedCatches = null; 116 } 117 118 /** 119 * Assign indices in all instructions that need them, using the 120 * given callback to perform lookups. This must be called before 121 * {@link #getInsns}. 122 * 123 * @param callback {@code non-null;} callback object 124 */ 125 public void assignIndices(AssignIndicesCallback callback) { 126 unprocessedInsns.assignIndices(callback); 127 } 128 129 /** 130 * Gets whether this instance has any position data to represent. 131 * 132 * @return {@code true} iff this instance has any position 133 * data to represent 134 */ 135 public boolean hasPositions() { 136 return (positionInfo != PositionList.NONE) 137 && unprocessedInsns.hasAnyPositionInfo(); 138 } 139 140 /** 141 * Gets whether this instance has any local variable data to represent. 142 * 143 * @return {@code true} iff this instance has any local variable 144 * data to represent 145 */ 146 public boolean hasLocals() { 147 return unprocessedInsns.hasAnyLocalInfo(); 148 } 149 150 /** 151 * Gets whether this instance has any catches at all (either typed 152 * or catch-all). 153 * 154 * @return whether this instance has any catches at all 155 */ 156 public boolean hasAnyCatches() { 157 return unprocessedCatches.hasAnyCatches(); 158 } 159 160 /** 161 * Gets the set of catch types handled anywhere in the code. 162 * 163 * @return {@code non-null;} the set of catch types 164 */ 165 public HashSet<Type> getCatchTypes() { 166 return unprocessedCatches.getCatchTypes(); 167 } 168 169 /** 170 * Gets the set of all constants referred to by instructions in 171 * the code. 172 * 173 * @return {@code non-null;} the set of constants 174 */ 175 public HashSet<Constant> getInsnConstants() { 176 return unprocessedInsns.getAllConstants(); 177 } 178 179 /** 180 * Gets the list of instructions. 181 * 182 * @return {@code non-null;} the instruction list 183 */ 184 public DalvInsnList getInsns() { 185 finishProcessingIfNecessary(); 186 return insns; 187 } 188 189 /** 190 * Gets the catch (exception handler) table. 191 * 192 * @return {@code non-null;} the catch table 193 */ 194 public CatchTable getCatches() { 195 finishProcessingIfNecessary(); 196 return catches; 197 } 198 199 /** 200 * Gets the source positions list. 201 * 202 * @return {@code non-null;} the source positions list 203 */ 204 public PositionList getPositions() { 205 finishProcessingIfNecessary(); 206 return positions; 207 } 208 209 /** 210 * Gets the source positions list. 211 * 212 * @return {@code non-null;} the source positions list 213 */ 214 public LocalList getLocals() { 215 finishProcessingIfNecessary(); 216 return locals; 217 } 218 219 /** 220 * Class used as a callback for {@link #assignIndices}. 221 */ 222 public static interface AssignIndicesCallback { 223 /** 224 * Gets the index for the given constant. 225 * 226 * @param cst {@code non-null;} the constant 227 * @return {@code >= -1;} the index or {@code -1} if the constant 228 * shouldn't actually be reified with an index 229 */ 230 public int getIndex(Constant cst); 231 } 232} 233