src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java
Index
Unified diffs
Context diffs
Sdiffs
Patch
New
Old
Previous File
Next File
*** old/src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java Sat Mar 22 02:03:03 2014
--- new/src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java Sat Mar 22 02:03:02 2014
*** 24,34 ****
--- 24,34 ----
*/
package java.lang.invoke;
import sun.invoke.util.VerifyAccess;
! import java.lang.invoke.LambdaForm.Name;
! import static java.lang.invoke.LambdaForm.*;
import sun.invoke.util.Wrapper;
import java.io.*;
import java.util.*;
*** 36,45 ****
--- 36,46 ----
import jdk.internal.org.objectweb.asm.*;
import java.lang.reflect.*;
import static java.lang.invoke.MethodHandleStatics.*;
import static java.lang.invoke.MethodHandleNatives.Constants.*;
+ import static java.lang.invoke.LambdaForm.BasicType.*;
import sun.invoke.util.VerifyType;
/**
* Code generation backend for LambdaForm.
* <p>
*** 113,123 ****
--- 114,124 ----
className, form.debugName, invokerType);
// Create an array to map name indexes to locals indexes.
Name[] names = form.names;
for (int i = 0, index = 0; i < localsMap.length; i++) {
localsMap[i] = index;
! index += Wrapper.forBasicType(names[i].type).stackSlots();
! index += names[i].type.basicTypeSlots();
}
}
/** instance counters for dumped classes */
*** 355,418 ****
--- 356,427 ----
}
/*
* NOTE: These load/store methods use the localsMap to find the correct index!
*/
! private void emitLoadInsn(char type, int index) {
! private void emitLoadInsn(BasicType type, int index) {
+ int opcode = loadInsnOpcode(type);
+ mv.visitVarInsn(opcode, localsMap[index]);
+ }
+
+ private int loadInsnOpcode(BasicType type) throws InternalError {
int opcode;
switch (type) {
! case 'I': opcode = Opcodes.ILOAD; break;
! case 'J': opcode = Opcodes.LLOAD; break;
! case 'F': opcode = Opcodes.FLOAD; break;
! case 'D': opcode = Opcodes.DLOAD; break;
! case 'L': opcode = Opcodes.ALOAD; break;
! case I_TYPE: opcode = Opcodes.ILOAD; break;
! case J_TYPE: opcode = Opcodes.LLOAD; break;
! case F_TYPE: opcode = Opcodes.FLOAD; break;
! case D_TYPE: opcode = Opcodes.DLOAD; break;
! case L_TYPE: opcode = Opcodes.ALOAD; break;
default:
throw new InternalError("unknown type: " + type);
}
! mv.visitVarInsn(opcode, localsMap[index]);
! return opcode;
}
private void emitAloadInsn(int index) {
! emitLoadInsn('L', index);
! emitLoadInsn(L_TYPE, index);
+ }
+
+ private void emitStoreInsn(BasicType type, int index) {
+ int opcode = storeInsnOpcode(type);
+ mv.visitVarInsn(opcode, localsMap[index]);
}
! private void emitStoreInsn(char type, int index) {
! private int storeInsnOpcode(BasicType type) throws InternalError {
int opcode;
switch (type) {
! case 'I': opcode = Opcodes.ISTORE; break;
! case 'J': opcode = Opcodes.LSTORE; break;
! case 'F': opcode = Opcodes.FSTORE; break;
! case 'D': opcode = Opcodes.DSTORE; break;
! case 'L': opcode = Opcodes.ASTORE; break;
! case I_TYPE: opcode = Opcodes.ISTORE; break;
! case J_TYPE: opcode = Opcodes.LSTORE; break;
! case F_TYPE: opcode = Opcodes.FSTORE; break;
! case D_TYPE: opcode = Opcodes.DSTORE; break;
! case L_TYPE: opcode = Opcodes.ASTORE; break;
default:
throw new InternalError("unknown type: " + type);
}
! mv.visitVarInsn(opcode, localsMap[index]);
! return opcode;
}
private void emitAstoreInsn(int index) {
! emitStoreInsn('L', index);
! emitStoreInsn(L_TYPE, index);
}
/**
* Emit a boxing call.
*
! * @param type primitive type class to box.
! * @param wrapper primitive type class to box.
*/
! private void emitBoxing(Class<?> type) {
Wrapper wrapper = Wrapper.forPrimitiveType(type);
! private void emitBoxing(Wrapper wrapper) {
String owner = "java/lang/" + wrapper.wrapperType().getSimpleName();
String name = "valueOf";
String desc = "(" + wrapper.basicTypeChar() + ")L" + owner + ";";
mv.visitMethodInsn(Opcodes.INVOKESTATIC, owner, name, desc, false);
}
/**
* Emit an unboxing call (plus preceding checkcast).
*
! * @param type wrapper type class to unbox.
! * @param wrapper wrapper type class to unbox.
*/
! private void emitUnboxing(Class<?> type) {
Wrapper wrapper = Wrapper.forWrapperType(type);
! private void emitUnboxing(Wrapper wrapper) {
String owner = "java/lang/" + wrapper.wrapperType().getSimpleName();
String name = wrapper.primitiveSimpleName() + "Value";
String desc = "()" + wrapper.basicTypeChar();
mv.visitTypeInsn(Opcodes.CHECKCAST, owner);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, owner, name, desc, false);
*** 422,434 ****
--- 431,446 ----
* Emit an implicit conversion.
*
* @param ptype type of value present on stack
* @param pclass type of value required on stack
*/
! private void emitImplicitConversion(char ptype, Class<?> pclass) {
! private void emitImplicitConversion(BasicType ptype, Class<?> pclass) {
+ assert(basicType(pclass) == ptype); // boxing/unboxing handled by caller
+ if (pclass == ptype.basicTypeClass() && ptype != L_TYPE)
+ return; // nothing to do
switch (ptype) {
! case 'L':
! case L_TYPE:
if (VerifyType.isNullConversion(Object.class, pclass))
return;
if (isStaticallyNameable(pclass)) {
mv.visitTypeInsn(Opcodes.CHECKCAST, getInternalName(pclass));
} else {
*** 438,476 ****
--- 450,479 ----
mv.visitMethodInsn(Opcodes.INVOKESTATIC, MHI, "castReference", CLL_SIG, false);
if (pclass.isArray())
mv.visitTypeInsn(Opcodes.CHECKCAST, OBJARY);
}
return;
! case 'I':
! case I_TYPE:
if (!VerifyType.isNullConversion(int.class, pclass))
! emitPrimCast(ptype, Wrapper.basicTypeChar(pclass));
return;
case 'J':
assert(pclass == long.class);
return;
case 'F':
assert(pclass == float.class);
return;
case 'D':
assert(pclass == double.class);
! emitPrimCast(ptype.basicTypeWrapper(), Wrapper.forPrimitiveType(pclass));
return;
}
throw new InternalError("bad implicit conversion: tc="+ptype+": "+pclass);
}
/**
* Emits an actual return instruction conforming to the given return type.
*/
! private void emitReturnInsn(Class<?> type) {
! private void emitReturnInsn(BasicType type) {
int opcode;
! switch (Wrapper.basicTypeChar(type)) {
! case 'I': opcode = Opcodes.IRETURN; break;
! case 'J': opcode = Opcodes.LRETURN; break;
! case 'F': opcode = Opcodes.FRETURN; break;
! case 'D': opcode = Opcodes.DRETURN; break;
! case 'L': opcode = Opcodes.ARETURN; break;
! case 'V': opcode = Opcodes.RETURN; break;
! case I_TYPE: opcode = Opcodes.IRETURN; break;
! case J_TYPE: opcode = Opcodes.LRETURN; break;
! case F_TYPE: opcode = Opcodes.FRETURN; break;
! case D_TYPE: opcode = Opcodes.DRETURN; break;
! case L_TYPE: opcode = Opcodes.ARETURN; break;
! case V_TYPE: opcode = Opcodes.RETURN; break;
default:
throw new InternalError("unknown return type: " + type);
}
mv.visitInsn(opcode);
}
*** 528,538 ****
--- 531,541 ----
// store the result from evaluating to the target name in a local if required
// (if this is the last value, i.e., the one that is going to be returned,
// avoid store/load/return and just return)
if (i == lambdaForm.names.length - 1 && i == lambdaForm.result) {
// return value - do nothing
! } else if (name.type != 'V') {
! } else if (name.type != V_TYPE) {
// non-void: actually assign
emitStoreInsn(name.type, name.index());
}
}
*** 862,940 ****
--- 865,928 ----
}
}
private void emitPushArgument(Name name, int paramIndex) {
Object arg = name.arguments[paramIndex];
! char ptype = name.function.parameterType(paramIndex);
! MethodType mtype = name.function.methodType();
! Class<?> ptype = name.function.methodType().parameterType(paramIndex);
! emitPushArgument(ptype, arg);
+ }
+
+ private void emitPushArgument(Class<?> ptype, Object arg) {
+ BasicType bptype = basicType(ptype);
if (arg instanceof Name) {
Name n = (Name) arg;
emitLoadInsn(n.type, n.index());
! emitImplicitConversion(n.type, mtype.parameterType(paramIndex));
! } else if ((arg == null || arg instanceof String) && ptype == 'L') {
! emitImplicitConversion(n.type, ptype);
! } else if ((arg == null || arg instanceof String) && bptype == L_TYPE) {
emitConst(arg);
} else {
! if (Wrapper.isWrapperType(arg.getClass()) && ptype != 'L') {
! if (Wrapper.isWrapperType(arg.getClass()) && bptype != L_TYPE) {
emitConst(arg);
} else {
mv.visitLdcInsn(constantPlaceholder(arg));
! emitImplicitConversion('L', mtype.parameterType(paramIndex));
! emitImplicitConversion(L_TYPE, ptype);
}
}
}
/**
* Emits a return statement from a LF invoker. If required, the result type is cast to the correct return type.
*/
private void emitReturn() {
// return statement
if (lambdaForm.result == -1) {
+ Class<?> rclass = invokerType.returnType();
+ BasicType rtype = lambdaForm.returnType();
+ assert(rtype == basicType(rclass)); // must agree
+ if (rtype == V_TYPE) {
// void
mv.visitInsn(Opcodes.RETURN);
+ // it doesn't matter what rclass is; the JVM will discard any value
} else {
LambdaForm.Name rn = lambdaForm.names[lambdaForm.result];
char rtype = Wrapper.basicTypeChar(invokerType.returnType());
// put return value on the stack if it is not already there
! if (lambdaForm.result != lambdaForm.names.length - 1) {
! if (lambdaForm.result != lambdaForm.names.length - 1 ||
+ lambdaForm.result < lambdaForm.arity) {
emitLoadInsn(rn.type, lambdaForm.result);
}
// potentially generate cast
// rtype is the return type of the invoker - generated code must conform to this
// rn.type is the type of the result Name in the LF
if (rtype != rn.type) {
// need cast
if (rtype == 'L') {
// possibly cast the primitive to the correct type for boxing
char boxedType = Wrapper.forWrapperType(invokerType.returnType()).basicTypeChar();
if (boxedType != rn.type) {
emitPrimCast(rn.type, boxedType);
}
// cast primitive to reference ("boxing")
emitBoxing(invokerType.returnType());
} else {
// to-primitive cast
if (rn.type != 'L') {
// prim-to-prim cast
emitPrimCast(rn.type, rtype);
} else {
// ref-to-prim cast ("unboxing")
throw new InternalError("no ref-to-prim (unboxing) casts supported right now");
}
}
}
+ emitImplicitConversion(rtype, rclass);
// generate actual return statement
! emitReturnInsn(invokerType.returnType());
! emitReturnInsn(rtype);
}
}
/**
* Emit a type conversion bytecode casting from "from" to "to".
*/
! private void emitPrimCast(char from, char to) {
! private void emitPrimCast(Wrapper from, Wrapper to) {
// Here's how.
// - indicates forbidden
// <-> indicates implicit
// to ----> boolean byte short char int long float double
// from boolean <-> - - - - - - -
*** 947,988 ****
--- 935,980 ----
// double - d2i,i2b d2i,i2s d2i,i2c d2i d2l d2f <->
if (from == to) {
// no cast required, should be dead code anyway
return;
}
Wrapper wfrom = Wrapper.forBasicType(from);
Wrapper wto = Wrapper.forBasicType(to);
if (wfrom.isSubwordOrInt()) {
+ if (from.isSubwordOrInt()) {
// cast from {byte,short,char,int} to anything
emitI2X(to);
} else {
// cast from {long,float,double} to anything
- if (wto.isSubwordOrInt()) {
// cast to {byte,short,char,int}
emitX2I(from);
- if (wto.bitWidth() < 32) {
// targets other than int require another conversion
emitI2X(to);
}
} else {
// cast to {long,float,double} - this is verbose
boolean error = false;
switch (from) {
! case 'J':
if (to == 'F') { mv.visitInsn(Opcodes.L2F); }
else if (to == 'D') { mv.visitInsn(Opcodes.L2D); }
! else error = true;
! case LONG:
+ switch (to) {
+ case FLOAT: mv.visitInsn(Opcodes.L2F); break;
! case DOUBLE: mv.visitInsn(Opcodes.L2D); break;
+ default: error = true; break;
+ }
break;
! case 'F':
if (to == 'J') { mv.visitInsn(Opcodes.F2L); }
else if (to == 'D') { mv.visitInsn(Opcodes.F2D); }
! else error = true;
! case FLOAT:
+ switch (to) {
+ case LONG : mv.visitInsn(Opcodes.F2L); break;
! case DOUBLE: mv.visitInsn(Opcodes.F2D); break;
+ default: error = true; break;
+ }
break;
! case 'D':
if (to == 'J') { mv.visitInsn(Opcodes.D2L); }
else if (to == 'F') { mv.visitInsn(Opcodes.D2F); }
! else error = true;
! case DOUBLE:
+ switch (to) {
+ case LONG : mv.visitInsn(Opcodes.D2L); break;
! case FLOAT: mv.visitInsn(Opcodes.D2F); break;
+ default: error = true; break;
+ }
break;
default:
error = true;
break;
}
*** 991,1051 ****
--- 983,1028 ----
}
}
}
}
! private void emitI2X(char type) {
! private void emitI2X(Wrapper type) {
switch (type) {
! case 'B': mv.visitInsn(Opcodes.I2B); break;
! case 'S': mv.visitInsn(Opcodes.I2S); break;
! case 'C': mv.visitInsn(Opcodes.I2C); break;
! case 'I': /* naught */ break;
! case 'J': mv.visitInsn(Opcodes.I2L); break;
! case 'F': mv.visitInsn(Opcodes.I2F); break;
! case 'D': mv.visitInsn(Opcodes.I2D); break;
! case 'Z':
! case BYTE: mv.visitInsn(Opcodes.I2B); break;
! case SHORT: mv.visitInsn(Opcodes.I2S); break;
! case CHAR: mv.visitInsn(Opcodes.I2C); break;
! case INT: /* naught */ break;
! case LONG: mv.visitInsn(Opcodes.I2L); break;
! case FLOAT: mv.visitInsn(Opcodes.I2F); break;
! case DOUBLE: mv.visitInsn(Opcodes.I2D); break;
! case BOOLEAN:
// For compatibility with ValueConversions and explicitCastArguments:
mv.visitInsn(Opcodes.ICONST_1);
mv.visitInsn(Opcodes.IAND);
break;
default: throw new InternalError("unknown type: " + type);
}
}
! private void emitX2I(char type) {
! private void emitX2I(Wrapper type) {
switch (type) {
! case 'J': mv.visitInsn(Opcodes.L2I); break;
! case 'F': mv.visitInsn(Opcodes.F2I); break;
! case 'D': mv.visitInsn(Opcodes.D2I); break;
! case LONG: mv.visitInsn(Opcodes.L2I); break;
! case FLOAT: mv.visitInsn(Opcodes.F2I); break;
! case DOUBLE: mv.visitInsn(Opcodes.D2I); break;
default: throw new InternalError("unknown type: " + type);
}
}
private static String basicTypeCharSignature(String prefix, MethodType type) {
StringBuilder buf = new StringBuilder(prefix);
for (Class<?> ptype : type.parameterList())
buf.append(Wrapper.forBasicType(ptype).basicTypeChar());
buf.append('_').append(Wrapper.forBasicType(type.returnType()).basicTypeChar());
return buf.toString();
}
/**
* Generate bytecode for a LambdaForm.vmentry which calls interpretWithArguments.
*/
static MemberName generateLambdaFormInterpreterEntryPoint(String sig) {
- assert(LambdaForm.isValidSignature(sig));
! //System.out.println("generateExactInvoker "+sig);
// compute method type
// first parameter and return type
! char tret = LambdaForm.signatureReturn(sig);
MethodType type = MethodType.methodType(LambdaForm.typeClass(tret), MethodHandle.class);
// other parameter types
int arity = LambdaForm.signatureArity(sig);
for (int i = 1; i < arity; i++) {
type = type.appendParameterTypes(LambdaForm.typeClass(sig.charAt(i)));
}
InvokerBytecodeGenerator g = new InvokerBytecodeGenerator("LFI", "interpret_"+tret, type);
! String name = "interpret_"+signatureReturn(sig).basicTypeChar();
+ MethodType type = signatureType(sig); // sig includes leading argument
+ type = type.changeParameterType(0, MethodHandle.class);
! InvokerBytecodeGenerator g = new InvokerBytecodeGenerator("LFI", name, type);
return g.loadMethod(g.generateLambdaFormInterpreterEntryPointBytes());
}
private byte[] generateLambdaFormInterpreterEntryPointBytes() {
classFilePrologue();
*** 1063,1076 ****
--- 1040,1053 ----
// fill parameter array
for (int i = 0; i < invokerType.parameterCount(); i++) {
Class<?> ptype = invokerType.parameterType(i);
mv.visitInsn(Opcodes.DUP);
emitIconstInsn(i);
! emitLoadInsn(Wrapper.basicTypeChar(ptype), i);
// box if primitive type
if (ptype.isPrimitive()) {
! emitBoxing(Wrapper.forPrimitiveType(ptype));
}
mv.visitInsn(Opcodes.AASTORE);
}
// invoke
emitAloadInsn(0);
*** 1079,1093 ****
--- 1056,1070 ----
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, LF, "interpretWithArguments", "([Ljava/lang/Object;)Ljava/lang/Object;", false);
// maybe unbox
Class<?> rtype = invokerType.returnType();
if (rtype.isPrimitive() && rtype != void.class) {
! emitUnboxing(Wrapper.asWrapperType(rtype));
! emitUnboxing(Wrapper.forPrimitiveType(rtype));
}
// return statement
! emitReturnInsn(basicType(rtype));
classFileEpilogue();
bogusMethod(invokerType);
final byte[] classFile = cw.toByteArray();
*** 1097,1108 ****
--- 1074,1085 ----
/**
* Generate bytecode for a NamedFunction invoker.
*/
static MemberName generateNamedFunctionInvoker(MethodTypeForm typeForm) {
- MethodType invokerType = LambdaForm.NamedFunction.INVOKER_METHOD_TYPE;
! String invokerName = basicTypeCharSignature("invoke_", typeForm.erasedType());
! String invokerName = "invoke_" + shortenSignature(basicTypeSignature(typeForm.erasedType()));
InvokerBytecodeGenerator g = new InvokerBytecodeGenerator("NFI", invokerName, invokerType);
return g.loadMethod(g.generateNamedFunctionInvokerImpl(typeForm));
}
static int nfi = 0;
*** 1130,1141 ****
--- 1107,1118 ----
Class<?> dptype = dstType.parameterType(i);
if (dptype.isPrimitive()) {
Class<?> sptype = dstType.basicType().wrap().parameterType(i);
Wrapper dstWrapper = Wrapper.forBasicType(dptype);
Wrapper srcWrapper = dstWrapper.isSubwordOrInt() ? Wrapper.INT : dstWrapper; // narrow subword from int
- emitUnboxing(srcWrapper.wrapperType());
! emitPrimCast(srcWrapper.basicTypeChar(), dstWrapper.basicTypeChar());
}
}
// Invoke
String targetDesc = dstType.basicType().toMethodDescriptorString();
*** 1145,1163 ****
--- 1122,1140 ----
Class<?> rtype = dstType.returnType();
if (rtype != void.class && rtype.isPrimitive()) {
Wrapper srcWrapper = Wrapper.forBasicType(rtype);
Wrapper dstWrapper = srcWrapper.isSubwordOrInt() ? Wrapper.INT : srcWrapper; // widen subword to int
// boolean casts not allowed
! emitPrimCast(srcWrapper.basicTypeChar(), dstWrapper.basicTypeChar());
- emitBoxing(dstWrapper.primitiveType());
! emitBoxing(dstWrapper);
}
// If the return type is void we return a null reference.
if (rtype == void.class) {
mv.visitInsn(Opcodes.ACONST_NULL);
}
! emitReturnInsn(Object.class); // NOTE: NamedFunction invokers always return a reference value.
! emitReturnInsn(L_TYPE); // NOTE: NamedFunction invokers always return a reference value.
classFileEpilogue();
bogusMethod(dstType);
final byte[] classFile = cw.toByteArray();
src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java
Index
Unified diffs
Context diffs
Sdiffs
Patch
New
Old
Previous File
Next File