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