8
8
9
9
package org .elasticsearch .painless .lookup ;
10
10
11
- import org .elasticsearch .bootstrap .BootstrapInfo ;
12
11
import org .elasticsearch .common .util .Maps ;
13
12
import org .elasticsearch .painless .Def ;
14
- import org .elasticsearch .painless .MethodWriter ;
15
- import org .elasticsearch .painless .WriterConstants ;
16
13
import org .elasticsearch .painless .spi .Whitelist ;
17
14
import org .elasticsearch .painless .spi .WhitelistClass ;
18
15
import org .elasticsearch .painless .spi .WhitelistClassBinding ;
25
22
import org .elasticsearch .painless .spi .annotation .CompileTimeOnlyAnnotation ;
26
23
import org .elasticsearch .painless .spi .annotation .InjectConstantAnnotation ;
27
24
import org .elasticsearch .painless .spi .annotation .NoImportAnnotation ;
28
- import org .objectweb .asm .ClassWriter ;
29
- import org .objectweb .asm .Opcodes ;
30
- import org .objectweb .asm .commons .GeneratorAdapter ;
31
25
32
26
import java .lang .invoke .MethodHandle ;
33
27
import java .lang .invoke .MethodHandles ;
37
31
import java .lang .reflect .Field ;
38
32
import java .lang .reflect .Method ;
39
33
import java .lang .reflect .Modifier ;
40
- import java .net .MalformedURLException ;
41
- import java .net .URL ;
42
- import java .security .AccessController ;
43
- import java .security .CodeSource ;
44
- import java .security .PrivilegedAction ;
45
- import java .security .SecureClassLoader ;
46
- import java .security .cert .Certificate ;
47
34
import java .util .ArrayList ;
48
35
import java .util .Arrays ;
49
36
import java .util .Collections ;
56
43
import java .util .function .Supplier ;
57
44
import java .util .regex .Pattern ;
58
45
59
- import static org .elasticsearch .painless .WriterConstants .DEF_TO_B_BYTE_IMPLICIT ;
60
- import static org .elasticsearch .painless .WriterConstants .DEF_TO_B_CHARACTER_IMPLICIT ;
61
- import static org .elasticsearch .painless .WriterConstants .DEF_TO_B_DOUBLE_IMPLICIT ;
62
- import static org .elasticsearch .painless .WriterConstants .DEF_TO_B_FLOAT_IMPLICIT ;
63
- import static org .elasticsearch .painless .WriterConstants .DEF_TO_B_INTEGER_IMPLICIT ;
64
- import static org .elasticsearch .painless .WriterConstants .DEF_TO_B_LONG_IMPLICIT ;
65
- import static org .elasticsearch .painless .WriterConstants .DEF_TO_B_SHORT_IMPLICIT ;
66
- import static org .elasticsearch .painless .WriterConstants .DEF_UTIL_TYPE ;
67
- import static org .elasticsearch .painless .WriterConstants .OBJECT_TYPE ;
68
46
import static org .elasticsearch .painless .lookup .PainlessLookupUtility .DEF_CLASS_NAME ;
69
47
import static org .elasticsearch .painless .lookup .PainlessLookupUtility .buildPainlessConstructorKey ;
70
48
import static org .elasticsearch .painless .lookup .PainlessLookupUtility .buildPainlessFieldKey ;
75
53
76
54
public final class PainlessLookupBuilder {
77
55
78
- private static final class BridgeLoader extends SecureClassLoader {
79
- BridgeLoader (ClassLoader parent ) {
80
- super (parent );
81
- }
82
-
83
- @ Override
84
- public Class <?> findClass (String name ) throws ClassNotFoundException {
85
- return Def .class .getName ().equals (name ) ? Def .class : super .findClass (name );
86
- }
87
-
88
- Class <?> defineBridge (String name , byte [] bytes ) {
89
- return defineClass (name , bytes , 0 , bytes .length , CODESOURCE );
90
- }
91
- }
92
-
93
- private static final CodeSource CODESOURCE ;
94
-
95
56
private static final Map <PainlessConstructor , PainlessConstructor > painlessConstructorCache = new HashMap <>();
96
57
private static final Map <PainlessMethod , PainlessMethod > painlessMethodCache = new HashMap <>();
97
58
private static final Map <PainlessField , PainlessField > painlessFieldCache = new HashMap <>();
98
59
private static final Map <PainlessClassBinding , PainlessClassBinding > painlessClassBindingCache = new HashMap <>();
99
60
private static final Map <PainlessInstanceBinding , PainlessInstanceBinding > painlessInstanceBindingCache = new HashMap <>();
100
- private static final Map <PainlessMethod , PainlessMethod > painlessBridgeCache = new HashMap <>();
61
+ private static final Map <PainlessMethod , PainlessMethod > painlessFilteredCache = new HashMap <>();
101
62
102
63
private static final Pattern CLASS_NAME_PATTERN = Pattern .compile ("^[_a-zA-Z][._a-zA-Z0-9]*$" );
103
64
private static final Pattern METHOD_NAME_PATTERN = Pattern .compile ("^[_a-zA-Z][_a-zA-Z0-9]*$" );
104
65
private static final Pattern FIELD_NAME_PATTERN = Pattern .compile ("^[_a-zA-Z][_a-zA-Z0-9]*$" );
105
66
106
- static {
107
- try {
108
- CODESOURCE = new CodeSource (new URL ("file:" + BootstrapInfo .UNTRUSTED_CODEBASE ), (Certificate []) null );
109
- } catch (MalformedURLException mue ) {
110
- throw new RuntimeException (mue );
111
- }
112
- }
113
-
114
67
public static PainlessLookup buildFromWhitelists (List <Whitelist > whitelists ) {
115
68
PainlessLookupBuilder painlessLookupBuilder = new PainlessLookupBuilder ();
116
69
String origin = "internal error" ;
@@ -2216,7 +2169,9 @@ private void setFunctionalInterfaceMethod(Class<?> targetClass, PainlessClassBui
2216
2169
* run-time resulting from calls with a def type value target.
2217
2170
*/
2218
2171
private void generateRuntimeMethods () {
2219
- for (PainlessClassBuilder painlessClassBuilder : classesToPainlessClassBuilders .values ()) {
2172
+ for (Map .Entry <Class <?>, PainlessClassBuilder > painlessClassBuilderEntry : classesToPainlessClassBuilders .entrySet ()) {
2173
+ Class <?> targetClass = painlessClassBuilderEntry .getKey ();
2174
+ PainlessClassBuilder painlessClassBuilder = painlessClassBuilderEntry .getValue ();
2220
2175
painlessClassBuilder .runtimeMethods .putAll (painlessClassBuilder .methods );
2221
2176
2222
2177
for (PainlessMethod painlessMethod : painlessClassBuilder .runtimeMethods .values ()) {
@@ -2228,63 +2183,25 @@ private void generateRuntimeMethods() {
2228
2183
|| typeParameter == Long .class
2229
2184
|| typeParameter == Float .class
2230
2185
|| typeParameter == Double .class ) {
2231
- generateBridgeMethod ( painlessClassBuilder , painlessMethod );
2186
+ generateFilteredMethod ( targetClass , painlessClassBuilder , painlessMethod );
2232
2187
}
2233
2188
}
2234
2189
}
2235
2190
}
2236
2191
}
2237
2192
2238
- private void generateBridgeMethod ( PainlessClassBuilder painlessClassBuilder , PainlessMethod painlessMethod ) {
2193
+ private void generateFilteredMethod ( Class <?> targetClass , PainlessClassBuilder painlessClassBuilder , PainlessMethod painlessMethod ) {
2239
2194
String painlessMethodKey = buildPainlessMethodKey (painlessMethod .javaMethod ().getName (), painlessMethod .typeParameters ().size ());
2240
- PainlessMethod bridgePainlessMethod = painlessBridgeCache .get (painlessMethod );
2195
+ PainlessMethod filteredPainlessMethod = painlessFilteredCache .get (painlessMethod );
2241
2196
2242
- if (bridgePainlessMethod == null ) {
2197
+ if (filteredPainlessMethod == null ) {
2243
2198
Method javaMethod = painlessMethod .javaMethod ();
2244
2199
boolean isStatic = Modifier .isStatic (painlessMethod .javaMethod ().getModifiers ());
2245
-
2246
- int bridgeClassFrames = ClassWriter .COMPUTE_FRAMES | ClassWriter .COMPUTE_MAXS ;
2247
- int bridgeClassAccess = Opcodes .ACC_PUBLIC | Opcodes .ACC_SUPER | Opcodes .ACC_FINAL ;
2248
- String bridgeClassName = "org/elasticsearch/painless/Bridge$"
2249
- + javaMethod .getDeclaringClass ().getSimpleName ()
2250
- + "$"
2251
- + javaMethod .getName ();
2252
- ClassWriter bridgeClassWriter = new ClassWriter (bridgeClassFrames );
2253
- bridgeClassWriter .visit (
2254
- WriterConstants .CLASS_VERSION ,
2255
- bridgeClassAccess ,
2256
- bridgeClassName ,
2257
- null ,
2258
- OBJECT_TYPE .getInternalName (),
2259
- null
2260
- );
2261
-
2262
- org .objectweb .asm .commons .Method bridgeConstructorType = new org .objectweb .asm .commons .Method (
2263
- "<init>" ,
2264
- MethodType .methodType (void .class ).toMethodDescriptorString ()
2265
- );
2266
- GeneratorAdapter bridgeConstructorWriter = new GeneratorAdapter (
2267
- Opcodes .ASM5 ,
2268
- bridgeConstructorType ,
2269
- bridgeClassWriter .visitMethod (
2270
- Opcodes .ACC_PRIVATE ,
2271
- bridgeConstructorType .getName (),
2272
- bridgeConstructorType .getDescriptor (),
2273
- null ,
2274
- null
2275
- )
2276
- );
2277
- bridgeConstructorWriter .visitCode ();
2278
- bridgeConstructorWriter .loadThis ();
2279
- bridgeConstructorWriter .invokeConstructor (OBJECT_TYPE , bridgeConstructorType );
2280
- bridgeConstructorWriter .returnValue ();
2281
- bridgeConstructorWriter .endMethod ();
2282
-
2283
- int bridgeTypeParameterOffset = isStatic ? 0 : 1 ;
2284
- List <Class <?>> bridgeTypeParameters = new ArrayList <>(javaMethod .getParameterTypes ().length + bridgeTypeParameterOffset );
2200
+ int filteredTypeParameterOffset = isStatic ? 0 : 1 ;
2201
+ List <Class <?>> filteredTypeParameters = new ArrayList <>(javaMethod .getParameterTypes ().length + filteredTypeParameterOffset );
2285
2202
2286
2203
if (isStatic == false ) {
2287
- bridgeTypeParameters .add (javaMethod .getDeclaringClass ());
2204
+ filteredTypeParameters .add (javaMethod .getDeclaringClass ());
2288
2205
}
2289
2206
2290
2207
for (Class <?> typeParameter : javaMethod .getParameterTypes ()) {
@@ -2295,78 +2212,48 @@ private void generateBridgeMethod(PainlessClassBuilder painlessClassBuilder, Pai
2295
2212
|| typeParameter == Long .class
2296
2213
|| typeParameter == Float .class
2297
2214
|| typeParameter == Double .class ) {
2298
- bridgeTypeParameters .add (Object .class );
2215
+ filteredTypeParameters .add (Object .class );
2299
2216
} else {
2300
- bridgeTypeParameters .add (typeParameter );
2217
+ filteredTypeParameters .add (typeParameter );
2301
2218
}
2302
2219
}
2303
2220
2304
- MethodType bridgeMethodType = MethodType .methodType (painlessMethod .returnType (), bridgeTypeParameters );
2305
- MethodWriter bridgeMethodWriter = new MethodWriter (
2306
- Opcodes .ACC_PUBLIC | Opcodes .ACC_STATIC ,
2307
- new org .objectweb .asm .commons .Method (painlessMethod .javaMethod ().getName (), bridgeMethodType .toMethodDescriptorString ()),
2308
- bridgeClassWriter ,
2309
- null ,
2310
- null
2311
- );
2312
- bridgeMethodWriter .visitCode ();
2313
-
2314
- if (isStatic == false ) {
2315
- bridgeMethodWriter .loadArg (0 );
2316
- }
2317
-
2318
- for (int typeParameterCount = 0 ; typeParameterCount < javaMethod .getParameterTypes ().length ; ++typeParameterCount ) {
2319
- bridgeMethodWriter .loadArg (typeParameterCount + bridgeTypeParameterOffset );
2320
- Class <?> typeParameter = javaMethod .getParameterTypes ()[typeParameterCount ];
2321
-
2322
- if (typeParameter == Byte .class ) bridgeMethodWriter .invokeStatic (DEF_UTIL_TYPE , DEF_TO_B_BYTE_IMPLICIT );
2323
- else if (typeParameter == Short .class ) bridgeMethodWriter .invokeStatic (DEF_UTIL_TYPE , DEF_TO_B_SHORT_IMPLICIT );
2324
- else if (typeParameter == Character .class ) bridgeMethodWriter .invokeStatic (DEF_UTIL_TYPE , DEF_TO_B_CHARACTER_IMPLICIT );
2325
- else if (typeParameter == Integer .class ) bridgeMethodWriter .invokeStatic (DEF_UTIL_TYPE , DEF_TO_B_INTEGER_IMPLICIT );
2326
- else if (typeParameter == Long .class ) bridgeMethodWriter .invokeStatic (DEF_UTIL_TYPE , DEF_TO_B_LONG_IMPLICIT );
2327
- else if (typeParameter == Float .class ) bridgeMethodWriter .invokeStatic (DEF_UTIL_TYPE , DEF_TO_B_FLOAT_IMPLICIT );
2328
- else if (typeParameter == Double .class ) bridgeMethodWriter .invokeStatic (DEF_UTIL_TYPE , DEF_TO_B_DOUBLE_IMPLICIT );
2329
- }
2330
-
2331
- bridgeMethodWriter .invokeMethodCall (painlessMethod );
2332
- bridgeMethodWriter .returnValue ();
2333
- bridgeMethodWriter .endMethod ();
2334
-
2335
- bridgeClassWriter .visitEnd ();
2221
+ MethodType filteredMethodType = MethodType .methodType (painlessMethod .returnType (), filteredTypeParameters );
2222
+ MethodHandle filteredMethodHandle = painlessMethod .methodHandle ();
2336
2223
2337
2224
try {
2338
- BridgeLoader bridgeLoader = AccessController .doPrivileged (new PrivilegedAction <BridgeLoader >() {
2339
- @ Override
2340
- public BridgeLoader run () {
2341
- return new BridgeLoader (javaMethod .getDeclaringClass ().getClassLoader ());
2225
+ for (int typeParameterCount = 0 ; typeParameterCount < javaMethod .getParameterTypes ().length ; ++typeParameterCount ) {
2226
+ Class <?> typeParameter = javaMethod .getParameterTypes ()[typeParameterCount ];
2227
+ MethodHandle castMethodHandle = Def .DEF_TO_BOXED_TYPE_IMPLICIT_CAST .get (typeParameter );
2228
+
2229
+ if (castMethodHandle != null ) {
2230
+ filteredMethodHandle = MethodHandles .filterArguments (
2231
+ filteredMethodHandle ,
2232
+ typeParameterCount + filteredTypeParameterOffset ,
2233
+ castMethodHandle
2234
+ );
2342
2235
}
2343
- });
2236
+ }
2344
2237
2345
- Class <?> bridgeClass = bridgeLoader .defineBridge (bridgeClassName .replace ('/' , '.' ), bridgeClassWriter .toByteArray ());
2346
- Method bridgeMethod = bridgeClass .getMethod (
2347
- painlessMethod .javaMethod ().getName (),
2348
- bridgeTypeParameters .toArray (new Class <?>[0 ])
2349
- );
2350
- MethodHandle bridgeHandle = lookup (bridgeClass ).unreflect (bridgeClass .getMethods ()[0 ]);
2351
- bridgePainlessMethod = new PainlessMethod (
2352
- bridgeMethod ,
2353
- bridgeClass ,
2238
+ filteredPainlessMethod = new PainlessMethod (
2239
+ painlessMethod .javaMethod (),
2240
+ targetClass ,
2354
2241
painlessMethod .returnType (),
2355
- bridgeTypeParameters ,
2356
- bridgeHandle ,
2357
- bridgeMethodType ,
2242
+ filteredTypeParameters ,
2243
+ filteredMethodHandle ,
2244
+ filteredMethodType ,
2358
2245
Collections .emptyMap ()
2359
2246
);
2360
- painlessClassBuilder .runtimeMethods .put (painlessMethodKey .intern (), bridgePainlessMethod );
2361
- painlessBridgeCache .put (painlessMethod , bridgePainlessMethod );
2247
+ painlessClassBuilder .runtimeMethods .put (painlessMethodKey .intern (), filteredPainlessMethod );
2248
+ painlessFilteredCache .put (painlessMethod , filteredPainlessMethod );
2362
2249
} catch (Exception exception ) {
2363
2250
throw new IllegalStateException (
2364
- "internal error occurred attempting to generate a bridge method [" + bridgeClassName + "]" ,
2251
+ "internal error occurred attempting to generate a runtime method [" + painlessMethodKey + "]" ,
2365
2252
exception
2366
2253
);
2367
2254
}
2368
2255
} else {
2369
- painlessClassBuilder .runtimeMethods .put (painlessMethodKey .intern (), bridgePainlessMethod );
2256
+ painlessClassBuilder .runtimeMethods .put (painlessMethodKey .intern (), filteredPainlessMethod );
2370
2257
}
2371
2258
}
2372
2259
0 commit comments