Skip to content

Instantly share code, notes, and snippets.

@JarvisCraft
Created September 9, 2019 19:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JarvisCraft/d66e69d47be56451a0f74cd9208457f6 to your computer and use it in GitHub Desktop.
Save JarvisCraft/d66e69d47be56451a0f74cd9208457f6 to your computer and use it in GitHub Desktop.
[OpenJDK] [PATCH] Allow LambdaMetaFactory generate direct field access instructions
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