1 /* 2 * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package java.lang.invoke; 27 28 import java.util.ArrayList; 29 import java.util.Arrays; 30 import static java.lang.invoke.LambdaForm.*; 31 import static java.lang.invoke.LambdaForm.BasicType.*; 32 33 /** Working storage for an LF that is being transformed. 34 * Similarly to a StringBuffer, the editing can take place in multiple steps. 35 */ 36 final class LambdaFormBuffer { 37 private int arity, length; 38 private Name[] names; 39 private Name[] originalNames; // snapshot of pre-transaction names 40 private byte flags; 41 private int firstChange; 42 private Name resultName; 43 private ArrayList<Name> dups; 44 45 private static final int F_TRANS = 0x10, F_OWNED = 0x03; 46 47 LambdaFormBuffer(LambdaForm lf) { 48 this.arity = lf.arity; 49 setNames(lf.names); 50 int result = lf.result; 51 if (result == LAST_RESULT) result = length - 1; 52 if (result >= 0 && lf.names[result].type != V_TYPE) { 53 resultName = lf.names[result]; 54 } 55 assert(lf.nameRefsAreLegal()); 56 } 57 58 private LambdaForm lambdaForm() { 59 assert(!inTrans()); // need endEdit call to tidy things up 60 return new LambdaForm(arity, nameArray(), resultIndex()); 61 } 62 63 Name name(int i) { 64 assert(i < length); 65 return names[i]; 66 } 67 68 Name[] nameArray() { 69 return Arrays.copyOf(names, length); 70 } 71 72 int resultIndex() { 73 if (resultName == null) return VOID_RESULT; 74 int index = indexOf(resultName, names); 75 assert(index >= 0); 76 return index; 77 } 78 79 void setNames(Name[] names2) { 80 names = originalNames = names2; // keep a record of where everything was to start with 81 length = names2.length; 82 flags = 0; 83 } 84 85 private boolean verifyArity() { 86 for (int i = 0; i < arity && i < firstChange; i++) { 87 assert(names[i].isParam()) : "#" + i + "=" + names[i]; 88 } 89 for (int i = arity; i < length; i++) { 90 assert(!names[i].isParam()) : "#" + i + "=" + names[i]; 91 } 92 for (int i = length; i < names.length; i++) { 93 assert(names[i] == null) : "#" + i + "=" + names[i]; 94 } 95 // check resultName also 96 if (resultName != null) { 97 int resultIndex = indexOf(resultName, names); 98 assert(resultIndex >= 0) : "not found: " + resultName.exprString() + Arrays.asList(names); 99 assert(names[resultIndex] == resultName); 100 } 101 return true; 102 } 103 104 private boolean verifyFirstChange() { 105 assert(inTrans()); 106 for (int i = 0; i < length; i++) { 107 if (names[i] != originalNames[i]) { 108 assert(firstChange == i) : Arrays.asList(firstChange, i, originalNames[i].exprString(), Arrays.asList(names)); 109 return true; 110 } 111 } 112 assert(firstChange == length) : Arrays.asList(firstChange, Arrays.asList(names)); 113 return true; 114 } 115 116 private static int indexOf(NamedFunction fn, NamedFunction[] fns) { 117 for (int i = 0; i < fns.length; i++) { 118 if (fns[i] == fn) return i; 119 } 120 return -1; 121 } 122 123 private static int indexOf(Name n, Name[] ns) { 124 for (int i = 0; i < ns.length; i++) { 125 if (ns[i] == n) return i; 126 } 127 return -1; 128 } 129 130 boolean inTrans() { 131 return (flags & F_TRANS) != 0; 132 } 133 134 int ownedCount() { 135 return flags & F_OWNED; 136 } 137 138 void growNames(int insertPos, int growLength) { 139 int oldLength = length; 140 int newLength = oldLength + growLength; 141 int oc = ownedCount(); 142 if (oc == 0 || newLength > names.length) { 143 names = Arrays.copyOf(names, (names.length + growLength) * 5 / 4); 144 if (oc == 0) { 145 flags++; 146 oc++; 147 assert(ownedCount() == oc); 148 } 149 } 150 if (originalNames != null && originalNames.length < names.length) { 151 originalNames = Arrays.copyOf(originalNames, names.length); 152 if (oc == 1) { 153 flags++; 154 oc++; 155 assert(ownedCount() == oc); 156 } 157 } 158 if (growLength == 0) return; 159 int insertEnd = insertPos + growLength; 160 int tailLength = oldLength - insertPos; 161 System.arraycopy(names, insertPos, names, insertEnd, tailLength); 162 Arrays.fill(names, insertPos, insertEnd, null); 163 if (originalNames != null) { 164 System.arraycopy(originalNames, insertPos, originalNames, insertEnd, tailLength); 165 Arrays.fill(originalNames, insertPos, insertEnd, null); 166 } 167 length = newLength; 168 if (firstChange >= insertPos) { 169 firstChange += growLength; 170 } 171 } 172 173 int lastIndexOf(Name n) { 174 int result = -1; 175 for (int i = 0; i < length; i++) { 176 if (names[i] == n) result = i; 177 } 178 return result; 179 } 180 181 /** We have just overwritten the name at pos1 with the name at pos2. 182 * This means that there are two copies of the name, which we will have to fix later. 183 */ 184 private void noteDuplicate(int pos1, int pos2) { 185 Name n = names[pos1]; 186 assert(n == names[pos2]); 187 assert(originalNames[pos1] != null); // something was replaced at pos1 188 assert(originalNames[pos2] == null || originalNames[pos2] == n); 189 if (dups == null) { 190 dups = new ArrayList<>(); 191 } 192 dups.add(n); 193 } 194 195 /** Replace duplicate names by nulls, and remove all nulls. */ 196 private void clearDuplicatesAndNulls() { 197 if (dups != null) { 198 // Remove duplicates. 199 assert(ownedCount() >= 1); 200 for (Name dup : dups) { 201 for (int i = firstChange; i < length; i++) { 202 if (names[i] == dup && originalNames[i] != dup) { 203 names[i] = null; 204 assert(Arrays.asList(names).contains(dup)); 205 break; // kill only one dup 206 } 207 } 208 } 209 dups.clear(); 210 } 211 // Now that we are done with originalNames, remove "killed" names. 212 int oldLength = length; 213 for (int i = firstChange; i < length; i++) { 214 if (names[i] == null) { 215 System.arraycopy(names, i + 1, names, i, (--length - i)); 216 --i; // restart loop at this position 217 } 218 } 219 if (length < oldLength) { 220 Arrays.fill(names, length, oldLength, null); 221 } 222 assert(!Arrays.asList(names).subList(0, length).contains(null)); 223 } 224 225 /** Create a private, writable copy of names. 226 * Preserve the original copy, for reference. 227 */ 228 void startEdit() { 229 assert(verifyArity()); 230 int oc = ownedCount(); 231 assert(!inTrans()); // no nested transactions 232 flags |= F_TRANS; 233 Name[] oldNames = names; 234 Name[] ownBuffer = (oc == 2 ? originalNames : null); 235 assert(ownBuffer != oldNames); 236 if (ownBuffer != null && ownBuffer.length >= length) { 237 names = copyNamesInto(ownBuffer); 238 } else { 239 // make a new buffer to hold the names 240 final int SLOP = 2; 241 names = Arrays.copyOf(oldNames, Math.max(length + SLOP, oldNames.length)); 242 if (oc < 2) ++flags; 243 assert(ownedCount() == oc + 1); 244 } 245 originalNames = oldNames; 246 assert(originalNames != names); 247 firstChange = length; 248 assert(inTrans()); 249 } 250 251 void changeName(int i, Name name) { 252 assert(inTrans()); 253 assert(i < length); 254 Name oldName = names[i]; 255 assert(oldName == originalNames[i]); // no multiple changes 256 assert(verifyFirstChange()); 257 if (ownedCount() == 0) 258 growNames(0, 0); 259 names[i] = name; 260 if (firstChange > i) { 261 firstChange = i; 262 } 263 if (resultName != null && resultName == oldName) { 264 resultName = name; 265 } 266 } 267 268 /** Change the result name. Null means a void result. */ 269 void setResult(Name name) { 270 assert(name == null || lastIndexOf(name) >= 0); 271 resultName = name; 272 } 273 274 /** Finish a transaction. */ 275 LambdaForm endEdit() { 276 assert(verifyFirstChange()); 277 // Assuming names have been changed pairwise from originalNames[i] to names[i], 278 // update arguments to ensure referential integrity. 279 for (int i = Math.max(firstChange, arity); i < length; i++) { 280 Name name = names[i]; 281 if (name == null) continue; // space for removed duplicate 282 Name newName = name.replaceNames(originalNames, names, firstChange, i); 283 if (newName != name) { 284 names[i] = newName; 285 if (resultName == name) { 286 resultName = newName; 287 } 288 } 289 } 290 assert(inTrans()); 291 flags &= ~F_TRANS; 292 clearDuplicatesAndNulls(); 293 originalNames = null; 294 // If any parameters have been changed, then reorder them as needed. 295 // This is a "sheep-and-goats" stable sort, pushing all non-parameters 296 // to the right of all parameters. 297 if (firstChange < arity) { 298 Name[] exprs = new Name[arity - firstChange]; 299 int argp = firstChange, exprp = 0; 300 for (int i = firstChange; i < arity; i++) { 301 Name name = names[i]; 302 if (name.isParam()) { 303 names[argp++] = name; 304 } else { 305 exprs[exprp++] = name; 306 } 307 } 308 assert(exprp == (arity - argp)); 309 // copy the exprs just after the last remaining param 310 System.arraycopy(exprs, 0, names, argp, exprp); 311 // adjust arity 312 arity -= exprp; 313 } 314 assert(verifyArity()); 315 return lambdaForm(); 316 } 317 318 private Name[] copyNamesInto(Name[] buffer) { 319 System.arraycopy(names, 0, buffer, 0, length); 320 Arrays.fill(buffer, length, buffer.length, null); 321 return buffer; 322 } 323 324 /** Replace any Name whose function is in oldFns with a copy 325 * whose function is in the corresponding position in newFns. 326 * Only do this if the arguments are exactly equal to the given. 327 */ 328 LambdaFormBuffer replaceFunctions(NamedFunction[] oldFns, NamedFunction[] newFns, 329 Object... forArguments) { 330 assert(inTrans()); 331 if (oldFns.length == 0) return this; 332 for (int i = arity; i < length; i++) { 333 Name n = names[i]; 334 int nfi = indexOf(n.function, oldFns); 335 if (nfi >= 0 && Arrays.equals(n.arguments, forArguments)) { 336 changeName(i, new Name(newFns[nfi], n.arguments)); 337 } 338 } 339 return this; 340 } 341 342 private void replaceName(int pos, Name binding) { 343 assert(inTrans()); 344 assert(verifyArity()); 345 assert(pos < arity); 346 Name param = names[pos]; 347 assert(param.isParam()); 348 assert(param.type == binding.type); 349 changeName(pos, binding); 350 } 351 352 /** Replace a parameter by a fresh parameter. */ 353 LambdaFormBuffer renameParameter(int pos, Name newParam) { 354 assert(newParam.isParam()); 355 replaceName(pos, newParam); 356 return this; 357 } 358 359 /** Replace a parameter by a fresh expression. */ 360 LambdaFormBuffer replaceParameterByNewExpression(int pos, Name binding) { 361 assert(!binding.isParam()); 362 assert(lastIndexOf(binding) < 0); // else use replaceParameterByCopy 363 replaceName(pos, binding); 364 return this; 365 } 366 367 /** Replace a parameter by another parameter or expression already in the form. */ 368 LambdaFormBuffer replaceParameterByCopy(int pos, int valuePos) { 369 assert(pos != valuePos); 370 replaceName(pos, names[valuePos]); 371 noteDuplicate(pos, valuePos); // temporarily, will occur twice in the names array 372 return this; 373 } 374 375 private void insertName(int pos, Name expr, boolean isParameter) { 376 assert(inTrans()); 377 assert(verifyArity()); 378 assert(isParameter ? pos <= arity : pos >= arity); 379 growNames(pos, 1); 380 if (isParameter) arity += 1; 381 changeName(pos, expr); 382 } 383 384 /** Insert a fresh expression. */ 385 LambdaFormBuffer insertExpression(int pos, Name expr) { 386 assert(!expr.isParam()); 387 insertName(pos, expr, false); 388 return this; 389 } 390 391 /** Insert a fresh parameter. */ 392 LambdaFormBuffer insertParameter(int pos, Name param) { 393 assert(param.isParam()); 394 insertName(pos, param, true); 395 return this; 396 } 397 }