61
61
import org .weakref .jmx .Managed ;
62
62
import org .weakref .jmx .Nested ;
63
63
64
- import java .lang .invoke . MethodHandle ;
64
+ import java .lang .reflect . Constructor ;
65
65
import java .util .List ;
66
66
import java .util .Map ;
67
67
import java .util .Optional ;
72
72
73
73
import static com .google .common .base .MoreObjects .toStringHelper ;
74
74
import static com .google .common .base .Throwables .throwIfInstanceOf ;
75
+ import static com .google .common .collect .ImmutableList .toImmutableList ;
75
76
import static io .airlift .bytecode .Access .FINAL ;
76
77
import static io .airlift .bytecode .Access .PRIVATE ;
77
78
import static io .airlift .bytecode .Access .PUBLIC ;
97
98
import static io .trino .sql .relational .DeterminismEvaluator .isDeterministic ;
98
99
import static io .trino .util .CompilerUtils .defineClass ;
99
100
import static io .trino .util .CompilerUtils .makeClassName ;
100
- import static io .trino .util .Reflection .constructorMethodHandle ;
101
101
import static java .util .Objects .requireNonNull ;
102
102
103
103
public class PageFunctionCompiler
@@ -198,9 +198,10 @@ private Supplier<PageProjection> compileProjectionInternal(RowExpression project
198
198
199
199
ClassDefinition pageProjectionWorkDefinition = definePageProjectWorkClass (result .getRewrittenExpression (), callSiteBinder , classNameSuffix );
200
200
201
- Class <?> pageProjectionWorkClass ;
201
+ Constructor <? extends PageProjectionWork > pageProjectionWorkConstructor ;
202
202
try {
203
- pageProjectionWorkClass = defineClass (pageProjectionWorkDefinition , PageProjectionWork .class , callSiteBinder .getBindings (), getClass ().getClassLoader ());
203
+ Class <? extends PageProjectionWork > pageProjectionWorkClass = defineClass (pageProjectionWorkDefinition , PageProjectionWork .class , callSiteBinder .getBindings (), getClass ().getClassLoader ());
204
+ pageProjectionWorkConstructor = pageProjectionWorkClass .getConstructor ();
204
205
}
205
206
catch (Exception e ) {
206
207
if (Throwables .getRootCause (e ) instanceof MethodTooLargeException ) {
@@ -210,12 +211,19 @@ private Supplier<PageProjection> compileProjectionInternal(RowExpression project
210
211
throw new TrinoException (COMPILER_ERROR , e );
211
212
}
212
213
213
- MethodHandle pageProjectionConstructor = constructorMethodHandle (pageProjectionWorkClass , BlockBuilder .class , ConnectorSession .class , SourcePage .class , SelectedPositions .class );
214
- return () -> new GeneratedPageProjection (
215
- result .getRewrittenExpression (),
216
- isExpressionDeterministic ,
217
- result .getInputChannels (),
218
- pageProjectionConstructor );
214
+ return () -> {
215
+ try {
216
+ PageProjectionWork pageProjectionWork = pageProjectionWorkConstructor .newInstance ();
217
+ return new GeneratedPageProjection (
218
+ result .getRewrittenExpression (),
219
+ isExpressionDeterministic ,
220
+ result .getInputChannels (),
221
+ pageProjectionWork );
222
+ }
223
+ catch (ReflectiveOperationException e ) {
224
+ throw new TrinoException (COMPILER_ERROR , e );
225
+ }
226
+ };
219
227
}
220
228
221
229
private static ParameterizedType generateProjectionWorkClassName (Optional <String > classNameSuffix )
@@ -232,89 +240,96 @@ private ClassDefinition definePageProjectWorkClass(RowExpression projection, Cal
232
240
type (PageProjectionWork .class ));
233
241
234
242
FieldDefinition blockBuilderField = classDefinition .declareField (a (PRIVATE ), "blockBuilder" , BlockBuilder .class );
235
- FieldDefinition sessionField = classDefinition .declareField (a (PRIVATE ), "session" , ConnectorSession .class );
236
- FieldDefinition selectedPositionsField = classDefinition .declareField (a (PRIVATE ), "selectedPositions" , SelectedPositions .class );
237
243
238
244
CachedInstanceBinder cachedInstanceBinder = new CachedInstanceBinder (classDefinition , callSiteBinder );
239
245
246
+ List <Integer > inputChannels = getInputChannels (projection );
247
+ List <FieldDefinition > blockFields = inputChannels .stream ()
248
+ .map (channel -> classDefinition .declareField (a (PRIVATE ), "block_" + channel , Block .class ))
249
+ .collect (toImmutableList ());
240
250
// process
241
- generateProcessMethod (classDefinition , blockBuilderField , sessionField , selectedPositionsField );
251
+ generateProcessMethod (classDefinition , blockBuilderField , blockFields , inputChannels );
242
252
243
253
// evaluate
244
254
Map <LambdaDefinitionExpression , CompiledLambda > compiledLambdaMap = generateMethodsForLambda (classDefinition , callSiteBinder , cachedInstanceBinder , projection );
245
255
generateEvaluateMethod (classDefinition , callSiteBinder , cachedInstanceBinder , compiledLambdaMap , projection , blockBuilderField );
246
256
247
257
// constructor
248
- Parameter blockBuilder = arg ("blockBuilder" , BlockBuilder .class );
249
- Parameter session = arg ("session" , ConnectorSession .class );
250
- Parameter page = arg ("page" , SourcePage .class );
251
- Parameter selectedPositions = arg ("selectedPositions" , SelectedPositions .class );
252
-
253
- MethodDefinition constructorDefinition = classDefinition .declareConstructor (a (PUBLIC ), blockBuilder , session , page , selectedPositions );
258
+ MethodDefinition constructorDefinition = classDefinition .declareConstructor (a (PUBLIC ));
254
259
255
260
BytecodeBlock body = constructorDefinition .getBody ();
256
261
Variable thisVariable = constructorDefinition .getThis ();
257
262
258
263
body .comment ("super();" )
259
264
.append (thisVariable )
260
- .invokeConstructor (Object .class )
261
- .append (thisVariable .setField (blockBuilderField , blockBuilder ))
262
- .append (thisVariable .setField (sessionField , session ))
263
- .append (thisVariable .setField (selectedPositionsField , selectedPositions ));
264
-
265
- for (int channel : getInputChannels (projection )) {
266
- FieldDefinition blockField = classDefinition .declareField (a (PRIVATE , FINAL ), "block_" + channel , Block .class );
267
- body .append (thisVariable .setField (blockField , page .invoke ("getBlock" , Block .class , constantInt (channel ))));
268
- }
265
+ .invokeConstructor (Object .class );
269
266
270
267
cachedInstanceBinder .generateInitializations (thisVariable , body );
271
268
body .ret ();
272
269
273
270
return classDefinition ;
274
271
}
275
272
276
- private static MethodDefinition generateProcessMethod (
273
+ private static void generateProcessMethod (
277
274
ClassDefinition classDefinition ,
278
- FieldDefinition blockBuilder ,
279
- FieldDefinition session ,
280
- FieldDefinition selectedPositions )
275
+ FieldDefinition blockBuilderField ,
276
+ List < FieldDefinition > blockFields ,
277
+ List < Integer > inputChannels )
281
278
{
282
- MethodDefinition method = classDefinition .declareMethod (a (PUBLIC ), "process" , type (Block .class ), ImmutableList .of ());
279
+ Parameter session = arg ("session" , ConnectorSession .class );
280
+ Parameter page = arg ("page" , SourcePage .class );
281
+ Parameter selectedPositions = arg ("selectedPositions" , SelectedPositions .class );
282
+ Parameter blockBuilder = arg ("blockBuilder" , BlockBuilder .class );
283
+
284
+ MethodDefinition method = classDefinition .declareMethod (
285
+ a (PUBLIC ),
286
+ "process" ,
287
+ type (Block .class ),
288
+ ImmutableList .<Parameter >builder ()
289
+ .add (session )
290
+ .add (page )
291
+ .add (selectedPositions )
292
+ .add (blockBuilder )
293
+ .build ());
283
294
284
295
Scope scope = method .getScope ();
285
296
Variable thisVariable = method .getThis ();
286
297
BytecodeBlock body = method .getBody ();
287
298
288
- Variable from = scope .declareVariable ("from" , body , thisVariable .getField (selectedPositions ).invoke ("getOffset" , int .class ));
289
- Variable to = scope .declareVariable ("to" , body , add (thisVariable .getField (selectedPositions ).invoke ("getOffset" , int .class ), thisVariable .getField (selectedPositions ).invoke ("size" , int .class )));
299
+ for (int i = 0 ; i < inputChannels .size (); i ++) {
300
+ int channel = inputChannels .get (i );
301
+ body .append (thisVariable .setField (blockFields .get (i ), page .invoke ("getBlock" , Block .class , constantInt (channel ))));
302
+ }
303
+ body .append (thisVariable .setField (blockBuilderField , blockBuilder ));
304
+
305
+ Variable from = scope .declareVariable ("from" , body , selectedPositions .invoke ("getOffset" , int .class ));
306
+ Variable to = scope .declareVariable ("to" , body , add (selectedPositions .invoke ("getOffset" , int .class ), selectedPositions .invoke ("size" , int .class )));
290
307
Variable positions = scope .declareVariable (int [].class , "positions" );
291
308
Variable index = scope .declareVariable (int .class , "index" );
292
309
293
310
IfStatement ifStatement = new IfStatement ()
294
- .condition (thisVariable . getField ( selectedPositions ) .invoke ("isList" , boolean .class ));
311
+ .condition (selectedPositions .invoke ("isList" , boolean .class ));
295
312
body .append (ifStatement );
296
313
297
314
ifStatement .ifTrue (new BytecodeBlock ()
298
- .append (positions .set (thisVariable . getField ( selectedPositions ) .invoke ("getPositions" , int [].class )))
315
+ .append (positions .set (selectedPositions .invoke ("getPositions" , int [].class )))
299
316
.append (new ForLoop ("positions loop" )
300
317
.initialize (index .set (from ))
301
318
.condition (lessThan (index , to ))
302
319
.update (index .increment ())
303
320
.body (new BytecodeBlock ()
304
- .append (thisVariable .invoke ("evaluate" , void .class , thisVariable . getField ( session ) , positions .getElement (index ))))));
321
+ .append (thisVariable .invoke ("evaluate" , void .class , session , positions .getElement (index ))))));
305
322
306
323
ifStatement .ifFalse (new ForLoop ("range based loop" )
307
324
.initialize (index .set (from ))
308
325
.condition (lessThan (index , to ))
309
326
.update (index .increment ())
310
327
.body (new BytecodeBlock ()
311
- .append (thisVariable .invoke ("evaluate" , void .class , thisVariable . getField ( session ) , index ))));
328
+ .append (thisVariable .invoke ("evaluate" , void .class , session , index ))));
312
329
313
330
body .comment ("return this.blockBuilder.build();" )
314
- .append (thisVariable .getField (blockBuilder ).invoke ("build" , Block .class ))
331
+ .append (thisVariable .getField (blockBuilderField ).invoke ("build" , Block .class ))
315
332
.retObject ();
316
-
317
- return method ;
318
333
}
319
334
320
335
private MethodDefinition generateEvaluateMethod (
0 commit comments