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