Skip to content

Commit cfd9c83

Browse files
committed
[Painless] Generate Bridge Methods (#36097)
We use MethodHandles.asType to cast argument types into the appropriate parameter types for method calls when the target of the call is a def type at runtime. Currently, certain implicit casts using the def type are asymmetric. It is possible to cast Integer -> float as an argument to parameter, but not from int -> Float (boxed to primitive with upcasting is okay, but primitive to boxed with upcasting is not). This PR introduces a solution to the issue by generating bridge methods for all whitelisted methods that have at least a single boxed type as an argument. The bridge method will conduct appropriate casts and then call the original method. This adds a bit of overhead for correctness. It should not be used often as Painless avoids boxed types as much as possible. Note that a large portion of this change is adding methods to do the appropriate def to boxed type casts and a few mechanical changes as well. The most important method for review is generateBridgeMethod in PainlessLookupBuilder.
1 parent ba8314c commit cfd9c83

File tree

11 files changed

+531
-123
lines changed

11 files changed

+531
-123
lines changed

modules/lang-painless/src/main/java/org/elasticsearch/painless/Def.java

Lines changed: 186 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ static MethodHandle lookupMethod(PainlessLookup painlessLookup, Map<String, Loca
196196
int numArguments = callSiteType.parameterCount();
197197
// simple case: no lambdas
198198
if (recipeString.isEmpty()) {
199-
PainlessMethod painlessMethod = painlessLookup.lookupRuntimePainlessMethod(receiverClass, name, numArguments - 1);
199+
PainlessMethod painlessMethod = painlessLookup.lookupRuntimePainlessMethod(receiverClass, name, numArguments - 1);
200200

201201
if (painlessMethod == null) {
202202
throw new IllegalArgumentException("dynamic method " +
@@ -445,7 +445,7 @@ static MethodHandle lookupSetter(PainlessLookup painlessLookup, Class<?> receive
445445
}
446446

447447
throw new IllegalArgumentException(
448-
"dynamic getter [" + typeToCanonicalTypeName(receiverClass) + ", " + name + "] not found");
448+
"dynamic setter [" + typeToCanonicalTypeName(receiverClass) + ", " + name + "] not found");
449449
}
450450

451451
/**
@@ -619,34 +619,29 @@ static MethodHandle lookupIterator(Class<?> receiverClass) {
619619
}
620620
}
621621

622+
// Conversion methods for def to primitive types.
622623

623-
// Conversion methods for Def to primitive types.
624-
625-
public static boolean DefToboolean(final Object value) {
624+
public static boolean defToboolean(final Object value) {
626625
return (boolean)value;
627626
}
628627

629-
public static byte DefTobyteImplicit(final Object value) {
628+
public static byte defTobyteImplicit(final Object value) {
630629
return (byte)value;
631630
}
632631

633-
public static short DefToshortImplicit(final Object value) {
632+
public static short defToshortImplicit(final Object value) {
634633
if (value instanceof Byte) {
635634
return (byte)value;
636635
} else {
637636
return (short)value;
638637
}
639638
}
640639

641-
public static char DefTocharImplicit(final Object value) {
642-
if (value instanceof Byte) {
643-
return (char)(byte)value;
644-
} else {
645-
return (char)value;
646-
}
640+
public static char defTocharImplicit(final Object value) {
641+
return (char)value;
647642
}
648643

649-
public static int DefTointImplicit(final Object value) {
644+
public static int defTointImplicit(final Object value) {
650645
if (value instanceof Byte) {
651646
return (byte)value;
652647
} else if (value instanceof Short) {
@@ -658,7 +653,7 @@ public static int DefTointImplicit(final Object value) {
658653
}
659654
}
660655

661-
public static long DefTolongImplicit(final Object value) {
656+
public static long defTolongImplicit(final Object value) {
662657
if (value instanceof Byte) {
663658
return (byte)value;
664659
} else if (value instanceof Short) {
@@ -672,7 +667,7 @@ public static long DefTolongImplicit(final Object value) {
672667
}
673668
}
674669

675-
public static float DefTofloatImplicit(final Object value) {
670+
public static float defTofloatImplicit(final Object value) {
676671
if (value instanceof Byte) {
677672
return (byte)value;
678673
} else if (value instanceof Short) {
@@ -688,7 +683,7 @@ public static float DefTofloatImplicit(final Object value) {
688683
}
689684
}
690685

691-
public static double DefTodoubleImplicit(final Object value) {
686+
public static double defTodoubleImplicit(final Object value) {
692687
if (value instanceof Byte) {
693688
return (byte)value;
694689
} else if (value instanceof Short) {
@@ -706,62 +701,228 @@ public static double DefTodoubleImplicit(final Object value) {
706701
}
707702
}
708703

709-
public static byte DefTobyteExplicit(final Object value) {
704+
public static byte defTobyteExplicit(final Object value) {
710705
if (value instanceof Character) {
711706
return (byte)(char)value;
712707
} else {
713708
return ((Number)value).byteValue();
714709
}
715710
}
716711

717-
public static short DefToshortExplicit(final Object value) {
712+
public static short defToshortExplicit(final Object value) {
718713
if (value instanceof Character) {
719714
return (short)(char)value;
720715
} else {
721716
return ((Number)value).shortValue();
722717
}
723718
}
724719

725-
public static char DefTocharExplicit(final Object value) {
720+
public static char defTocharExplicit(final Object value) {
726721
if (value instanceof Character) {
727-
return ((Character)value);
722+
return (char)value;
728723
} else {
729724
return (char)((Number)value).intValue();
730725
}
731726
}
732727

733-
public static int DefTointExplicit(final Object value) {
728+
public static int defTointExplicit(final Object value) {
734729
if (value instanceof Character) {
735730
return (char)value;
736731
} else {
737732
return ((Number)value).intValue();
738733
}
739734
}
740735

741-
public static long DefTolongExplicit(final Object value) {
736+
public static long defTolongExplicit(final Object value) {
742737
if (value instanceof Character) {
743738
return (char)value;
744739
} else {
745740
return ((Number)value).longValue();
746741
}
747742
}
748743

749-
public static float DefTofloatExplicit(final Object value) {
744+
public static float defTofloatExplicit(final Object value) {
750745
if (value instanceof Character) {
751746
return (char)value;
752747
} else {
753748
return ((Number)value).floatValue();
754749
}
755750
}
756751

757-
public static double DefTodoubleExplicit(final Object value) {
752+
public static double defTodoubleExplicit(final Object value) {
758753
if (value instanceof Character) {
759754
return (char)value;
760755
} else {
761756
return ((Number)value).doubleValue();
762757
}
763758
}
764759

760+
// Conversion methods for def to boxed types.
761+
762+
public static Byte defToByteImplicit(final Object value) {
763+
if (value == null) {
764+
return null;
765+
} else {
766+
return (Byte)value;
767+
}
768+
}
769+
770+
public static Short defToShortImplicit(final Object value) {
771+
if (value == null) {
772+
return null;
773+
} else if (value instanceof Byte) {
774+
return (short)(byte)value;
775+
} else {
776+
return (Short)value;
777+
}
778+
}
779+
780+
public static Character defToCharacterImplicit(final Object value) {
781+
if (value == null) {
782+
return null;
783+
} else {
784+
return (Character)value;
785+
}
786+
}
787+
788+
public static Integer defToIntegerImplicit(final Object value) {
789+
if (value == null) {
790+
return null;
791+
} else if (value instanceof Byte) {
792+
return (int)(byte)value;
793+
} else if (value instanceof Short) {
794+
return (int)(short)value;
795+
} else if (value instanceof Character) {
796+
return (int)(char)value;
797+
} else {
798+
return (Integer)value;
799+
}
800+
}
801+
802+
public static Long defToLongImplicit(final Object value) {
803+
if (value == null) {
804+
return null;
805+
} else if (value instanceof Byte) {
806+
return (long)(byte)value;
807+
} else if (value instanceof Short) {
808+
return (long)(short)value;
809+
} else if (value instanceof Character) {
810+
return (long)(char)value;
811+
} else if (value instanceof Integer) {
812+
return (long)(int)value;
813+
} else {
814+
return (Long)value;
815+
}
816+
}
817+
818+
public static Float defToFloatImplicit(final Object value) {
819+
if (value == null) {
820+
return null;
821+
} else if (value instanceof Byte) {
822+
return (float)(byte)value;
823+
} else if (value instanceof Short) {
824+
return (float)(short)value;
825+
} else if (value instanceof Character) {
826+
return (float)(char)value;
827+
} else if (value instanceof Integer) {
828+
return (float)(int)value;
829+
} else if (value instanceof Long) {
830+
return (float)(long)value;
831+
} else {
832+
return (Float)value;
833+
}
834+
}
835+
836+
public static Double defToDoubleImplicit(final Object value) {
837+
if (value == null) {
838+
return null;
839+
} else if (value instanceof Byte) {
840+
return (double)(byte)value;
841+
} else if (value instanceof Short) {
842+
return (double)(short)value;
843+
} else if (value instanceof Character) {
844+
return (double)(char)value;
845+
} else if (value instanceof Integer) {
846+
return (double)(int)value;
847+
} else if (value instanceof Long) {
848+
return (double)(long)value;
849+
} else if (value instanceof Float) {
850+
return (double)(float)value;
851+
} else {
852+
return (Double)value;
853+
}
854+
}
855+
856+
public static Byte defToByteExplicit(final Object value) {
857+
if (value == null) {
858+
return null;
859+
} else if (value instanceof Character) {
860+
return (byte)(char)value;
861+
} else {
862+
return ((Number)value).byteValue();
863+
}
864+
}
865+
866+
public static Short defToShortExplicit(final Object value) {
867+
if (value == null) {
868+
return null;
869+
} else if (value instanceof Character) {
870+
return (short)(char)value;
871+
} else {
872+
return ((Number)value).shortValue();
873+
}
874+
}
875+
876+
public static Character defToCharacterExplicit(final Object value) {
877+
if (value == null) {
878+
return null;
879+
} else if (value instanceof Character) {
880+
return (Character)value;
881+
} else {
882+
return (char)((Number)value).intValue();
883+
}
884+
}
885+
886+
public static Integer defToIntegerExplicit(final Object value) {
887+
if (value == null) {
888+
return null;
889+
} else if (value instanceof Character) {
890+
return (int)(char)value;
891+
} else {
892+
return ((Number)value).intValue();
893+
}
894+
}
895+
896+
public static Long defToLongExplicit(final Object value) {
897+
if (value == null) {
898+
return null;
899+
} else if (value instanceof Character) {
900+
return (long)(char)value;
901+
} else {
902+
return ((Number)value).longValue();
903+
}
904+
}
905+
906+
public static Float defToFloatExplicit(final Object value) {
907+
if (value == null) {
908+
return null;
909+
} else if (value instanceof Character) {
910+
return (float)(char)value;
911+
} else {
912+
return ((Number)value).floatValue();
913+
}
914+
}
915+
916+
public static Double defToDoubleExplicit(final Object value) {
917+
if (value == null) {
918+
return null;
919+
} else if (value instanceof Character) {
920+
return (double)(char)value;
921+
} else {
922+
return ((Number)value).doubleValue();
923+
}
924+
}
925+
765926
/**
766927
* "Normalizes" the index into a {@code Map} by making no change to the index.
767928
*/

modules/lang-painless/src/main/java/org/elasticsearch/painless/FeatureTest.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,17 @@ public static float staticAddFloatsTest(float x, float y) {
3939
return x + y;
4040
}
4141

42+
/** static method with a type parameter Number */
43+
public static int staticNumberTest(Number number) {
44+
return number.intValue();
45+
}
46+
4247
private int x;
4348
private int y;
4449
public int z;
4550

51+
private Integer i;
52+
4653
/** empty ctor */
4754
public FeatureTest() {
4855
}
@@ -73,6 +80,20 @@ public void setY(int y) {
7380
this.y = y;
7481
}
7582

83+
/** getter for i */
84+
public Integer getI() {
85+
return i;
86+
}
87+
88+
/** setter for y */
89+
public void setI(Integer i) {
90+
this.i = i;
91+
}
92+
93+
public Double mixedAdd(int i, Byte b, char c, Float f) {
94+
return (double)(i + b + c + f);
95+
}
96+
7697
/** method taking two functions! */
7798
public Object twoFunctionsOfX(Function<Object,Object> f, Function<Object,Object> g) {
7899
return f.apply(g.apply(x));

0 commit comments

Comments
 (0)