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.cf.code; 18 19import com.android.dex.util.ExceptionWithContext; 20import com.android.dx.rop.code.RegisterSpec; 21import com.android.dx.rop.type.Type; 22import com.android.dx.rop.type.TypeBearer; 23import com.android.dx.util.Hex; 24 25/** 26 * Representation of an array of local variables, with Java semantics. 27 * 28 * <p><b>Note:</b> For the most part, the documentation for this class 29 * ignores the distinction between {@link com.android.dx.rop.type.Type} and {@link 30 * com.android.dx.rop.type.TypeBearer}.</p> 31 */ 32public class OneLocalsArray extends LocalsArray { 33 /** {@code non-null;} actual array */ 34 private final TypeBearer[] locals; 35 36 /** 37 * Constructs an instance. The locals array initially consists of 38 * all-uninitialized values (represented as {@code null}s). 39 * 40 * @param maxLocals {@code >= 0;} the maximum number of locals this instance 41 * can refer to 42 */ 43 public OneLocalsArray(int maxLocals) { 44 super(maxLocals != 0); 45 locals = new TypeBearer[maxLocals]; 46 } 47 48 /** @inheritDoc */ 49 public OneLocalsArray copy() { 50 OneLocalsArray result = new OneLocalsArray(locals.length); 51 52 System.arraycopy(locals, 0, result.locals, 0, locals.length); 53 54 return result; 55 } 56 57 /** @inheritDoc */ 58 public void annotate(ExceptionWithContext ex) { 59 for (int i = 0; i < locals.length; i++) { 60 TypeBearer type = locals[i]; 61 String s = (type == null) ? "<invalid>" : type.toString(); 62 ex.addContext("locals[" + Hex.u2(i) + "]: " + s); 63 } 64 } 65 66 /** {@inheritDoc*/ 67 public String toHuman() { 68 StringBuilder sb = new StringBuilder(); 69 70 for (int i = 0; i < locals.length; i++) { 71 TypeBearer type = locals[i]; 72 String s = (type == null) ? "<invalid>" : type.toString(); 73 sb.append("locals[" + Hex.u2(i) + "]: " + s + "\n"); 74 } 75 76 return sb.toString(); 77 } 78 79 /** @inheritDoc */ 80 public void makeInitialized(Type type) { 81 int len = locals.length; 82 83 if (len == 0) { 84 // We have to check for this before checking for immutability. 85 return; 86 } 87 88 throwIfImmutable(); 89 90 Type initializedType = type.getInitializedType(); 91 92 for (int i = 0; i < len; i++) { 93 if (locals[i] == type) { 94 locals[i] = initializedType; 95 } 96 } 97 } 98 99 /** @inheritDoc */ 100 public int getMaxLocals() { 101 return locals.length; 102 } 103 104 /** @inheritDoc */ 105 public void set(int idx, TypeBearer type) { 106 throwIfImmutable(); 107 108 try { 109 type = type.getFrameType(); 110 } catch (NullPointerException ex) { 111 // Elucidate the exception 112 throw new NullPointerException("type == null"); 113 } 114 115 if (idx < 0) { 116 throw new IndexOutOfBoundsException("idx < 0"); 117 } 118 119 // Make highest possible out-of-bounds check happen first. 120 if (type.getType().isCategory2()) { 121 locals[idx + 1] = null; 122 } 123 124 locals[idx] = type; 125 126 if (idx != 0) { 127 TypeBearer prev = locals[idx - 1]; 128 if ((prev != null) && prev.getType().isCategory2()) { 129 locals[idx - 1] = null; 130 } 131 } 132 } 133 134 /** @inheritDoc */ 135 public void set(RegisterSpec spec) { 136 set(spec.getReg(), spec); 137 } 138 139 /** @inheritDoc */ 140 public void invalidate(int idx) { 141 throwIfImmutable(); 142 locals[idx] = null; 143 } 144 145 /** @inheritDoc */ 146 public TypeBearer getOrNull(int idx) { 147 return locals[idx]; 148 } 149 150 /** @inheritDoc */ 151 public TypeBearer get(int idx) { 152 TypeBearer result = locals[idx]; 153 154 if (result == null) { 155 return throwSimException(idx, "invalid"); 156 } 157 158 return result; 159 } 160 161 /** @inheritDoc */ 162 public TypeBearer getCategory1(int idx) { 163 TypeBearer result = get(idx); 164 Type type = result.getType(); 165 166 if (type.isUninitialized()) { 167 return throwSimException(idx, "uninitialized instance"); 168 } 169 170 if (type.isCategory2()) { 171 return throwSimException(idx, "category-2"); 172 } 173 174 return result; 175 } 176 177 /** @inheritDoc */ 178 public TypeBearer getCategory2(int idx) { 179 TypeBearer result = get(idx); 180 181 if (result.getType().isCategory1()) { 182 return throwSimException(idx, "category-1"); 183 } 184 185 return result; 186 } 187 188 /** @inheritDoc */ 189 @Override 190 public LocalsArray merge(LocalsArray other) { 191 if (other instanceof OneLocalsArray) { 192 return merge((OneLocalsArray)other); 193 } else { //LocalsArraySet 194 // LocalsArraySet knows how to merge me. 195 return other.merge(this); 196 } 197 } 198 199 /** 200 * Merges this OneLocalsArray instance with another OneLocalsArray 201 * instance. A more-refined version of {@link #merge(LocalsArray) merge} 202 * which is called by that method when appropriate. 203 * 204 * @param other locals array with which to merge 205 * @return this instance if merge was a no-op, or a new instance if 206 * the merge resulted in a change. 207 */ 208 public OneLocalsArray merge(OneLocalsArray other) { 209 try { 210 return Merger.mergeLocals(this, other); 211 } catch (SimException ex) { 212 ex.addContext("underlay locals:"); 213 annotate(ex); 214 ex.addContext("overlay locals:"); 215 other.annotate(ex); 216 throw ex; 217 } 218 } 219 220 /** @inheritDoc */ 221 @Override 222 public LocalsArraySet mergeWithSubroutineCaller 223 (LocalsArray other, int predLabel) { 224 225 LocalsArraySet result = new LocalsArraySet(getMaxLocals()); 226 return result.mergeWithSubroutineCaller(other, predLabel); 227 } 228 229 /**{@inheritDoc}*/ 230 @Override 231 protected OneLocalsArray getPrimary() { 232 return this; 233 } 234 235 /** 236 * Throws a properly-formatted exception. 237 * 238 * @param idx the salient local index 239 * @param msg {@code non-null;} useful message 240 * @return never (keeps compiler happy) 241 */ 242 private static TypeBearer throwSimException(int idx, String msg) { 243 throw new SimException("local " + Hex.u2(idx) + ": " + msg); 244 } 245} 246