@@ -3218,10 +3218,61 @@ class QAST::CompilerJAST {
3218
3218
)
3219
3219
)
3220
3220
}
3221
-
3221
+
3222
+ my $ ARG_EXP_USE_BINDER := 0 ;
3223
+ my $ ARG_EXP_NO_ARGS := 1 ;
3224
+ my $ ARG_EXP_OBJ := 2 ;
3225
+ method try_setup_args_expectation ($ jmeth , $ block , $ il ) {
3226
+ # Needing an args array forces the binder.
3227
+ if $ * NEED_ARGS_ARRAY {
3228
+ return $ ARG_EXP_USE_BINDER ;
3229
+ }
3230
+
3231
+ # Otherwise, go by arity, then look at particular cases.
3232
+ my int $ num_params := + $ block . params;
3233
+ if $ num_params == 0 {
3234
+ # Easy; just don't add any extra args in.
3235
+ $ jmeth . args_expectation($ ARG_EXP_NO_ARGS );
3236
+ return $ ARG_EXP_NO_ARGS ;
3237
+ }
3238
+ elsif $ num_params == 1 {
3239
+ # Look for one required positional case. Methods with no params
3240
+ # beyond the invocant are always this.
3241
+ my $ param := $ block . params[0 ];
3242
+ if ! $ param . named && ! $ param . slurpy && ! $ param . default {
3243
+ if nqp ::objprimspec($ param . returns ) == 0 {
3244
+ $ jmeth . add_argument(' __arg_0' , $ TYPE_SMO );
3245
+ $ il . append (JAST::Instruction. new ( : op(' aload' ), ' __arg_0' ));
3246
+ if $ param . scope eq ' local' {
3247
+ $ il . append (JAST::Instruction. new ( : op(' astore' ), $ param . name ));
3248
+ }
3249
+ else {
3250
+ $ il . append (JAST::Instruction. new ( : op(' aload' ), ' cf' ));
3251
+ $ il . append (JAST::PushIndex. new ( : value($ block . lexical_idx($ param . name )) ));
3252
+ $ il . append (JAST::Instruction. new ( : op(' invokestatic' ), $ TYPE_OPS ,
3253
+ ' bindlex_o' , $ TYPE_SMO , $ TYPE_SMO , $ TYPE_CF , ' Integer' ));
3254
+ $ il . append ($ POP );
3255
+ }
3256
+ $ jmeth . args_expectation($ ARG_EXP_OBJ );
3257
+ return $ ARG_EXP_OBJ ;
3258
+ }
3259
+ else {
3260
+ return $ ARG_EXP_USE_BINDER ;
3261
+ }
3262
+ }
3263
+ else {
3264
+ return $ ARG_EXP_USE_BINDER ;
3265
+ }
3266
+ }
3267
+ else {
3268
+ return $ ARG_EXP_USE_BINDER ;
3269
+ }
3270
+ }
3271
+
3222
3272
multi method as_jast (QAST ::Block $ node , : $ want ) {
3223
3273
# Do block compilation in a nested block, so we can produce a result based on
3224
3274
# the containing block's stack.
3275
+ my int $ args_expectation ;
3225
3276
unless $ * CODEREFS . know_cuid($ node . cuid) {
3226
3277
# Block gets fresh BlockInfo.
3227
3278
my $ * BINDVAL := 0 ;
@@ -3407,6 +3458,7 @@ class QAST::CompilerJAST {
3407
3458
$ param_idx ++ ;
3408
3459
}
3409
3460
}
3461
+ $ args_expectation := $ * JMETH . args_expectation();
3410
3462
3411
3463
# Add all the locals.
3412
3464
my @ all_locals ;
@@ -3600,8 +3652,7 @@ class QAST::CompilerJAST {
3600
3652
elsif $ blocktype eq ' immediate' || $ blocktype eq ' immediate_static' {
3601
3653
# Can emit a direct JVM level call. First, get self, TC,
3602
3654
# code ref, and callsite descriptor (empty) onto the stack.
3603
- # We know immediate blocks have no args, so simply don't
3604
- # pass any.
3655
+ # May or may not need args array.
3605
3656
my $ il := JAST::InstructionList. new ();
3606
3657
$ * STACK . spill_to_locals($ il );
3607
3658
$ il . append ($ ALOAD_0 );
@@ -3613,13 +3664,25 @@ class QAST::CompilerJAST {
3613
3664
$ il . append (JAST::Instruction. new ( : op(' getstatic' ),
3614
3665
$ TYPE_OPS , ' emptyCallSite' , $ TYPE_CSD ));
3615
3666
$ il . append ($ ACONST_NULL );
3667
+ if $ args_expectation != $ ARG_EXP_NO_ARGS {
3668
+ $ il . append (JAST::Instruction. new ( : op(' getstatic' ),
3669
+ $ TYPE_OPS , ' emptyArgList' , " [$ TYPE_OBJ" ));
3670
+ }
3616
3671
3617
3672
# Emit the virtual call.
3618
- $ il . append (savesite(JAST::Instruction. new ( : op(' invokestatic' ),
3619
- ' L' ~ $ * JCLASS . name ~ ' ;' ,
3620
- $ * CODEREFS . cuid_to_jastmethname($ node . cuid),
3621
- ' V' , $ TYPE_CU , $ TYPE_TC , $ TYPE_CR , $ TYPE_CSD , $ TYPE_RESUME )));
3622
-
3673
+ if $ args_expectation == $ ARG_EXP_NO_ARGS {
3674
+ $ il . append (savesite(JAST::Instruction. new ( : op(' invokestatic' ),
3675
+ ' L' ~ $ * JCLASS . name ~ ' ;' ,
3676
+ $ * CODEREFS . cuid_to_jastmethname($ node . cuid),
3677
+ ' V' , $ TYPE_CU , $ TYPE_TC , $ TYPE_CR , $ TYPE_CSD , $ TYPE_RESUME )));
3678
+ }
3679
+ else {
3680
+ $ il . append (savesite(JAST::Instruction. new ( : op(' invokestatic' ),
3681
+ ' L' ~ $ * JCLASS . name ~ ' ;' ,
3682
+ $ * CODEREFS . cuid_to_jastmethname($ node . cuid),
3683
+ ' V' , $ TYPE_CU , $ TYPE_TC , $ TYPE_CR , $ TYPE_CSD , $ TYPE_RESUME , " [$ TYPE_OBJ" )));
3684
+ }
3685
+
3623
3686
# Load result onto the stack, unless in void context.
3624
3687
if $ * WANT != $ RT_VOID {
3625
3688
$ il . append (JAST::Instruction. new ( : op(' aload' ), ' cf' ));
@@ -3640,56 +3703,6 @@ class QAST::CompilerJAST {
3640
3703
}
3641
3704
}
3642
3705
3643
- my $ ARG_EXP_USE_BINDER := 0 ;
3644
- my $ ARG_EXP_NO_ARGS := 1 ;
3645
- my $ ARG_EXP_OBJ := 2 ;
3646
- method try_setup_args_expectation ($ jmeth , $ block , $ il ) {
3647
- # Needing an args array forces the binder.
3648
- if $ * NEED_ARGS_ARRAY {
3649
- return $ ARG_EXP_USE_BINDER ;
3650
- }
3651
-
3652
- # Otherwise, go by arity, then look at particular cases.
3653
- my int $ num_params := + $ block . params;
3654
- if $ num_params == 0 {
3655
- # Easy; just don't add any extra args in.
3656
- $ jmeth . args_expectation($ ARG_EXP_NO_ARGS );
3657
- return $ ARG_EXP_NO_ARGS ;
3658
- }
3659
- elsif $ num_params == 1 {
3660
- # Look for one required positional case. Methods with no params
3661
- # beyond the invocant are always this.
3662
- my $ param := $ block . params[0 ];
3663
- if ! $ param . named && ! $ param . slurpy && ! $ param . default {
3664
- if nqp ::objprimspec($ param . returns ) == 0 {
3665
- $ jmeth . add_argument(' __arg_0' , $ TYPE_SMO );
3666
- $ il . append (JAST::Instruction. new ( : op(' aload' ), ' __arg_0' ));
3667
- if $ param . scope eq ' local' {
3668
- $ il . append (JAST::Instruction. new ( : op(' astore' ), $ param . name ));
3669
- }
3670
- else {
3671
- $ il . append (JAST::Instruction. new ( : op(' aload' ), ' cf' ));
3672
- $ il . append (JAST::PushIndex. new ( : value($ block . lexical_idx($ param . name )) ));
3673
- $ il . append (JAST::Instruction. new ( : op(' invokestatic' ), $ TYPE_OPS ,
3674
- ' bindlex_o' , $ TYPE_SMO , $ TYPE_SMO , $ TYPE_CF , ' Integer' ));
3675
- $ il . append ($ POP );
3676
- }
3677
- $ jmeth . args_expectation($ ARG_EXP_OBJ );
3678
- return $ ARG_EXP_OBJ ;
3679
- }
3680
- else {
3681
- return $ ARG_EXP_USE_BINDER ;
3682
- }
3683
- }
3684
- else {
3685
- return $ ARG_EXP_USE_BINDER ;
3686
- }
3687
- }
3688
- else {
3689
- return $ ARG_EXP_USE_BINDER ;
3690
- }
3691
- }
3692
-
3693
3706
multi method as_jast (QAST ::Stmts $ node , : $ want ) {
3694
3707
self . compile_all_the_stmts($ node . list, $ node . resultchild, : node($ node . node))
3695
3708
}
0 commit comments