From 05d2aaeeaad7da64cb4ab67f786b43bb3d9bbd9a Mon Sep 17 00:00:00 2001 From: jnthn Date: Fri, 10 May 2013 13:37:10 +0200 Subject: [PATCH] Implement custom_args. Suppresses the generation of parameter handling code. Used by Rakudo as it has its own binder (which now needs porting to the JVM). --- src/vm/jvm/QAST/Compiler.nqp | 189 ++++++++++++++++++----------------- 1 file changed, 96 insertions(+), 93 deletions(-) diff --git a/src/vm/jvm/QAST/Compiler.nqp b/src/vm/jvm/QAST/Compiler.nqp index 9167c2d867..3c1a665123 100644 --- a/src/vm/jvm/QAST/Compiler.nqp +++ b/src/vm/jvm/QAST/Compiler.nqp @@ -2955,112 +2955,115 @@ class QAST::CompilerJAST { 'Void', $TYPE_TC, $TYPE_CR )); $*JMETH.append(JAST::Instruction.new( :op('astore'), 'cf' )); - # Analyze parameters to get count of required/optional and make sure - # all is in order. - my int $pos_required := 0; - my int $pos_optional := 0; - my int $pos_slurpy := 0; - for $block.params { - if $_.named { - # Don't count. - } - elsif $_.slurpy { - $pos_slurpy := 1; - } - elsif $_.default { - if $pos_slurpy { - nqp::die("Optional positionals must come before all slurpy positionals"); + # Unless we have custom args processing... + my $il := JAST::InstructionList.new(); + unless $node.custom_args { + # Analyze parameters to get count of required/optional and make sure + # all is in order. + my int $pos_required := 0; + my int $pos_optional := 0; + my int $pos_slurpy := 0; + for $block.params { + if $_.named { + # Don't count. } - $pos_optional++; - } - else { - if $pos_optional { - nqp::die("Required positionals must come before all optional positionals"); + elsif $_.slurpy { + $pos_slurpy := 1; } - if $pos_slurpy { - nqp::die("Required positionals must come before all slurpy positionals"); + elsif $_.default { + if $pos_slurpy { + nqp::die("Optional positionals must come before all slurpy positionals"); + } + $pos_optional++; + } + else { + if $pos_optional { + nqp::die("Required positionals must come before all optional positionals"); + } + if $pos_slurpy { + nqp::die("Required positionals must come before all slurpy positionals"); + } + $pos_required++; } - $pos_required++; } - } - - # Emit arity check instruction. - my $il := JAST::InstructionList.new(); - $il.append(JAST::Instruction.new( :op('aload'), 'cf' )); - $il.append(JAST::Instruction.new( :op('aload'), 'csd' )); - $il.append(JAST::Instruction.new( :op('aload'), '__args' )); - $il.append(JAST::PushIndex.new( :value($pos_required) )); - $il.append(JAST::PushIndex.new( :value($pos_slurpy ?? -1 !! $pos_required + $pos_optional) )); - $il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS, - "checkarity", $TYPE_CSD, $TYPE_CF, $TYPE_CSD, "[$TYPE_OBJ", 'Integer', 'Integer' )); - $il.append(JAST::Instruction.new( :op('astore'), 'csd' )); - $il.append($ALOAD_1); - $il.append(JAST::Instruction.new( :op('getfield'), $TYPE_TC, 'flatArgs', "[$TYPE_OBJ" )); - $il.append(JAST::Instruction.new( :op('astore'), '__args' )); - - # Emit instructions to load each parameter. - my int $param_idx := 0; - for $block.params { - my $type; - if $_.slurpy { - $type := $RT_OBJ; - $il.append($ALOAD_1); - $il.append(JAST::Instruction.new( :op('aload'), 'cf' )); - $il.append(JAST::Instruction.new( :op('aload'), 'csd' )); - $il.append(JAST::Instruction.new( :op('aload'), '__args' )); - if $_.named { - $il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS, - "namedslurpy", $TYPE_SMO, $TYPE_TC, $TYPE_CF, $TYPE_CSD, "[$TYPE_OBJ" )); + + # Emit arity check instruction. + $il.append(JAST::Instruction.new( :op('aload'), 'cf' )); + $il.append(JAST::Instruction.new( :op('aload'), 'csd' )); + $il.append(JAST::Instruction.new( :op('aload'), '__args' )); + $il.append(JAST::PushIndex.new( :value($pos_required) )); + $il.append(JAST::PushIndex.new( :value($pos_slurpy ?? -1 !! $pos_required + $pos_optional) )); + $il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS, + "checkarity", $TYPE_CSD, $TYPE_CF, $TYPE_CSD, "[$TYPE_OBJ", 'Integer', 'Integer' )); + $il.append(JAST::Instruction.new( :op('astore'), 'csd' )); + $il.append($ALOAD_1); + $il.append(JAST::Instruction.new( :op('getfield'), $TYPE_TC, 'flatArgs', "[$TYPE_OBJ" )); + $il.append(JAST::Instruction.new( :op('astore'), '__args' )); + + # Emit instructions to load each parameter. + my int $param_idx := 0; + for $block.params { + my $type; + if $_.slurpy { + $type := $RT_OBJ; + $il.append($ALOAD_1); + $il.append(JAST::Instruction.new( :op('aload'), 'cf' )); + $il.append(JAST::Instruction.new( :op('aload'), 'csd' )); + $il.append(JAST::Instruction.new( :op('aload'), '__args' )); + if $_.named { + $il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS, + "namedslurpy", $TYPE_SMO, $TYPE_TC, $TYPE_CF, $TYPE_CSD, "[$TYPE_OBJ" )); + } + else { + $il.append(JAST::PushIndex.new( :value($pos_required + $pos_optional) )); + $il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS, + "posslurpy", $TYPE_SMO, $TYPE_TC, $TYPE_CF, $TYPE_CSD, "[$TYPE_OBJ", 'Integer' )); + } } else { - $il.append(JAST::PushIndex.new( :value($pos_required + $pos_optional) )); - $il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS, - "posslurpy", $TYPE_SMO, $TYPE_TC, $TYPE_CF, $TYPE_CSD, "[$TYPE_OBJ", 'Integer' )); + $type := rttype_from_typeobj($_.returns); + my $jt := jtype($type); + my $tc := typechar($type); + my $opt := $_.default ?? "opt_" !! ""; + $il.append(JAST::Instruction.new( :op('aload'), 'cf' )); + $il.append(JAST::Instruction.new( :op('aload'), 'csd' )); + $il.append(JAST::Instruction.new( :op('aload'), '__args' )); + if $_.named { + $il.append(JAST::PushSVal.new( :value($_.named) )); + $il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS, + "namedparam_$opt$tc", $jt, $TYPE_CF, $TYPE_CSD, "[$TYPE_OBJ", $TYPE_STR )); + } + else { + $il.append(JAST::PushIndex.new( :value($param_idx) )); + $il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS, + "posparam_$opt$tc", $jt, $TYPE_CF, $TYPE_CSD, "[$TYPE_OBJ", 'Integer' )); + } + if $opt { + my $lbl := JAST::Label.new( :name(self.unique("opt_param")) ); + $il.append($ALOAD_1); + $il.append(JAST::Instruction.new( :op('getfield'), $TYPE_TC, + 'lastParameterExisted', "Integer" )); + $il.append(JAST::Instruction.new( :op('ifne'), $lbl )); + $il.append(pop_ins($type)); + my $default := self.as_jast($_.default, :want($type)); + $il.append($default.jast); + $*STACK.obtain($il, $default); + $il.append($lbl); + } } - } - else { - $type := rttype_from_typeobj($_.returns); - my $jt := jtype($type); - my $tc := typechar($type); - my $opt := $_.default ?? "opt_" !! ""; - $il.append(JAST::Instruction.new( :op('aload'), 'cf' )); - $il.append(JAST::Instruction.new( :op('aload'), 'csd' )); - $il.append(JAST::Instruction.new( :op('aload'), '__args' )); - if $_.named { - $il.append(JAST::PushSVal.new( :value($_.named) )); - $il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS, - "namedparam_$opt$tc", $jt, $TYPE_CF, $TYPE_CSD, "[$TYPE_OBJ", $TYPE_STR )); + if $_.scope eq 'local' { + $il.append(JAST::Instruction.new( :op(store_ins($type)), $_.name )); } else { - $il.append(JAST::PushIndex.new( :value($param_idx) )); + my $jtype := jtype($type); + $il.append(JAST::Instruction.new( :op('aload'), 'cf' )); + $il.append(JAST::PushIndex.new( :value($block.lexical_idx($_.name)) )); $il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS, - "posparam_$opt$tc", $jt, $TYPE_CF, $TYPE_CSD, "[$TYPE_OBJ", 'Integer' )); - } - if $opt { - my $lbl := JAST::Label.new( :name(self.unique("opt_param")) ); - $il.append($ALOAD_1); - $il.append(JAST::Instruction.new( :op('getfield'), $TYPE_TC, - 'lastParameterExisted', "Integer" )); - $il.append(JAST::Instruction.new( :op('ifne'), $lbl )); + 'bindlex_' ~ typechar($type), $jtype, $jtype, $TYPE_CF, 'Integer' )); $il.append(pop_ins($type)); - my $default := self.as_jast($_.default, :want($type)); - $il.append($default.jast); - $*STACK.obtain($il, $default); - $il.append($lbl); } + $param_idx++; } - if $_.scope eq 'local' { - $il.append(JAST::Instruction.new( :op(store_ins($type)), $_.name )); - } - else { - my $jtype := jtype($type); - $il.append(JAST::Instruction.new( :op('aload'), 'cf' )); - $il.append(JAST::PushIndex.new( :value($block.lexical_idx($_.name)) )); - $il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS, - 'bindlex_' ~ typechar($type), $jtype, $jtype, $TYPE_CF, 'Integer' )); - $il.append(pop_ins($type)); - } - $param_idx++; } # Add all the locals.