1 /* 2 * Copyright (c) 2017, 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 jdk.experimental.bytecode.*; 29 import jdk.experimental.bytecode.MacroCodeBuilder.FieldAccessKind; 30 import jdk.experimental.bytecode.MacroCodeBuilder.InvocationKind; 31 import jdk.experimental.value.MethodHandleBuilder; 32 import sun.invoke.util.VerifyType; 33 import sun.invoke.util.Wrapper; 34 import valhalla.shady.MinimalValueTypes_1_0; 35 36 import java.lang.invoke.LambdaForm.BasicType; 37 import java.lang.invoke.LambdaForm.Name; 38 import java.lang.invoke.MethodHandles.Lookup; 39 import java.util.Arrays; 40 import java.util.stream.Stream; 41 42 import static java.lang.invoke.LambdaForm.BasicType.L_TYPE; 43 import static java.lang.invoke.LambdaForm.BasicType.V_TYPE; 44 import static java.lang.invoke.LambdaForm.BasicType.basicType; 45 import static java.lang.invoke.MethodHandleNatives.Constants.REF_getField; 46 import static java.lang.invoke.MethodHandleNatives.Constants.REF_getStatic; 47 import static java.lang.invoke.MethodHandleNatives.Constants.REF_invokeInterface; 48 import static java.lang.invoke.MethodHandleNatives.Constants.REF_invokeSpecial; 49 import static java.lang.invoke.MethodHandleNatives.Constants.REF_invokeStatic; 50 import static java.lang.invoke.MethodHandleNatives.Constants.REF_invokeVirtual; 51 import static java.lang.invoke.MethodHandleNatives.Constants.REF_putField; 52 import static java.lang.invoke.MethodHandleNatives.Constants.REF_putStatic; 53 import static java.lang.invoke.MethodHandleStatics.PROFILE_GWT; 54 import static java.lang.invoke.MethodHandleStatics.PROFILE_LEVEL; 55 import static java.lang.invoke.MethodHandleStatics.newInternalError; 56 import static jdk.experimental.bytecode.MacroCodeBuilder.CondKind.EQ; 57 import static jdk.experimental.bytecode.MacroCodeBuilder.CondKind.NE; 58 59 /** 60 * Utility class for spinning classfiles associated with lambda forms. 61 */ 62 class LambdaFormBuilder extends MethodHandleBuilder { 63 64 private static final String OBJ = "java/lang/Object"; 65 private static final String CLASS_PREFIX = "java/lang/invoke/LambdaForm$Value$"; 66 private static final String DEFAULT_CLASS = "MH"; 67 private static final String LL_SIG = "(L" + OBJ + ";)L" + OBJ + ";"; 68 private static final String LLV_SIG = "(L" + OBJ + ";L" + OBJ + ";)V"; 69 70 private static final String MH = "java/lang/invoke/MethodHandle"; 71 private static final String MHARY2 = "[[L" + MH + ";"; 72 73 static MemberName generateCustomizedCode(LambdaForm form, MethodType invokerType) { 74 String invokerName = form.lambdaName(); 75 int p = invokerName.indexOf('.'); 76 boolean overrideNames = p != -1; 77 String methodName = overrideNames ? invokerName.substring(p + 1) : invokerName; 78 String className = overrideNames ? 79 CLASS_PREFIX + invokerName.substring(0, p) : 80 CLASS_PREFIX + DEFAULT_CLASS; 81 if (MinimalValueTypes_1_0.DUMP_CLASS_FILES) { 82 // When DUMP_CLASS_FILES is true methodName will have a unique id 83 className = className + "_" + methodName; 84 } 85 return MethodHandleBuilder.loadCode(Lookup.IMPL_LOOKUP.in(LambdaForm.class), className, methodName, invokerType.toMethodDescriptorString(), 86 M -> new LambdaFormCodeBuilder(form, invokerType, M), clazz -> InvokerBytecodeGenerator.resolveInvokerMember(clazz, methodName, invokerType), 87 C -> new LambdaFormBuilder(C, form).generateLambdaFormBody()); 88 } 89 90 LambdaFormCodeBuilder builder; 91 LambdaForm lambdaForm; 92 93 LambdaFormBuilder(LambdaFormCodeBuilder builder, LambdaForm lambdaForm) { 94 this.builder = builder; 95 this.lambdaForm = lambdaForm; 96 } 97 98 /** Generates code to check that actual receiver and LambdaForm matches */ 99 private boolean checkActualReceiver() { 100 // Expects MethodHandle on the stack and actual receiver MethodHandle in slot #0 101 builder.dup().load(0).invokestatic(MethodHandleImpl.class, "assertSame", LLV_SIG, false); 102 return true; 103 } 104 105 void generateLambdaFormBody() { 106 if (lambdaForm.customized != null && MethodHandleBuilder.ENABLE_POOL_PATCHES) { 107 // Since LambdaForm is customized for a particular MethodHandle, it's safe to substitute 108 // receiver MethodHandle (at slot #0) with an embedded constant and use it instead. 109 // It enables more efficient code generation in some situations, since embedded constants 110 // are compile-time constants for JIT compiler. 111 builder.ldc(lambdaForm.customized) 112 .checkcast(MethodHandle.class); 113 assert(checkActualReceiver()); // generates runtime check 114 builder.store(0); 115 } 116 117 // iterate over the form's names, generating bytecode instructions for each 118 // start iterating at the first name following the arguments 119 Name onStack = null; 120 for (int i = lambdaForm.arity; i < lambdaForm.names.length; i++) { 121 Name name = lambdaForm.names[i]; 122 123 if (onStack != null && onStack.type != V_TYPE) { 124 // non-void: actually assign 125 builder.store(fromBasicType(onStack.type), onStack.index()); 126 } 127 onStack = name; // unless otherwise modified below 128 MemberName member = name.function.member(); 129 MethodHandleImpl.Intrinsic intr = name.function.intrinsicName(); 130 switch (intr) { 131 case SELECT_ALTERNATIVE: { 132 assert lambdaForm.isSelectAlternative(i); 133 if (PROFILE_GWT) { 134 assert(name.arguments[0] instanceof Name && 135 ((Name)name.arguments[0]).refersTo(MethodHandleImpl.class, "profileBoolean")); 136 builder.method().withAnnotation(AnnotationsBuilder.Kind.RUNTIME_VISIBLE, InvokerBytecodeGenerator.INJECTEDPROFILE_SIG); 137 } 138 onStack = emitSelectAlternative(name, lambdaForm.names[i+1]); 139 i++; // skip MH.invokeBasic of the selectAlternative result 140 continue; 141 142 } 143 144 case LOOP: { 145 assert lambdaForm.isLoop(i); 146 onStack = emitLoop(i); 147 i += 2; // jump to the end of the LOOP idiom 148 continue; 149 } 150 case IDENTITY: { 151 assert (name.arguments.length == 1); 152 builder.pushArguments(name, 0); 153 continue; 154 } 155 case ZERO: { 156 assert (name.arguments.length == 0); 157 assert (name.type != BasicType.Q_TYPE); 158 builder.ldc(name.type.basicTypeWrapper().zero()); 159 continue; 160 } 161 // TODO: case GUARD_WITH_CATCH: 162 // TODO: case TRY_FINALLY: 163 // TODO: case NEW_ARRAY: 164 // TODO: case ARRAY_LOAD: 165 // TODO: case ARRAY_STORE: 166 // TODO: case ARRAY_LENGTH: 167 } 168 if (InvokerBytecodeGenerator.isStaticallyInvocable(member)) { 169 builder.invokeStaticName(member, name); 170 } else { 171 builder.invokeName(name); 172 } 173 } 174 builder.return_(onStack); 175 } 176 177 private Name emitLoop(int pos) { 178 Name args = lambdaForm.names[pos]; 179 Name invoker = lambdaForm.names[pos+1]; 180 Name result = lambdaForm.names[pos+2]; 181 182 // extract clause and loop-local state types 183 // find the type info in the loop invocation 184 BasicType[] loopClauseTypes = (BasicType[]) invoker.arguments[0]; 185 Class<?>[] loopLocalStateTypes = Stream.of(loopClauseTypes). 186 filter(bt -> bt != BasicType.V_TYPE).map(BasicType::basicTypeClass).toArray(Class<?>[]::new); 187 188 Class<?>[] localTypes = new Class<?>[loopLocalStateTypes.length + 1]; 189 localTypes[0] = MethodHandleImpl.LoopClauses.class; 190 System.arraycopy(loopLocalStateTypes, 0, localTypes, 1, loopLocalStateTypes.length); 191 192 final int clauseDataIndex = builder.extendLocalsMap(localTypes); 193 final int firstLoopStateIndex = clauseDataIndex + 1; 194 195 Class<?> returnType = result.function.resolvedHandle().type().returnType(); 196 MethodType loopType = args.function.resolvedHandle().type() 197 .dropParameterTypes(0,1) 198 .changeReturnType(returnType); 199 MethodType loopHandleType = loopType.insertParameterTypes(0, loopLocalStateTypes); 200 MethodType predType = loopHandleType.changeReturnType(boolean.class); 201 MethodType finiType = loopHandleType; 202 203 final int nClauses = loopClauseTypes.length; 204 205 // indices to invoker arguments to load method handle arrays 206 final int inits = 1; 207 final int steps = 2; 208 final int preds = 3; 209 final int finis = 4; 210 211 // PREINIT: 212 builder.pushArgument(MethodHandleImpl.LoopClauses.class, invoker.arguments[1]) 213 .getfield(MethodHandleImpl.LoopClauses.class, "clauses", MHARY2) 214 .store(TypeTag.A, clauseDataIndex); 215 216 // INIT: 217 for (int c = 0, state = 0; c < nClauses; ++c) { 218 MethodType cInitType = loopType.changeReturnType(loopClauseTypes[c].basicTypeClass()); 219 builder.invokeLoopHandle(inits, c, args, false, cInitType, loopLocalStateTypes, clauseDataIndex, firstLoopStateIndex); 220 if (cInitType.returnType() != void.class) { 221 builder.store(fromClass(cInitType.returnType()), firstLoopStateIndex + state); 222 ++state; 223 } 224 } 225 226 // LOOP: 227 String loopLabel = builder.label(); 228 String doneLabel = builder.label(); 229 builder.label(loopLabel); 230 231 String val = null; 232 for (int c = 0, s = 0; c < nClauses; ++c) { 233 MethodType stepType = loopHandleType.changeReturnType(loopClauseTypes[c].basicTypeClass()); 234 boolean isVoid = (stepType.returnType() == void.class); 235 236 // invoke loop step 237 builder.invokeLoopHandle(steps, c, args, true, stepType, loopLocalStateTypes, clauseDataIndex, firstLoopStateIndex); 238 if (!isVoid) { 239 builder.store(fromClass(stepType.returnType()), firstLoopStateIndex + s); 240 ++s; 241 } 242 243 String nextLabel = builder.label(); 244 245 // invoke loop predicate 246 builder.invokeLoopHandle(preds, c, args, true, predType, loopLocalStateTypes, clauseDataIndex, firstLoopStateIndex) 247 .emitCondJump(Opcode.IFEQ, NE, nextLabel) 248 .invokeLoopHandle(finis, c, args, true, finiType, loopLocalStateTypes, clauseDataIndex, firstLoopStateIndex) 249 .goto_(doneLabel) 250 .label(nextLabel); 251 } 252 builder.goto_(loopLabel) 253 .label(doneLabel); 254 255 return result; 256 } 257 258 /** 259 * Emit bytecode for the selectAlternative idiom. 260 * 261 * The pattern looks like (Cf. MethodHandleImpl.makeGuardWithTest): 262 * <blockquote><pre>{@code 263 * Lambda(a0:L,a1:I)=>{ 264 * t2:I=foo.test(a1:I); 265 * t3:L=MethodHandleImpl.selectAlternative(t2:I,(MethodHandle(int)int),(MethodHandle(int)int)); 266 * t4:I=MethodHandle.invokeBasic(t3:L,a1:I);t4:I} 267 * }</pre></blockquote> 268 */ 269 private Name emitSelectAlternative(Name selectAlternativeName, Name invokeBasicName) { 270 assert InvokerBytecodeGenerator.isStaticallyInvocable(invokeBasicName); 271 272 Name receiver = (Name) invokeBasicName.arguments[0]; 273 274 String fallbackLabel = builder.label(); 275 String doneLabel = builder.label(); 276 277 builder.pushArgument(selectAlternativeName, 0) // load test result 278 .emitCondJump(Opcode.IFEQ, EQ, fallbackLabel) // if_icmp L_fallback 279 .pushArgument(selectAlternativeName, 1) // get 2nd argument of selectAlternative 280 .store(TypeTag.A, receiver.index()) // store the MH in the receiver slot 281 .invokeStaticName(invokeBasicName) // invoke selectAlternativeName.arguments[1] 282 .goto_(doneLabel) 283 .label(fallbackLabel) 284 .pushArgument(selectAlternativeName, 2) // get 3rd argument of selectAlternative 285 .store(TypeTag.A, receiver.index()) // store the MH in the receiver slot 286 .invokeStaticName(invokeBasicName) // invoke selectAlternativeName.arguments[2] 287 .label(doneLabel); 288 289 return invokeBasicName; // return what's on stack 290 } 291 292 static class LambdaFormCodeBuilder extends MethodHandleCodeBuilder<LambdaFormCodeBuilder> { 293 294 LambdaForm lambdaForm; 295 MethodType invokerType; 296 int maxLocals; 297 int[] localsMap; 298 private MethodBuilder<Class<?>, String, byte[]> methodBuilder; 299 private int labelCount = 0; 300 301 public LambdaFormCodeBuilder(LambdaForm form, MethodType invokerType, MethodBuilder<Class<?>, String, byte[]> methodBuilder) { 302 super(methodBuilder); 303 if (form.forceInline) { 304 methodBuilder.withAnnotation(AnnotationsBuilder.Kind.RUNTIME_VISIBLE, "Ljdk/internal/vm/annotation/ForceInline;"); 305 } 306 methodBuilder.withAnnotation(AnnotationsBuilder.Kind.RUNTIME_VISIBLE, "Ljava/lang/invoke/LambdaForm$Hidden;") 307 .withAnnotation(AnnotationsBuilder.Kind.RUNTIME_VISIBLE, "Ljava/lang/invoke/LambdaForm$Compiled;"); 308 this.lambdaForm = form; 309 this.invokerType = invokerType; 310 this.maxLocals = form.names.length; 311 this.localsMap = computeLocalsMap(form); 312 this.methodBuilder = methodBuilder; 313 } 314 315 static int[] computeLocalsMap(LambdaForm lform) { 316 int localsMapSize = lform.names.length; 317 int[] localsMap = new int[localsMapSize+1]; // last entry of localsMap is count of allocated local slots 318 for (int i = 0, index = 0; i < localsMap.length; i++) { 319 localsMap[i] = index; 320 if (i < lform.names.length) { 321 BasicType type = lform.names[i].type(); 322 index += type.basicTypeSlots(); 323 } 324 } 325 return localsMap; 326 } 327 328 @Override 329 public LambdaFormCodeBuilder load(int index) { 330 return super.load(localsMap[index]); 331 } 332 333 @Override 334 public LambdaFormCodeBuilder store(int index) { 335 return super.store(localsMap[index]); 336 } 337 338 @Override 339 public LambdaFormCodeBuilder load(TypeTag type, int n) { 340 return super.load(type, localsMap[n]); 341 } 342 343 @Override 344 public LambdaFormCodeBuilder store(TypeTag type, int n) { 345 return super.store(type, localsMap[n]); 346 } 347 348 /** 349 * Emits a return statement from a LF invoker. If required, the result type is cast to the correct return type. 350 */ 351 private void return_(Name onStack) { 352 // return statement 353 Class<?> rclass = invokerType.returnType(); 354 BasicType rtype = lambdaForm.returnType(); 355 assert(rtype == basicType(rclass)); // must agree 356 if (rtype == V_TYPE) { 357 // void 358 return_(); 359 // it doesn't matter what rclass is; the JVM will discard any value 360 } else { 361 LambdaForm.Name rn = lambdaForm.names[lambdaForm.result]; 362 363 // put return value on the stack if it is not already there 364 if (rn != onStack) { 365 load(lambdaForm.result); 366 } 367 368 coerce(rtype, rclass, rn); 369 370 // generate actual return statement 371 return_(fromBasicType(rtype)); 372 } 373 } 374 375 /** 376 * Emit an implicit conversion for an argument which must be of the given pclass. 377 * This is usually a no-op, except when pclass is a subword type or a reference other than Object or an interface. 378 * 379 * @param ptype type of value present on stack 380 * @param pclass type of value required on stack 381 * @param arg compile-time representation of value on stack (Node, constant) or null if none 382 */ 383 private LambdaFormCodeBuilder coerce(BasicType ptype, Class<?> pclass, Object arg) { 384 assert(basicType(pclass) == ptype); // boxing/unboxing handled by caller 385 if (pclass == ptype.basicTypeClass() && ptype != L_TYPE) 386 return this; // nothing to do 387 switch (ptype) { 388 case L_TYPE: 389 if (VerifyType.isNullConversion(Object.class, pclass, false)) { 390 if (PROFILE_LEVEL > 0) 391 coerce(Object.class, arg); 392 return this; 393 } 394 coerce(pclass, arg); 395 return this; 396 case I_TYPE: 397 if (!VerifyType.isNullConversion(int.class, pclass, false)) 398 conv(fromBasicType(ptype), fromBasicType(BasicType.basicType(pclass))); 399 return this; 400 case Q_TYPE: 401 if (!MinimalValueTypes_1_0.isValueType(pclass)) { 402 vbox(Object.class); 403 return this; 404 } 405 assert pclass == arg.getClass(); 406 return this; //assume they are equal 407 } 408 throw newInternalError("bad implicit conversion: tc="+ptype+": "+pclass); 409 } 410 411 private LambdaFormCodeBuilder coerce(Class<?> cls, Object arg) { 412 Name writeBack = null; // local to write back result 413 if (arg instanceof Name) { 414 Name n = (Name) arg; 415 if (cls.isAssignableFrom(typeOfLocal(n.index()))) 416 return this; // this cast was already performed 417 if (lambdaForm.useCount(n) > 1) { 418 // This guy gets used more than once. 419 writeBack = n; 420 } 421 } 422 if (InvokerBytecodeGenerator.isStaticallyNameable(cls)) { 423 checkcast(cls); 424 } else { 425 ldc(cls) 426 .checkcast(Class.class) 427 .swap() 428 .invokevirtual(Class.class, "cast", LL_SIG, false); 429 if (Object[].class.isAssignableFrom(cls)) 430 checkcast(Object[].class); 431 else if (PROFILE_LEVEL > 0) 432 checkcast(Object.class); 433 } 434 if (writeBack != null) { 435 dup().store(TypeTag.A, writeBack.index()); 436 } 437 return this; 438 } 439 440 LambdaFormCodeBuilder invokeStaticName(Name name) { 441 return invokeStaticName(name.function.member(), name); 442 } 443 444 /** 445 * Emit an invoke for the given name, using the MemberName directly. 446 */ 447 LambdaFormCodeBuilder invokeStaticName(MemberName member, Name name) { 448 assert(member.equals(name.function.member())); 449 Class<?> defc = member.getDeclaringClass(); 450 String mname = member.getName(); 451 String mtype; 452 byte refKind = member.getReferenceKind(); 453 if (refKind == REF_invokeSpecial) { 454 // in order to pass the verifier, we need to convert this to invokevirtual in all cases 455 assert(member.canBeStaticallyBound()) : member; 456 refKind = REF_invokeVirtual; 457 } 458 459 assert(!(member.getDeclaringClass().isInterface() && refKind == REF_invokeVirtual)); 460 461 // push arguments 462 pushArguments(name); 463 464 // invocation 465 if (member.isMethod()) { 466 mtype = member.getMethodType().toMethodDescriptorString(); 467 invoke(invKindFromRefKind(refKind), defc, mname, mtype, 468 member.getDeclaringClass().isInterface()); 469 } else { 470 mtype = MethodType.toFieldDescriptorString(member.getFieldType()); 471 getfield(fieldKindFromRefKind(refKind), defc, mname, mtype); 472 } 473 // Issue a type assertion for the result, so we can avoid casts later. 474 if (name.type == L_TYPE) { 475 Class<?> rtype = member.getInvocationType().returnType(); 476 assert(!rtype.isPrimitive()); 477 } 478 return this; 479 } 480 481 /** 482 * Emit an invoke for the given name. 483 */ 484 LambdaFormCodeBuilder invokeName(Name name) { 485 //assert(!isLinkerMethodInvoke(name)); // should use the static path for these 486 if (true) { 487 // push receiver 488 MethodHandle target = name.function.resolvedHandle(); 489 assert(target != null) : name.exprString(); 490 ldc(target); 491 coerce(MethodHandle.class, target); 492 } 493 494 // push arguments 495 pushArguments(name); 496 497 // invocation 498 MethodType type = name.function.methodType(); 499 invokevirtual(MethodHandle.class, "invokeBasic", type.basicType().toMethodDescriptorString(), false); 500 return this; 501 } 502 503 private LambdaFormCodeBuilder pushArguments(Name args) { 504 return pushArguments(args, 0); 505 } 506 507 private LambdaFormCodeBuilder pushArguments(Name args, int start) { 508 for (int i = start; i < args.arguments.length; i++) { 509 pushArgument(args, i); 510 } 511 return this; 512 } 513 514 private LambdaFormCodeBuilder pushArgument(Name name, int paramIndex) { 515 Object arg = name.arguments[paramIndex]; 516 Class<?> ptype = name.function.methodType().parameterType(paramIndex); 517 return pushArgument(ptype, arg); 518 } 519 520 private LambdaFormCodeBuilder pushArgument(Class<?> ptype, Object arg) { 521 BasicType bptype = basicType(ptype); 522 if (arg instanceof Name) { 523 Name n = (Name) arg; 524 load(fromBasicType(n.type), n.index()); 525 coerce(n.type, ptype, n); 526 } else if ((arg == null || arg instanceof String) && bptype == L_TYPE) { 527 ldc(arg); 528 } else { 529 if (Wrapper.isWrapperType(arg.getClass()) && bptype != L_TYPE) { 530 ldc(arg); 531 } else { 532 ldc(arg); 533 coerce(L_TYPE, ptype, arg); 534 } 535 } 536 return this; 537 } 538 539 private LambdaFormCodeBuilder invokeLoopHandle(int handles, int clause, Name args, boolean pushLocalState, 540 MethodType type, Class<?>[] loopLocalStateTypes, int clauseDataSlot, 541 int firstLoopStateSlot) { 542 // load handle for clause 543 load(TypeTag.A, clauseDataSlot) 544 .ldc(handles - 1) 545 .aaload() 546 .ldc(clause) 547 .aaload(); 548 549 // load loop state (preceding the other arguments) 550 if (pushLocalState) { 551 for (int s = 0; s < loopLocalStateTypes.length; ++s) { 552 load(fromClass(loopLocalStateTypes[s]), firstLoopStateSlot + s); 553 } 554 } 555 // load loop args (skip 0: method handle) 556 return pushArguments(args, 1) 557 .invokevirtual(MethodHandle.class, "invokeBasic", type.toMethodDescriptorString(), false); 558 } 559 560 MethodBuilder<Class<?>, String, byte[]> method() { 561 return methodBuilder; 562 } 563 564 String label() { 565 return "label" + labelCount++; 566 } 567 568 private int extendLocalsMap(Class<?>[] types) { 569 int firstSlot = localsMap.length - 1; 570 localsMap = Arrays.copyOf(localsMap, localsMap.length + types.length); 571 int index = localsMap[firstSlot - 1] + 1; 572 int lastSlots = 0; 573 for (int i = 0; i < types.length; ++i) { 574 localsMap[firstSlot + i] = index; 575 lastSlots = BasicType.basicType(types[i]).basicTypeSlots(); 576 index += lastSlots; 577 } 578 localsMap[localsMap.length - 1] = index - lastSlots; 579 maxLocals = types.length; 580 return firstSlot; 581 } 582 583 Class<?> typeOfLocal(int index) { 584 return typeHelper.symbol(state.locals.get(localsMap[index])); 585 } 586 } 587 588 /*** Utility methods ***/ 589 590 static TypeTag fromBasicType(BasicType type) { 591 switch (type) { 592 case I_TYPE: return TypeTag.I; 593 case J_TYPE: return TypeTag.J; 594 case F_TYPE: return TypeTag.F; 595 case D_TYPE: return TypeTag.D; 596 case L_TYPE: return TypeTag.A; 597 case V_TYPE: return TypeTag.V; 598 case Q_TYPE: return TypeTag.Q; 599 default: 600 throw new InternalError("unknown type: " + type); 601 } 602 } 603 604 static InvocationKind invKindFromRefKind(int refKind) { 605 switch (refKind) { 606 case REF_invokeVirtual: return InvocationKind.INVOKEVIRTUAL; 607 case REF_invokeStatic: return InvocationKind.INVOKESTATIC; 608 case REF_invokeSpecial: return InvocationKind.INVOKESPECIAL; 609 case REF_invokeInterface: return InvocationKind.INVOKEINTERFACE; 610 } 611 throw new InternalError("refKind="+refKind); 612 } 613 614 static FieldAccessKind fieldKindFromRefKind(int refKind) { 615 switch (refKind) { 616 case REF_getField: 617 case REF_putField: return FieldAccessKind.INSTANCE; 618 case REF_getStatic: 619 case REF_putStatic: return FieldAccessKind.STATIC; 620 } 621 throw new InternalError("refKind="+refKind); 622 } 623 624 static TypeTag fromClass(Class<?> cls) { 625 return fromBasicType(BasicType.basicType(cls)); 626 } 627 }