1166 * try { |
1166 * try { |
1167 * return a1.invokeBasic(a6, a7); |
1167 * return a1.invokeBasic(a6, a7); |
1168 * } catch (Throwable e) { |
1168 * } catch (Throwable e) { |
1169 * if (!a2.isInstance(e)) throw e; |
1169 * if (!a2.isInstance(e)) throw e; |
1170 * return a3.invokeBasic(ex, a6, a7); |
1170 * return a3.invokeBasic(ex, a6, a7); |
1171 * }} |
1171 * }}</pre></blockquote> |
1172 */ |
1172 */ |
1173 private Name emitGuardWithCatch(int pos) { |
1173 private Name emitGuardWithCatch(int pos) { |
1174 Name args = lambdaForm.names[pos]; |
1174 Name args = lambdaForm.names[pos]; |
1175 Name invoker = lambdaForm.names[pos+1]; |
1175 Name invoker = lambdaForm.names[pos+1]; |
1176 Name result = lambdaForm.names[pos+2]; |
1176 Name result = lambdaForm.names[pos+2]; |
1261 * <blockquote><pre>{@code |
1261 * <blockquote><pre>{@code |
1262 * TRY: (--) |
1262 * TRY: (--) |
1263 * load target (-- target) |
1263 * load target (-- target) |
1264 * load args (-- args... target) |
1264 * load args (-- args... target) |
1265 * INVOKEVIRTUAL MethodHandle.invokeBasic (depends) |
1265 * INVOKEVIRTUAL MethodHandle.invokeBasic (depends) |
1266 * FINALLY_NORMAL: (-- r) |
1266 * FINALLY_NORMAL: (-- r_2nd* r) |
1267 * load cleanup (-- cleanup r) |
1267 * store returned value (--) |
1268 * SWAP (-- r cleanup) |
1268 * load cleanup (-- cleanup) |
1269 * ACONST_NULL (-- t r cleanup) |
1269 * ACONST_NULL (-- t cleanup) |
1270 * SWAP (-- r t cleanup) |
1270 * load returned value (-- r_2nd* r t cleanup) |
1271 * load args (-- args... r t cleanup) |
1271 * load args (-- args... r_2nd* r t cleanup) |
1272 * INVOKEVIRTUAL MethodHandle.invokeBasic (-- r) |
1272 * INVOKEVIRTUAL MethodHandle.invokeBasic (-- r_2nd* r) |
1273 * GOTO DONE |
1273 * GOTO DONE |
1274 * CATCH: (-- t) |
1274 * CATCH: (-- t) |
1275 * DUP (-- t t) |
1275 * DUP (-- t t) |
1276 * FINALLY_EXCEPTIONAL: (-- t t) |
1276 * FINALLY_EXCEPTIONAL: (-- t t) |
1277 * load cleanup (-- cleanup t t) |
1277 * load cleanup (-- cleanup t t) |
1278 * SWAP (-- t cleanup t) |
1278 * SWAP (-- t cleanup t) |
1279 * load default for r (-- r t cleanup t) |
1279 * load default for r (-- r_2nd* r t cleanup t) |
1280 * load args (-- args... r t cleanup t) |
1280 * load args (-- args... r_2nd* r t cleanup t) |
1281 * INVOKEVIRTUAL MethodHandle.invokeBasic (-- r t) |
1281 * INVOKEVIRTUAL MethodHandle.invokeBasic (-- r_2nd* r t) |
1282 * POP (-- t) |
1282 * POP/POP2* (-- t) |
1283 * ATHROW |
1283 * ATHROW |
1284 * DONE: (-- r) |
1284 * DONE: (-- r) |
1285 * }</pre></blockquote> |
1285 * }</pre></blockquote> |
|
1286 * * = depends on whether the return type takes up 2 stack slots. |
1286 */ |
1287 */ |
1287 private Name emitTryFinally(int pos) { |
1288 private Name emitTryFinally(int pos) { |
1288 Name args = lambdaForm.names[pos]; |
1289 Name args = lambdaForm.names[pos]; |
1289 Name invoker = lambdaForm.names[pos+1]; |
1290 Name invoker = lambdaForm.names[pos+1]; |
1290 Name result = lambdaForm.names[pos+2]; |
1291 Name result = lambdaForm.names[pos+2]; |
1293 Label lTo = new Label(); |
1294 Label lTo = new Label(); |
1294 Label lCatch = new Label(); |
1295 Label lCatch = new Label(); |
1295 Label lDone = new Label(); |
1296 Label lDone = new Label(); |
1296 |
1297 |
1297 Class<?> returnType = result.function.resolvedHandle().type().returnType(); |
1298 Class<?> returnType = result.function.resolvedHandle().type().returnType(); |
|
1299 BasicType basicReturnType = BasicType.basicType(returnType); |
1298 boolean isNonVoid = returnType != void.class; |
1300 boolean isNonVoid = returnType != void.class; |
|
1301 |
1299 MethodType type = args.function.resolvedHandle().type() |
1302 MethodType type = args.function.resolvedHandle().type() |
1300 .dropParameterTypes(0,1) |
1303 .dropParameterTypes(0,1) |
1301 .changeReturnType(returnType); |
1304 .changeReturnType(returnType); |
1302 MethodType cleanupType = type.insertParameterTypes(0, Throwable.class); |
1305 MethodType cleanupType = type.insertParameterTypes(0, Throwable.class); |
1303 if (isNonVoid) { |
1306 if (isNonVoid) { |
1314 emitPushArguments(args, 1); // load args (skip 0: method handle) |
1317 emitPushArguments(args, 1); // load args (skip 0: method handle) |
1315 mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, MH, "invokeBasic", type.basicType().toMethodDescriptorString(), false); |
1318 mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, MH, "invokeBasic", type.basicType().toMethodDescriptorString(), false); |
1316 mv.visitLabel(lTo); |
1319 mv.visitLabel(lTo); |
1317 |
1320 |
1318 // FINALLY_NORMAL: |
1321 // FINALLY_NORMAL: |
|
1322 int index = extendLocalsMap(new Class<?>[]{ returnType }); |
|
1323 if (isNonVoid) { |
|
1324 emitStoreInsn(basicReturnType, index); |
|
1325 } |
1319 emitPushArgument(invoker, 1); // load cleanup |
1326 emitPushArgument(invoker, 1); // load cleanup |
1320 if (isNonVoid) { |
|
1321 mv.visitInsn(Opcodes.SWAP); |
|
1322 } |
|
1323 mv.visitInsn(Opcodes.ACONST_NULL); |
1327 mv.visitInsn(Opcodes.ACONST_NULL); |
1324 if (isNonVoid) { |
1328 if (isNonVoid) { |
1325 mv.visitInsn(Opcodes.SWAP); |
1329 emitLoadInsn(basicReturnType, index); |
1326 } |
1330 } |
1327 emitPushArguments(args, 1); // load args (skip 0: method handle) |
1331 emitPushArguments(args, 1); // load args (skip 0: method handle) |
1328 mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, MH, "invokeBasic", cleanupDesc, false); |
1332 mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, MH, "invokeBasic", cleanupDesc, false); |
1329 mv.visitJumpInsn(Opcodes.GOTO, lDone); |
1333 mv.visitJumpInsn(Opcodes.GOTO, lDone); |
1330 |
1334 |
1339 emitZero(BasicType.basicType(returnType)); // load default for result |
1343 emitZero(BasicType.basicType(returnType)); // load default for result |
1340 } |
1344 } |
1341 emitPushArguments(args, 1); // load args (skip 0: method handle) |
1345 emitPushArguments(args, 1); // load args (skip 0: method handle) |
1342 mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, MH, "invokeBasic", cleanupDesc, false); |
1346 mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, MH, "invokeBasic", cleanupDesc, false); |
1343 if (isNonVoid) { |
1347 if (isNonVoid) { |
1344 mv.visitInsn(Opcodes.POP); |
1348 emitPopInsn(basicReturnType); |
1345 } |
1349 } |
1346 mv.visitInsn(Opcodes.ATHROW); |
1350 mv.visitInsn(Opcodes.ATHROW); |
1347 |
1351 |
1348 // DONE: |
1352 // DONE: |
1349 mv.visitLabel(lDone); |
1353 mv.visitLabel(lDone); |
1350 |
1354 |
1351 return result; |
1355 return result; |
|
1356 } |
|
1357 |
|
1358 private void emitPopInsn(BasicType type) { |
|
1359 mv.visitInsn(popInsnOpcode(type)); |
|
1360 } |
|
1361 |
|
1362 private static int popInsnOpcode(BasicType type) { |
|
1363 switch (type) { |
|
1364 case I_TYPE: |
|
1365 case F_TYPE: |
|
1366 case L_TYPE: |
|
1367 return Opcodes.POP; |
|
1368 case J_TYPE: |
|
1369 case D_TYPE: |
|
1370 return Opcodes.POP2; |
|
1371 default: |
|
1372 throw new InternalError("unknown type: " + type); |
|
1373 } |
1352 } |
1374 } |
1353 |
1375 |
1354 /** |
1376 /** |
1355 * Emit bytecode for the loop idiom. |
1377 * Emit bytecode for the loop idiom. |
1356 * <p> |
1378 * <p> |