Created
September 9, 2019 19:26
-
-
Save JarvisCraft/d66e69d47be56451a0f74cd9208457f6 to your computer and use it in GitHub Desktop.
[OpenJDK] [PATCH] Allow LambdaMetaFactory generate direct field access instructions
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/src/java.base/share/classes/java/lang/invoke/AbstractValidatingLambdaMetafactory.java b/src/java.base/share/classes/java/lang/invoke/AbstractValidatingLambdaMetafactory.java | |
--- a/src/java.base/share/classes/java/lang/invoke/AbstractValidatingLambdaMetafactory.java | |
+++ b/src/java.base/share/classes/java/lang/invoke/AbstractValidatingLambdaMetafactory.java | |
@@ -61,6 +61,7 @@ | |
final MethodHandleInfo implInfo; // Info about the implementation method handle "MethodHandleInfo[5 CC.impl(int)String]" | |
final int implKind; // Invocation kind for implementation "5"=invokevirtual | |
final boolean implIsInstanceMethod; // Is the implementation an instance method "true" | |
+ final boolean implIsMethodNotField; // "true" for method and "false" for field | |
final Class<?> implClass; // Class for referencing the implementation method "class CC" | |
final MethodType instantiatedMethodType; // Instantiated erased functional interface method type "(Integer)Object" | |
final boolean isSerializable; // Should the returned instance be serializable | |
@@ -131,7 +132,8 @@ | |
this.implMethod = implMethod; | |
this.implMethodType = implMethod.type(); | |
this.implInfo = caller.revealDirect(implMethod); | |
- switch (implInfo.getReferenceKind()) { | |
+ final int referenceKind = implInfo.getReferenceKind(); | |
+ switch (referenceKind) { | |
case REF_invokeVirtual: | |
case REF_invokeInterface: | |
this.implClass = implMethodType.parameterType(0); | |
@@ -139,20 +141,40 @@ | |
// Example: implMethodType is (Cloneable)String, implInfo is for Object.toString | |
this.implKind = implClass.isInterface() ? REF_invokeInterface : REF_invokeVirtual; | |
this.implIsInstanceMethod = true; | |
+ this.implIsMethodNotField = true; | |
break; | |
case REF_invokeSpecial: | |
// JDK-8172817: should use referenced class here, but we don't know what it was | |
this.implClass = implInfo.getDeclaringClass(); | |
this.implKind = REF_invokeSpecial; | |
this.implIsInstanceMethod = true; | |
+ this.implIsMethodNotField = true; | |
break; | |
case REF_invokeStatic: | |
case REF_newInvokeSpecial: | |
// JDK-8172817: should use referenced class here for invokestatic, but we don't know what it was | |
this.implClass = implInfo.getDeclaringClass(); | |
- this.implKind = implInfo.getReferenceKind(); | |
+ this.implKind = referenceKind; | |
this.implIsInstanceMethod = false; | |
+ this.implIsMethodNotField = true; | |
break; | |
+ // instance field access | |
+ case REF_getField: | |
+ case REF_putField: | |
+ this.implClass = implInfo.getDeclaringClass(); | |
+ this.implKind = referenceKind; | |
+ this.implIsInstanceMethod = true; | |
+ this.implIsMethodNotField = false; | |
+ break; | |
+ // static field access | |
+ case REF_getStatic: | |
+ case REF_putStatic: | |
+ this.implClass = implInfo.getDeclaringClass(); | |
+ this.implKind = referenceKind; | |
+ this.implIsInstanceMethod = false; | |
+ this.implIsMethodNotField = false; | |
+ break; | |
+ // default failure due to int-switch | |
default: | |
throw new LambdaConversionException(String.format("Unsupported MethodHandle kind: %s", implInfo)); | |
} | |
diff --git a/src/java.base/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java b/src/java.base/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java | |
--- a/src/java.base/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java | |
+++ b/src/java.base/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java | |
@@ -461,10 +461,16 @@ | |
convertArgumentTypes(methodType); | |
- // Invoke the method we want to forward to | |
- visitMethodInsn(invocationOpcode(), implMethodClassName, | |
- implMethodName, implMethodDesc, | |
- implClass.isInterface()); | |
+ // implement the method depending on whether it is a method invocation or field access | |
+ if (implIsMethodNotField) { | |
+ // Invoke the method we want to forward to | |
+ visitMethodInsn(methodInvocationOpcode(), implMethodClassName, | |
+ implMethodName, implMethodDesc, | |
+ implClass.isInterface()); | |
+ } else { | |
+ // Access the field we want to get/set | |
+ visitFieldInsn(fieldAccessOpcode(), implMethodClassName, implMethodName, implMethodDesc); | |
+ } | |
// Convert the return value (if any) and return it | |
// Note: if adapting from non-void to void, the 'return' | |
@@ -490,7 +496,7 @@ | |
} | |
} | |
- private int invocationOpcode() throws InternalError { | |
+ private int methodInvocationOpcode() throws InternalError { | |
switch (implKind) { | |
case MethodHandleInfo.REF_invokeStatic: | |
return INVOKESTATIC; | |
@@ -503,7 +509,22 @@ | |
case MethodHandleInfo.REF_invokeSpecial: | |
return INVOKESPECIAL; | |
default: | |
- throw new InternalError("Unexpected invocation kind: " + implKind); | |
+ throw new InternalError("Unexpected method invocation kind: " + implKind); | |
+ } | |
+ } | |
+ | |
+ private int fieldAccessOpcode() throws InternalError { | |
+ switch (implKind) { | |
+ case MethodHandleInfo.REF_getStatic: | |
+ return GETSTATIC; | |
+ case MethodHandleInfo.REF_putStatic: | |
+ return PUTSTATIC; | |
+ case MethodHandleInfo.REF_getField: | |
+ return GETFIELD; | |
+ case MethodHandleInfo.REF_putField: | |
+ return PUTFIELD; | |
+ default: | |
+ throw new InternalError("Unexpected field access kind: " + implKind); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment