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.AnnotationsBuilder; 29 import jdk.experimental.bytecode.MacroCodeBuilder.FieldAccessKind; 30 import jdk.experimental.bytecode.MacroCodeBuilder.InvocationKind; 31 import jdk.experimental.bytecode.MethodBuilder; 32 import jdk.experimental.bytecode.TypeTag; 33 import jdk.experimental.value.MethodHandleBuilder; 34 import sun.invoke.util.VerifyType; 35 import sun.invoke.util.Wrapper; 36 import valhalla.shady.MinimalValueTypes_1_0; 37 38 import java.lang.invoke.LambdaForm.BasicType; 39 import java.lang.invoke.LambdaForm.Name; 40 import java.lang.invoke.MethodHandles.Lookup; 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_LEVEL; 54 import static java.lang.invoke.MethodHandleStatics.newInternalError; 55 56 /** 57 * Utility class for spinning classfiles associated with lambda forms. 58 */ 59 class LambdaFormBuilder extends MethodHandleBuilder { 60 61 private static final String OBJ = "java/lang/Object"; 62 private static final String CLASS_PREFIX = "java/lang/invoke/LambdaForm$Value$"; 63 private static final String DEFAULT_CLASS = "MH"; 64 private static final String LL_SIG = "(L" + OBJ + ";)L" + OBJ + ";"; 65 66 static MemberName generateCustomizedCode(LambdaForm form, MethodType invokerType) { 67 String invokerName = form.lambdaName(); 68 int p = invokerName.indexOf('.'); 69 boolean overrideNames = p != -1; 70 String methodName = overrideNames ? invokerName.substring(p + 1) : invokerName; 71 String className = overrideNames ? 72 CLASS_PREFIX + invokerName.substring(0, p) : 73 CLASS_PREFIX + DEFAULT_CLASS; 74 if (MinimalValueTypes_1_0.DUMP_CLASS_FILES) { 75 // When DUMP_CLASS_FILES is true methodName will have a unique id 76 className = className + "_" + methodName; 77 } 78 return MethodHandleBuilder.loadCode(Lookup.IMPL_LOOKUP.in(LambdaForm.class), className, methodName, invokerType.toMethodDescriptorString(), 79 M -> new LambdaFormCodeBuilder(form, M), clazz -> InvokerBytecodeGenerator.resolveInvokerMember(clazz, methodName, invokerType), 80 C -> new LambdaFormBuilder(C, form, invokerType).generateLambdaFormBody()); 81 } 82 83 LambdaFormCodeBuilder builder; 84 LambdaForm lambdaForm; 85 MethodType invokerType; 86 int maxLocals; 87 int[] localsMap; 88 89 LambdaFormBuilder(LambdaFormCodeBuilder builder, LambdaForm lambdaForm, MethodType invokerType) { 90 this.builder = builder; 91 this.lambdaForm = lambdaForm; 92 this.invokerType = invokerType; 93 this.maxLocals = lambdaForm.names.length; 94 this.localsMap = computeLocalsMap(lambdaForm); 95 } 96 97 static int[] computeLocalsMap(LambdaForm lform) { 98 int localsMapSize = lform.names.length; 99 int[] localsMap = new int[localsMapSize+1]; // last entry of localsMap is count of allocated local slots 100 for (int i = 0, index = 0; i < localsMap.length; i++) { 101 localsMap[i] = index; 102 if (i < lform.names.length) { 103 BasicType type = lform.names[i].type(); 104 index += type.basicTypeSlots(); 105 } 106 } 107 return localsMap; 108 } 109 110 void generateLambdaFormBody() { 111 // iterate over the form's names, generating bytecode instructions for each 112 // start iterating at the first name following the arguments 113 Name onStack = null; 114 for (int i = lambdaForm.arity; i < lambdaForm.names.length; i++) { 115 Name name = lambdaForm.names[i]; 116 117 if (onStack != null && onStack.type != V_TYPE) { 118 // non-void: actually assign 119 builder.store(fromBasicType(onStack.type), localsMap[onStack.index()]); 120 } 121 onStack = name; // unless otherwise modified below 122 MemberName member = name.function.member(); 123 if (InvokerBytecodeGenerator.isStaticallyInvocable(member)) { 124 emitStaticInvoke(member, name); 125 } else { 126 emitInvoke(name); 127 } 128 } 129 emitReturn(onStack); 130 } 131 132 /** 133 * Emits a return statement from a LF invoker. If required, the result type is cast to the correct return type. 134 */ 135 private void emitReturn(Name onStack) { 136 // return statement 137 Class<?> rclass = invokerType.returnType(); 138 BasicType rtype = lambdaForm.returnType(); 139 assert(rtype == basicType(rclass)); // must agree 140 if (rtype == V_TYPE) { 141 // void 142 builder.return_(); 143 // it doesn't matter what rclass is; the JVM will discard any value 144 } else { 145 LambdaForm.Name rn = lambdaForm.names[lambdaForm.result]; 146 147 // put return value on the stack if it is not already there 148 if (rn != onStack) { 149 builder.load(localsMap[lambdaForm.result]); 150 } 151 152 emitImplicitConversion(rtype, rclass, rn); 153 154 // generate actual return statement 155 builder.return_(fromBasicType(rtype)); 156 } 157 } 158 159 /** 160 * Emit an implicit conversion for an argument which must be of the given pclass. 161 * This is usually a no-op, except when pclass is a subword type or a reference other than Object or an interface. 162 * 163 * @param ptype type of value present on stack 164 * @param pclass type of value required on stack 165 * @param arg compile-time representation of value on stack (Node, constant) or null if none 166 */ 167 private void emitImplicitConversion(BasicType ptype, Class<?> pclass, Object arg) { 168 assert(basicType(pclass) == ptype); // boxing/unboxing handled by caller 169 if (pclass == ptype.basicTypeClass() && ptype != L_TYPE) 170 return; // nothing to do 171 switch (ptype) { 172 case L_TYPE: 173 if (VerifyType.isNullConversion(Object.class, pclass, false)) { 174 if (PROFILE_LEVEL > 0) 175 emitReferenceCast(Object.class, arg); 176 return; 177 } 178 emitReferenceCast(pclass, arg); 179 return; 180 case I_TYPE: 181 if (!VerifyType.isNullConversion(int.class, pclass, false)) 182 builder.conv(fromBasicType(ptype), fromBasicType(BasicType.basicType(pclass))); 183 return; 184 case Q_TYPE: 185 if (!MinimalValueTypes_1_0.isValueType(pclass)) { 186 builder.vbox(Object.class); 187 return; 188 } 189 assert pclass == arg.getClass(); 190 return; //assume they are equal 191 } 192 throw newInternalError("bad implicit conversion: tc="+ptype+": "+pclass); 193 } 194 195 private void emitReferenceCast(Class<?> cls, Object arg) { 196 Name writeBack = null; // local to write back result 197 if (arg instanceof Name) { 198 Name n = (Name) arg; 199 if (cls.isAssignableFrom(builder.typeOfLocal(localsMap[n.index()]))) 200 return; // this cast was already performed 201 if (lambdaForm.useCount(n) > 1) { 202 // This guy gets used more than once. 203 writeBack = n; 204 } 205 } 206 if (InvokerBytecodeGenerator.isStaticallyNameable(cls)) { 207 builder.checkcast(cls); 208 } else { 209 builder.ldc(cls) 210 .checkcast(Class.class) 211 .swap() 212 .invokevirtual(Class.class, "cast", LL_SIG, false); 213 if (Object[].class.isAssignableFrom(cls)) 214 builder.checkcast(Object[].class); 215 else if (PROFILE_LEVEL > 0) 216 builder.checkcast(Object.class); 217 } 218 if (writeBack != null) { 219 builder.dup().astore(localsMap[writeBack.index()]); 220 } 221 } 222 223 /** 224 * Emit an invoke for the given name, using the MemberName directly. 225 */ 226 void emitStaticInvoke(MemberName member, Name name) { 227 assert(member.equals(name.function.member())); 228 Class<?> defc = member.getDeclaringClass(); 229 String mname = member.getName(); 230 String mtype; 231 byte refKind = member.getReferenceKind(); 232 if (refKind == REF_invokeSpecial) { 233 // in order to pass the verifier, we need to convert this to invokevirtual in all cases 234 assert(member.canBeStaticallyBound()) : member; 235 refKind = REF_invokeVirtual; 236 } 237 238 assert(!(member.getDeclaringClass().isInterface() && refKind == REF_invokeVirtual)); 239 240 // push arguments 241 emitPushArguments(name); 242 243 // invocation 244 if (member.isMethod()) { 245 mtype = member.getMethodType().toMethodDescriptorString(); 246 builder.invoke(invKindFromRefKind(refKind), defc, mname, mtype, 247 member.getDeclaringClass().isInterface()); 248 } else { 249 mtype = MethodType.toFieldDescriptorString(member.getFieldType()); 250 builder.getfield(fieldKindFromRefKind(refKind), defc, mname, mtype); 251 } 252 // Issue a type assertion for the result, so we can avoid casts later. 253 if (name.type == L_TYPE) { 254 Class<?> rtype = member.getInvocationType().returnType(); 255 assert(!rtype.isPrimitive()); 256 } 257 } 258 259 /** 260 * Emit an invoke for the given name. 261 */ 262 void emitInvoke(Name name) { 263 //assert(!isLinkerMethodInvoke(name)); // should use the static path for these 264 if (true) { 265 // push receiver 266 MethodHandle target = name.function.resolvedHandle(); 267 assert(target != null) : name.exprString(); 268 builder.ldc(target); 269 emitReferenceCast(MethodHandle.class, target); 270 } 271 272 // push arguments 273 emitPushArguments(name); 274 275 // invocation 276 MethodType type = name.function.methodType(); 277 builder.invokevirtual(MethodHandle.class, "invokeBasic", type.basicType().toMethodDescriptorString(), false); 278 } 279 280 private void emitPushArguments(Name args) { 281 emitPushArguments(args, 0); 282 } 283 284 private void emitPushArguments(Name args, int start) { 285 for (int i = start; i < args.arguments.length; i++) { 286 emitPushArgument(args, i); 287 } 288 } 289 290 private void emitPushArgument(Name name, int paramIndex) { 291 Object arg = name.arguments[paramIndex]; 292 Class<?> ptype = name.function.methodType().parameterType(paramIndex); 293 emitPushArgument(ptype, arg); 294 } 295 296 private void emitPushArgument(Class<?> ptype, Object arg) { 297 BasicType bptype = basicType(ptype); 298 if (arg instanceof Name) { 299 Name n = (Name) arg; 300 builder.load(fromBasicType(n.type), localsMap[n.index()]); 301 emitImplicitConversion(n.type, ptype, n); 302 } else if ((arg == null || arg instanceof String) && bptype == L_TYPE) { 303 builder.ldc(arg); 304 } else { 305 if (Wrapper.isWrapperType(arg.getClass()) && bptype != L_TYPE) { 306 builder.ldc(arg); 307 } else { 308 builder.ldc(arg); 309 emitImplicitConversion(L_TYPE, ptype, arg); 310 } 311 } 312 } 313 314 TypeTag fromBasicType(BasicType type) { 315 switch (type) { 316 case I_TYPE: return TypeTag.I; 317 case J_TYPE: return TypeTag.J; 318 case F_TYPE: return TypeTag.F; 319 case D_TYPE: return TypeTag.D; 320 case L_TYPE: return TypeTag.A; 321 case V_TYPE: return TypeTag.V; 322 case Q_TYPE: return TypeTag.Q; 323 default: 324 throw new InternalError("unknown type: " + type); 325 } 326 } 327 328 InvocationKind invKindFromRefKind(int refKind) { 329 switch (refKind) { 330 case REF_invokeVirtual: return InvocationKind.INVOKEVIRTUAL; 331 case REF_invokeStatic: return InvocationKind.INVOKESTATIC; 332 case REF_invokeSpecial: return InvocationKind.INVOKESPECIAL; 333 case REF_invokeInterface: return InvocationKind.INVOKEINTERFACE; 334 } 335 throw new InternalError("refKind="+refKind); 336 } 337 338 FieldAccessKind fieldKindFromRefKind(int refKind) { 339 switch (refKind) { 340 case REF_getField: 341 case REF_putField: return FieldAccessKind.INSTANCE; 342 case REF_getStatic: 343 case REF_putStatic: return FieldAccessKind.STATIC; 344 } 345 throw new InternalError("refKind="+refKind); 346 } 347 348 static class LambdaFormCodeBuilder extends MethodHandleCodeBuilder { 349 public LambdaFormCodeBuilder(LambdaForm form, MethodBuilder<Class<?>, String, byte[]> methodBuilder) { 350 super(methodBuilder); 351 if (form.forceInline) { 352 methodBuilder.withAnnotation(AnnotationsBuilder.Kind.RUNTIME_VISIBLE, "Ljdk/internal/vm/annotation/ForceInline;"); 353 } 354 methodBuilder.withAnnotation(AnnotationsBuilder.Kind.RUNTIME_VISIBLE, "Ljava/lang/invoke/LambdaForm$Hidden;") 355 .withAnnotation(AnnotationsBuilder.Kind.RUNTIME_VISIBLE, "Ljava/lang/invoke/LambdaForm$Compiled;"); 356 } 357 358 Class<?> typeOfLocal(int index) { 359 return typeHelper.symbol(state.locals.get(index)); 360 } 361 } 362 }