Bug 574946 - ECJ creates wrong method handle which fails at runtime with a ClassCastException
Summary: ECJ creates wrong method handle which fails at runtime with a ClassCastException
Status: NEW
Alias: None
Product: JDT
Classification: Eclipse Project
Component: Core (show other bugs)
Version: 4.20   Edit
Hardware: All All
: P3 normal with 1 vote (vote)
Target Milestone: ---   Edit
Assignee: JDT-Core-Inbox CLA
QA Contact: Sravan Kumar Lakkimsetti CLA
URL:
Whiteboard: stalebug
Keywords:
Depends on:
Blocks:
 
Reported: 2021-07-21 09:15 EDT by Johannes Döbler CLA
Modified: 2023-07-28 16:53 EDT (History)
5 users (show)

See Also:


Attachments
demonstrates the bug (1.05 KB, text/plain)
2021-07-21 09:15 EDT, Johannes Döbler CLA
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Johannes Döbler CLA 2021-07-21 09:15:24 EDT
Created attachment 286814 [details]
demonstrates the bug

Eclipse Compiler for Java (ECJ) compiles the attached source file without problems. When the compiled class is run it erroneously fails with a ClassCastException. The same class compiled by javac runs without problems.

The bug is caused by a bug in ECJs type parameter tracking:
The bootstrap method for method handle Object::hashCode in line 38 has wrong MethodType "(Ljava/lang/Class;)Ljava/lang/Integer" when compiled with ECJ and correct MethodType "(Ljava/lang/String;)Ljava/lang/Integer" when compiled with javac.

This is a variation of https://bugs.eclipse.org/bugs/show_bug.cgi?id=574309.
That report describes a compile time error, whereas this bug report describes a erroneous runtime error, therefore I opened a new bug report.
Comment 1 Jay Arthanareeswaran CLA 2021-08-06 01:38:11 EDT
The difference seems to be in the Bootstrap method argument:

Bootstrap methods:
  0 : # 95 invokestatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
	Method arguments:
		#96 (Ljava/lang/Object;)Ljava/lang/Object;
		#101 java/lang/Object.getClass:()Ljava/lang/Class;
		#103 (Ljava/lang/String;)Ljava/lang/Class;,
  1 : # 95 invokestatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
	Method arguments:
		#104 (Ljava/lang/Object;)Ljava/lang/Object;
		#109 java/lang/Object.hashCode:()I
		#111 (Ljava/lang/Class;)Ljava/lang/Integer;
}

At index 1, we have the last argument as Ljava/lang/Class; which probably should have been String.
Comment 2 Jay Arthanareeswaran CLA 2021-08-06 02:11:02 EDT
One more observation:

The following code produces two bootstrap methods for lambda meta factory, despite the arguments being the same. Of course, the second one gets the wrong third argument.

 bug4.prop(Object::hashCode)
            .back()
            .prop(Object::hashCode) // fails when compiled with ECJ, no problem when compiled with javac
            .back();

Bootstrap methods:
  0 : # 105 invokestatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
	Method arguments:
		#106 (Ljava/lang/Object;)Ljava/lang/Object;
		#111 java/lang/Object.hashCode:()I
		#113 (Ljava/lang/String;)Ljava/lang/Integer;,
  1 : # 105 invokestatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
	Method arguments:
		#114 (Ljava/lang/Object;)Ljava/lang/Object;
		#115 java/lang/Object.hashCode:()I
		#117 (Ljava/lang/Integer;)Ljava/lang/Integer;
Comment 3 Jay Arthanareeswaran CLA 2021-08-06 02:41:21 EDT
(In reply to Jay Arthanareeswaran from comment #2)
> One more observation:
> 
> The following code produces two bootstrap methods for lambda meta factory,
> despite the arguments being the same. Of course, the second one gets the
> wrong third argument.

What's causing this is the wrong descriptor of the functional interface. In the first one, we get 

public abstract java.lang.Integer apply(java.lang.String) 

and in the second case, it is

public abstract java.lang.Integer apply(java.lang.Integer)
Comment 4 Jay Arthanareeswaran CLA 2021-08-06 03:15:42 EDT
Looks like we are in inference area!

The first MessageSend's actualReceiverType resolves to

 bug4.prop(Object::hashCode) => 
    public class MethodHandleBug<java.lang.String,capture#1-of ?,capture#2-of ?>

By the time we get to the second one:

  bug4.prop(Object::hashCode).back() => 
    public class MethodHandleBug<java.lang.Integer,capture#2-of ?,capture#3-of ?>

And we don't seem to recover from this:

  bug4.prop(Object::hashCode).back().prop(Object::hashCode) =>
     capture#2-of ?

Beyond this is bit of black magic to me. Copying Stephan to throw some light here, if he can.
Comment 5 Eclipse Genie CLA 2023-07-28 16:53:14 EDT
This bug hasn't had any activity in quite some time. Maybe the problem got resolved, was a duplicate of something else, or became less pressing for some reason - or maybe it's still relevant but just hasn't been looked at yet.

If you have further information on the current state of the bug, please add it. The information can be, for example, that the problem still occurs, that you still want the feature, that more information is needed, or that the bug is (for whatever reason) no longer relevant.

--
The automated Eclipse Genie.