5
# Instruction constants for argument-less ops.
6
my $ACONST_NULL := JAST::Instruction.new( :op('aconst_null') );
7
my $ALOAD_0 := JAST::Instruction.new( :op('aload_0') );
8
my $ALOAD_1 := JAST::Instruction.new( :op('aload_1') );
9
my $IASTORE := JAST::Instruction.new( :op('iastore') );
10
my $LASTORE := JAST::Instruction.new( :op('lastore') );
11
my $AALOAD := JAST::Instruction.new( :op('aaload') );
12
my $AASTORE := JAST::Instruction.new( :op('aastore') );
13
my $BASTORE := JAST::Instruction.new( :op('bastore') );
14
my $POP := JAST::Instruction.new( :op('pop') );
15
my $POP2 := JAST::Instruction.new( :op('pop2') );
16
my $DUP := JAST::Instruction.new( :op('dup') );
17
my $DUP_X2 := JAST::Instruction.new( :op('dup_x2') );
18
my $DUP2 := JAST::Instruction.new( :op('dup2') );
19
my $SWAP := JAST::Instruction.new( :op('swap') );
20
my $IADD := JAST::Instruction.new( :op('iadd') );
21
my $LADD := JAST::Instruction.new( :op('ladd') );
22
my $LSUB := JAST::Instruction.new( :op('lsub') );
23
my $IAND := JAST::Instruction.new( :op('iand') );
24
my $I2L := JAST::Instruction.new( :op('i2l') );
25
my $I2B := JAST::Instruction.new( :op('i2b') );
26
my $L2I := JAST::Instruction.new( :op('l2i') );
27
my $L2D := JAST::Instruction.new( :op('l2d') );
28
my $D2L := JAST::Instruction.new( :op('d2l') );
29
my $LCMP := JAST::Instruction.new( :op('lcmp') );
30
my $DCMPL := JAST::Instruction.new( :op('dcmpl') );
31
my $RETURN := JAST::Instruction.new( :op('return') );
32
my $ARETURN := JAST::Instruction.new( :op('areturn') );
33
my $IRETURN := JAST::Instruction.new( :op('ireturn') );
34
my $ATHROW := JAST::Instruction.new( :op('athrow') );
36
# Common constant loads.
37
my $IVAL_ZERO := JAST::PushIVal.new( :value(0) );
38
my $IVAL_ONE := JAST::PushIVal.new( :value(1) );
39
my $IVAL_MINUSONE := JAST::PushIVal.new( :value(-1) );
40
my $NVAL_ZERO := JAST::PushNVal.new( :value(0.0) );
42
# Some common types we'll need.
43
my $TYPE_TC := 'Lorg/perl6/nqp/runtime/ThreadContext;';
44
my $TYPE_CU := 'Lorg/perl6/nqp/runtime/CompilationUnit;';
45
my $TYPE_CR := 'Lorg/perl6/nqp/runtime/CodeRef;';
46
my $TYPE_CF := 'Lorg/perl6/nqp/runtime/CallFrame;';
47
my $TYPE_OPS := 'Lorg/perl6/nqp/runtime/Ops;';
48
my $TYPE_NATIVE_OPS := 'Lorg/perl6/nqp/runtime/NativeCallOps;';
49
my $TYPE_CSD := 'Lorg/perl6/nqp/runtime/CallSiteDescriptor;';
50
my $TYPE_SMO := 'Lorg/perl6/nqp/sixmodel/SixModelObject;';
51
my $TYPE_STR := 'Ljava/lang/String;';
52
my $TYPE_OBJ := 'Ljava/lang/Object;';
53
my $TYPE_MATH := 'Ljava/lang/Math;';
54
my $TYPE_MH := 'Ljava/lang/invoke/MethodHandle;';
55
my $TYPE_MT := 'Ljava/lang/invoke/MethodType;';
56
my $TYPE_MHS := 'Ljava/lang/invoke/MethodHandles;';
57
my $TYPE_MHL := 'Ljava/lang/invoke/MethodHandles$Lookup;';
58
my $TYPE_CLASS := 'Ljava/lang/Class;';
59
my $TYPE_LONG := 'Ljava/lang/Long;';
60
my $TYPE_DOUBLE := 'Ljava/lang/Double;';
61
my $TYPE_EH := 'Lorg/perl6/nqp/runtime/ExceptionHandling;';
62
my $TYPE_EX_LEX := 'Lorg/perl6/nqp/runtime/LexoticException;';
63
my $TYPE_EX_UNWIND := 'Lorg/perl6/nqp/runtime/UnwindException;';
64
my $TYPE_EX_CONT := 'Lorg/perl6/nqp/runtime/ControlException;';
65
my $TYPE_EX_RT := 'Ljava/lang/RuntimeException;';
66
my $TYPE_EX_SAVE := 'Lorg/perl6/nqp/runtime/SaveStackException;';
67
my $TYPE_THROWABLE := 'Ljava/lang/Throwable;';
68
my $TYPE_RESUME := 'Lorg/perl6/nqp/runtime/ResumeStatus$Frame;';
70
# Exception handler categories.
71
my $EX_CAT_CATCH := 1;
74
my $EX_CAT_LAST := 16;
75
my $EX_CAT_TAKE := 32;
76
my $EX_CAT_WARN := 64;
77
my $EX_CAT_SUCCEED := 128;
78
my $EX_CAT_PROCEED := 256;
79
my $EX_CAT_CONTROL := $EX_CAT_NEXT +| $EX_CAT_REDO +| $EX_CAT_LAST +|
80
$EX_CAT_TAKE +| $EX_CAT_WARN +|
81
$EX_CAT_SUCCEED +| $EX_CAT_PROCEED;
83
# Exception handler kinds.
84
my $EX_UNWIND_SIMPLE := 0;
85
my $EX_UNWIND_OBJECT := 1;
88
# Represents the result of turning some QAST into JAST. That includes any
89
# instructions, but also some metadata that goes with them.
96
has $!jast; # The JAST
97
has int $!type; # Result type (obj/int/num/str)
98
has str $!local; # Local where the result is; if empty, it's on the stack
100
method jast() { $!jast }
101
method type() { $!type }
102
method local() { $!local }
104
method set_local($local) { $!local := $local }
106
sub result($jast, int $type) {
107
my $r := nqp::create(Result);
108
nqp::bindattr($r, Result, '$!jast', $jast);
109
nqp::bindattr_i($r, Result, '$!type', $type);
110
nqp::bindattr_s($r, Result, '$!local', '');
114
sub result_from_cf($il, $rtype) {
115
if $*WANT != $RT_VOID {
116
$il.append(JAST::Instruction.new( :op('aload'), 'cf' ));
117
$il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
118
'result_' ~ typechar($rtype), jtype($rtype), $TYPE_CF ));
122
result($il, $RT_VOID)
125
my @jtypes := [$TYPE_SMO, 'Long', 'Double', $TYPE_STR];
126
sub jtype($type_idx) { @jtypes[$type_idx] }
127
my @rttypes := [$RT_OBJ, $RT_INT, $RT_NUM, $RT_STR];
128
sub rttype_from_typeobj($typeobj) {
129
@rttypes[nqp::objprimspec($typeobj)]
131
my @typeobjs := [NQPMu, int, num, str];
132
sub typeobj_from_rttype($rttype) {
135
my @typechars := ['o', 'i', 'n', 's'];
136
sub typechar($type_idx) { @typechars[$type_idx] }
138
# Various typed instructions.
139
my @store_ins := ['astore', 'lstore', 'dstore', 'astore'];
140
sub store_ins($type) {
143
my @load_ins := ['aload', 'lload', 'dload', 'aload'];
144
sub load_ins($type) {
166
# Mapping of QAST::Want type identifiers to $RT_*.
167
my %WANTMAP := nqp::hash(
169
'I', $RT_INT, 'i', $RT_INT,
170
'N', $RT_NUM, 'n', $RT_NUM,
171
'S', $RT_STR, 's', $RT_STR,
172
'P', $RT_OBJ, 'p', $RT_OBJ
175
# Utility for getting a fresh temporary by type.
176
my @fresh_methods := ["fresh_o", "fresh_i", "fresh_n", "fresh_s"];
178
my $meth := @fresh_methods[$type];
182
my $meth := @fresh_methods[$type];
193
my @arg_types := [$ARG_OBJ, $ARG_INT, $ARG_NUM, $ARG_STR];
194
sub arg_type($t) { @arg_types[$t] }
196
class QAST::OperationsJAST {
197
# Maps operations to code that will handle them. Hash of code.
200
# Maps HLL-specific operations to code that will handle them.
201
# Hash of hash of code.
204
# Mapping of how to box/unbox by HLL.
208
# What we know about inlinability.
209
my %core_inlinability;
210
my %hll_inlinability;
212
# What we know about op native results types.
213
my %core_result_type;
216
# Compiles an operation.
217
method compile_op($qastcomp, $hll, $op) {
220
if %hll_ops{$hll} && %hll_ops{$hll}{$name} -> $mapper {
221
return $mapper($qastcomp, $op);
224
if %core_ops{$name} -> $mapper {
225
return $mapper($qastcomp, $op);
227
nqp::die("No registered operation handler for '$name'");
230
# Adds a core op handler.
231
method add_core_op($op, $handler, :$inlinable = 1) {
232
%core_ops{$op} := $handler;
233
self.set_core_op_inlinability($op, $inlinable);
236
# Adds a HLL op handler.
237
method add_hll_op($hll, $op, $handler, :$inlinable = 1) {
238
%hll_ops{$hll} := {} unless nqp::existskey(%hll_ops, $hll);
239
%hll_ops{$hll}{$op} := $handler;
240
self.set_hll_op_inlinability($hll, $op, $inlinable);
243
# Sets op inlinability at a core level.
244
method set_core_op_inlinability($op, $inlinable) {
245
%core_inlinability{$op} := $inlinable;
248
# Sets op inlinability at a HLL level. (Can override at HLL level whether
249
# or not the HLL overrides the op itself.)
250
method set_hll_op_inlinability($hll, $op, $inlinable) {
251
%hll_inlinability{$hll} := {} unless nqp::existskey(%hll_inlinability, $hll);
252
%hll_inlinability{$hll}{$op} := $inlinable;
255
# Checks if an op is considered inlinable.
256
method is_inlinable($hll, $op) {
257
if nqp::existskey(%hll_inlinability, $hll) {
258
if nqp::existskey(%hll_inlinability{$hll}, $op) {
259
return %hll_inlinability{$hll}{$op};
262
return %core_inlinability{$op} // 0;
265
# Adds a core nqp:: op provided directly by a JVM op.
266
method map_jvm_core_op($op, $jvm_op, @stack_in, $stack_out) {
267
my $ins := JAST::Instruction.new( :op($jvm_op) );
268
self.add_core_op($op, op_mapper($op, $ins, @stack_in, $stack_out));
269
self.set_core_op_result_type($op, $stack_out);
272
# Adds a HLL nqp:: op provided directly by a JVM op.
273
method map_jvm_hll_op($hll, $op, $jvm_op, @stack_in, $stack_out) {
274
my $ins := JAST::Instruction.new( :op($jvm_op) );
275
self.add_hll_op($hll, $op, op_mapper($op, $ins, @stack_in, $stack_out));
276
self.set_hll_op_result_type($hll, $op, $stack_out);
279
# Adds a core nqp:: op provided by a static method in the
281
method map_classlib_core_op($op, $class, $method, @stack_in, $stack_out, :$tc, :$cont, :$inlinable = 1) {
284
nqp::push(@jtypes_in, jtype($_));
286
nqp::push(@jtypes_in, $TYPE_TC) if $tc;
287
my $ins := JAST::Instruction.new( :op('invokestatic'),
288
$class, $method, $cont ?? 'Void' !! jtype($stack_out), |@jtypes_in );
289
self.add_core_op($op, op_mapper($op, $ins, @stack_in, $stack_out, :$tc, :$cont));
290
self.set_core_op_inlinability($op, $inlinable);
291
self.set_core_op_result_type($op, $stack_out);
294
# Adds a core nqp:: op provided by a static method in the
296
method map_classlib_hll_op($hll, $op, $class, $method, @stack_in, $stack_out, :$tc, :$cont, :$inlinable = 1) {
299
nqp::push(@jtypes_in, jtype($_));
301
nqp::push(@jtypes_in, $TYPE_TC) if $tc;
302
my $ins := JAST::Instruction.new( :op('invokestatic'),
303
$class, $method, $cont ?? 'Void' !! jtype($stack_out), |@jtypes_in );
304
self.add_hll_op($hll, $op, op_mapper($op, $ins, @stack_in, $stack_out, :$tc, :$cont));
305
self.set_core_op_inlinability($op, $inlinable);
306
self.set_hll_op_result_type($hll, $op, $stack_out);
309
# Generates an operation mapper. Covers a range of operations,
310
# including those provided by calling a method and those that are
311
# just JVM op invocations.
312
sub op_mapper($op, $instruction, @stack_in, $stack_out, :$tc = 0, :$cont = 0) {
313
my int $expected_args := +@stack_in;
314
return -> $qastcomp, $node {
315
if +@($node) != $expected_args {
316
nqp::die("Operation '$op' requires $expected_args operands");
320
my $il := JAST::InstructionList.new();
323
while $i < $expected_args {
324
my $type := @stack_in[$i];
325
my $operand := $node[$i];
326
my $operand_res := $qastcomp.as_jast($node[$i], :want($type));
327
$il.append($operand_res.jast);
329
nqp::push(@arg_res, $operand_res);
333
$*STACK.spill_to_locals($il) if $cont;
334
$*STACK.obtain($il, |@arg_res) if @arg_res;
336
$il.append($ALOAD_1);
339
$il.append(savesite($instruction));
340
result_from_cf($il, $stack_out);
342
$il.append($instruction);
343
result($il, $stack_out)
348
# Sets op native result type at a core level.
349
method set_core_op_result_type($op, $type) {
350
if $type == $RT_INT {
351
%core_result_type{$op} := int;
353
elsif $type == $RT_NUM {
354
%core_result_type{$op} := num;
356
elsif $type == $RT_STR {
357
%core_result_type{$op} := str;
361
# Sets op inlinability at a HLL level. (Can override at HLL level whether
362
# or not the HLL overrides the op itself.)
363
method set_hll_op_result_type($hll, $op, $type) {
364
%hll_result_type{$hll} := {} unless nqp::existskey(%hll_result_type, $hll);
365
if $type == $RT_INT {
366
%hll_result_type{$hll}{$op} := int;
368
elsif $type == $RT_NUM {
369
%hll_result_type{$hll}{$op} := num;
371
elsif $type == $RT_STR {
372
%hll_result_type{$hll}{$op} := str;
376
# Sets returns on an op node if we it has a native result type.
377
method attach_result_type($hll, $node) {
379
if nqp::existskey(%hll_result_type, $hll) {
380
if nqp::existskey(%hll_result_type{$hll}, $op) {
381
$node.returns(%hll_result_type{$hll}{$op});
385
if nqp::existskey(%core_result_type, $op) {
386
$node.returns(%core_result_type{$op});
390
# Adds a HLL box handler.
391
method add_hll_box($hll, $type, $handler) {
392
unless $type == $RT_INT || $type == $RT_NUM || $type == $RT_STR {
393
nqp::die("Unknown box type '$type'");
395
%hll_box{$hll} := {} unless nqp::existskey(%hll_box, $hll);
396
%hll_box{$hll}{$type} := $handler;
399
# Adds a HLL unbox handler.
400
method add_hll_unbox($hll, $type, $handler) {
401
unless $type == $RT_INT || $type == $RT_NUM || $type == $RT_STR {
402
nqp::die("Unknown unbox type '$type'");
404
%hll_unbox{$hll} := {} unless nqp::existskey(%hll_unbox, $hll);
405
%hll_unbox{$hll}{$type} := $handler;
408
# Generates instructions to box what's currently on the stack top.
409
method box($qastcomp, $hll, $type) {
410
(%hll_box{$hll} // %hll_box{''}){$type}($qastcomp)
413
# Generates instructions to unbox what's currently on the stack top.
414
method unbox($qastcomp, $hll, $type) {
415
(%hll_unbox{$hll} // %hll_unbox{''}){$type}($qastcomp)
418
# Builds a result; helper method for extensions to the ops from outside
420
method result($jast, int $type) {
426
my $index := $*BLOCK.alloc_save_site;
427
my $reenter := JAST::Label.new( :name( "reenter_"~$index ) );
428
my $saver := JAST::Label.new( :name( "SAVER" ) );
429
my $try := JAST::InstructionList.new();
430
my $catch := JAST::InstructionList.new();
433
$try.append($reenter);
435
$catch.append(JAST::PushIndex.new( :value($index) ));
436
$catch.append(JAST::Instruction.new( :op('goto'), $saver ));
438
JAST::TryCatch.new( :try($try), :catch($catch), :type($TYPE_EX_SAVE) );
442
QAST::OperationsJAST.add_core_op('chain', -> $qastcomp, $op {
443
# First, we build up the list of nodes in the chain
446
while nqp::istype($cpast, QAST::Op) && $cpast.op eq 'chain' {
447
nqp::push(@clist, $cpast);
451
my $il := JAST::InstructionList.new();
452
my $result := $*TA.fresh_o();
453
my $endlabel := JAST::Label.new(:name($qastcomp.unique('chain_end_')));
455
$cpast := nqp::pop(@clist);
456
my $apast := $cpast[0];
457
my $ares := $qastcomp.as_jast($apast, :want($RT_OBJ));
458
my $atmp := $*TA.fresh_o();
459
$il.append($ares.jast);
460
$*STACK.obtain($il, $ares);
461
$il.append(JAST::Instruction.new( :op('astore'), $atmp ));
465
my $bpast := $cpast[1];
466
my $bres := $qastcomp.as_jast($bpast, :want($RT_OBJ));
467
my $btmp := $*TA.fresh_o();
468
$il.append($bres.jast);
469
$*STACK.obtain($il, $bres);
470
$il.append(JAST::Instruction.new( :op('astore'), $btmp ));
472
$*STACK.spill_to_locals($il);
473
my $cs_idx := $*CODEREFS.get_callsite_idx([$ARG_OBJ, $ARG_OBJ], []);
474
$il.append(JAST::PushSVal.new( :value($cpast.name) )),
475
$il.append(JAST::PushIndex.new( :value($cs_idx) )),
476
$il.append($ALOAD_1);
477
$il.append(JAST::Instruction.new( :op('aload'), $atmp ));
478
$il.append(JAST::Instruction.new( :op('aload'), $btmp ));
479
$il.append(savesite(JAST::InvokeDynamic.new(
480
'subcall_noa', 'V', [$TYPE_STR, 'I', $TYPE_TC, $TYPE_SMO, $TYPE_SMO],
481
'org/perl6/nqp/runtime/IndyBootstrap', 'subcall_noa',
483
$il.append(JAST::Instruction.new( :op('aload'), 'cf' ));
484
$il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
485
'result_o', $TYPE_SMO, $TYPE_CF ));
486
$il.append(JAST::Instruction.new( :op('astore'), $result ));
489
$il.append(JAST::Instruction.new( :op('aload'), $result ));
490
$il.append($ALOAD_1);
491
$il.append(JAST::Instruction.new( :op('invokestatic'),
492
$TYPE_OPS, 'istrue', 'Long', $TYPE_SMO, $TYPE_TC ));
493
$il.append($IVAL_ZERO);
495
$il.append(JAST::Instruction.new( :op('ifeq'), $endlabel ));
496
$cpast := nqp::pop(@clist);
504
$il.append($endlabel);
505
$il.append(JAST::Instruction.new( :op('aload'), $result ));
509
# Set of sequential statements
510
QAST::OperationsJAST.add_core_op('stmts', -> $qastcomp, $op {
511
$qastcomp.as_jast(QAST::Stmts.new( |@($op) ))
515
QAST::OperationsJAST.add_core_op('list', -> $qastcomp, $op {
516
# Just desugar to create the empty list.
517
my $arr := $qastcomp.as_jast(QAST::Op.new(
519
QAST::Op.new( :op('hlllist') )
522
# Put list into a temporary so we can push to it.
523
my $il := JAST::InstructionList.new();
524
$il.append($arr.jast);
525
$*STACK.obtain($il, $arr);
526
my $list_tmp := $*TA.fresh_o();
527
$il.append(JAST::Instruction.new( :op('astore'), $list_tmp ));
529
# Push things to the list.
531
my $item := $qastcomp.as_jast($_, :want($RT_OBJ));
532
$il.append($item.jast);
533
$*STACK.obtain($il, $item);
534
$il.append(JAST::Instruction.new( :op('aload'), $list_tmp ));
536
$il.append($ALOAD_1);
537
$il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS, 'push',
538
$TYPE_SMO, $TYPE_SMO, $TYPE_SMO, $TYPE_TC ));
542
$il.append(JAST::Instruction.new( :op('aload'), $list_tmp ));
543
result($il, $RT_OBJ);
549
QAST::OperationsJAST.add_core_op('list_i', -> $qastcomp, $op {
550
# Just desugar to create the empty list.
551
my $arr := $qastcomp.as_jast(QAST::Op.new(
553
QAST::Op.new( :op('bootintarray') )
556
# Put list into a temporary so we can push to it.
557
my $il := JAST::InstructionList.new();
558
$il.append($arr.jast);
559
$*STACK.obtain($il, $arr);
560
my $list_tmp := $*TA.fresh_o();
561
$il.append(JAST::Instruction.new( :op('astore'), $list_tmp ));
563
# Push things to the list.
565
my $item := $qastcomp.as_jast($_, :want($RT_INT));
566
$il.append($item.jast);
567
$*STACK.obtain($il, $item);
568
$il.append(JAST::Instruction.new( :op('aload'), $list_tmp ));
571
$il.append($ALOAD_1);
572
$il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS, 'push_i',
573
'Long', $TYPE_SMO, 'Long', $TYPE_TC ));
577
$il.append(JAST::Instruction.new( :op('aload'), $list_tmp ));
578
result($il, $RT_OBJ);
584
QAST::OperationsJAST.add_core_op('list_n', -> $qastcomp, $op {
585
# Just desugar to create the empty list.
586
my $arr := $qastcomp.as_jast(QAST::Op.new(
588
QAST::Op.new( :op('bootnumarray') )
591
# Put list into a temporary so we can push to it.
592
my $il := JAST::InstructionList.new();
593
$il.append($arr.jast);
594
$*STACK.obtain($il, $arr);
595
my $list_tmp := $*TA.fresh_o();
596
$il.append(JAST::Instruction.new( :op('astore'), $list_tmp ));
598
# Push things to the list.
600
my $item := $qastcomp.as_jast($_, :want($RT_NUM));
601
$il.append($item.jast);
602
$*STACK.obtain($il, $item);
603
$il.append(JAST::Instruction.new( :op('aload'), $list_tmp ));
606
$il.append($ALOAD_1);
607
$il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS, 'push_n',
608
'Double', $TYPE_SMO, 'Double', $TYPE_TC ));
612
$il.append(JAST::Instruction.new( :op('aload'), $list_tmp ));
613
result($il, $RT_OBJ);
619
QAST::OperationsJAST.add_core_op('list_s', -> $qastcomp, $op {
620
# Just desugar to create the empty list.
621
my $arr := $qastcomp.as_jast(QAST::Op.new(
623
QAST::Op.new( :op('bootstrarray') )
626
# Put list into a temporary so we can push to it.
627
my $il := JAST::InstructionList.new();
628
$il.append($arr.jast);
629
$*STACK.obtain($il, $arr);
630
my $list_tmp := $*TA.fresh_o();
631
$il.append(JAST::Instruction.new( :op('astore'), $list_tmp ));
633
# Push things to the list.
635
my $item := $qastcomp.as_jast($_, :want($RT_STR));
636
$il.append($item.jast);
637
$*STACK.obtain($il, $item);
638
$il.append(JAST::Instruction.new( :op('aload'), $list_tmp ));
640
$il.append($ALOAD_1);
641
$il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS, 'push_s',
642
$TYPE_STR, $TYPE_SMO, $TYPE_STR, $TYPE_TC ));
646
$il.append(JAST::Instruction.new( :op('aload'), $list_tmp ));
647
result($il, $RT_OBJ);
653
QAST::OperationsJAST.add_core_op('qlist', -> $qastcomp, $op {
654
$qastcomp.as_jast(QAST::Op.new( :op('list'), |@($op) ))
656
QAST::OperationsJAST.add_core_op('hash', -> $qastcomp, $op {
657
# Just desugar to create the empty hash.
658
my $hash := $qastcomp.as_jast(QAST::Op.new(
660
QAST::Op.new( :op('hllhash') )
663
# Put hash into a temporary so we can add the items to it.
664
my $il := JAST::InstructionList.new();
665
$il.append($hash.jast);
666
$*STACK.obtain($il, $hash);
667
my $hash_tmp := $*TA.fresh_o();
668
$il.append(JAST::Instruction.new( :op('astore'), $hash_tmp ));
670
my $key_tmp := $*TA.fresh_s();
671
my $val_tmp := $*TA.fresh_o();
672
for $op.list -> $key, $val {
673
my $key_res := $qastcomp.as_jast($key, :want($RT_STR));
674
$il.append($key_res.jast);
675
$*STACK.obtain($il, $key_res);
676
$il.append(JAST::Instruction.new( :op('astore'), $key_tmp ));
678
my $val_res := $qastcomp.as_jast($val, :want($RT_OBJ));
679
$il.append($val_res.jast);
680
$*STACK.obtain($il, $val_res);
681
$il.append(JAST::Instruction.new( :op('astore'), $val_tmp ));
683
$il.append(JAST::Instruction.new( :op('aload'), $hash_tmp ));
684
$il.append(JAST::Instruction.new( :op('aload'), $key_tmp ));
685
$il.append(JAST::Instruction.new( :op('aload'), $val_tmp ));
686
$il.append($ALOAD_1);
687
$il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS, 'bindkey',
688
$TYPE_SMO, $TYPE_SMO, $TYPE_STR, $TYPE_SMO, $TYPE_TC ));
692
$il.append(JAST::Instruction.new( :op('aload'), $hash_tmp ));
693
result($il, $RT_OBJ);
701
sub boolify_instructions($il, $cond_type) {
702
if $cond_type == $RT_INT {
703
$il.append($IVAL_ZERO);
706
elsif $cond_type == $RT_NUM {
707
$il.append($NVAL_ZERO);
710
elsif $cond_type == $RT_STR {
711
$il.append(JAST::Instruction.new( :op('invokestatic'),
712
$TYPE_OPS, 'istrue_s', 'Long', $TYPE_STR ));
713
$il.append($IVAL_ZERO);
717
$il.append($ALOAD_1);
718
$il.append(JAST::Instruction.new( :op('invokestatic'),
719
$TYPE_OPS, 'istrue', 'Long', $TYPE_SMO, $TYPE_TC ));
720
$il.append($IVAL_ZERO);
724
for <if unless> -> $op_name {
725
QAST::OperationsJAST.add_core_op($op_name, -> $qastcomp, $op {
726
# Check operand count.
727
my $operands := +$op.list;
728
nqp::die("Operation '$op_name' needs either 2 or 3 operands")
729
if $operands < 2 || $operands > 3;
731
# See if any immediate block wants to be passed the condition.
732
my $im_then := nqp::istype($op[1], QAST::Block) &&
733
($op[1].blocktype eq 'immediate' || $op[1].blocktype eq 'immediate_static') &&
735
my $im_else := $operands == 3 &&
736
nqp::istype($op[2], QAST::Block) &&
737
($op[2].blocktype eq 'immediate' || $op[2].blocktype eq 'immediate_static') &&
740
# Create labels and a place to store the overall result.
741
my $if_id := $qastcomp.unique($op_name);
742
my $else_lbl := JAST::Label.new(:name($if_id ~ '_else'));
743
my $end_lbl := JAST::Label.new(:name($if_id ~ '_end'));
747
# Compile conditional expression and saving of it if we need to.
748
my $il := JAST::InstructionList.new();
749
$*STACK.spill_to_locals($il);
750
my $cond := $qastcomp.as_jast($op[0]);
751
$il.append($cond.jast);
752
$*STACK.obtain($il, $cond);
753
if $im_then || $im_else {
754
my $im_local := QAST::Node.unique('__IM_');
755
$*BLOCK.add_local(QAST::Var.new(
757
:returns(typeobj_from_rttype($cond.type))
760
$op[1].blocktype('declaration');
761
$op[1] := QAST::Op.new(
763
QAST::Var.new( :name($im_local), :scope('local') )
767
$op[2].blocktype('declaration');
768
$op[2] := QAST::Op.new(
770
QAST::Var.new( :name($im_local), :scope('local') )
773
$il.append(dup_ins($cond.type));
774
$il.append(JAST::Instruction.new( :op(store_ins($cond.type)), $im_local ));
776
unless $*WANT == $RT_VOID || $operands == 3 {
777
$il.append(dup_ins($cond.type));
778
$res_type := $cond.type;
779
$res_temp := fresh($res_type);
780
$il.append(JAST::Instruction.new( :op(store_ins($res_type)), $res_temp ));
784
boolify_instructions($il, $cond.type);
785
$il.append(JAST::Instruction.new($else_lbl,
786
:op($op_name eq 'if' ?? 'ifeq' !! 'ifne')));
788
# Compile the "then".
789
my $then := $qastcomp.as_jast($op[1]);
790
$il.append($then.jast);
792
# What comes next depends on whether there's an else.
794
# A little care needed here; we make sure we obtain the
795
# result of the then, but before we actually use it we
796
# compile the else branch so we can see what result type
797
# is needed. It's fine as we don't append the else JAST
799
$*STACK.obtain($il, $then);
800
my $else := $qastcomp.as_jast($op[2]);
801
if $*WANT == $RT_VOID {
802
$il.append(pop_ins($then.type));
805
$res_type := $then.type == $else.type ?? $then.type !! $RT_OBJ;
806
$res_temp := fresh($res_type);
807
$il.append($qastcomp.coercion($then, $res_type));
808
$il.append(JAST::Instruction.new( :op(store_ins($res_type)), $res_temp ));
811
# Then branch needs to go to the loop end.
812
$il.append(JAST::Instruction.new( :op('goto'), $end_lbl ));
814
# Emit the else branch.
815
$il.append($else_lbl);
816
$il.append($else.jast);
817
$*STACK.obtain($il, $else);
818
if $*WANT == $RT_VOID {
819
$il.append(pop_ins($else.type));
822
$il.append($qastcomp.coercion($else, $res_type));
823
$il.append(JAST::Instruction.new( :op(store_ins($res_type)), $res_temp ));
827
# If void context, just pop the result and we're done.
828
# Otherwise, need to find a common type between it and
830
$*STACK.obtain($il, $then);
831
if $*WANT == $RT_VOID {
832
$il.append(pop_ins($then.type));
833
$il.append($else_lbl);
835
elsif $then.type == $res_type {
836
# Already have a common type.
837
$il.append(JAST::Instruction.new( :op(store_ins($res_type)), $res_temp ));
838
$il.append($else_lbl);
841
# Need a new result, and to coerce both condition and
842
# result of then to it as needed (basically, add an else
843
# that handles coercion).
844
my $old_res_type := $res_type;
845
my $old_res_temp := $res_temp;
846
$res_type := $RT_OBJ;
847
$res_temp := fresh($res_type);
848
$il.append($qastcomp.coercion($then, $res_type));
849
$il.append(JAST::Instruction.new( :op(store_ins($res_type)), $res_temp ));
850
$il.append(JAST::Instruction.new( :op('goto'), $end_lbl ));
851
$il.append($else_lbl);
852
$il.append(JAST::Instruction.new( :op(load_ins($old_res_type)), $old_res_temp ));
853
$il.append($qastcomp.coercion($cond, $res_type));
854
$il.append(JAST::Instruction.new( :op(store_ins($res_type)), $res_temp ));
858
# Add final label and load result if neded.
859
$il.append($end_lbl);
861
$il.append(JAST::Instruction.new( :op(load_ins($res_type)), $res_temp ));
862
result($il, $res_type);
865
result($il, $RT_VOID);
870
QAST::OperationsJAST.add_core_op('defor', -> $qastcomp, $op {
872
nqp::die("Operation 'defor' needs 2 operands");
874
my $tmp := $op.unique('defined');
875
$qastcomp.as_jast(QAST::Stmts.new(
878
QAST::Var.new( :name($tmp), :scope('local'), :decl('var') ),
885
QAST::Var.new( :name($tmp), :scope('local') )
887
QAST::Var.new( :name($tmp), :scope('local') ),
892
QAST::OperationsJAST.add_core_op('xor', -> $qastcomp, $op {
893
my $prefix := $op.unique('xor');
894
my $falselabel := JAST::Label.new(:name($prefix ~ '_false'));
895
my $endlabel := JAST::Label.new(:name($prefix ~ '_end'));
900
if $_.named eq 'false' {
904
nqp::push(@childlist, $_);
908
my $r := $*TA.fresh_o();
909
my $b := $*TA.fresh_o();
910
my $i := $*TA.fresh_i();
911
my $t := $*TA.fresh_i();
912
my $u := $*TA.fresh_i();
914
my $il := JAST::InstructionList.new();
915
my $apast := nqp::shift(@childlist);
916
my $ares := $qastcomp.as_jast($apast, :want($RT_OBJ));
917
$il.append($ares.jast);
918
$*STACK.obtain($il, $ares);
920
$il.append(JAST::Instruction.new( :op('astore'), $r ));
921
$il.append($ALOAD_1);
922
$il.append(JAST::Instruction.new( :op('invokestatic'),
923
$TYPE_OPS, 'istrue', 'Long', $TYPE_SMO, $TYPE_TC ));
924
$il.append(JAST::Instruction.new( :op('lstore'), $t ));
926
my $have_middle_child := 1;
928
while $have_middle_child {
929
my $bpast := nqp::shift(@childlist);
930
$bres := $qastcomp.as_jast($bpast, :want($RT_OBJ));
931
$il.append($bres.jast);
932
$*STACK.obtain($il, $bres);
934
$il.append(JAST::Instruction.new( :op('astore'), $b ));
935
$il.append($ALOAD_1);
936
$il.append(JAST::Instruction.new( :op('invokestatic'),
937
$TYPE_OPS, 'istrue', 'Long', $TYPE_SMO, $TYPE_TC ));
939
$il.append(JAST::Instruction.new( :op('lstore'), $u ));
941
$il.append(JAST::Instruction.new( :op('lload'), $t ));
944
$il.append(JAST::Instruction.new( :op('ifne'), $falselabel ));
947
my $truelabel := JAST::Label.new(:name($op.unique('xor_true')));
948
$il.append(JAST::Instruction.new( :op('lload'), $t ));
950
$il.append(JAST::Instruction.new( :op('ifne'), $truelabel ));
951
$il.append(JAST::Instruction.new( :op('aload'), $b ));
952
$il.append(JAST::Instruction.new( :op('astore'), $r ));
953
$il.append(JAST::Instruction.new( :op('lload'), $u ));
954
$il.append(JAST::Instruction.new( :op('lstore'), $t ));
955
$il.append($truelabel);
958
$have_middle_child := 0;
962
$il.append(JAST::Instruction.new( :op('lload'), $t ));
964
$il.append(JAST::Instruction.new( :op('ifne'), $endlabel ));
965
$il.append(JAST::Instruction.new( :op('aload'), $b ));
966
$il.append(JAST::Instruction.new( :op('astore'), $r ));
967
$il.append(JAST::Instruction.new( :op('goto'), $endlabel ));
968
$il.append($falselabel);
971
my $fres := $qastcomp.as_jast($fpast, :want($RT_OBJ));
972
$il.append($fres.jast);
973
$*STACK.obtain($il, $fres);
974
$il.append(JAST::Instruction.new( :op('astore'), $r ));
977
$il.append($ACONST_NULL);
978
$il.append(JAST::Instruction.new( :op('astore'), $r ));
981
$il.append($endlabel);
982
$il.append(JAST::Instruction.new( :op('aload'), $r ));
986
QAST::OperationsJAST.add_core_op('ifnull', -> $qastcomp, $op {
988
nqp::die("The 'ifnull' op expects two children");
991
# Compile the expression.
992
my $il := JAST::InstructionList.new();
993
$*STACK.spill_to_locals($il);
994
my $expr := $qastcomp.as_jast($op[0], :want($RT_OBJ));
995
$il.append($expr.jast);
998
my $lbl := JAST::Label.new( :name($qastcomp.unique('ifnull_')) );
999
$*STACK.obtain($il, $expr);
1001
$il.append(JAST::Instruction.new( :op('ifnonnull'), $lbl ));
1005
my $then := $qastcomp.as_jast($op[1], :want($RT_OBJ));
1006
$il.append($then.jast);
1007
$*STACK.obtain($il, $then);
1010
result($il, $RT_OBJ);
1014
for ('', 'repeat_') -> $repness {
1015
for <while until> -> $op_name {
1016
QAST::OperationsJAST.add_core_op("$repness$op_name", -> $qastcomp, $op {
1017
# Check if we need a handler and operand count.
1021
if $_.named eq 'nohandler' { $handler := 0; }
1022
else { @operands.push($_) }
1024
if +@operands != 2 && +@operands != 3 {
1025
nqp::die("Operation '$repness$op_name' needs 2 or 3 operands");
1028
# See if there's an immediate block wanting to be passed the condition.
1029
my $has_im := nqp::istype(@operands[1], QAST::Block) &&
1030
(@operands[1].blocktype eq 'immediate' || @operands[1].blocktype eq 'immediate_static') &&
1031
@operands[1].arity > 0;
1034
my $while_id := $qastcomp.unique($op_name);
1035
my $test_lbl := JAST::Label.new( :name($while_id ~ '_test') );
1036
my $next_lbl := JAST::Label.new( :name($while_id ~ '_next') );
1037
my $redo_lbl := JAST::Label.new( :name($while_id ~ '_redo') );
1038
my $done_lbl := JAST::Label.new( :name($while_id ~ '_done') );
1040
# If we need handlers, produce them.
1044
$l_handler_id := &*REGISTER_UNWIND_HANDLER($*HANDLER_IDX, $EX_CAT_LAST);
1045
$nr_handler_id := &*REGISTER_UNWIND_HANDLER($l_handler_id, $EX_CAT_NEXT + $EX_CAT_REDO)
1048
# Emit loop prelude, evaluating condition.
1049
my $testil := JAST::InstructionList.new();
1050
$*STACK.spill_to_locals($testil);
1052
# It's a repeat_ variant, need to go straight into the
1053
# loop body unconditionally.
1054
$testil.append(JAST::Instruction.new( :op('goto'), $redo_lbl ));
1056
$testil.append($test_lbl);
1057
my $cond_res := $qastcomp.as_jast_in_handler(@operands[0], $l_handler_id || $*HANDLER_IDX);
1058
$testil.append($cond_res.jast);
1059
$*STACK.obtain($testil, $cond_res);
1061
my $im_local := QAST::Node.unique('__IM_');
1062
$*BLOCK.add_local(QAST::Var.new(
1064
:returns(typeobj_from_rttype($cond_res.type))
1066
@operands[1].blocktype('declaration');
1067
@operands[1] := QAST::Op.new(
1068
:op('call'), @operands[1],
1069
QAST::Var.new( :name($im_local), :scope('local') )
1071
$testil.append(dup_ins($cond_res.type));
1072
$testil.append(JAST::Instruction.new( :op(store_ins($cond_res.type)), $im_local ));
1075
# Compile loop body, then do any analysis of result type if
1076
# in non-void context.
1077
my $body_res := $qastcomp.as_jast_in_handler(@operands[1], $nr_handler_id || $*HANDLER_IDX);
1080
if $*WANT != $RT_VOID {
1081
$res_type := $cond_res.type == $body_res.type
1084
$res := $*TA."fresh_{typechar($res_type)}"();
1087
# If we're non-void, store the condition's evaluation as a
1090
$testil.append(dup_ins($cond_res.type));
1091
$testil.append($qastcomp.coercion($cond_res, $res_type));
1092
$testil.append(JAST::Instruction.new( :op(store_ins($res_type)), $res ));
1096
boolify_instructions($testil, $cond_res.type);
1097
$testil.append(JAST::Instruction.new($done_lbl,
1098
:op($op_name eq 'while' ?? 'ifeq' !! 'ifne')));
1100
# Emit the loop body; stash the result if needed.
1101
my $il := JAST::InstructionList.new();
1102
$il.append($redo_lbl);
1103
my $body_il := JAST::InstructionList.new();
1104
$body_il.append($body_res.jast);
1105
$*STACK.obtain($body_il, $body_res);
1107
$body_il.append($qastcomp.coercion($body_res, $res_type));
1108
$body_il.append(JAST::Instruction.new( :op(store_ins($res_type)), $res ));
1111
$body_il.append(pop_ins($body_res.type));
1114
# Add redo and next handler if needed.
1116
my $catch := JAST::InstructionList.new();
1117
$qastcomp.unwind_check($catch, $nr_handler_id);
1118
$catch.append(JAST::Instruction.new( :op('getfield'), $TYPE_EX_UNWIND, 'category', 'Long' ));
1119
$catch.append(JAST::PushIVal.new( :value($EX_CAT_REDO) ));
1120
$catch.append($LCMP);
1121
$catch.append(JAST::Instruction.new( :op('ifeq'), $redo_lbl ));
1122
$body_il := $qastcomp.delimit_handler(
1123
JAST::TryCatch.new( :try($body_il), :$catch, :type($TYPE_EX_UNWIND) ),
1124
$l_handler_id, $nr_handler_id);
1126
$il.append($body_il);
1128
# If there's a third child, evaluate it as part of the
1130
if +@operands == 3 {
1131
my $next_res := $qastcomp.as_jast_in_handler(@operands[2],
1132
$l_handler_id || $*HANDLER_IDX, :want($RT_VOID));
1133
$il.append($next_res.jast);
1134
$*STACK.obtain($il, $next_res);
1137
# Emit the iteration jump and end label.
1138
$il.append(JAST::Instruction.new( :op('goto'), $test_lbl ));
1139
$il.append($done_lbl);
1141
# If needed, wrap the whole thing in a last exception handler.
1143
my $catch := JAST::InstructionList.new();
1144
$qastcomp.unwind_check($catch, $l_handler_id);
1145
$catch.append($POP);
1146
$il := $qastcomp.delimit_handler(
1147
JAST::TryCatch.new( :try($il), :catch($catch), :type($TYPE_EX_UNWIND) ),
1148
$*HANDLER_IDX, $l_handler_id);
1151
my $res_il := JAST::InstructionList.new();
1152
$res_il.append($testil);
1153
$res_il.append($il);
1155
$res_il.append(JAST::Instruction.new( :op(load_ins($res_type)), $res ));
1156
result($res_il, $res_type)
1159
result($res_il, $RT_VOID)
1165
QAST::OperationsJAST.add_core_op('for', -> $qastcomp, $op {
1169
if $_.named eq 'nohandler' { $handler := 0; }
1170
else { @operands.push($_) }
1173
if +@operands != 2 {
1174
nqp::die("Operation 'for' needs 2 operands");
1176
unless nqp::istype(@operands[1], QAST::Block) {
1177
nqp::die("Operation 'for' expects a block as its second operand");
1179
if @operands[1].blocktype eq 'immediate' {
1180
@operands[1].blocktype('declaration');
1182
elsif @operands[1].blocktype eq 'immediate_static' {
1183
@operands[1].blocktype('declaration_static');
1186
# Create result temporary if we'll need one.
1187
my $res := $*WANT == $RT_VOID ?? 0 !! $*TA.fresh_o();
1189
# If we need handlers, produce them.
1194
$l_handler_id := &*REGISTER_UNWIND_HANDLER($*HANDLER_IDX, $EX_CAT_LAST);
1195
$n_handler_id := &*REGISTER_UNWIND_HANDLER($l_handler_id, $EX_CAT_NEXT);
1196
$r_handler_id := &*REGISTER_UNWIND_HANDLER($n_handler_id, $EX_CAT_REDO);
1199
# Evaluate the thing we'll iterate over, get the iterator and
1200
# store it in a temporary.
1201
my $il := JAST::InstructionList.new();
1202
$*STACK.spill_to_locals($il);
1203
my $list_res := $qastcomp.as_jast(@operands[0]);
1204
$il.append($list_res.jast);
1205
$*STACK.obtain($il, $list_res);
1208
$il.append(JAST::Instruction.new( :op('astore'), $res ));
1210
my $iter_tmp := $*TA.fresh_o();
1211
$il.append($ALOAD_1);
1212
$il.append(JAST::Instruction.new( :op('invokestatic'),
1213
$TYPE_OPS, 'iter', $TYPE_SMO, $TYPE_SMO, $TYPE_TC ));
1214
$il.append(JAST::Instruction.new( :op('astore'), $iter_tmp ));
1216
# Do similar for the block.
1217
my $block_res := $qastcomp.as_jast(@operands[1], :want($RT_OBJ));
1218
my $block_tmp := $op.unique('iterblock');
1219
$*BLOCK.add_local(QAST::Var.new( :name($block_tmp), :scope('local') ));
1220
$il.append($block_res.jast);
1221
$*STACK.obtain($il, $block_res);
1222
$il.append(JAST::Instruction.new( :op('astore'), $block_tmp ));
1224
# Some labels we'll need.
1225
my $for_id := $qastcomp.unique('for');
1226
my $lbl_next := JAST::Label.new( :name($for_id ~ 'next') );
1227
my $lbl_redo := JAST::Label.new( :name($for_id ~ 'redo') );
1228
my $lbl_done := JAST::Label.new( :name($for_id ~ 'done') );
1231
my $loop_il := JAST::InstructionList.new();
1232
$loop_il.append($lbl_next);
1233
$loop_il.append(JAST::Instruction.new( :op('aload'), $iter_tmp ));
1234
$loop_il.append($ALOAD_1);
1235
$loop_il.append(JAST::Instruction.new( :op('invokestatic'),
1236
$TYPE_OPS, 'istrue', 'Long', $TYPE_SMO, $TYPE_TC ));
1237
$loop_il.append($L2I);
1238
$loop_il.append(JAST::Instruction.new( :op('ifeq'), $lbl_done ));
1240
# Fetch values into temporaries (on the stack ain't enough in case
1242
my $val_il := JAST::InstructionList.new();
1244
my $arity := @operands[1].arity || 1;
1246
my $tmp := $op.unique('itertmp');
1247
$*BLOCK.add_local(QAST::Var.new( :name($tmp), :scope('local') ));
1248
$val_il.append(JAST::Instruction.new( :op('aload'), $iter_tmp ));
1249
$val_il.append($ALOAD_1);
1250
$val_il.append(JAST::Instruction.new( :op('invokestatic'),
1251
$TYPE_OPS, 'shift', $TYPE_SMO, $TYPE_SMO, $TYPE_TC ));
1252
$val_il.append(JAST::Instruction.new( :op('astore'), $tmp ));
1253
nqp::push(@val_temps, $tmp);
1254
$arity := $arity - 1;
1256
$val_il.append($lbl_redo);
1258
# Now do block invocation.
1259
my $inv_ast := QAST::Op.new(
1261
QAST::Var.new( :name($block_tmp), :scope('local') )
1264
$inv_ast.push(QAST::Var.new( :name($_), :scope('local') ));
1266
my $inv_res := $qastcomp.as_jast($inv_ast, :want($res ?? $RT_OBJ !! $RT_VOID));
1267
my $inv_il := JAST::InstructionList.new();
1268
$inv_il.append($inv_res.jast);
1269
$*STACK.obtain($inv_il, $inv_res);
1271
$inv_il.append(JAST::Instruction.new( :op('astore'), $res ));
1274
# Wrap block invocation in redo handler if needed.
1276
my $catch := JAST::InstructionList.new();
1277
$qastcomp.unwind_check($catch, $r_handler_id);
1278
$catch.append($POP);
1279
$catch.append(JAST::Instruction.new( :op('goto'), $lbl_redo ));
1280
$inv_il := $qastcomp.delimit_handler(
1281
JAST::TryCatch.new( :try($inv_il), :$catch, :type($TYPE_EX_UNWIND) ),
1282
$n_handler_id, $r_handler_id);
1284
$val_il.append($inv_il);
1286
# Wrap value fetching and call in "next" handler if needed.
1288
my $catch := JAST::InstructionList.new();
1289
$qastcomp.unwind_check($catch, $n_handler_id);
1290
$catch.append($POP);
1291
$val_il := $qastcomp.delimit_handler(
1292
JAST::TryCatch.new( :try($val_il), :$catch, :type($TYPE_EX_UNWIND) ),
1293
$l_handler_id, $n_handler_id);
1295
$loop_il.append($val_il);
1296
$loop_il.append(JAST::Instruction.new( :op('goto'), $lbl_next ));
1298
# Emit postlude, wrapping in last handler if needed.
1300
my $catch := JAST::InstructionList.new();
1301
$qastcomp.unwind_check($catch, $l_handler_id);
1302
$catch.append($POP);
1303
$catch.append(JAST::Instruction.new( :op('goto'), $lbl_done ));
1304
$loop_il := $qastcomp.delimit_handler(
1305
JAST::TryCatch.new( :try($loop_il), :$catch, :type($TYPE_EX_UNWIND) ),
1306
$*HANDLER_IDX, $l_handler_id);
1308
$il.append($loop_il);
1309
$il.append($lbl_done);
1311
# Result, as needed.
1313
$il.append(JAST::Instruction.new( :op('aload'), $res ));
1314
result($il, $RT_OBJ)
1317
result($il, $RT_VOID)
1322
sub process_args_onto_stack($qastcomp, @children, $il, :$obj_first, :$inv_first, :$name_first, :$obj_second) {
1323
# Make sure we do positionals before nameds.
1327
nqp::push(($_.named ?? @named !! @pos), $_);
1330
for @named { nqp::push(@order, $_) }
1332
# Process the arguments, computing each of them and putting them onto the
1335
my @arg_jtypes := [$TYPE_TC];
1339
while $i < +@order {
1341
if $i == 0 && ($obj_first || $inv_first) || $i == 1 && $obj_second {
1342
$arg_res := $qastcomp.as_jast(@order[$i], :want($RT_OBJ));
1344
elsif $i == 0 && $name_first {
1345
$arg_res := $qastcomp.as_jast(@order[$i], :want($RT_STR));
1348
$arg_res := $qastcomp.as_jast(@order[$i]);
1350
$il.append($arg_res.jast);
1351
nqp::push(@arg_results, $arg_res);
1353
my int $type := $arg_res.type;
1354
if $type == $RT_INT {
1355
nqp::push(@arg_jtypes, 'J');
1357
elsif $type == $RT_NUM {
1358
nqp::push(@arg_jtypes, 'D');
1361
nqp::push(@arg_jtypes, jtype($arg_res.type));
1364
unless $i == 0 && ($inv_first || $name_first) {
1366
if @order[$i].flat {
1367
$flags := @order[$i].named ?? 24 !! 16;
1369
elsif @order[$i].named -> $name {
1371
nqp::push(@argnames, $name);
1373
nqp::push(@callsite, arg_type($type) + $flags);
1379
# Return callsite index (which may create it if needed).
1380
return [$*CODEREFS.get_callsite_idx(@callsite, @argnames), @arg_results, @arg_jtypes];
1382
QAST::OperationsJAST.add_core_op('call', :!inlinable, sub ($qastcomp, $node) {
1383
my $il := JAST::InstructionList.new();
1385
# If it's a direct call, then use invokedynamic to resolve the name in
1386
# the current lexical scope.
1387
if $node.name ne "" {
1388
# Process arguments and force them into locals.
1389
my @argstuff := process_args_onto_stack($qastcomp, @($node), $il);
1390
my $cs_idx := @argstuff[0];
1391
$*STACK.spill_to_locals($il);
1393
# Emit the call. Note, name passed as extra arg as some valid names in
1394
# Perl 6 are not valid method names on the JVM. We use the fact that
1395
# the stack was spilled to sneak the ThreadContext arg in.
1396
nqp::unshift(@argstuff[2], 'I');
1397
nqp::unshift(@argstuff[2], $TYPE_STR);
1398
$il.append(JAST::PushSVal.new( :value($node.name) ));
1399
$il.append(JAST::PushIndex.new( :value($cs_idx) ));
1400
$il.append($ALOAD_1);
1401
$*STACK.obtain($il, |@argstuff[1]) if @argstuff[1];
1402
$il.append(savesite(JAST::InvokeDynamic.new(
1403
'subcall_noa', 'V', @argstuff[2],
1404
'org/perl6/nqp/runtime/IndyBootstrap', 'subcall_noa'
1408
# Otherwise, it's an indirect call.
1410
# Ensure we have a thing to invoke.
1411
nqp::die("A 'call' node must have a name or at least one child") unless +@($node) >= 1;
1413
# Proces arguments, making sure first one is an object (since that is
1414
# the thing to invoke).
1415
my @argstuff := process_args_onto_stack($qastcomp, @($node), $il, :inv_first);
1416
my $cs_idx := @argstuff[0];
1417
$*STACK.spill_to_locals($il);
1419
# Emit the call, using the same thread context trick. The first thing
1421
nqp::unshift(@argstuff[2], 'I');
1422
$il.append(JAST::PushIndex.new( :value($cs_idx) ));
1423
$il.append($ALOAD_1);
1424
$*STACK.obtain($il, |@argstuff[1]) if @argstuff[1];
1425
$il.append(savesite(JAST::InvokeDynamic.new(
1426
'indcall_noa', 'V', @argstuff[2],
1427
'org/perl6/nqp/runtime/IndyBootstrap', 'indcall_noa'
1431
result_from_cf($il, rttype_from_typeobj($node.returns));
1433
QAST::OperationsJAST.add_core_op('callmethod', -> $qastcomp, $node {
1434
my $il := JAST::InstructionList.new();
1436
# Ensure we have an invocant.
1438
nqp::die("A 'callmethod' node must have at least one child");
1440
my @children := nqp::clone(@($node));
1442
# If it's a direct call, we can get invokedynamic to do something smart
1443
# with guard clauses for us.
1444
if $node.name ne '' {
1445
# Process arguments and force them into locals.
1446
my @argstuff := process_args_onto_stack($qastcomp, @children, $il, :obj_first);
1447
my $cs_idx := @argstuff[0];
1448
$*STACK.spill_to_locals($il);
1450
# Emit the call. Note, name passed as extra arg as some valid names in
1451
# Perl 6 are not valid method names on the JVM. We use the fact that
1452
# the stack was spilled to sneak the ThreadContext arg in.
1453
nqp::unshift(@argstuff[2], 'I');
1454
nqp::unshift(@argstuff[2], $TYPE_STR);
1455
$il.append(JAST::PushSVal.new( :value($node.name) ));
1456
$il.append(JAST::PushIndex.new( :value($cs_idx) ));
1457
$il.append($ALOAD_1);
1458
$*STACK.obtain($il, |@argstuff[1]) if @argstuff[1];
1459
$il.append(savesite(JAST::InvokeDynamic.new(
1460
'methcall_noa', 'V', @argstuff[2],
1461
'org/perl6/nqp/runtime/IndyBootstrap', 'methcall_noa',
1465
# Otherwise, it's indirect, and we need to resolve the method each and
1466
# every call. Still wire it through invokedynamic, but it can't do quite
1469
# Ensure we have a name, and re-arrange it to come first.
1470
if +@children == 1 {
1471
nqp::die("Method call must either supply a name or have a child node that evaluates to the name");
1473
my $inv := nqp::shift(@children);
1474
my $name := nqp::shift(@children);
1475
nqp::unshift(@children, $inv);
1476
nqp::unshift(@children, $name);
1478
# Process arguments and force them into locals.
1479
my @argstuff := process_args_onto_stack($qastcomp, @children, $il, :name_first, :obj_second);
1480
my $cs_idx := @argstuff[0];
1481
$*STACK.spill_to_locals($il);
1484
nqp::unshift(@argstuff[2], 'I');
1485
$il.append(JAST::PushIndex.new( :value($cs_idx) ));
1486
$il.append($ALOAD_1);
1487
$*STACK.obtain($il, |@argstuff[1]) if @argstuff[1];
1488
$il.append(savesite(JAST::InvokeDynamic.new(
1489
'indmethcall_noa', 'V', @argstuff[2],
1490
'org/perl6/nqp/runtime/IndyBootstrap', 'indmethcall_noa'
1494
result_from_cf($il, rttype_from_typeobj($node.returns));
1497
my $num_lexotics := 0;
1498
QAST::OperationsJAST.add_core_op('lexotic', :!inlinable, -> $qastcomp, $op {
1499
# Create the lexotic lexical.
1500
my $target := nqp::floor_n(nqp::time_n() * 1000) * 10000 + $num_lexotics++;
1501
my $il := JAST::InstructionList.new();
1502
$*BLOCK.add_lexical(QAST::Var.new( :name($op.name) ));
1503
$il.append(JAST::PushIVal.new( :value($target) ));
1504
$il.append(JAST::Instruction.new( :op('aload'), 'tc' ));
1505
$il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
1506
'lexotic_tc', $TYPE_SMO, 'Long', $TYPE_TC ));
1507
$il.append(JAST::Instruction.new( :op('aload'), 'cf' ));
1508
$il.append(JAST::PushIndex.new( :value($*BLOCK.lexical_idx($op.name)) ));
1509
$il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
1510
'bindlex_o', $TYPE_SMO, $TYPE_SMO, $TYPE_CF, 'Integer' ));
1513
# Compile the things inside the lexotic
1514
my $*WANT := $RT_OBJ;
1515
my $stmt_res := $qastcomp.coerce($qastcomp.compile_all_the_stmts($op.list()), $RT_OBJ);
1516
$*STACK.obtain($il, $stmt_res);
1518
# Build up catch for the lexotic (rethrows if wrong thing).
1519
my $miss_lbl := JAST::Label.new( :name($qastcomp.unique('lexotic_miss_')) );
1520
my $done_lbl := JAST::Label.new( :name($qastcomp.unique('lexotic_done_')) );
1521
my $catch_il := JAST::InstructionList.new();
1522
$catch_il.append($DUP);
1523
$catch_il.append(JAST::Instruction.new( :op('getfield'), $TYPE_EX_LEX, 'target', 'Long' ));
1524
$catch_il.append(JAST::PushIVal.new( :value($target) ));
1525
$catch_il.append($LCMP);
1526
$catch_il.append(JAST::Instruction.new( :op('ifne'), $miss_lbl ));
1527
$catch_il.append(JAST::Instruction.new( :op('getfield'), $TYPE_EX_LEX, 'payload', $TYPE_SMO ));
1528
$catch_il.append(JAST::Instruction.new( :op('goto'), $done_lbl ));
1529
$catch_il.append($miss_lbl);
1530
$catch_il.append($ATHROW);
1531
$catch_il.append($done_lbl);
1533
# Finally, assemble try/catch.
1534
$il.append(JAST::TryCatch.new(
1535
:try($stmt_res.jast),
1540
result($il, $RT_OBJ);
1544
QAST::OperationsJAST.add_core_op('bind', -> $qastcomp, $op {
1546
my @children := $op.list;
1547
if +@children != 2 {
1548
nqp::die("A 'bind' op must have exactly two children");
1550
unless nqp::istype(@children[0], QAST::Var) {
1551
nqp::die("First child of a 'bind' op must be a QAST::Var");
1554
# Set the QAST of the think we're to bind, then delegate to
1555
# the compilation of the QAST::Var to handle the rest.
1556
my $*BINDVAL := @children[1];
1557
$qastcomp.as_jast(@children[0])
1560
# Exception handling/munging.
1561
QAST::OperationsJAST.map_classlib_core_op('die_s', $TYPE_OPS, 'die_s_c', [$RT_STR], $RT_STR, :tc, :cont);
1562
QAST::OperationsJAST.map_classlib_core_op('die', $TYPE_OPS, 'die_s_c', [$RT_STR], $RT_STR, :tc, :cont);
1563
QAST::OperationsJAST.map_classlib_core_op('exception', $TYPE_OPS, 'exception', [], $RT_OBJ, :tc);
1564
QAST::OperationsJAST.map_classlib_core_op('getextype', $TYPE_OPS, 'getextype', [$RT_OBJ], $RT_INT, :tc);
1565
QAST::OperationsJAST.map_classlib_core_op('setextype', $TYPE_OPS, 'setextype', [$RT_OBJ, $RT_INT], $RT_INT, :tc);
1566
QAST::OperationsJAST.map_classlib_core_op('getpayload', $TYPE_OPS, 'getpayload', [$RT_OBJ], $RT_OBJ, :tc);
1567
QAST::OperationsJAST.map_classlib_core_op('setpayload', $TYPE_OPS, 'setpayload', [$RT_OBJ, $RT_OBJ], $RT_OBJ, :tc);
1568
QAST::OperationsJAST.map_classlib_core_op('getmessage', $TYPE_OPS, 'getmessage', [$RT_OBJ], $RT_STR, :tc);
1569
QAST::OperationsJAST.map_classlib_core_op('setmessage', $TYPE_OPS, 'setmessage', [$RT_OBJ, $RT_STR], $RT_STR, :tc);
1570
QAST::OperationsJAST.map_classlib_core_op('newexception', $TYPE_OPS, 'newexception', [], $RT_OBJ, :tc);
1571
QAST::OperationsJAST.map_classlib_core_op('backtrace', $TYPE_OPS, 'backtrace', [$RT_OBJ], $RT_OBJ, :tc);
1572
QAST::OperationsJAST.map_classlib_core_op('backtracestrings', $TYPE_OPS, 'backtracestrings', [$RT_OBJ], $RT_OBJ, :tc);
1573
QAST::OperationsJAST.map_classlib_core_op('throw', $TYPE_OPS, '_throw_c', [$RT_OBJ], $RT_OBJ, :tc, :cont);
1574
QAST::OperationsJAST.map_classlib_core_op('rethrow', $TYPE_OPS, 'rethrow_c', [$RT_OBJ], $RT_OBJ, :tc, :cont);
1575
QAST::OperationsJAST.map_classlib_core_op('resume', $TYPE_OPS, 'resume', [$RT_OBJ], $RT_OBJ, :tc);
1576
my %handler_names := nqp::hash(
1577
'CATCH', $EX_CAT_CATCH,
1578
'CONTROL', $EX_CAT_CONTROL,
1579
'NEXT', $EX_CAT_NEXT,
1580
'LAST', $EX_CAT_LAST,
1581
'REDO', $EX_CAT_REDO,
1582
'TAKE', $EX_CAT_TAKE,
1583
'WARN', $EX_CAT_WARN,
1584
'PROCEED', $EX_CAT_PROCEED,
1585
'SUCCEED', $EX_CAT_SUCCEED,
1587
QAST::OperationsJAST.add_core_op('handle', :!inlinable, sub ($qastcomp, $op) {
1588
my @children := nqp::clone($op.list());
1590
nqp::die("The 'handle' op requires at least one child");
1593
# If there's exactly one child, then there's nothing protecting
1594
# it; just compile it and we're done.
1595
my $protected := @children.shift();
1597
return $qastcomp.as_jast($protected);
1600
# Otherwise, we need to generate an install a handler block, which will
1601
# decide that to do by category.
1603
my $hblock := QAST::Block.new(
1606
QAST::Var.new( :name('__category__'), :scope('local'), :decl('var') ),
1609
QAST::Op.new( :op('exception') )
1611
my $push_target := $hblock;
1612
for @children -> $type, $handler {
1613
# Get the category mask.
1614
unless nqp::existskey(%handler_names, $type) {
1615
nqp::die("Invalid handler type '$type'");
1617
my $cat_mask := %handler_names{$type};
1619
# Chain in this handler.
1620
my $check := QAST::Op.new(
1624
QAST::Var.new( :name('__category__'), :scope('local') ),
1625
QAST::IVal.new( :value($cat_mask) )
1629
$push_target.push($check);
1630
$push_target := $check;
1633
$mask := nqp::bitor_i($mask, $cat_mask);
1636
# Compile, create a lexical to put the handler in, and add it. Should
1637
# also force the stack to empty.
1638
my $name := QAST::Node.unique('!HANDLER_');
1639
$*BLOCK.add_lexical(QAST::Var.new( :name($name) ));
1640
my $lexidx := $*BLOCK.lexical_idx($name);
1641
my $il := JAST::InstructionList.new();
1642
$*STACK.spill_to_locals($il);
1643
my $hb_res := $qastcomp.as_jast($hblock, :want($RT_OBJ));
1644
$il.append($hb_res.jast);
1645
$*STACK.obtain($il, $hb_res);
1646
$il.append(JAST::Instruction.new( :op('aload'), 'cf' ));
1647
$il.append(JAST::PushIndex.new( :value($lexidx) ));
1648
$il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
1649
'bindlex_o', $TYPE_SMO, $TYPE_SMO, $TYPE_CF, 'Integer' ));
1652
# Register a handler.
1653
my $handler := &*REGISTER_BLOCK_HANDLER($*HANDLER_IDX, $mask, $lexidx);
1655
# Evaluate the protected code and stash it in a temporary.
1656
my $result := $*TA.fresh_o();
1657
my $prores := $qastcomp.as_jast_in_handler($protected, $handler, :want($RT_OBJ));
1658
my $tryil := JAST::InstructionList.new();
1659
$tryil.append($prores.jast);
1660
$*STACK.obtain($tryil, $prores);
1661
$tryil.append(JAST::Instruction.new( :op('astore'), $result ));
1663
# The catch part just handles unwind; grab the result. Also check "exit
1664
# after unwind" flag, used to force this whole block to exit.
1665
my $catchil := JAST::InstructionList.new();
1666
my $exitlbl := JAST::Label.new( :name($qastcomp.unique('unwindexit')) );
1667
$qastcomp.unwind_check($catchil, $handler);
1668
$catchil.append(JAST::Instruction.new( :op('getfield'), $TYPE_EX_UNWIND, 'result', $TYPE_SMO ));
1669
$catchil.append(JAST::Instruction.new( :op('astore'), $result ));
1670
$catchil.append(JAST::Instruction.new( :op('aload'), 'cf' ));
1671
$catchil.append(JAST::Instruction.new( :op('getfield'), $TYPE_CF, 'exitAfterUnwind', "Z" ));
1672
$catchil.append(JAST::Instruction.new( :op('ifeq'), $exitlbl ));
1673
$catchil.append(JAST::Instruction.new( :op('aload'), $result ));
1674
$catchil.append(JAST::Instruction.new( :op('aload'), 'cf' ));
1675
$catchil.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
1676
'return_o', 'Void', $TYPE_SMO, $TYPE_CF ));
1677
$catchil.append(JAST::Instruction.new( :op('aload'), 'cf' ));
1678
$catchil.append(JAST::Instruction.new( :op('invokevirtual'),
1679
$TYPE_CF, 'leave', 'Void' ));
1680
$catchil.append($RETURN);
1681
$catchil.append($exitlbl);
1683
# Wrap it all up in try/catch etc.
1684
$il.append($qastcomp.delimit_handler(
1685
JAST::TryCatch.new( :try($tryil), :catch($catchil), :type($TYPE_EX_UNWIND) ),
1686
$*HANDLER_IDX, $handler));
1688
# Evaluate to the result.
1689
$il.append(JAST::Instruction.new( :op('aload'), $result ));
1690
result($il, $RT_OBJ);
1693
# Control exception throwing.
1694
my %control_map := nqp::hash(
1695
'next', $EX_CAT_NEXT,
1696
'last', $EX_CAT_LAST,
1697
'redo', $EX_CAT_REDO
1699
QAST::OperationsJAST.add_core_op('control', -> $qastcomp, $op {
1700
my $name := $op.name;
1701
if nqp::existskey(%control_map, $name) {
1702
my $cat := %control_map{$name};
1703
my $il := JAST::InstructionList.new();
1704
$*STACK.spill_to_locals($il);
1705
$il.append(JAST::PushIVal.new( :value($cat) ));
1706
$il.append($ALOAD_1);
1707
$il.append(savesite(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
1708
'throwcatdyn_c', 'Void', 'Long', $TYPE_TC )));
1709
result_from_cf($il, $RT_OBJ);
1712
nqp::die("Unknown control exception type '$name'");
1716
# Default ways to box/unbox (for no particular HLL).
1717
QAST::OperationsJAST.add_hll_box('', $RT_INT, -> $qastcomp {
1718
my $il := JAST::InstructionList.new();
1719
$il.append($ALOAD_1);
1720
$il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
1721
'bootint', $TYPE_SMO, $TYPE_TC ));
1722
$il.append($ALOAD_1);
1723
$il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
1724
'box_i', $TYPE_SMO, 'Long', $TYPE_SMO, $TYPE_TC ));
1727
QAST::OperationsJAST.add_hll_box('', $RT_NUM, -> $qastcomp {
1728
my $il := JAST::InstructionList.new();
1729
$il.append($ALOAD_1);
1730
$il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
1731
'bootnum', $TYPE_SMO, $TYPE_TC ));
1732
$il.append($ALOAD_1);
1733
$il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
1734
'box_n', $TYPE_SMO, 'Double', $TYPE_SMO, $TYPE_TC ));
1737
QAST::OperationsJAST.add_hll_box('', $RT_STR, -> $qastcomp {
1738
my $il := JAST::InstructionList.new();
1739
$il.append($ALOAD_1);
1740
$il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
1741
'bootstr', $TYPE_SMO, $TYPE_TC ));
1742
$il.append($ALOAD_1);
1743
$il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
1744
'box_s', $TYPE_SMO, $TYPE_STR, $TYPE_SMO, $TYPE_TC ));
1747
QAST::OperationsJAST.add_hll_unbox('', $RT_INT, -> $qastcomp {
1748
my $il := JAST::InstructionList.new();
1749
$il.append($ALOAD_1);
1750
$il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
1751
'unbox_i', 'Long', $TYPE_SMO, $TYPE_TC ));
1754
QAST::OperationsJAST.add_hll_unbox('', $RT_NUM, -> $qastcomp {
1755
my $il := JAST::InstructionList.new();
1756
$il.append($ALOAD_1);
1757
$il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
1758
'unbox_n', 'Double', $TYPE_SMO, $TYPE_TC ));
1761
QAST::OperationsJAST.add_hll_unbox('', $RT_STR, -> $qastcomp {
1762
my $il := JAST::InstructionList.new();
1763
$il.append($ALOAD_1);
1764
$il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
1765
'unbox_s', $TYPE_STR, $TYPE_SMO, $TYPE_TC ));
1769
# Context introspection; note that lexpads and contents are actually the same object
1770
# in the JVM port, which allows a little op re-use.
1771
QAST::OperationsJAST.map_classlib_core_op('ctx', $TYPE_OPS, 'ctx', [], $RT_OBJ, :tc, :!inlinable);
1772
QAST::OperationsJAST.map_classlib_core_op('ctxouter', $TYPE_OPS, 'ctxouter', [$RT_OBJ], $RT_OBJ, :tc, :!inlinable);
1773
QAST::OperationsJAST.map_classlib_core_op('ctxcaller', $TYPE_OPS, 'ctxcaller', [$RT_OBJ], $RT_OBJ, :tc, :!inlinable);
1774
QAST::OperationsJAST.map_classlib_core_op('curcode', $TYPE_OPS, 'curcode', [], $RT_OBJ, :tc, :!inlinable);
1775
QAST::OperationsJAST.map_classlib_core_op('callercode', $TYPE_OPS, 'callercode', [], $RT_OBJ, :tc, :!inlinable);
1776
QAST::OperationsJAST.map_classlib_core_op('ctxlexpad', $TYPE_OPS, 'ctxlexpad', [$RT_OBJ], $RT_OBJ, :tc, :!inlinable);
1777
QAST::OperationsJAST.map_classlib_core_op('curlexpad', $TYPE_OPS, 'ctx', [], $RT_OBJ, :tc, :!inlinable);
1778
QAST::OperationsJAST.map_classlib_core_op('lexprimspec', $TYPE_OPS, 'lexprimspec', [$RT_OBJ, $RT_STR], $RT_INT, :tc, :!inlinable);
1780
# Argument capture processing, for writing things like multi-dispatchers in
1781
# high level languages.
1782
QAST::OperationsJAST.add_core_op('usecapture', :!inlinable, -> $qastcomp, $op {
1783
my $il := JAST::InstructionList.new();
1784
$il.append($ALOAD_1);
1785
$il.append(JAST::Instruction.new( :op('aload'), 'csd' ));
1786
$il.append(JAST::Instruction.new( :op('aload'), '__args' ));
1787
$il.append(JAST::Instruction.new( :op('invokestatic'),
1788
$TYPE_OPS, 'usecapture', $TYPE_SMO, $TYPE_TC, $TYPE_CSD, "[$TYPE_OBJ" ));
1789
result($il, $RT_OBJ)
1791
QAST::OperationsJAST.add_core_op('savecapture', :!inlinable, -> $qastcomp, $op {
1792
my $il := JAST::InstructionList.new();
1793
$il.append($ALOAD_1);
1794
$il.append(JAST::Instruction.new( :op('aload'), 'csd' ));
1795
$il.append(JAST::Instruction.new( :op('aload'), '__args' ));
1796
$il.append(JAST::Instruction.new( :op('invokestatic'),
1797
$TYPE_OPS, 'savecapture', $TYPE_SMO, $TYPE_TC, $TYPE_CSD, "[$TYPE_OBJ" ));
1798
result($il, $RT_OBJ)
1800
QAST::OperationsJAST.map_classlib_core_op('captureposelems', $TYPE_OPS, 'captureposelems', [$RT_OBJ], $RT_INT, :tc);
1801
QAST::OperationsJAST.map_classlib_core_op('captureposarg', $TYPE_OPS, 'captureposarg', [$RT_OBJ, $RT_INT], $RT_OBJ, :tc);
1802
QAST::OperationsJAST.map_classlib_core_op('captureposarg_i', $TYPE_OPS, 'captureposarg_i', [$RT_OBJ, $RT_INT], $RT_INT, :tc);
1803
QAST::OperationsJAST.map_classlib_core_op('captureposarg_n', $TYPE_OPS, 'captureposarg_n', [$RT_OBJ, $RT_INT], $RT_NUM, :tc);
1804
QAST::OperationsJAST.map_classlib_core_op('captureposarg_s', $TYPE_OPS, 'captureposarg_s', [$RT_OBJ, $RT_INT], $RT_STR, :tc);
1805
QAST::OperationsJAST.map_classlib_core_op('captureposprimspec', $TYPE_OPS, 'captureposprimspec', [$RT_OBJ, $RT_INT], $RT_INT, :tc);
1806
QAST::OperationsJAST.map_classlib_core_op('captureexistsnamed', $TYPE_OPS, 'captureexistsnamed', [$RT_OBJ, $RT_STR], $RT_INT, :tc);
1807
QAST::OperationsJAST.map_classlib_core_op('capturehasnameds', $TYPE_OPS, 'capturehasnameds', [$RT_OBJ], $RT_INT, :tc);
1809
# Multiple dispatch related.
1810
QAST::OperationsJAST.map_classlib_core_op('invokewithcapture', $TYPE_OPS, 'invokewithcapture', [$RT_OBJ, $RT_OBJ], $RT_OBJ, :tc);
1811
QAST::OperationsJAST.map_classlib_core_op('multicacheadd', $TYPE_OPS, 'multicacheadd', [$RT_OBJ, $RT_OBJ, $RT_OBJ], $RT_OBJ, :tc);
1812
QAST::OperationsJAST.map_classlib_core_op('multicachefind', $TYPE_OPS, 'multicachefind', [$RT_OBJ, $RT_OBJ], $RT_OBJ, :tc);
1815
my %const_map := nqp::hash(
1816
'CCLASS_ANY', 65535,
1817
'CCLASS_UPPERCASE', 1,
1818
'CCLASS_LOWERCASE', 2,
1819
'CCLASS_ALPHABETIC', 4,
1820
'CCLASS_NUMERIC', 8,
1821
'CCLASS_HEXADECIMAL', 16,
1822
'CCLASS_WHITESPACE', 32,
1823
'CCLASS_PRINTING', 64,
1824
'CCLASS_BLANK', 256,
1825
'CCLASS_CONTROL', 512,
1826
'CCLASS_PUNCTUATION', 1024,
1827
'CCLASS_ALPHANUMERIC', 2048,
1828
'CCLASS_NEWLINE', 4096,
1829
'CCLASS_WORD', 8192,
1835
'HLL_ROLE_ARRAY', 4,
1843
'CONTROL_SUCCEED', 128,
1844
'CONTROL_PROCEED', 256,
1852
'STAT_CREATETIME', 5,
1853
'STAT_ACCESSTIME', 6,
1854
'STAT_MODIFYTIME', 7,
1855
'STAT_CHANGETIME', 8,
1856
'STAT_BACKUPTIME', 9,
1860
'STAT_PLATFORM_DEV', -1,
1861
'STAT_PLATFORM_INODE', -2,
1862
'STAT_PLATFORM_MODE', -3,
1863
'STAT_PLATFORM_NLINKS', -4,
1864
'STAT_PLATFORM_DEVTYPE', -5,
1865
'STAT_PLATFORM_BLOCKSIZE', -6,
1866
'STAT_PLATFORM_BLOCKS', -7,
1868
QAST::OperationsJAST.add_core_op('const', -> $qastcomp, $op {
1869
if nqp::existskey(%const_map, $op.name) {
1870
$qastcomp.as_jast(QAST::IVal.new( :value(%const_map{$op.name}) ))
1873
nqp::die("Unknown constant '" ~ $op.name ~ "'");
1877
# Default way to do positional and associative lookups.
1878
QAST::OperationsJAST.map_classlib_core_op('positional_get', $TYPE_OPS, 'atpos', [$RT_OBJ, $RT_INT], $RT_OBJ, :tc);
1879
QAST::OperationsJAST.map_classlib_core_op('positional_bind', $TYPE_OPS, 'bindpos', [$RT_OBJ, $RT_INT, $RT_OBJ], $RT_OBJ, :tc);
1880
QAST::OperationsJAST.map_classlib_core_op('associative_get', $TYPE_OPS, 'atkey', [$RT_OBJ, $RT_STR], $RT_OBJ, :tc);
1881
QAST::OperationsJAST.map_classlib_core_op('associative_bind', $TYPE_OPS, 'bindkey', [$RT_OBJ, $RT_STR, $RT_OBJ], $RT_OBJ, :tc);
1884
QAST::OperationsJAST.map_classlib_core_op('print', $TYPE_OPS, 'print', [$RT_STR], $RT_STR, :tc);
1885
QAST::OperationsJAST.map_classlib_core_op('say', $TYPE_OPS, 'say', [$RT_STR], $RT_STR, :tc);
1886
QAST::OperationsJAST.map_classlib_core_op('stat', $TYPE_OPS, 'stat', [$RT_STR, $RT_INT], $RT_INT);
1887
QAST::OperationsJAST.map_classlib_core_op('open', $TYPE_OPS, 'open', [$RT_STR, $RT_STR], $RT_OBJ, :tc);
1888
QAST::OperationsJAST.map_classlib_core_op('filereadable', $TYPE_OPS, 'filereadable', [$RT_STR], $RT_INT, :tc);
1889
QAST::OperationsJAST.map_classlib_core_op('filewritable', $TYPE_OPS, 'filewritable', [$RT_STR], $RT_INT, :tc);
1890
QAST::OperationsJAST.map_classlib_core_op('fileexecutable', $TYPE_OPS, 'fileexecutable', [$RT_STR], $RT_INT, :tc);
1891
QAST::OperationsJAST.map_classlib_core_op('fileislink', $TYPE_OPS, 'fileislink', [$RT_STR], $RT_INT, :tc);
1892
QAST::OperationsJAST.map_classlib_core_op('getstdin', $TYPE_OPS, 'getstdin', [], $RT_OBJ, :tc);
1893
QAST::OperationsJAST.map_classlib_core_op('getstdout', $TYPE_OPS, 'getstdout', [], $RT_OBJ, :tc);
1894
QAST::OperationsJAST.map_classlib_core_op('getstderr', $TYPE_OPS, 'getstderr', [], $RT_OBJ, :tc);
1895
QAST::OperationsJAST.map_classlib_core_op('setencoding', $TYPE_OPS, 'setencoding', [$RT_OBJ, $RT_STR], $RT_OBJ, :tc);
1896
QAST::OperationsJAST.map_classlib_core_op('setinputlinesep', $TYPE_OPS, 'setinputlinesep', [$RT_OBJ, $RT_STR], $RT_OBJ, :tc);
1897
QAST::OperationsJAST.map_classlib_core_op('tellfh', $TYPE_OPS, 'tellfh', [$RT_OBJ], $RT_INT, :tc);
1898
QAST::OperationsJAST.map_classlib_core_op('readfh', $TYPE_OPS, 'readfh', [$RT_OBJ, $RT_OBJ, $RT_INT], $RT_OBJ, :tc);
1899
QAST::OperationsJAST.map_classlib_core_op('writefh', $TYPE_OPS, 'writefh', [$RT_OBJ, $RT_OBJ], $RT_OBJ, :tc);
1900
QAST::OperationsJAST.map_classlib_core_op('printfh', $TYPE_OPS, 'printfh', [$RT_OBJ, $RT_STR], $RT_STR, :tc);
1901
QAST::OperationsJAST.map_classlib_core_op('sayfh', $TYPE_OPS, 'sayfh', [$RT_OBJ, $RT_STR], $RT_STR, :tc);QAST::OperationsJAST.map_classlib_core_op('sayfh', $TYPE_OPS, 'sayfh', [$RT_OBJ, $RT_STR], $RT_STR, :tc);
1902
QAST::OperationsJAST.map_classlib_core_op('flushfh', $TYPE_OPS, 'flushfh', [$RT_OBJ], $RT_OBJ, :tc);QAST::OperationsJAST.map_classlib_core_op('sayfh', $TYPE_OPS, 'sayfh', [$RT_OBJ, $RT_STR], $RT_STR, :tc);
1903
QAST::OperationsJAST.map_classlib_core_op('readlinefh', $TYPE_OPS, 'readlinefh', [$RT_OBJ], $RT_STR, :tc);
1904
QAST::OperationsJAST.map_classlib_core_op('readlineintfh', $TYPE_OPS, 'readlineintfh', [$RT_OBJ, $RT_STR], $RT_STR, :tc);
1905
QAST::OperationsJAST.map_classlib_core_op('readallfh', $TYPE_OPS, 'readallfh', [$RT_OBJ], $RT_STR, :tc);
1906
QAST::OperationsJAST.map_classlib_core_op('getcfh', $TYPE_OPS, 'getcfh', [$RT_OBJ], $RT_STR, :tc);
1907
QAST::OperationsJAST.map_classlib_core_op('eoffh', $TYPE_OPS, 'eoffh', [$RT_OBJ], $RT_INT, :tc);
1908
QAST::OperationsJAST.map_classlib_core_op('closefh', $TYPE_OPS, 'closefh', [$RT_OBJ], $RT_OBJ, :tc);
1910
QAST::OperationsJAST.map_classlib_core_op('chmod', $TYPE_OPS, 'chmod', [$RT_STR, $RT_INT], $RT_INT, :tc);
1911
QAST::OperationsJAST.map_classlib_core_op('unlink', $TYPE_OPS, 'unlink', [$RT_STR], $RT_INT, :tc);
1912
QAST::OperationsJAST.map_classlib_core_op('rmdir', $TYPE_OPS, 'rmdir', [$RT_STR], $RT_INT, :tc);
1913
QAST::OperationsJAST.map_classlib_core_op('cwd', $TYPE_OPS, 'cwd', [], $RT_STR);
1914
QAST::OperationsJAST.map_classlib_core_op('chdir', $TYPE_OPS, 'chdir', [$RT_STR], $RT_STR, :tc);
1915
QAST::OperationsJAST.map_classlib_core_op('mkdir', $TYPE_OPS, 'mkdir', [$RT_STR, $RT_INT], $RT_INT, :tc);
1916
QAST::OperationsJAST.map_classlib_core_op('rename', $TYPE_OPS, 'rename', [$RT_STR, $RT_STR], $RT_INT, :tc);
1917
QAST::OperationsJAST.map_classlib_core_op('copy', $TYPE_OPS, 'copy', [$RT_STR, $RT_STR], $RT_INT, :tc);
1918
QAST::OperationsJAST.map_classlib_core_op('link', $TYPE_OPS, 'link', [$RT_STR, $RT_STR], $RT_INT, :tc);
1920
# Two variants of shell until we deprecate shell1
1921
QAST::OperationsJAST.map_classlib_core_op('shell1', $TYPE_OPS, 'shell1', [$RT_STR], $RT_INT, :tc);
1922
QAST::OperationsJAST.map_classlib_core_op('shell3', $TYPE_OPS, 'shell3', [$RT_STR, $RT_STR, $RT_OBJ], $RT_INT, :tc);
1923
QAST::OperationsJAST.add_core_op('shell', -> $qastcomp, $op {
1924
my @operands := $op.list;
1925
$qastcomp.as_jast(+@operands == 1
1926
?? QAST::Op.new( :op('shell1'), |@operands )
1927
!! QAST::Op.new( :op('shell3'), |@operands ));
1929
QAST::OperationsJAST.map_classlib_core_op('spawn', $TYPE_OPS, 'spawn', [$RT_OBJ, $RT_STR, $RT_OBJ], $RT_INT, :tc);
1930
QAST::OperationsJAST.map_classlib_core_op('openpipe', $TYPE_OPS, 'openpipe', [$RT_STR, $RT_STR, $RT_OBJ, $RT_STR], $RT_OBJ, :tc);
1932
QAST::OperationsJAST.map_classlib_core_op('symlink', $TYPE_OPS, 'symlink', [$RT_STR, $RT_STR], $RT_INT, :tc);
1934
QAST::OperationsJAST.map_classlib_core_op('opendir', $TYPE_OPS, 'opendir', [$RT_STR], $RT_OBJ, :tc);
1935
QAST::OperationsJAST.map_classlib_core_op('nextfiledir', $TYPE_OPS, 'nextfiledir', [$RT_OBJ], $RT_STR, :tc);
1936
QAST::OperationsJAST.map_classlib_core_op('closedir', $TYPE_OPS, 'closedir', [$RT_OBJ], $RT_INT, :tc);
1938
QAST::OperationsJAST.map_classlib_core_op('openasync', $TYPE_OPS, 'openasync', [$RT_STR, $RT_STR], $RT_OBJ, :tc);
1939
QAST::OperationsJAST.map_classlib_core_op('slurpasync', $TYPE_OPS, 'slurpasync', [$RT_OBJ, $RT_OBJ, $RT_OBJ, $RT_OBJ], $RT_OBJ, :tc);
1940
QAST::OperationsJAST.map_classlib_core_op('linesasync', $TYPE_OPS, 'linesasync', [$RT_OBJ, $RT_OBJ, $RT_INT, $RT_OBJ, $RT_OBJ, $RT_OBJ], $RT_OBJ, :tc);
1942
QAST::OperationsJAST.map_classlib_core_op('socket', $TYPE_OPS, 'socket', [$RT_INT], $RT_OBJ, :tc);
1943
QAST::OperationsJAST.map_classlib_core_op('connect', $TYPE_OPS, 'connect', [$RT_OBJ, $RT_STR, $RT_INT], $RT_OBJ, :tc);
1944
QAST::OperationsJAST.map_classlib_core_op('bindsock', $TYPE_OPS, 'bindsock', [$RT_OBJ, $RT_STR, $RT_INT], $RT_OBJ, :tc);
1945
QAST::OperationsJAST.map_classlib_core_op('accept', $TYPE_OPS, 'accept', [$RT_OBJ], $RT_OBJ, :tc);
1947
QAST::OperationsJAST.map_classlib_core_op('debugnoop', $TYPE_OPS, 'debugnoop', [$RT_OBJ], $RT_OBJ, :tc);
1950
QAST::OperationsJAST.map_classlib_core_op('time_i', $TYPE_OPS, 'time_i', [], $RT_INT);
1951
QAST::OperationsJAST.map_classlib_core_op('time_n', $TYPE_OPS, 'time_n', [], $RT_NUM);
1954
QAST::OperationsJAST.map_jvm_core_op('add_i', 'ladd', [$RT_INT, $RT_INT], $RT_INT);
1955
QAST::OperationsJAST.map_classlib_core_op('add_I', $TYPE_OPS, 'add_I', [$RT_OBJ, $RT_OBJ, $RT_OBJ], $RT_OBJ, :tc);
1956
QAST::OperationsJAST.map_jvm_core_op('add_n', 'dadd', [$RT_NUM, $RT_NUM], $RT_NUM);
1957
QAST::OperationsJAST.map_jvm_core_op('sub_i', 'lsub', [$RT_INT, $RT_INT], $RT_INT);
1958
QAST::OperationsJAST.map_classlib_core_op('sub_I', $TYPE_OPS, 'sub_I', [$RT_OBJ, $RT_OBJ, $RT_OBJ], $RT_OBJ, :tc);
1959
QAST::OperationsJAST.map_jvm_core_op('sub_n', 'dsub', [$RT_NUM, $RT_NUM], $RT_NUM);
1960
QAST::OperationsJAST.map_jvm_core_op('mul_i', 'lmul', [$RT_INT, $RT_INT], $RT_INT);
1961
QAST::OperationsJAST.map_classlib_core_op('mul_I', $TYPE_OPS, 'mul_I', [$RT_OBJ, $RT_OBJ, $RT_OBJ], $RT_OBJ, :tc);
1962
QAST::OperationsJAST.map_jvm_core_op('mul_n', 'dmul', [$RT_NUM, $RT_NUM], $RT_NUM);
1963
QAST::OperationsJAST.map_jvm_core_op('div_i', 'ldiv', [$RT_INT, $RT_INT], $RT_INT);
1964
QAST::OperationsJAST.map_classlib_core_op('div_I', $TYPE_OPS, 'div_I', [$RT_OBJ, $RT_OBJ, $RT_OBJ], $RT_OBJ, :tc);
1965
QAST::OperationsJAST.map_classlib_core_op('div_In', $TYPE_OPS, 'div_In', [$RT_OBJ, $RT_OBJ], $RT_NUM, :tc);
1966
QAST::OperationsJAST.map_jvm_core_op('div_n', 'ddiv', [$RT_NUM, $RT_NUM], $RT_NUM);
1967
QAST::OperationsJAST.map_jvm_core_op('mod_i', 'lrem', [$RT_INT, $RT_INT], $RT_INT);
1968
QAST::OperationsJAST.map_classlib_core_op('mod_I', $TYPE_OPS, 'mod_I', [$RT_OBJ, $RT_OBJ, $RT_OBJ], $RT_OBJ, :tc);
1969
QAST::OperationsJAST.map_classlib_core_op('expmod_I', $TYPE_OPS, 'expmod_I', [$RT_OBJ, $RT_OBJ, $RT_OBJ, $RT_OBJ], $RT_OBJ, :tc);
1970
QAST::OperationsJAST.map_classlib_core_op('isprime_I', $TYPE_OPS, 'isprime_I', [$RT_OBJ, $RT_INT], $RT_INT, :tc);
1971
QAST::OperationsJAST.map_classlib_core_op('rand_n', $TYPE_OPS, 'rand_n', [$RT_NUM], $RT_NUM, :tc);
1972
QAST::OperationsJAST.map_classlib_core_op('srand', $TYPE_OPS, 'srand', [$RT_INT], $RT_INT, :tc);
1973
QAST::OperationsJAST.map_classlib_core_op('rand_I', $TYPE_OPS, 'rand_I', [$RT_OBJ, $RT_OBJ], $RT_OBJ, :tc);
1974
QAST::OperationsJAST.map_classlib_core_op('mod_n', $TYPE_OPS, 'mod_n', [$RT_NUM, $RT_NUM], $RT_NUM);
1975
QAST::OperationsJAST.map_classlib_core_op('pow_n', $TYPE_OPS, 'pow_n', [$RT_NUM, $RT_NUM], $RT_NUM);
1976
QAST::OperationsJAST.map_classlib_core_op('pow_I', $TYPE_OPS, 'pow_I', [$RT_OBJ, $RT_OBJ, $RT_OBJ, $RT_OBJ], $RT_OBJ, :tc);
1977
QAST::OperationsJAST.map_jvm_core_op('neg_i', 'lneg', [$RT_INT], $RT_INT);
1978
QAST::OperationsJAST.map_classlib_core_op('neg_I', $TYPE_OPS, 'neg_I', [$RT_OBJ, $RT_OBJ], $RT_OBJ, :tc);
1979
QAST::OperationsJAST.map_jvm_core_op('neg_n', 'dneg', [$RT_NUM], $RT_NUM);
1980
QAST::OperationsJAST.map_classlib_core_op('abs_i', $TYPE_MATH, 'abs', [$RT_INT], $RT_INT);
1981
QAST::OperationsJAST.map_classlib_core_op('abs_I', $TYPE_OPS, 'abs_I', [$RT_OBJ, $RT_OBJ], $RT_OBJ, :tc);
1982
QAST::OperationsJAST.map_classlib_core_op('abs_n', $TYPE_MATH, 'abs', [$RT_NUM], $RT_NUM);
1984
QAST::OperationsJAST.map_classlib_core_op('ceil_n', $TYPE_MATH, 'ceil', [$RT_NUM], $RT_NUM);
1985
QAST::OperationsJAST.map_classlib_core_op('floor_n', $TYPE_MATH, 'floor', [$RT_NUM], $RT_NUM);
1986
QAST::OperationsJAST.map_classlib_core_op('ln_n', $TYPE_MATH, 'log', [$RT_NUM], $RT_NUM);
1987
QAST::OperationsJAST.map_classlib_core_op('sqrt_n', $TYPE_MATH, 'sqrt', [$RT_NUM], $RT_NUM);
1988
QAST::OperationsJAST.map_classlib_core_op('log_n', $TYPE_MATH, 'log', [$RT_NUM], $RT_NUM);
1989
QAST::OperationsJAST.map_classlib_core_op('exp_n', $TYPE_MATH, 'exp', [$RT_NUM], $RT_NUM);
1990
QAST::OperationsJAST.map_classlib_core_op('isnanorinf', $TYPE_OPS, 'isnanorinf', [$RT_NUM], $RT_INT);
1991
QAST::OperationsJAST.map_classlib_core_op('inf', $TYPE_OPS, 'inf', [], $RT_NUM);
1992
QAST::OperationsJAST.map_classlib_core_op('neginf', $TYPE_OPS, 'neginf', [], $RT_NUM);
1993
QAST::OperationsJAST.map_classlib_core_op('nan', $TYPE_OPS, 'nan', [], $RT_NUM);
1994
QAST::OperationsJAST.map_classlib_core_op('radix', $TYPE_OPS, 'radix', [$RT_INT, $RT_STR, $RT_INT, $RT_INT], $RT_OBJ, :tc);
1995
QAST::OperationsJAST.map_classlib_core_op('radix_I', $TYPE_OPS, 'radix_I', [$RT_INT, $RT_STR, $RT_INT, $RT_INT, $RT_OBJ], $RT_OBJ, :tc);
1998
QAST::OperationsJAST.map_classlib_core_op('sin_n', $TYPE_MATH, 'sin', [$RT_NUM], $RT_NUM);
1999
QAST::OperationsJAST.map_classlib_core_op('asin_n', $TYPE_MATH, 'asin', [$RT_NUM], $RT_NUM);
2000
QAST::OperationsJAST.map_classlib_core_op('cos_n', $TYPE_MATH, 'cos', [$RT_NUM], $RT_NUM);
2001
QAST::OperationsJAST.map_classlib_core_op('acos_n', $TYPE_MATH, 'acos', [$RT_NUM], $RT_NUM);
2002
QAST::OperationsJAST.map_classlib_core_op('tan_n', $TYPE_MATH, 'tan', [$RT_NUM], $RT_NUM);
2003
QAST::OperationsJAST.map_classlib_core_op('atan_n', $TYPE_MATH, 'atan', [$RT_NUM], $RT_NUM);
2004
QAST::OperationsJAST.map_classlib_core_op('atan2_n', $TYPE_MATH, 'atan2', [$RT_NUM, $RT_NUM], $RT_NUM);
2005
QAST::OperationsJAST.map_classlib_core_op('sinh_n', $TYPE_MATH, 'sinh', [$RT_NUM], $RT_NUM);
2006
QAST::OperationsJAST.map_classlib_core_op('cosh_n', $TYPE_MATH, 'cosh', [$RT_NUM], $RT_NUM);
2007
QAST::OperationsJAST.map_classlib_core_op('tanh_n', $TYPE_MATH, 'tanh', [$RT_NUM], $RT_NUM);
2008
QAST::OperationsJAST.map_classlib_core_op('sec_n', $TYPE_OPS, 'sec_n', [$RT_NUM], $RT_NUM);
2009
QAST::OperationsJAST.map_classlib_core_op('asec_n', $TYPE_OPS, 'asec_n', [$RT_NUM], $RT_NUM);
2010
QAST::OperationsJAST.map_classlib_core_op('sech_n', $TYPE_OPS, 'sech_n', [$RT_NUM], $RT_NUM);
2012
# esoteric math opcodes
2013
QAST::OperationsJAST.map_classlib_core_op('gcd_i', $TYPE_OPS, 'gcd_i', [$RT_INT, $RT_INT], $RT_INT);
2014
QAST::OperationsJAST.map_classlib_core_op('gcd_I', $TYPE_OPS, 'gcd_I', [$RT_OBJ, $RT_OBJ, $RT_OBJ], $RT_OBJ, :tc);
2015
QAST::OperationsJAST.map_classlib_core_op('lcm_i', $TYPE_OPS, 'lcm_i', [$RT_INT, $RT_INT], $RT_INT);
2016
QAST::OperationsJAST.map_classlib_core_op('lcm_I', $TYPE_OPS, 'lcm_I', [$RT_OBJ, $RT_OBJ, $RT_OBJ], $RT_OBJ, :tc);
2018
# string bitwise ops
2019
QAST::OperationsJAST.map_classlib_core_op('bitor_s', $TYPE_OPS, 'bitor_s', [$RT_STR, $RT_STR], $RT_STR);
2020
QAST::OperationsJAST.map_classlib_core_op('bitxor_s', $TYPE_OPS, 'bitxor_s', [$RT_STR, $RT_STR], $RT_STR);
2021
QAST::OperationsJAST.map_classlib_core_op('bitand_s', $TYPE_OPS, 'bitand_s', [$RT_STR, $RT_STR], $RT_STR);
2024
QAST::OperationsJAST.map_classlib_core_op('chars', $TYPE_OPS, 'chars', [$RT_STR], $RT_INT);
2025
QAST::OperationsJAST.map_classlib_core_op('uc', $TYPE_OPS, 'uc', [$RT_STR], $RT_STR);
2026
QAST::OperationsJAST.map_classlib_core_op('lc', $TYPE_OPS, 'lc', [$RT_STR], $RT_STR);
2027
QAST::OperationsJAST.map_classlib_core_op('x', $TYPE_OPS, 'x', [$RT_STR, $RT_INT], $RT_STR);
2028
QAST::OperationsJAST.map_classlib_core_op('iscclass', $TYPE_OPS, 'iscclass', [$RT_INT, $RT_STR, $RT_INT], $RT_INT);
2029
QAST::OperationsJAST.map_classlib_core_op('concat', $TYPE_OPS, 'concat', [$RT_STR, $RT_STR], $RT_STR);
2030
QAST::OperationsJAST.map_classlib_core_op('chr', $TYPE_OPS, 'chr', [$RT_INT], $RT_STR, :tc);
2031
QAST::OperationsJAST.map_classlib_core_op('join', $TYPE_OPS, 'join', [$RT_STR, $RT_OBJ], $RT_STR, :tc);
2032
QAST::OperationsJAST.map_classlib_core_op('split', $TYPE_OPS, 'split', [$RT_STR, $RT_STR], $RT_OBJ, :tc);
2033
QAST::OperationsJAST.map_classlib_core_op('findcclass', $TYPE_OPS, 'findcclass', [$RT_INT, $RT_STR, $RT_INT, $RT_INT], $RT_INT);
2034
QAST::OperationsJAST.map_classlib_core_op('findnotcclass', $TYPE_OPS, 'findnotcclass', [$RT_INT, $RT_STR, $RT_INT, $RT_INT], $RT_INT);
2035
QAST::OperationsJAST.add_core_op('sprintf', -> $qastcomp, $op {
2036
my @operands := $op.list;
2043
QAST::SVal.new( :value('nqp') ),
2044
QAST::SVal.new( :value('sprintf') )
2049
QAST::OperationsJAST.add_core_op('sprintfdirectives', -> $qastcomp, $op {
2050
my @operands := $op.list;
2057
QAST::SVal.new( :value('nqp') ),
2058
QAST::SVal.new( :value('sprintfdirectives') )
2063
QAST::OperationsJAST.add_core_op('sprintfaddargumenthandler', -> $qastcomp, $op {
2064
my @operands := $op.list;
2071
QAST::SVal.new( :value('nqp') ),
2072
QAST::SVal.new( :value('sprintfaddargumenthandler') )
2077
QAST::OperationsJAST.map_classlib_core_op('escape', $TYPE_OPS, 'escape', [$RT_STR], $RT_STR);
2078
QAST::OperationsJAST.map_classlib_core_op('flip', $TYPE_OPS, 'flip', [$RT_STR], $RT_STR);
2079
QAST::OperationsJAST.map_classlib_core_op('replace', $TYPE_OPS, 'replace', [$RT_STR, $RT_INT, $RT_INT, $RT_STR], $RT_STR);
2081
# substr can take 2 or 3 args, so needs special handling.
2082
QAST::OperationsJAST.map_classlib_core_op('substr2', $TYPE_OPS, 'substr2', [$RT_STR, $RT_INT], $RT_STR);
2083
QAST::OperationsJAST.map_classlib_core_op('substr3', $TYPE_OPS, 'substr3', [$RT_STR, $RT_INT, $RT_INT], $RT_STR);
2084
QAST::OperationsJAST.add_core_op('substr', -> $qastcomp, $op {
2085
my @operands := $op.list;
2086
$qastcomp.as_jast(+@operands == 2
2087
?? QAST::Op.new( :op('substr2'), |@operands )
2088
!! QAST::Op.new( :op('substr3'), |@operands ));
2091
# ord can be on a the first char in a string or at a particular char.
2092
QAST::OperationsJAST.map_classlib_core_op('ordfirst', $TYPE_OPS, 'ordfirst', [$RT_STR], $RT_INT);
2093
QAST::OperationsJAST.map_classlib_core_op('ordat', $TYPE_OPS, 'ordat', [$RT_STR, $RT_INT], $RT_INT);
2094
QAST::OperationsJAST.add_core_op('ord', -> $qastcomp, $op {
2095
my @operands := $op.list;
2096
$qastcomp.as_jast(+@operands == 1
2097
?? QAST::Op.new( :op('ordfirst'), |@operands )
2098
!! QAST::Op.new( :op('ordat'), |@operands ));
2101
# index may or may not take a starting position
2102
QAST::OperationsJAST.map_classlib_core_op('indexfrom', $TYPE_OPS, 'indexfrom', [$RT_STR, $RT_STR, $RT_INT], $RT_INT);
2103
QAST::OperationsJAST.add_core_op('index', -> $qastcomp, $op {
2104
my @operands := $op.list;
2105
$qastcomp.as_jast(+@operands == 2
2106
?? QAST::Op.new( :op('indexfrom'), |@operands, QAST::IVal.new( :value(0)) )
2107
!! QAST::Op.new( :op('indexfrom'), |@operands ));
2110
# rindex may or may not take a starting position
2111
QAST::OperationsJAST.map_classlib_core_op('rindexfromend', $TYPE_OPS, 'rindexfromend', [$RT_STR, $RT_STR], $RT_INT);
2112
QAST::OperationsJAST.map_classlib_core_op('rindexfrom', $TYPE_OPS, 'rindexfrom', [$RT_STR, $RT_STR, $RT_INT], $RT_INT);
2113
QAST::OperationsJAST.add_core_op('rindex', -> $qastcomp, $op {
2114
my @operands := $op.list;
2115
$qastcomp.as_jast(+@operands == 2
2116
?? QAST::Op.new( :op('rindexfromend'), |@operands )
2117
!! QAST::Op.new( :op('rindexfrom'), |@operands ));
2120
QAST::OperationsJAST.map_classlib_core_op('codepointfromname', $TYPE_OPS, 'codepointfromname', [$RT_STR], $RT_INT);
2121
QAST::OperationsJAST.map_classlib_core_op('encode', $TYPE_OPS, 'encode', [$RT_STR, $RT_STR, $RT_OBJ], $RT_OBJ, :tc);
2122
QAST::OperationsJAST.map_classlib_core_op('decode', $TYPE_OPS, 'decode', [$RT_OBJ, $RT_STR], $RT_STR, :tc);
2124
# serialization context opcodes
2125
QAST::OperationsJAST.map_classlib_core_op('sha1', $TYPE_OPS, 'sha1', [$RT_STR], $RT_STR);
2126
QAST::OperationsJAST.map_classlib_core_op('createsc', $TYPE_OPS, 'createsc', [$RT_STR], $RT_OBJ, :tc);
2127
QAST::OperationsJAST.map_classlib_core_op('scsetobj', $TYPE_OPS, 'scsetobj', [$RT_OBJ, $RT_INT, $RT_OBJ], $RT_OBJ, :tc);
2128
QAST::OperationsJAST.map_classlib_core_op('scsetcode', $TYPE_OPS, 'scsetcode', [$RT_OBJ, $RT_INT, $RT_OBJ], $RT_OBJ, :tc);
2129
QAST::OperationsJAST.map_classlib_core_op('scgetobj', $TYPE_OPS, 'scgetobj', [$RT_OBJ, $RT_INT], $RT_OBJ, :tc);
2130
QAST::OperationsJAST.map_classlib_core_op('scgethandle', $TYPE_OPS, 'scgethandle', [$RT_OBJ], $RT_STR, :tc);
2131
QAST::OperationsJAST.map_classlib_core_op('scgetdesc', $TYPE_OPS, 'scgetdesc', [$RT_OBJ], $RT_STR, :tc);
2132
QAST::OperationsJAST.map_classlib_core_op('scgetobjidx', $TYPE_OPS, 'scgetobjidx', [$RT_OBJ, $RT_OBJ], $RT_INT, :tc);
2133
QAST::OperationsJAST.map_classlib_core_op('scsetdesc', $TYPE_OPS, 'scsetdesc', [$RT_OBJ, $RT_STR], $RT_STR, :tc);
2134
QAST::OperationsJAST.map_classlib_core_op('scobjcount', $TYPE_OPS, 'scobjcount', [$RT_OBJ], $RT_INT, :tc);
2135
QAST::OperationsJAST.map_classlib_core_op('setobjsc', $TYPE_OPS, 'setobjsc', [$RT_OBJ, $RT_OBJ], $RT_OBJ, :tc);
2136
QAST::OperationsJAST.map_classlib_core_op('getobjsc', $TYPE_OPS, 'getobjsc', [$RT_OBJ], $RT_OBJ, :tc);
2137
QAST::OperationsJAST.map_classlib_core_op('serialize', $TYPE_OPS, 'serialize', [$RT_OBJ, $RT_OBJ], $RT_STR, :tc);
2138
QAST::OperationsJAST.map_classlib_core_op('deserialize', $TYPE_OPS, 'deserialize', [$RT_STR, $RT_OBJ, $RT_OBJ, $RT_OBJ, $RT_OBJ], $RT_STR, :tc);
2139
QAST::OperationsJAST.map_classlib_core_op('wval', $TYPE_OPS, 'wval', [$RT_STR, $RT_INT], $RT_OBJ, :tc);
2140
QAST::OperationsJAST.map_classlib_core_op('scwbdisable', $TYPE_OPS, 'scwbdisable', [], $RT_INT, :tc);
2141
QAST::OperationsJAST.map_classlib_core_op('scwbenable', $TYPE_OPS, 'scwbenable', [], $RT_INT, :tc);
2142
QAST::OperationsJAST.map_classlib_core_op('pushcompsc', $TYPE_OPS, 'pushcompsc', [$RT_OBJ], $RT_OBJ, :tc);
2143
QAST::OperationsJAST.map_classlib_core_op('popcompsc', $TYPE_OPS, 'popcompsc', [], $RT_OBJ, :tc);
2146
QAST::OperationsJAST.map_classlib_core_op('bitor_i', $TYPE_OPS, 'bitor_i', [$RT_INT, $RT_INT], $RT_INT);
2147
QAST::OperationsJAST.map_classlib_core_op('bitor_I', $TYPE_OPS, 'bitor_I', [$RT_OBJ, $RT_OBJ, $RT_OBJ], $RT_OBJ, :tc);
2148
QAST::OperationsJAST.map_classlib_core_op('bitxor_i', $TYPE_OPS, 'bitxor_i', [$RT_INT, $RT_INT], $RT_INT);
2149
QAST::OperationsJAST.map_classlib_core_op('bitxor_I', $TYPE_OPS, 'bitxor_I', [$RT_OBJ, $RT_OBJ, $RT_OBJ], $RT_OBJ, :tc);
2150
QAST::OperationsJAST.map_classlib_core_op('bitand_i', $TYPE_OPS, 'bitand_i', [$RT_INT, $RT_INT], $RT_INT);
2151
QAST::OperationsJAST.map_classlib_core_op('bitand_I', $TYPE_OPS, 'bitand_I', [$RT_OBJ, $RT_OBJ, $RT_OBJ], $RT_OBJ, :tc);
2152
QAST::OperationsJAST.map_classlib_core_op('bitneg_i', $TYPE_OPS, 'bitneg_i', [$RT_INT], $RT_INT);
2153
QAST::OperationsJAST.map_classlib_core_op('bitneg_I', $TYPE_OPS, 'bitneg_I', [$RT_OBJ, $RT_OBJ], $RT_OBJ, :tc);
2154
QAST::OperationsJAST.map_classlib_core_op('bitshiftl_i', $TYPE_OPS, 'bitshiftl_i', [$RT_INT, $RT_INT], $RT_INT);
2155
QAST::OperationsJAST.map_classlib_core_op('bitshiftl_I', $TYPE_OPS, 'bitshiftl_I', [$RT_OBJ, $RT_INT, $RT_OBJ], $RT_OBJ, :tc);
2156
QAST::OperationsJAST.map_classlib_core_op('bitshiftr_i', $TYPE_OPS, 'bitshiftr_i', [$RT_INT, $RT_INT], $RT_INT);
2157
QAST::OperationsJAST.map_classlib_core_op('bitshiftr_I', $TYPE_OPS, 'bitshiftr_I', [$RT_OBJ, $RT_INT, $RT_OBJ], $RT_OBJ, :tc);
2159
# relational opcodes
2160
QAST::OperationsJAST.map_classlib_core_op('cmp_i', $TYPE_OPS, 'cmp_i', [$RT_INT, $RT_INT], $RT_INT);
2161
QAST::OperationsJAST.map_classlib_core_op('iseq_i', $TYPE_OPS, 'iseq_i', [$RT_INT, $RT_INT], $RT_INT);
2162
QAST::OperationsJAST.map_classlib_core_op('isne_i', $TYPE_OPS, 'isne_i', [$RT_INT, $RT_INT], $RT_INT);
2163
QAST::OperationsJAST.map_classlib_core_op('islt_i', $TYPE_OPS, 'islt_i', [$RT_INT, $RT_INT], $RT_INT);
2164
QAST::OperationsJAST.map_classlib_core_op('isle_i', $TYPE_OPS, 'isle_i', [$RT_INT, $RT_INT], $RT_INT);
2165
QAST::OperationsJAST.map_classlib_core_op('isgt_i', $TYPE_OPS, 'isgt_i', [$RT_INT, $RT_INT], $RT_INT);
2166
QAST::OperationsJAST.map_classlib_core_op('isge_i', $TYPE_OPS, 'isge_i', [$RT_INT, $RT_INT], $RT_INT);
2168
QAST::OperationsJAST.map_classlib_core_op('bool_I', $TYPE_OPS, 'bool_I', [$RT_OBJ], $RT_INT, :tc);
2169
QAST::OperationsJAST.map_classlib_core_op('cmp_I', $TYPE_OPS, 'cmp_I', [$RT_OBJ, $RT_OBJ], $RT_INT, :tc);
2170
QAST::OperationsJAST.map_classlib_core_op('iseq_I', $TYPE_OPS, 'iseq_I', [$RT_OBJ, $RT_OBJ], $RT_INT, :tc);
2171
QAST::OperationsJAST.map_classlib_core_op('isne_I', $TYPE_OPS, 'isne_I', [$RT_OBJ, $RT_OBJ], $RT_INT, :tc);
2172
QAST::OperationsJAST.map_classlib_core_op('islt_I', $TYPE_OPS, 'islt_I', [$RT_OBJ, $RT_OBJ], $RT_INT, :tc);
2173
QAST::OperationsJAST.map_classlib_core_op('isle_I', $TYPE_OPS, 'isle_I', [$RT_OBJ, $RT_OBJ], $RT_INT, :tc);
2174
QAST::OperationsJAST.map_classlib_core_op('isgt_I', $TYPE_OPS, 'isgt_I', [$RT_OBJ, $RT_OBJ], $RT_INT, :tc);
2175
QAST::OperationsJAST.map_classlib_core_op('isge_I', $TYPE_OPS, 'isge_I', [$RT_OBJ, $RT_OBJ], $RT_INT, :tc);
2177
QAST::OperationsJAST.map_classlib_core_op('cmp_n', $TYPE_OPS, 'cmp_n', [$RT_NUM, $RT_NUM], $RT_INT);
2178
QAST::OperationsJAST.map_classlib_core_op('iseq_n', $TYPE_OPS, 'iseq_n', [$RT_NUM, $RT_NUM], $RT_INT);
2179
QAST::OperationsJAST.map_classlib_core_op('isne_n', $TYPE_OPS, 'isne_n', [$RT_NUM, $RT_NUM], $RT_INT);
2180
QAST::OperationsJAST.map_classlib_core_op('islt_n', $TYPE_OPS, 'islt_n', [$RT_NUM, $RT_NUM], $RT_INT);
2181
QAST::OperationsJAST.map_classlib_core_op('isle_n', $TYPE_OPS, 'isle_n', [$RT_NUM, $RT_NUM], $RT_INT);
2182
QAST::OperationsJAST.map_classlib_core_op('isgt_n', $TYPE_OPS, 'isgt_n', [$RT_NUM, $RT_NUM], $RT_INT);
2183
QAST::OperationsJAST.map_classlib_core_op('isge_n', $TYPE_OPS, 'isge_n', [$RT_NUM, $RT_NUM], $RT_INT);
2185
QAST::OperationsJAST.map_classlib_core_op('cmp_s', $TYPE_OPS, 'cmp_s', [$RT_STR, $RT_STR], $RT_INT);
2186
QAST::OperationsJAST.map_classlib_core_op('iseq_s', $TYPE_OPS, 'iseq_s', [$RT_STR, $RT_STR], $RT_INT);
2187
QAST::OperationsJAST.map_classlib_core_op('isne_s', $TYPE_OPS, 'isne_s', [$RT_STR, $RT_STR], $RT_INT);
2188
QAST::OperationsJAST.map_classlib_core_op('islt_s', $TYPE_OPS, 'islt_s', [$RT_STR, $RT_STR], $RT_INT);
2189
QAST::OperationsJAST.map_classlib_core_op('isle_s', $TYPE_OPS, 'isle_s', [$RT_STR, $RT_STR], $RT_INT);
2190
QAST::OperationsJAST.map_classlib_core_op('isgt_s', $TYPE_OPS, 'isgt_s', [$RT_STR, $RT_STR], $RT_INT);
2191
QAST::OperationsJAST.map_classlib_core_op('isge_s', $TYPE_OPS, 'isge_s', [$RT_STR, $RT_STR], $RT_INT);
2194
QAST::OperationsJAST.map_classlib_core_op('fromstr_I', $TYPE_OPS, 'fromstr_I', [$RT_STR, $RT_OBJ], $RT_OBJ, :tc);
2195
QAST::OperationsJAST.map_classlib_core_op('tostr_I', $TYPE_OPS, 'tostr_I', [$RT_OBJ], $RT_STR, :tc);
2196
QAST::OperationsJAST.map_classlib_core_op('base_I', $TYPE_OPS, 'base_I', [$RT_OBJ, $RT_INT], $RT_STR, :tc);
2197
QAST::OperationsJAST.map_classlib_core_op('isbig_I', $TYPE_OPS, 'isbig_I', [$RT_OBJ], $RT_INT, :tc);
2198
QAST::OperationsJAST.map_classlib_core_op('fromnum_I', $TYPE_OPS, 'fromnum_I', [$RT_NUM, $RT_OBJ], $RT_OBJ, :tc);
2199
QAST::OperationsJAST.map_classlib_core_op('tonum_I', $TYPE_OPS, 'tonum_I', [$RT_OBJ], $RT_NUM, :tc);
2202
QAST::OperationsJAST.map_classlib_core_op('not_i', $TYPE_OPS, 'not_i', [$RT_INT], $RT_INT);
2205
QAST::OperationsJAST.map_classlib_core_op('atpos', $TYPE_OPS, 'atpos', [$RT_OBJ, $RT_INT], $RT_OBJ, :tc);
2206
QAST::OperationsJAST.map_classlib_core_op('atpos_i', $TYPE_OPS, 'atpos_i', [$RT_OBJ, $RT_INT], $RT_INT, :tc);
2207
QAST::OperationsJAST.map_classlib_core_op('atpos_n', $TYPE_OPS, 'atpos_n', [$RT_OBJ, $RT_INT], $RT_NUM, :tc);
2208
QAST::OperationsJAST.map_classlib_core_op('atpos_s', $TYPE_OPS, 'atpos_s', [$RT_OBJ, $RT_INT], $RT_STR, :tc);
2209
QAST::OperationsJAST.map_classlib_core_op('atkey', $TYPE_OPS, 'atkey', [$RT_OBJ, $RT_STR], $RT_OBJ, :tc);
2210
QAST::OperationsJAST.map_classlib_core_op('atkey_i', $TYPE_OPS, 'atkey_i', [$RT_OBJ, $RT_STR], $RT_INT, :tc);
2211
QAST::OperationsJAST.map_classlib_core_op('atkey_n', $TYPE_OPS, 'atkey_n', [$RT_OBJ, $RT_STR], $RT_NUM, :tc);
2212
QAST::OperationsJAST.map_classlib_core_op('atkey_s', $TYPE_OPS, 'atkey_s', [$RT_OBJ, $RT_STR], $RT_STR, :tc);
2213
QAST::OperationsJAST.map_classlib_core_op('bindpos', $TYPE_OPS, 'bindpos', [$RT_OBJ, $RT_INT, $RT_OBJ], $RT_OBJ, :tc);
2214
QAST::OperationsJAST.map_classlib_core_op('bindpos_i', $TYPE_OPS, 'bindpos_i', [$RT_OBJ, $RT_INT, $RT_INT], $RT_INT, :tc);
2215
QAST::OperationsJAST.map_classlib_core_op('bindpos_n', $TYPE_OPS, 'bindpos_n', [$RT_OBJ, $RT_INT, $RT_NUM], $RT_NUM, :tc);
2216
QAST::OperationsJAST.map_classlib_core_op('bindpos_s', $TYPE_OPS, 'bindpos_s', [$RT_OBJ, $RT_INT, $RT_STR], $RT_STR, :tc);
2217
QAST::OperationsJAST.map_classlib_core_op('bindkey', $TYPE_OPS, 'bindkey', [$RT_OBJ, $RT_STR, $RT_OBJ], $RT_OBJ, :tc);
2218
QAST::OperationsJAST.map_classlib_core_op('bindkey_i', $TYPE_OPS, 'bindkey_i', [$RT_OBJ, $RT_STR, $RT_INT], $RT_INT, :tc);
2219
QAST::OperationsJAST.map_classlib_core_op('bindkey_n', $TYPE_OPS, 'bindkey_n', [$RT_OBJ, $RT_STR, $RT_NUM], $RT_NUM, :tc);
2220
QAST::OperationsJAST.map_classlib_core_op('bindkey_s', $TYPE_OPS, 'bindkey_s', [$RT_OBJ, $RT_STR, $RT_STR], $RT_STR, :tc);
2221
QAST::OperationsJAST.map_classlib_core_op('existspos', $TYPE_OPS, 'existspos', [$RT_OBJ, $RT_INT], $RT_INT, :tc);
2222
QAST::OperationsJAST.map_classlib_core_op('existskey', $TYPE_OPS, 'existskey', [$RT_OBJ, $RT_STR], $RT_INT, :tc);
2223
QAST::OperationsJAST.map_classlib_core_op('deletekey', $TYPE_OPS, 'deletekey', [$RT_OBJ, $RT_STR], $RT_OBJ, :tc);
2224
QAST::OperationsJAST.map_classlib_core_op('elems', $TYPE_OPS, 'elems', [$RT_OBJ], $RT_INT, :tc);
2225
QAST::OperationsJAST.map_classlib_core_op('setelems', $TYPE_OPS, 'setelems', [$RT_OBJ, $RT_INT], $RT_OBJ, :tc);
2226
QAST::OperationsJAST.map_classlib_core_op('push', $TYPE_OPS, 'push', [$RT_OBJ, $RT_OBJ], $RT_OBJ, :tc);
2227
QAST::OperationsJAST.map_classlib_core_op('push_i', $TYPE_OPS, 'push_i', [$RT_OBJ, $RT_INT], $RT_INT, :tc);
2228
QAST::OperationsJAST.map_classlib_core_op('push_n', $TYPE_OPS, 'push_n', [$RT_OBJ, $RT_NUM], $RT_NUM, :tc);
2229
QAST::OperationsJAST.map_classlib_core_op('push_s', $TYPE_OPS, 'push_s', [$RT_OBJ, $RT_STR], $RT_STR, :tc);
2230
QAST::OperationsJAST.map_classlib_core_op('pop', $TYPE_OPS, 'pop', [$RT_OBJ], $RT_OBJ, :tc);
2231
QAST::OperationsJAST.map_classlib_core_op('pop_i', $TYPE_OPS, 'pop_i', [$RT_OBJ], $RT_INT, :tc);
2232
QAST::OperationsJAST.map_classlib_core_op('pop_n', $TYPE_OPS, 'pop_n', [$RT_OBJ], $RT_NUM, :tc);
2233
QAST::OperationsJAST.map_classlib_core_op('pop_s', $TYPE_OPS, 'pop_s', [$RT_OBJ], $RT_STR, :tc);
2234
QAST::OperationsJAST.map_classlib_core_op('unshift', $TYPE_OPS, 'unshift', [$RT_OBJ, $RT_OBJ], $RT_OBJ, :tc);
2235
QAST::OperationsJAST.map_classlib_core_op('unshift_i', $TYPE_OPS, 'unshift_i', [$RT_OBJ, $RT_INT], $RT_INT, :tc);
2236
QAST::OperationsJAST.map_classlib_core_op('unshift_n', $TYPE_OPS, 'unshift_n', [$RT_OBJ, $RT_NUM], $RT_NUM, :tc);
2237
QAST::OperationsJAST.map_classlib_core_op('unshift_s', $TYPE_OPS, 'unshift_s', [$RT_OBJ, $RT_STR], $RT_STR, :tc);
2238
QAST::OperationsJAST.map_classlib_core_op('shift', $TYPE_OPS, 'shift', [$RT_OBJ], $RT_OBJ, :tc);
2239
QAST::OperationsJAST.map_classlib_core_op('shift_i', $TYPE_OPS, 'shift_i', [$RT_OBJ], $RT_INT, :tc);
2240
QAST::OperationsJAST.map_classlib_core_op('shift_n', $TYPE_OPS, 'shift_n', [$RT_OBJ], $RT_NUM, :tc);
2241
QAST::OperationsJAST.map_classlib_core_op('shift_s', $TYPE_OPS, 'shift_s', [$RT_OBJ], $RT_STR, :tc);
2242
QAST::OperationsJAST.map_classlib_core_op('splice', $TYPE_OPS, 'splice', [$RT_OBJ, $RT_OBJ, $RT_INT, $RT_INT], $RT_OBJ, :tc);
2243
QAST::OperationsJAST.map_classlib_core_op('isint', $TYPE_OPS, 'isint', [$RT_OBJ], $RT_INT, :tc);
2244
QAST::OperationsJAST.map_classlib_core_op('isnum', $TYPE_OPS, 'isnum', [$RT_OBJ], $RT_INT, :tc);
2245
QAST::OperationsJAST.map_classlib_core_op('isstr', $TYPE_OPS, 'isstr', [$RT_OBJ], $RT_INT, :tc);
2246
QAST::OperationsJAST.map_classlib_core_op('islist', $TYPE_OPS, 'islist', [$RT_OBJ], $RT_INT, :tc);
2247
QAST::OperationsJAST.map_classlib_core_op('ishash', $TYPE_OPS, 'ishash', [$RT_OBJ], $RT_INT, :tc);
2248
QAST::OperationsJAST.map_classlib_core_op('iterator', $TYPE_OPS, 'iter', [$RT_OBJ], $RT_OBJ, :tc);
2249
QAST::OperationsJAST.map_classlib_core_op('iterkey_s', $TYPE_OPS, 'iterkey_s', [$RT_OBJ], $RT_STR, :tc);
2250
QAST::OperationsJAST.map_classlib_core_op('iterval', $TYPE_OPS, 'iterval', [$RT_OBJ], $RT_OBJ, :tc);
2254
QAST::OperationsJAST.map_jvm_core_op('null', 'aconst_null', [], $RT_OBJ);
2255
QAST::OperationsJAST.map_jvm_core_op('null_s', 'aconst_null', [], $RT_STR);
2256
QAST::OperationsJAST.map_classlib_core_op('what', $TYPE_OPS, 'what', [$RT_OBJ], $RT_OBJ, :tc);
2257
QAST::OperationsJAST.map_classlib_core_op('how', $TYPE_OPS, 'how', [$RT_OBJ], $RT_OBJ, :tc);
2258
QAST::OperationsJAST.map_classlib_core_op('who', $TYPE_OPS, 'who', [$RT_OBJ], $RT_OBJ, :tc);
2259
QAST::OperationsJAST.map_classlib_core_op('where', $TYPE_OPS, 'where', [$RT_OBJ], $RT_INT, :tc);
2260
QAST::OperationsJAST.map_classlib_core_op('findmethod', $TYPE_OPS, 'findmethod', [$RT_OBJ, $RT_STR], $RT_OBJ, :tc);
2261
QAST::OperationsJAST.map_classlib_core_op('setwho', $TYPE_OPS, 'setwho', [$RT_OBJ, $RT_OBJ], $RT_OBJ, :tc);
2262
QAST::OperationsJAST.map_classlib_core_op('rebless', $TYPE_OPS, 'rebless', [$RT_OBJ, $RT_OBJ], $RT_OBJ, :tc);
2263
QAST::OperationsJAST.map_classlib_core_op('knowhow', $TYPE_OPS, 'knowhow', [], $RT_OBJ, :tc);
2264
QAST::OperationsJAST.map_classlib_core_op('knowhowattr', $TYPE_OPS, 'knowhowattr', [], $RT_OBJ, :tc);
2265
QAST::OperationsJAST.map_classlib_core_op('bootint', $TYPE_OPS, 'bootint', [], $RT_OBJ, :tc);
2266
QAST::OperationsJAST.map_classlib_core_op('bootnum', $TYPE_OPS, 'bootnum', [], $RT_OBJ, :tc);
2267
QAST::OperationsJAST.map_classlib_core_op('bootstr', $TYPE_OPS, 'bootstr', [], $RT_OBJ, :tc);
2268
QAST::OperationsJAST.map_classlib_core_op('bootarray', $TYPE_OPS, 'bootarray', [], $RT_OBJ, :tc);
2269
QAST::OperationsJAST.map_classlib_core_op('bootintarray', $TYPE_OPS, 'bootintarray', [], $RT_OBJ, :tc);
2270
QAST::OperationsJAST.map_classlib_core_op('bootnumarray', $TYPE_OPS, 'bootnumarray', [], $RT_OBJ, :tc);
2271
QAST::OperationsJAST.map_classlib_core_op('bootstrarray', $TYPE_OPS, 'bootstrarray', [], $RT_OBJ, :tc);
2272
QAST::OperationsJAST.map_classlib_core_op('boothash', $TYPE_OPS, 'boothash', [], $RT_OBJ, :tc);
2273
QAST::OperationsJAST.map_classlib_core_op('hlllist', $TYPE_OPS, 'hlllist', [], $RT_OBJ, :tc);
2274
QAST::OperationsJAST.map_classlib_core_op('hllhash', $TYPE_OPS, 'hllhash', [], $RT_OBJ, :tc);
2275
QAST::OperationsJAST.map_classlib_core_op('create', $TYPE_OPS, 'create', [$RT_OBJ], $RT_OBJ, :tc);
2276
QAST::OperationsJAST.map_classlib_core_op('clone', $TYPE_OPS, 'clone', [$RT_OBJ], $RT_OBJ, :tc);
2277
QAST::OperationsJAST.map_classlib_core_op('isconcrete', $TYPE_OPS, 'isconcrete', [$RT_OBJ], $RT_INT, :tc);
2278
QAST::OperationsJAST.map_classlib_core_op('isnull', $TYPE_OPS, 'isnull', [$RT_OBJ], $RT_INT);
2279
QAST::OperationsJAST.map_classlib_core_op('isnull_s', $TYPE_OPS, 'isnull_s', [$RT_STR], $RT_INT);
2280
QAST::OperationsJAST.map_classlib_core_op('istrue', $TYPE_OPS, 'istrue', [$RT_OBJ], $RT_INT, :tc);
2281
QAST::OperationsJAST.map_classlib_core_op('isfalse', $TYPE_OPS, 'isfalse', [$RT_OBJ], $RT_INT, :tc);
2282
QAST::OperationsJAST.map_classlib_core_op('istype', $TYPE_OPS, 'istype', [$RT_OBJ, $RT_OBJ], $RT_INT, :tc);
2283
QAST::OperationsJAST.map_classlib_core_op('eqaddr', $TYPE_OPS, 'eqaddr', [$RT_OBJ, $RT_OBJ], $RT_INT);
2284
QAST::OperationsJAST.map_classlib_core_op('getattr', $TYPE_OPS, 'getattr', [$RT_OBJ, $RT_OBJ, $RT_STR], $RT_OBJ, :tc);
2285
QAST::OperationsJAST.map_classlib_core_op('getattr_i', $TYPE_OPS, 'getattr_i', [$RT_OBJ, $RT_OBJ, $RT_STR], $RT_INT, :tc);
2286
QAST::OperationsJAST.map_classlib_core_op('getattr_n', $TYPE_OPS, 'getattr_n', [$RT_OBJ, $RT_OBJ, $RT_STR], $RT_NUM, :tc);
2287
QAST::OperationsJAST.map_classlib_core_op('getattr_s', $TYPE_OPS, 'getattr_s', [$RT_OBJ, $RT_OBJ, $RT_STR], $RT_STR, :tc);
2288
QAST::OperationsJAST.map_classlib_core_op('bindattr', $TYPE_OPS, 'bindattr', [$RT_OBJ, $RT_OBJ, $RT_STR, $RT_OBJ], $RT_OBJ, :tc);
2289
QAST::OperationsJAST.map_classlib_core_op('bindattr_i', $TYPE_OPS, 'bindattr_i', [$RT_OBJ, $RT_OBJ, $RT_STR, $RT_INT], $RT_INT, :tc);
2290
QAST::OperationsJAST.map_classlib_core_op('bindattr_n', $TYPE_OPS, 'bindattr_n', [$RT_OBJ, $RT_OBJ, $RT_STR, $RT_NUM], $RT_NUM, :tc);
2291
QAST::OperationsJAST.map_classlib_core_op('bindattr_s', $TYPE_OPS, 'bindattr_s', [$RT_OBJ, $RT_OBJ, $RT_STR, $RT_STR], $RT_STR, :tc);
2292
QAST::OperationsJAST.map_classlib_core_op('attrinited', $TYPE_OPS, 'attrinited', [$RT_OBJ, $RT_OBJ, $RT_STR], $RT_INT, :tc);
2293
QAST::OperationsJAST.map_classlib_core_op('attrhintfor', $TYPE_OPS, 'attrhintfor', [$RT_OBJ, $RT_STR], $RT_INT, :tc);
2294
QAST::OperationsJAST.map_classlib_core_op('unbox_i', $TYPE_OPS, 'unbox_i', [$RT_OBJ], $RT_INT, :tc);
2295
QAST::OperationsJAST.map_classlib_core_op('unbox_n', $TYPE_OPS, 'unbox_n', [$RT_OBJ], $RT_NUM, :tc);
2296
QAST::OperationsJAST.map_classlib_core_op('unbox_s', $TYPE_OPS, 'unbox_s', [$RT_OBJ], $RT_STR, :tc);
2297
QAST::OperationsJAST.map_classlib_core_op('box_i', $TYPE_OPS, 'box_i', [$RT_INT, $RT_OBJ], $RT_OBJ, :tc);
2298
QAST::OperationsJAST.map_classlib_core_op('box_n', $TYPE_OPS, 'box_n', [$RT_NUM, $RT_OBJ], $RT_OBJ, :tc);
2299
QAST::OperationsJAST.map_classlib_core_op('box_s', $TYPE_OPS, 'box_s', [$RT_STR, $RT_OBJ], $RT_OBJ, :tc);
2300
QAST::OperationsJAST.map_classlib_core_op('can', $TYPE_OPS, 'can', [$RT_OBJ, $RT_STR], $RT_INT, :tc);
2301
QAST::OperationsJAST.map_classlib_core_op('reprname', $TYPE_OPS, 'reprname', [$RT_OBJ], $RT_STR);
2302
QAST::OperationsJAST.map_classlib_core_op('newtype', $TYPE_OPS, 'newtype', [$RT_OBJ, $RT_STR], $RT_OBJ, :tc);
2303
QAST::OperationsJAST.map_classlib_core_op('composetype', $TYPE_OPS, 'composetype', [$RT_OBJ, $RT_OBJ], $RT_OBJ, :tc);
2304
QAST::OperationsJAST.map_classlib_core_op('setboolspec', $TYPE_OPS, 'setboolspec', [$RT_OBJ, $RT_INT, $RT_OBJ], $RT_OBJ, :tc);
2305
QAST::OperationsJAST.map_classlib_core_op('setmethcache', $TYPE_OPS, 'setmethcache', [$RT_OBJ, $RT_OBJ], $RT_OBJ, :tc);
2306
QAST::OperationsJAST.map_classlib_core_op('setmethcacheauth', $TYPE_OPS, 'setmethcacheauth', [$RT_OBJ, $RT_INT], $RT_OBJ, :tc);
2307
QAST::OperationsJAST.map_classlib_core_op('settypecache', $TYPE_OPS, 'settypecache', [$RT_OBJ, $RT_OBJ], $RT_OBJ, :tc);
2308
QAST::OperationsJAST.map_classlib_core_op('settypecheckmode', $TYPE_OPS, 'settypecheckmode', [$RT_OBJ, $RT_INT], $RT_OBJ, :tc);
2309
QAST::OperationsJAST.map_classlib_core_op('objprimspec', $TYPE_OPS, 'objprimspec', [$RT_OBJ], $RT_INT, :tc);
2310
QAST::OperationsJAST.map_classlib_core_op('isinvokable', $TYPE_OPS, 'isinvokable', [$RT_OBJ], $RT_INT, :tc);
2311
QAST::OperationsJAST.map_classlib_core_op('setinvokespec', $TYPE_OPS, 'setinvokespec', [$RT_OBJ, $RT_OBJ, $RT_STR, $RT_OBJ], $RT_OBJ, :tc);
2314
# defined - overridden by HLL, but by default same as .DEFINITE.
2315
QAST::OperationsJAST.map_classlib_core_op('defined', $TYPE_OPS, 'isconcrete', [$RT_OBJ], $RT_INT, :tc);
2318
QAST::OperationsJAST.map_classlib_core_op('setcontspec', $TYPE_OPS, 'setcontspec', [$RT_OBJ, $RT_STR, $RT_OBJ], $RT_OBJ, :tc);
2319
QAST::OperationsJAST.map_classlib_core_op('iscont', $TYPE_OPS, 'iscont', [$RT_OBJ], $RT_INT);
2320
QAST::OperationsJAST.map_classlib_core_op('decont', $TYPE_OPS, 'decont', [$RT_OBJ], $RT_OBJ, :tc);
2321
QAST::OperationsJAST.map_classlib_core_op('assign', $TYPE_OPS, 'assign', [$RT_OBJ, $RT_OBJ], $RT_OBJ, :tc);
2322
QAST::OperationsJAST.map_classlib_core_op('assignunchecked', $TYPE_OPS, 'assignunchecked', [$RT_OBJ, $RT_OBJ], $RT_OBJ, :tc);
2324
# lexical related opcodes
2325
QAST::OperationsJAST.map_classlib_core_op('getlex', $TYPE_OPS, 'getlex', [$RT_STR], $RT_OBJ, :tc);
2326
QAST::OperationsJAST.map_classlib_core_op('getlex_i', $TYPE_OPS, 'getlex_i', [$RT_STR], $RT_INT, :tc);
2327
QAST::OperationsJAST.map_classlib_core_op('getlex_n', $TYPE_OPS, 'getlex_n', [$RT_STR], $RT_NUM, :tc);
2328
QAST::OperationsJAST.map_classlib_core_op('getlex_s', $TYPE_OPS, 'getlex_s', [$RT_STR], $RT_STR, :tc);
2329
QAST::OperationsJAST.map_classlib_core_op('bindlex', $TYPE_OPS, 'bindlex', [$RT_STR, $RT_OBJ], $RT_OBJ, :tc);
2330
QAST::OperationsJAST.map_classlib_core_op('bindlex_i', $TYPE_OPS, 'bindlex_i', [$RT_STR, $RT_INT], $RT_INT, :tc);
2331
QAST::OperationsJAST.map_classlib_core_op('bindlex_n', $TYPE_OPS, 'bindlex_n', [$RT_STR, $RT_NUM], $RT_NUM, :tc);
2332
QAST::OperationsJAST.map_classlib_core_op('bindlex_s', $TYPE_OPS, 'bindlex_s', [$RT_STR, $RT_STR], $RT_STR, :tc);
2333
QAST::OperationsJAST.map_classlib_core_op('getlexdyn', $TYPE_OPS, 'getlexdyn', [$RT_STR], $RT_OBJ, :tc);
2334
QAST::OperationsJAST.map_classlib_core_op('bindlexdyn', $TYPE_OPS, 'bindlexdyn', [$RT_STR, $RT_OBJ], $RT_OBJ, :tc);
2335
QAST::OperationsJAST.map_classlib_core_op('getlexcaller', $TYPE_OPS, 'getlexcaller', [$RT_STR], $RT_OBJ, :tc);
2336
QAST::OperationsJAST.map_classlib_core_op('getlexouter', $TYPE_OPS, 'getlexouter', [$RT_STR], $RT_OBJ, :tc);
2337
QAST::OperationsJAST.map_classlib_core_op('getlexrel', $TYPE_OPS, 'getlexrel', [$RT_OBJ, $RT_STR], $RT_OBJ, :tc);
2338
QAST::OperationsJAST.map_classlib_core_op('getlexreldyn', $TYPE_OPS, 'getlexreldyn', [$RT_OBJ, $RT_STR], $RT_OBJ, :tc);
2339
QAST::OperationsJAST.map_classlib_core_op('getlexrelcaller', $TYPE_OPS, 'getlexrelcaller', [$RT_OBJ, $RT_STR], $RT_OBJ, :tc);
2340
QAST::OperationsJAST.add_core_op('locallifetime', -> $qastcomp, $op {
2341
my @children := nqp::clone($op.list());
2343
nqp::die('locallifetime requires at least one child');
2345
my $arg := @children.shift();
2346
my $ta := $qastcomp.new_temp_allocator;
2348
$*BLOCK.tempify($ta, @children);
2349
my $res := $qastcomp.as_jast($op[0]);
2350
$*BLOCK.untempify($ta, @children);
2355
# code object related opcodes
2356
QAST::OperationsJAST.map_classlib_core_op('takeclosure', $TYPE_OPS, 'takeclosure', [$RT_OBJ], $RT_OBJ, :tc);
2357
QAST::OperationsJAST.map_classlib_core_op('getcodeobj', $TYPE_OPS, 'getcodeobj', [$RT_OBJ], $RT_OBJ, :tc);
2358
QAST::OperationsJAST.map_classlib_core_op('setcodeobj', $TYPE_OPS, 'setcodeobj', [$RT_OBJ, $RT_OBJ], $RT_OBJ, :tc);
2359
QAST::OperationsJAST.map_classlib_core_op('getcodename', $TYPE_OPS, 'getcodename', [$RT_OBJ], $RT_STR, :tc);
2360
QAST::OperationsJAST.map_classlib_core_op('setcodename', $TYPE_OPS, 'setcodename', [$RT_OBJ, $RT_STR], $RT_OBJ, :tc);
2361
QAST::OperationsJAST.map_classlib_core_op('getcodecuid', $TYPE_OPS, 'getcodecuid', [$RT_OBJ], $RT_STR, :tc);
2362
QAST::OperationsJAST.map_classlib_core_op('forceouterctx', $TYPE_OPS, 'forceouterctx', [$RT_OBJ, $RT_OBJ], $RT_OBJ, :tc);
2363
QAST::OperationsJAST.map_classlib_core_op('freshcoderef', $TYPE_OPS, 'freshcoderef', [$RT_OBJ], $RT_OBJ, :tc);
2364
QAST::OperationsJAST.map_classlib_core_op('markcodestatic', $TYPE_OPS, 'markcodestatic', [$RT_OBJ], $RT_OBJ, :tc);
2365
QAST::OperationsJAST.map_classlib_core_op('markcodestub', $TYPE_OPS, 'markcodestub', [$RT_OBJ], $RT_OBJ, :tc);
2366
QAST::OperationsJAST.map_classlib_core_op('getstaticcode', $TYPE_OPS, 'getstaticcode', [$RT_OBJ], $RT_OBJ, :tc);
2367
QAST::OperationsJAST.add_core_op('setdispatcher', -> $qastcomp, $op {
2369
nqp::die('setdispatcher requires one operand');
2371
my $il := JAST::InstructionList.new();
2372
my $dispres := $qastcomp.as_jast($op[0], :want($RT_OBJ));
2373
$il.append($dispres.jast);
2374
$*STACK.obtain($il, $dispres);
2376
$il.append($ALOAD_1);
2378
$il.append(JAST::Instruction.new( :op('putfield'), $TYPE_TC, 'currentDispatcher', $TYPE_SMO ));
2379
result($il, $RT_OBJ);
2381
QAST::OperationsJAST.add_core_op('takedispatcher', -> $qastcomp, $op {
2382
if +@($op) != 1 || !nqp::istype($op[0], QAST::SVal) {
2383
nqp::die('takedispatcher requires one string literal operand');
2385
my $name := $op[0].value;
2386
my $idx := $*BLOCK.lexical_type($name);
2387
unless nqp::defined($idx) {
2388
nqp::die('takedispatcher used with non-existing lexical');
2390
my $il := JAST::InstructionList.new();
2391
$il.append(JAST::PushIndex.new( :value($*BLOCK.lexical_idx($name)) ));
2392
$il.append($ALOAD_1);
2393
$il.append(JAST::Instruction.new( :op('invokestatic'),
2394
$TYPE_OPS, 'takedispatcher', 'V', 'I', $TYPE_TC ));
2395
result($il, $RT_VOID);
2397
QAST::OperationsJAST.add_core_op('setup_blv', -> $qastcomp, $op {
2398
if +@($op) != 1 || !nqp::ishash($op[0]) {
2399
nqp::die('setup_blv requires one hash operand');
2402
my $il := JAST::InstructionList.new();
2406
for $_.value -> @lex {
2407
nqp::push(@bits, @lex[0]);
2408
my $sc := nqp::getobjsc(@lex[1]);
2409
nqp::push(@bits, nqp::scgethandle($sc));
2410
nqp::push(@bits, ~nqp::scgetobjidx($sc, @lex[1]));
2411
nqp::push(@bits, ~@lex[2]);
2413
$il.append($ALOAD_0);
2414
$il.append($ALOAD_1);
2415
$il.append(JAST::PushIndex.new( :value($qastcomp.cuid_to_qbid($cuid)) ));
2416
$il.append(JAST::PushSVal.new( :value(nqp::join("\0", @bits)) ));
2417
$il.append(JAST::Instruction.new( :op('invokevirtual'),
2418
$TYPE_CU, 'setLexValues', 'Void', $TYPE_TC, 'I', $TYPE_STR ));
2421
$il.append($ACONST_NULL);
2422
result($il, $RT_OBJ)
2425
# language/compiler ops
2426
QAST::OperationsJAST.map_classlib_core_op('getcomp', $TYPE_OPS, 'getcomp', [$RT_STR], $RT_OBJ, :tc);
2427
QAST::OperationsJAST.map_classlib_core_op('bindcomp', $TYPE_OPS, 'bindcomp', [$RT_STR, $RT_OBJ], $RT_OBJ, :tc);
2428
QAST::OperationsJAST.map_classlib_core_op('getcurhllsym', $TYPE_OPS, 'getcurhllsym', [$RT_STR], $RT_OBJ, :tc);
2429
QAST::OperationsJAST.map_classlib_core_op('bindcurhllsym', $TYPE_OPS, 'bindcurhllsym', [$RT_STR, $RT_OBJ], $RT_OBJ, :tc);
2430
QAST::OperationsJAST.map_classlib_core_op('gethllsym', $TYPE_OPS, 'gethllsym', [$RT_STR, $RT_STR], $RT_OBJ, :tc);
2431
QAST::OperationsJAST.map_classlib_core_op('bindhllsym', $TYPE_OPS, 'bindhllsym', [$RT_STR, $RT_STR, $RT_OBJ], $RT_OBJ, :tc);
2432
QAST::OperationsJAST.map_classlib_core_op('sethllconfig', $TYPE_OPS, 'sethllconfig', [$RT_STR, $RT_OBJ], $RT_OBJ, :tc);
2433
QAST::OperationsJAST.map_classlib_core_op('loadbytecode', $TYPE_OPS, 'loadbytecode', [$RT_STR], $RT_STR, :tc);
2434
QAST::OperationsJAST.map_classlib_core_op('usecompilerhllconfig', $TYPE_OPS, 'usecompilerhllconfig', [], $RT_INT, :tc);
2435
QAST::OperationsJAST.map_classlib_core_op('usecompileehllconfig', $TYPE_OPS, 'usecompileehllconfig', [], $RT_INT, :tc);
2436
QAST::OperationsJAST.map_classlib_core_op('settypehll', $TYPE_OPS, 'settypehll', [$RT_OBJ, $RT_STR], $RT_OBJ, :tc);
2437
QAST::OperationsJAST.map_classlib_core_op('settypehllrole', $TYPE_OPS, 'settypehllrole', [$RT_OBJ, $RT_INT], $RT_OBJ, :tc);
2438
QAST::OperationsJAST.map_classlib_core_op('hllize', $TYPE_OPS, 'hllize', [$RT_OBJ], $RT_OBJ, :tc);
2439
QAST::OperationsJAST.map_classlib_core_op('hllizefor', $TYPE_OPS, 'hllizefor', [$RT_OBJ, $RT_STR], $RT_OBJ, :tc);
2441
# regex engine related opcodes
2442
QAST::OperationsJAST.map_classlib_core_op('nfafromstatelist', $TYPE_OPS, 'nfafromstatelist', [$RT_OBJ, $RT_OBJ], $RT_OBJ, :tc);
2443
QAST::OperationsJAST.map_classlib_core_op('nfatostatelist', $TYPE_OPS, 'nfatostatelist', [$RT_OBJ], $RT_OBJ, :tc);
2444
QAST::OperationsJAST.map_classlib_core_op('nfarunproto', $TYPE_OPS, 'nfarunproto', [$RT_OBJ, $RT_STR, $RT_INT], $RT_OBJ, :tc);
2445
QAST::OperationsJAST.map_classlib_core_op('nfarunalt', $TYPE_OPS, 'nfarunalt', [$RT_OBJ, $RT_STR, $RT_INT, $RT_OBJ, $RT_OBJ, $RT_OBJ], $RT_OBJ, :tc);
2447
# process related opcodes
2448
QAST::OperationsJAST.map_classlib_core_op('exit', $TYPE_OPS, 'exit', [$RT_INT], $RT_INT, :tc);
2449
QAST::OperationsJAST.map_classlib_core_op('sleep', $TYPE_OPS, 'sleep', [$RT_NUM], $RT_NUM);
2450
QAST::OperationsJAST.map_classlib_core_op('getenvhash', $TYPE_OPS, 'getenvhash', [], $RT_OBJ, :tc);
2451
QAST::OperationsJAST.map_classlib_core_op('getpid', $TYPE_OPS, 'getpid', [], $RT_INT, :tc);
2452
QAST::OperationsJAST.map_classlib_core_op('jvmgetproperties', $TYPE_OPS, 'jvmgetproperties', [], $RT_OBJ, :tc);
2454
# JVM-specific ops for compilation unit handling
2455
QAST::OperationsJAST.map_classlib_core_op('compilejastlines', $TYPE_OPS, 'compilejastlines', [$RT_OBJ], $RT_OBJ, :tc);
2456
QAST::OperationsJAST.map_classlib_core_op('compilejastlinestofile', $TYPE_OPS, 'compilejastlinestofile', [$RT_OBJ, $RT_STR], $RT_OBJ, :tc);
2457
QAST::OperationsJAST.map_classlib_core_op('loadcompunit', $TYPE_OPS, 'loadcompunit', [$RT_OBJ, $RT_INT], $RT_OBJ, :tc);
2458
QAST::OperationsJAST.map_classlib_core_op('iscompunit', $TYPE_OPS, 'iscompunit', [$RT_OBJ], $RT_INT, :tc);
2459
QAST::OperationsJAST.map_classlib_core_op('compunitmainline', $TYPE_OPS, 'compunitmainline', [$RT_OBJ], $RT_OBJ, :tc);
2460
QAST::OperationsJAST.map_classlib_core_op('compunitcodes', $TYPE_OPS, 'compunitcodes', [$RT_OBJ], $RT_OBJ, :tc);
2461
QAST::OperationsJAST.map_classlib_core_op('jvmclasspaths', $TYPE_OPS, 'jvmclasspaths', [], $RT_OBJ, :tc);
2463
# JVM-specific ops for continuation handling
2464
# The three main continuation ops are fudgy because they need to be called partially like subs
2465
QAST::OperationsJAST.map_classlib_core_op('continuationclone', $TYPE_OPS, 'continuationclone', [$RT_OBJ], $RT_OBJ, :tc);
2466
QAST::OperationsJAST.map_classlib_core_op('continuationreset', $TYPE_OPS, 'continuationreset', [$RT_OBJ, $RT_OBJ], $RT_OBJ, :tc, :cont);
2467
QAST::OperationsJAST.map_classlib_core_op('continuationcontrol', $TYPE_OPS, 'continuationcontrol', [$RT_INT, $RT_OBJ, $RT_OBJ], $RT_OBJ, :tc, :cont);
2468
QAST::OperationsJAST.map_classlib_core_op('continuationinvoke', $TYPE_OPS, 'continuationinvoke', [$RT_OBJ, $RT_OBJ], $RT_OBJ, :tc, :cont);
2471
QAST::OperationsJAST.map_classlib_core_op('jvmeqaddr', $TYPE_OPS, 'jvmeqaddr', [$RT_OBJ, $RT_OBJ], $RT_INT, :tc);
2472
QAST::OperationsJAST.map_classlib_core_op('jvmisnull', $TYPE_OPS, 'jvmisnull', [$RT_OBJ], $RT_INT, :tc);
2473
QAST::OperationsJAST.map_classlib_core_op('jvmbootinterop', $TYPE_OPS, 'jvmbootinterop', [], $RT_OBJ, :tc);
2474
QAST::OperationsJAST.map_classlib_core_op('jvmgetconfig', $TYPE_OPS, 'jvmgetconfig', [], $RT_OBJ, :tc);
2477
QAST::OperationsJAST.map_classlib_core_op('initnativecall', $TYPE_NATIVE_OPS, 'init', [], $RT_INT);
2478
QAST::OperationsJAST.map_classlib_core_op('buildnativecall', $TYPE_NATIVE_OPS, 'build', [$RT_OBJ, $RT_STR, $RT_STR, $RT_STR, $RT_OBJ, $RT_OBJ], $RT_INT, :tc);
2479
QAST::OperationsJAST.map_classlib_core_op('nativecall', $TYPE_NATIVE_OPS, 'call', [$RT_OBJ, $RT_OBJ, $RT_OBJ], $RT_OBJ, :tc);
2480
QAST::OperationsJAST.map_classlib_core_op('nativecallrefresh', $TYPE_NATIVE_OPS, 'refresh', [$RT_OBJ], $RT_INT);
2482
class QAST::CompilerJAST {
2483
# Responsible for handling issues around code references, building the
2484
# switch statement dispatcher, etc.
2485
my class CodeRefBuilder {
2488
has @!jastmeth_names;
2495
%!cuid_to_idx := {};
2496
@!jastmeth_names := [];
2499
%!callsite_map := {};
2502
method register_method($jastmeth, $cuid) {
2503
%!cuid_to_idx{$cuid} := $!cur_idx;
2504
nqp::push(@!jastmeth_names, $jastmeth.name);
2505
nqp::push(@!cuids, $cuid);
2506
$!cur_idx := $!cur_idx + 1;
2509
method know_cuid($cuid) {
2510
nqp::existskey(%!cuid_to_idx, $cuid)
2513
method cuid_to_idx($cuid) {
2514
nqp::existskey(%!cuid_to_idx, $cuid)
2515
?? %!cuid_to_idx{$cuid}
2516
!! nqp::die("Unknown CUID '$cuid'")
2519
method cuid_to_jastmethname($cuid) {
2520
@!jastmeth_names[self.cuid_to_idx($cuid)]
2523
method get_callsite_idx(@arg_types, @arg_names) {
2524
my $key := join("-", @arg_types) ~ ';' ~ join("\0", @arg_names);
2525
if nqp::existskey(%!callsite_map, $key) {
2526
return %!callsite_map{$key};
2529
my $idx := +@!callsites;
2530
nqp::push(@!callsites, [@arg_types, @arg_names]);
2531
%!callsite_map{$key} := $idx;
2540
method callsites() {
2541
my $csa := JAST::Method.new( :name('getCallSites'), :returns("[$TYPE_CSD"), :static(0) );
2544
$csa.append(JAST::PushIndex.new( :value(+@!callsites) ));
2545
$csa.append(JAST::Instruction.new( :op('anewarray'), $TYPE_CSD ));
2547
# All all the callsites
2549
for @!callsites -> @cs {
2550
my @cs_flags := @cs[0];
2551
my @cs_names := @cs[1];
2552
$csa.append($DUP); # Target array.
2553
$csa.append(JAST::PushIndex.new( :value($i++) )); # Index.
2554
$csa.append(JAST::Instruction.new( :op('new'), $TYPE_CSD ));
2556
$csa.append(JAST::PushIndex.new( :value(+@cs_flags) ));
2557
$csa.append(JAST::Instruction.new( :op('newarray'), 'Byte' ));
2561
$csa.append(JAST::PushIndex.new( :value($j++) ));
2562
$csa.append(JAST::PushIndex.new( :value($_) ));
2564
$csa.append($BASTORE);
2567
$csa.append(JAST::PushIndex.new( :value(+@cs_names) ));
2568
$csa.append(JAST::Instruction.new( :op('anewarray'), $TYPE_STR ));
2572
$csa.append(JAST::PushIndex.new( :value($j++) ));
2573
$csa.append(JAST::PushSVal.new( :value($_) ));
2574
$csa.append($AASTORE);
2578
$csa.append($ACONST_NULL);
2580
$csa.append(JAST::Instruction.new( :op('invokespecial'),
2581
$TYPE_CSD, '<init>', 'Void', '[Byte', "[$TYPE_STR"));
2582
$csa.append($AASTORE);
2585
# Return the array. Add method to class.
2586
$csa.append($ARETURN);
2587
$*JCLASS.add_method($csa);
2591
# Holds information about the QAST::Block we're currently compiling.
2592
my class BlockInfo {
2593
has $!qast; # The QAST::Block
2594
has $!outer; # Outer block's BlockInfo
2595
has @!params; # QAST::Var nodes of params
2596
has @!locals; # QAST::Var nodes of declared locals
2597
has @!lexicals; # QAST::Var nodes of declared lexicals
2598
has %!local_types; # Mapping of local registers to type names
2599
has %!lexical_types; # Mapping of lexical names to types
2600
has %!lexical_idxs; # Lexical indexes (but have to know type too)
2601
has @!lexical_names; # List by type of lexial name lists
2602
has int $!num_save_sites; # Count of points where a SaveStackException handler is needed
2603
has %!local2temp; # Maps local names to temporarization info
2605
method new($qast, $outer) {
2606
my $obj := nqp::create(self);
2607
$obj.BUILD($qast, $outer);
2611
method BUILD($qast, $outer) {
2614
@!params := nqp::list();
2615
@!locals := nqp::list();
2616
@!lexicals := nqp::list();
2617
%!local_types := nqp::hash();
2618
%!lexical_types := nqp::hash();
2619
%!lexical_idxs := nqp::hash();
2620
%!local2temp := nqp::hash();
2621
@!lexical_names := nqp::list([],[],[],[]);
2624
method add_param($var) {
2625
if $var.scope eq 'local' {
2626
self.add_local($var);
2629
self.add_lexical($var);
2631
@!params[+@!params] := $var;
2634
method add_lexical($var, :$is_static, :$is_cont, :$is_state) {
2635
self.register_lexical($var);
2636
if $is_static || $is_cont || $is_state {
2637
my %blv := %*BLOCK_LEX_VALUES;
2638
unless nqp::existskey(%blv, $!qast.cuid) {
2639
%blv{$!qast.cuid} := [];
2641
my $flags := $is_static ?? 0 !!
2643
nqp::push(%blv{$!qast.cuid}, [$var.name, $var.value, $flags]);
2645
@!lexicals[+@!lexicals] := $var;
2648
method add_local($var) {
2649
my $tempify := %!local2temp{$var.name};
2652
nqp::die("Local '"~$var.name~"' already declared");
2654
my int $type := rttype_from_typeobj($var.returns);
2655
my str $tch := typechar($type);
2656
my str $local := $tempify[1]."fresh_$tch"();
2657
$tempify[0] := [ $local, $type ];
2659
self.register_local($var);
2660
@!locals[+@!locals] := $var;
2664
method tempify($ta, @vars) {
2666
%!local2temp{$v} := [ '', $ta ];
2670
method untempify($ta, @vars) {
2672
nqp::deletekey(%!local2temp, $v);
2677
method register_lexical($var) {
2678
my $name := $var.name;
2679
my $type := rttype_from_typeobj($var.returns);
2680
if nqp::existskey(%!lexical_types, $name) {
2681
nqp::die("Lexical '$name' already declared");
2683
%!lexical_types{$name} := $type;
2684
%!lexical_idxs{$name} := +@!lexical_names[$type];
2685
nqp::push(@!lexical_names[$type], $name);
2688
method register_local($var) {
2689
my $name := $var.name;
2690
if nqp::existskey(%!local_types, $name) {
2691
nqp::die("Local '$name' already declared");
2693
%!local_types{$name} := rttype_from_typeobj($var.returns);
2696
method alloc_save_site() {
2697
my $index := $!num_save_sites;
2698
$!num_save_sites := $index + 1;
2702
method num_save_sites() { $!num_save_sites }
2704
method qast() { $!qast }
2705
method outer() { $!outer }
2706
method params() { @!params }
2707
method lexicals() { @!lexicals }
2708
method locals() { @!locals }
2710
method local_info($name) {
2711
my $tempify := %!local2temp{$name};
2712
$tempify ?? $tempify[0] !! [ $name, %!local_types{$name} ]
2714
method lexical_type($name) { %!lexical_types{$name} }
2715
method lexical_idx($name) { %!lexical_idxs{$name} }
2716
method lexical_names_by_type() { @!lexical_names }
2719
my class BlockTempAlloc {
2730
@!free_i ?? nqp::pop(@!free_i) !! "__TMP_I_" ~ $!cur_i++
2734
@!free_n ?? nqp::pop(@!free_n) !! "__TMP_N_" ~ $!cur_n++
2738
@!free_s ?? nqp::pop(@!free_s) !! "__TMP_S_" ~ $!cur_s++
2742
@!free_o ?? nqp::pop(@!free_o) !! "__TMP_O_" ~ $!cur_o++
2745
method release(@i, @n, @s, @o) {
2746
for @i { nqp::push(@!free_i, $_) }
2747
for @n { nqp::push(@!free_n, $_) }
2748
for @s { nqp::push(@!free_s, $_) }
2749
for @o { nqp::push(@!free_o, $_) }
2752
method add_temps_to_set($set) {
2753
sub temps($prefix, $n, $type) {
2756
nqp::push($set, ["$prefix$i", $type]);
2760
temps("__TMP_I_", $!cur_i, $RT_INT);
2761
temps("__TMP_N_", $!cur_n, $RT_NUM);
2762
temps("__TMP_S_", $!cur_s, $RT_STR);
2763
temps("__TMP_O_", $!cur_o, $RT_OBJ);
2767
my class StmtTempAlloc {
2774
my $al := $*BLOCK_TA.fresh_i();
2775
nqp::push(@!used_i, $al);
2780
my $al := $*BLOCK_TA.fresh_n();
2781
nqp::push(@!used_n, $al);
2786
my $al := $*BLOCK_TA.fresh_s();
2787
nqp::push(@!used_s, $al);
2792
my $al := $*BLOCK_TA.fresh_o();
2793
nqp::push(@!used_o, $al);
2798
$*BLOCK_TA.release(@!used_i, @!used_n, @!used_s, @!used_o)
2802
method new_temp_allocator() { StmtTempAlloc.new }
2804
method jast($source, :$classname!, *%adverbs) {
2805
# Wrap $source in a QAST::CompUnit if it's not already a viable root node.
2806
unless nqp::istype($source, QAST::CompUnit) {
2807
my $unit := $source;
2808
$unit := QAST::Block.new($unit) unless nqp::istype($unit, QAST::Block);
2809
$source := QAST::CompUnit.new(:hll(''), $unit);
2812
# Set up a JAST::Class that will hold all the blocks (which become Java
2813
# methods) that we shall compile.
2814
my $file := nqp::ifnull(nqp::getlexdyn('$?FILES'), "");
2815
my $*JCLASS := JAST::Class.new(
2817
:super('org.perl6.nqp.runtime.CompilationUnit'),
2821
# We'll also need to keep track of all the blocks we compile into Java
2822
# methods; the CodeRefBuilder takes care of that.
2823
my $*CODEREFS := CodeRefBuilder.new();
2825
# Now compile $source. By the end of this, the various data structures
2826
# set up above will be fully populated.
2827
self.as_jast($source);
2829
# Make various code-ref/dispatch related things.
2830
$*CODEREFS.jastify();
2832
# Finally, we hand back the finished class.
2836
# Tracks what is currently on the stack, and what things that were on the
2837
# stack have been spilled to temporaries and thus will need re-instating
2838
# at some point in the future.
2839
my class StackState {
2843
method push($result) {
2844
nqp::istype($result, Result)
2845
?? nqp::push(@!stack, $result)
2846
!! nqp::die("Can only push a Result onto the stack")
2849
method obtain($il, *@things) {
2851
if nqp::elems(@things) == 0 {
2852
nqp::die("Should not try to obtain zero stack elements");
2854
if nqp::elems(@!stack) < nqp::elems(@things) {
2855
nqp::die("Cannot obtain from empty or undersized stack");
2858
# See if the things we need are all on the stack.
2859
my int $sp := @!stack - +@things;
2862
my int $all_stack := 1;
2863
my int $all_local := 1;
2864
while $tp < +@things {
2865
unless nqp::istype(@things[$tp], Result) {
2866
nqp::die("Should only look up Result objects on the stack");
2868
unless nqp::eqaddr(@!stack[$sp], @things[$tp]) {
2872
if @!stack[$sp].local {
2881
# If they're all on the stack, easy.
2883
for @things { nqp::pop(@!stack) }
2887
# If they're all local, load them onto the stack. Also, we can
2888
# re-use the stack saving temporaries.
2891
my $local := $_.local;
2892
my $type := $_.type;
2893
$il.append(JAST::Instruction.new( :op(load_ins($type)), $local ));
2894
if nqp::islist(@!spill_locals[$type]) {
2895
nqp::push(@!spill_locals[$type], $local);
2898
@!spill_locals[$type] := [$local];
2905
# Mix of local and stack: just spill everything still on the
2906
# stack, and try again.
2908
self.spill_to_locals($il);
2909
return self.obtain($il, |@things);
2913
# Otherwise, bad access.
2914
nqp::die("Out-of-order access or re-use of stack items");
2917
# Spills the currnet stack contents to local variables.
2918
method spill_to_locals($il) {
2919
sub obtain_temp($type) {
2920
if $type == $RT_VOID {
2921
nqp::die("Cannot spill a stack containing a void");
2923
if @!spill_locals[$type] {
2924
nqp::pop(@!spill_locals[$type])
2931
my $sp := nqp::elems(@!stack);
2933
my $item := @!stack[$sp];
2934
unless $item.local {
2935
my $temp := obtain_temp($item.type);
2936
$il.append(JAST::Instruction.new( :op(store_ins($item.type)), $temp ));
2937
$item.set_local($temp);
2948
method unique($prefix = '') { $prefix ~ $serno++ }
2950
proto method as_jast($node, :$want) {
2952
if nqp::defined($want) {
2953
$*WANT := %WANTMAP{$want} // $want;
2954
if nqp::istype($node, QAST::Want) {
2955
self.coerce(self.as_jast(want($node, $*WANT)), $*WANT)
2958
self.coerce({*}, $*WANT)
2966
my %want_char := nqp::hash($RT_INT, 'I', $RT_NUM, 'N', $RT_STR, 'S');
2967
sub want($node, $type) {
2968
my @possibles := nqp::clone($node.list);
2969
my $best := @possibles.shift;
2970
my $char := %want_char{$type};
2971
for @possibles -> $sel, $ast {
2972
if nqp::index($sel, $char) >= 0 {
2979
method cuid_to_qbid(str $cuid) {
2980
my $map := %*CUID_TO_QBID;
2981
nqp::existskey($map, $cuid) ?? $map{$cuid} !! ($map{$cuid} := $*NEXT_QBID++);
2984
multi method as_jast(QAST::CompUnit $cu, :$want) {
2985
# A compilation-unit-wide source of IDs for handlers.
2994
# Should have a single child which is the outer block.
2995
if +@($cu) != 1 || !nqp::istype($cu[0], QAST::Block) {
2996
nqp::die("QAST::CompUnit should have one child that is a QAST::Block");
3000
my $*NEXT_QBID := 0;
3001
# Pre-seed to make sure that qbids correspond to serialization IDs
3002
my $*COMP_MODE := $cu.compilation_mode;
3004
for $cu.code_ref_blocks() -> $qblock {
3005
%*CUID_TO_QBID{$qblock.cuid} := $*NEXT_QBID++;
3009
# Hash mapping blocks with static lexicals to an array of arrays. Each
3010
# of the sub-arrays has the form [$name, $value, $flags], where flags
3011
# are 0 = static lex, 1 = container, 2 = state container.
3012
my %*BLOCK_LEX_VALUES;
3014
# Compile the block.
3015
my $block_jast := self.as_jast($cu[0]);
3017
# If we are in compilation mode, or have pre-deserialization or
3018
# post-deserialization tasks, handle those. Overall, the process
3019
# is to desugar this into simpler QAST nodes, then compile those.
3020
my @pre_des := $cu.pre_deserialize;
3021
my @post_des := $cu.post_deserialize;
3022
if %*BLOCK_LEX_VALUES {
3023
nqp::push(@post_des, QAST::Block.new(
3024
:blocktype('immediate'),
3025
QAST::Op.new( :op('setup_blv'), %*BLOCK_LEX_VALUES )
3028
if $*COMP_MODE || @pre_des || @post_des {
3029
# Create a block into which we'll install all of the other
3031
my $block := QAST::Block.new( :blocktype('raw') );
3033
# Add pre-deserialization tasks, each as a QAST::Stmt.
3035
$block.push(QAST::Stmt.new($_));
3038
# If we need to do deserialization, emit code for that.
3040
$block.push(self.deserialization_code($cu.sc(), $cu.code_ref_blocks(),
3041
$cu.repo_conflict_resolver()));
3044
# Add post-deserialization tasks.
3045
my $cur_pd_block := QAST::Block.new( :blocktype('immediate') );
3048
$cur_pd_block.push(QAST::Stmt.new($_));
3051
$block.push($cur_pd_block);
3052
$cur_pd_block := QAST::Block.new( :blocktype('immediate') );
3056
$block.push($cur_pd_block);
3058
# Compile to JAST and register this block as the deserialization
3060
self.as_jast($block);
3061
my $des_meth := JAST::Method.new( :name('deserializeQbid'), :returns('I'), :static(0) );
3062
$des_meth.append(JAST::PushIndex.new( :value(self.cuid_to_qbid($block.cuid)) ));
3063
$des_meth.append($IRETURN);
3064
$*JCLASS.add_method($des_meth);
3067
# Compile and include load-time logic, if any.
3068
if nqp::defined($cu.load) {
3069
my $load_block := QAST::Block.new(
3072
QAST::Op.new( :op('null') )
3074
self.as_jast($load_block);
3075
my $load_meth := JAST::Method.new( :name('loadQbid'), :returns('I'), :static(0) );
3076
$load_meth.append(JAST::PushIndex.new( :value(self.cuid_to_qbid($load_block.cuid)) ));
3077
$load_meth.append($IRETURN);
3078
$*JCLASS.add_method($load_meth);
3081
# Compile and include main-time logic, if any, and then add a Java
3082
# main that will lead to its invocation.
3083
if nqp::defined($cu.main) {
3084
my $main_block := QAST::Block.new(
3087
QAST::Op.new( :op('null') )
3089
self.as_jast($main_block);
3090
my $main_meth := JAST::Method.new( :name('main'), :returns('Void') );
3091
$main_meth.add_argument('argv', "[$TYPE_STR");
3092
$main_meth.append(JAST::PushCVal.new( :value('L' ~ $*JCLASS.name ~ ';') ));
3093
$main_meth.append(JAST::PushIndex.new( :value(self.cuid_to_qbid($main_block.cuid)) ));
3094
$main_meth.append($ALOAD_0);
3095
$main_meth.append(JAST::Instruction.new( :op('invokestatic'),
3096
$TYPE_CU, 'enterFromMain',
3097
'Void', 'Ljava/lang/Class;', 'I', "[$TYPE_STR"));
3098
$main_meth.append($RETURN);
3099
$*JCLASS.add_method($main_meth);
3100
my $entry_cuid_meth := JAST::Method.new( :name('entryQbid'), :returns('I'), :static(0) );
3101
$entry_cuid_meth.append(JAST::PushIndex.new( :value(self.cuid_to_qbid($main_block.cuid)) ));
3102
$entry_cuid_meth.append($IRETURN);
3103
$*JCLASS.add_method($entry_cuid_meth);
3106
# Add method that returns HLL name.
3107
my $hll_meth := JAST::Method.new( :name('hllName'), :returns($TYPE_STR), :static(0) );
3108
$hll_meth.append(JAST::PushSVal.new( :value($*HLL) ));
3109
$hll_meth.append($ARETURN);
3110
$*JCLASS.add_method($hll_meth);
3112
# Add method that returns the mainline block.
3113
my $mainline_meth := JAST::Method.new( :name('mainlineQbid'), :returns('I'), :static(0) );
3114
$mainline_meth.append(JAST::PushIndex.new( :value(self.cuid_to_qbid($cu[0].cuid)) ));
3115
$mainline_meth.append($IRETURN);
3116
$*JCLASS.add_method($mainline_meth);
3121
method deserialization_code($sc, @code_ref_blocks, $repo_conf_res) {
3123
my $sh := nqp::list_s();
3124
my $serialized := nqp::serialize($sc, $sh);
3126
if %*COMPILING<%?OPTIONS><target> eq 'jar' {
3127
$*JCLASS.serialized($serialized);
3128
$serialized := nqp::null();
3131
# Now it's serialized, pop this SC off the compiling SC stack.
3135
my $sh_ast := QAST::Op.new( :op('list_s') );
3136
my $sh_elems := nqp::elems($sh);
3138
while $i < $sh_elems {
3139
$sh_ast.push(nqp::isnull_s(nqp::atpos_s($sh, $i))
3140
?? QAST::Op.new( :op('null_s') )
3141
!! QAST::SVal.new( :value(nqp::atpos_s($sh, $i)) ));
3144
$sh_ast := QAST::Block.new( :blocktype('immediate'), $sh_ast );
3146
# Handle repossession conflict resolution code, if any.
3148
$repo_conf_res.push(QAST::Var.new( :name('conflicts'), :scope('local') ));
3151
$repo_conf_res := QAST::Op.new(
3153
QAST::SVal.new( :value('Repossession conflicts occurred during deserialization') )
3157
# Which of our methods need to be serialized?
3158
my $count_meth := JAST::Method.new( :name('serializedCodeRefCount'), :returns('I'), :static(0) );
3159
$count_meth.append(JAST::PushIndex.new( :value(+@code_ref_blocks) ));
3160
$count_meth.append($IRETURN);
3161
$*JCLASS.add_method($count_meth);
3163
# Overall deserialization QAST.
3167
QAST::Var.new( :name('cur_sc'), :scope('local'), :decl('var') ),
3168
QAST::Op.new( :op('createsc'), QAST::SVal.new( :value(nqp::scgethandle($sc)) ) )
3172
QAST::Var.new( :name('cur_sc'), :scope('local') ),
3173
QAST::SVal.new( :value(nqp::scgetdesc($sc)) )
3177
QAST::Var.new( :name('conflicts'), :scope('local'), :decl('var') ),
3178
QAST::Op.new( :op('list') )
3182
nqp::isnull($serialized) ?? QAST::Op.new( :op('null_s') ) !! QAST::SVal.new( :value($serialized) ),
3183
QAST::Var.new( :name('cur_sc'), :scope('local') ),
3185
QAST::Op.new( :op('null') ),
3186
QAST::Var.new( :name('conflicts'), :scope('local') )
3192
QAST::Var.new( :name('conflicts'), :scope('local') )
3199
multi method as_jast(QAST::Block $node, :$want) {
3200
# Do block compilation in a tested block, so we can produce a result based on
3201
# the containing block's stack.
3202
unless $*CODEREFS.know_cuid($node.cuid) {
3203
# Block gets fresh BlockInfo.
3205
my $outer := try $*BLOCK;
3206
my $block := BlockInfo.new($node, $outer);
3208
# This array will contain any catch/control exception handlers the
3209
# block gets. A contextual lets us track nesting of handlers.
3211
my $*HANDLER_IDX := 0;
3212
my &*REGISTER_UNWIND_HANDLER := sub ($outer, $category, :$ex_obj) {
3213
my $unwind := $*EH_IDX++;
3214
nqp::push(@handlers, [$unwind, $outer, $category,
3215
$ex_obj ?? $EX_UNWIND_OBJECT !! $EX_UNWIND_SIMPLE]);
3218
my &*REGISTER_BLOCK_HANDLER := sub ($outer, $category, $lexidx) {
3219
my $unwind := $*EH_IDX++;
3220
nqp::push(@handlers, [$unwind, $outer, $category,
3221
$EX_BLOCK, $lexidx]);
3225
# Create JAST method and register it with the block's compilation unit
3226
# unique ID and name. (Note, always void return here as return values
3227
# are handled out of band).
3228
my $*JMETH := JAST::Method.new( :name('qb_'~self.cuid_to_qbid($node.cuid)), :returns('Void'), :static(1) );
3229
$*JMETH.cr_name($node.name);
3230
$*JMETH.cr_cuid($node.cuid) unless $*COMP_MODE;
3231
$*CODEREFS.register_method($*JMETH, $node.cuid);
3233
# Set outer if we have one.
3234
if nqp::istype($outer, BlockInfo) {
3235
$*JMETH.cr_outer(self.cuid_to_qbid($outer.qast.cuid));
3237
$*JMETH.cr_outer(-1); # marks as coderef
3240
# Always take ThreadContext and callsite descriptor as arguments.
3241
$*JMETH.add_argument('cu', $TYPE_CU);
3242
$*JMETH.add_argument('tc', $TYPE_TC);
3243
$*JMETH.add_argument('cr', $TYPE_CR);
3244
$*JMETH.add_argument('csd', $TYPE_CSD);
3245
$*JMETH.add_argument('__args', "[$TYPE_OBJ");
3246
$*JMETH.add_argument('resume', $TYPE_RESUME);
3248
# Set up temporaries allocator.
3249
my $*BLOCK_TA := BlockTempAlloc.new();
3250
my $*TA := $*BLOCK_TA;
3252
# Compile method body.
3254
my $*STACK := StackState.new();
3256
my $*BLOCK := $block;
3258
$body := self.compile_all_the_stmts($node.list, :node($node.node));
3259
$*STACK.obtain(NQPMu, $body);
3262
# Stash lexical names.
3263
my @lex_names := $block.lexical_names_by_type();
3264
$*JMETH.cr_olex(@lex_names[$RT_OBJ]);
3265
$*JMETH.cr_ilex(@lex_names[$RT_INT]);
3266
$*JMETH.cr_nlex(@lex_names[$RT_NUM]);
3267
$*JMETH.cr_slex(@lex_names[$RT_STR]);
3269
# Unless we have custom args processing...
3270
my $il := JAST::InstructionList.new();
3271
unless $node.custom_args {
3272
# Analyze parameters to get count of required/optional and make sure
3274
my int $pos_required := 0;
3275
my int $pos_optional := 0;
3276
my int $pos_slurpy := 0;
3286
nqp::die("Optional positionals must come before all slurpy positionals");
3292
nqp::die("Required positionals must come before all optional positionals");
3295
nqp::die("Required positionals must come before all slurpy positionals");
3301
# Emit arity check instruction.
3302
$il.append(JAST::Instruction.new( :op('aload'), 'cf' ));
3303
$il.append(JAST::Instruction.new( :op('aload'), 'csd' ));
3304
$il.append(JAST::Instruction.new( :op('aload'), '__args' ));
3305
$il.append(JAST::PushIndex.new( :value($pos_required) ));
3306
$il.append(JAST::PushIndex.new( :value($pos_slurpy ?? -1 !! $pos_required + $pos_optional) ));
3307
$il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
3308
"checkarity", $TYPE_CSD, $TYPE_CF, $TYPE_CSD, "[$TYPE_OBJ", 'Integer', 'Integer' ));
3309
$il.append(JAST::Instruction.new( :op('astore'), 'csd' ));
3310
$il.append($ALOAD_1);
3311
$il.append(JAST::Instruction.new( :op('getfield'), $TYPE_TC, 'flatArgs', "[$TYPE_OBJ" ));
3312
$il.append(JAST::Instruction.new( :op('astore'), '__args' ));
3314
# Emit instructions to load each parameter.
3315
my int $param_idx := 0;
3320
$il.append($ALOAD_1);
3321
$il.append(JAST::Instruction.new( :op('aload'), 'cf' ));
3322
$il.append(JAST::Instruction.new( :op('aload'), 'csd' ));
3323
$il.append(JAST::Instruction.new( :op('aload'), '__args' ));
3325
$il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
3326
"namedslurpy", $TYPE_SMO, $TYPE_TC, $TYPE_CF, $TYPE_CSD, "[$TYPE_OBJ" ));
3329
$il.append(JAST::PushIndex.new( :value($pos_required + $pos_optional) ));
3330
$il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
3331
"posslurpy", $TYPE_SMO, $TYPE_TC, $TYPE_CF, $TYPE_CSD, "[$TYPE_OBJ", 'Integer' ));
3335
$type := rttype_from_typeobj($_.returns);
3336
my $jt := jtype($type);
3337
my $tc := typechar($type);
3338
my $opt := $_.default ?? "opt_" !! "";
3339
$il.append(JAST::Instruction.new( :op('aload'), 'cf' ));
3340
$il.append(JAST::Instruction.new( :op('aload'), 'csd' ));
3341
$il.append(JAST::Instruction.new( :op('aload'), '__args' ));
3343
$il.append(JAST::PushSVal.new( :value($_.named) ));
3344
$il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
3345
"namedparam_$opt$tc", $jt, $TYPE_CF, $TYPE_CSD, "[$TYPE_OBJ", $TYPE_STR ));
3348
$il.append(JAST::PushIndex.new( :value($param_idx) ));
3349
$il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
3350
"posparam_$opt$tc", $jt, $TYPE_CF, $TYPE_CSD, "[$TYPE_OBJ", 'Integer' ));
3353
my $lbl := JAST::Label.new( :name(self.unique("opt_param")) );
3354
$il.append($ALOAD_1);
3355
$il.append(JAST::Instruction.new( :op('getfield'), $TYPE_TC,
3356
'lastParameterExisted', "Integer" ));
3357
$il.append(JAST::Instruction.new( :op('ifne'), $lbl ));
3358
$il.append(pop_ins($type));
3360
my $*BLOCK := $block;
3361
my $default := self.as_jast($_.default, :want($type));
3362
$il.append($default.jast);
3363
$*STACK.obtain($il, $default);
3368
if $_.scope eq 'local' {
3369
$il.append(JAST::Instruction.new( :op(store_ins($type)), $_.name ));
3372
my $jtype := jtype($type);
3373
$il.append(JAST::Instruction.new( :op('aload'), 'cf' ));
3374
$il.append(JAST::PushIndex.new( :value($block.lexical_idx($_.name)) ));
3375
$il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
3376
'bindlex_' ~ typechar($type), $jtype, $jtype, $TYPE_CF, 'Integer' ));
3377
$il.append(pop_ins($type));
3383
# Add all the locals.
3385
for $block.locals { nqp::push(@all_locals, $block.local_info($_.name)) }
3386
$*BLOCK_TA.add_temps_to_set(@all_locals);
3391
$*JMETH.add_local($name, jtype($type));
3392
# use $*JMETH so it goes into the prelude section and doesn't clobber the assignments above...
3393
if $type == $RT_INT {
3394
$*JMETH.append(JAST::PushIVal.new( :value(0) ));
3396
elsif $type == $RT_NUM {
3397
$*JMETH.append(JAST::PushNVal.new( :value(0) ));
3400
$*JMETH.append($ACONST_NULL);
3402
$*JMETH.append(JAST::Instruction.new( :op(store_ins($type)), $name ));
3405
# Flatten handlers and store.
3406
my @flat_handlers := [nqp::elems(@handlers)];
3408
nqp::push(@flat_handlers, nqp::elems($_));
3409
for $_ { nqp::push(@flat_handlers, $_) }
3411
$*JMETH.cr_handlers(@flat_handlers);
3413
# Add method body JAST.
3414
$il.append($body.jast);
3416
# Store return value.
3417
$il.append(JAST::Instruction.new( :op('aload'), 'cf' ));
3418
$il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
3419
'return_' ~ typechar($body.type), 'Void', jtype($body.type), $TYPE_CF ));
3421
# make sure this goes before the body
3422
my int $save_sites := $block.num_save_sites;
3424
$*JMETH.append(JAST::Instruction.new( :op('aload'), 'resume' ));
3425
$*JMETH.append(JAST::Instruction.new( :op('ifnonnull'), JAST::Label.new( :name('RESUME') ) ));
3428
# Emit prelude (after checking for resume). This creates and stashes the CallFrame.
3429
$*JMETH.add_local('cf', $TYPE_CF);
3430
$*JMETH.append(JAST::Instruction.new( :op('new'), $TYPE_CF ));
3431
$*JMETH.append($DUP);
3432
$*JMETH.append($ALOAD_1);
3433
$*JMETH.append(JAST::Instruction.new( :op('aload'), 'cr' ));
3434
$*JMETH.append(JAST::Instruction.new( :op('invokespecial'), $TYPE_CF, '<init>',
3435
'Void', $TYPE_TC, $TYPE_CR ));
3436
$*JMETH.append(JAST::Instruction.new( :op('astore'), 'cf' ));
3438
# Emit the postlude. We catch any exceptions. Control ones are
3439
# rethrown, after calling CallFrame.leave. Others are passed on to
3440
# dieInternal. Finally, if there's no exception, we also need to
3441
# call CallFrame.leave.
3442
$il.append(JAST::Instruction.new( :op('aload'), 'cf' ));
3443
$il.append(JAST::Instruction.new( :op('invokevirtual'),
3444
$TYPE_CF, 'leave', 'Void' ));
3445
my $posthan := JAST::InstructionList.new();
3446
my $nclab := JAST::Label.new( :name('non_cont_ex') );
3447
$posthan.append($DUP);
3448
$posthan.append(JAST::Instruction.new( :op('instanceof'), $TYPE_EX_CONT ));
3449
$posthan.append(JAST::Instruction.new( :op('ifeq'), $nclab ));
3450
$posthan.append(JAST::Instruction.new( :op('aload'), 'cf' ));
3451
$posthan.append(JAST::Instruction.new( :op('invokevirtual'),
3452
$TYPE_CF, 'leave', 'Void' ));
3453
$posthan.append($ATHROW);
3454
$posthan.append($nclab);
3455
$posthan.append($ALOAD_1);
3456
$posthan.append($SWAP);
3457
$posthan.append(JAST::Instruction.new( :op('invokestatic'),
3458
$TYPE_EH, 'dieInternal', $TYPE_EX_RT, $TYPE_TC, $TYPE_THROWABLE ));
3459
$posthan.append($ATHROW);
3460
$*JMETH.append(JAST::TryCatch.new( :try($il), :catch($posthan),
3461
:type($TYPE_THROWABLE) ));
3462
$*JMETH.append($RETURN);
3465
my $saver := JAST::InstructionList.new;
3466
my $resume := JAST::InstructionList.new;
3468
$saver.append(JAST::Label.new( :name( 'SAVER' ) ));
3469
$saver.append($ACONST_NULL);
3472
# don't save/reload the resume pointer (could get messy :p) or the thread context (restored separately since we can change threads)
3473
# or the callframe (can also change)
3474
# also self doesn't get saved/restored, but that's OK because the resume handle is primed with it.
3475
for $*JMETH.arguments { nqp::push(@merged, $_) unless $_[0] eq 'resume' || $_[0] eq 'tc' || $_[0] eq 'cu' }
3476
for $*JMETH.locals { nqp::push(@merged, $_) unless $_[0] eq 'cf' }
3479
my int $ict := +@merged;
3481
$saver.append(JAST::PushIndex.new( :value(+@merged) ));
3482
$saver.append(JAST::Instruction.new( :op('anewarray'), $TYPE_OBJ ));
3484
$resume.append(JAST::Label.new( :name( 'RESUME' ) ));
3485
$resume.append(JAST::Instruction.new( :op('aload'), 'resume' ));
3486
$resume.append(JAST::Instruction.new( :op('getfield'), $TYPE_RESUME, 'tc', $TYPE_TC ));
3487
$resume.append(JAST::Instruction.new( :op('astore'), 'tc' ));
3488
$resume.append(JAST::Instruction.new( :op('aload'), 'resume' ));
3489
$resume.append(JAST::Instruction.new( :op('getfield'), $TYPE_RESUME, 'callFrame', $TYPE_CF ));
3490
$resume.append(JAST::Instruction.new( :op('astore'), 'cf' ));
3491
$resume.append(JAST::Instruction.new( :op('aload'), 'resume' ));
3492
$resume.append(JAST::Instruction.new( :op('getfield'), $TYPE_RESUME, 'saveSpace', '['~$TYPE_OBJ ));
3495
$saver.append($DUP);
3496
$saver.append(JAST::PushIndex.new( :value($i) ));
3498
$resume.append($DUP) if $i+1 != $ict; # assuming @merged > 0, which is guaranteed currently
3499
$resume.append(JAST::PushIndex.new( :value($i) ));
3500
$resume.append($AALOAD);
3503
# later, we might want to consolidate multiple doubles/longs into a single part of the save record
3504
if $_[1] eq 'Double' {
3505
$saver.append(JAST::Instruction.new( :op('dload'), $_[0] ));
3506
$saver.append(JAST::Instruction.new( :op('invokestatic'),
3507
$TYPE_DOUBLE, 'valueOf', $TYPE_DOUBLE, 'Double' ));
3509
$resume.append(JAST::Instruction.new( :op('checkcast'), $TYPE_DOUBLE ));
3510
$resume.append(JAST::Instruction.new( :op('invokevirtual'),
3511
$TYPE_DOUBLE, 'doubleValue', 'Double' ));
3512
$resume.append(JAST::Instruction.new( :op('dstore'), $_[0] ));
3514
elsif $_[1] eq 'Long' {
3515
$saver.append(JAST::Instruction.new( :op('lload'), $_[0] ));
3516
$saver.append(JAST::Instruction.new( :op('invokestatic'),
3517
$TYPE_LONG, 'valueOf', $TYPE_LONG, 'Long' ));
3519
$resume.append(JAST::Instruction.new( :op('checkcast'), $TYPE_LONG ));
3520
$resume.append(JAST::Instruction.new( :op('invokevirtual'),
3521
$TYPE_LONG, 'longValue', 'Long' ));
3522
$resume.append(JAST::Instruction.new( :op('lstore'), $_[0] ));
3525
$saver.append(JAST::Instruction.new( :op('aload'), $_[0] ));
3526
$resume.append(JAST::Instruction.new( :op('checkcast'), $_[1] ));
3527
$resume.append(JAST::Instruction.new( :op('astore'), $_[0] ));
3530
$saver.append($AASTORE);
3533
$saver.append(JAST::Instruction.new( :op('aload'), 'cf' ));
3534
$saver.append(JAST::Instruction.new( :op('invokevirtual'),
3535
$TYPE_EX_SAVE, 'pushFrame', $TYPE_EX_SAVE, "Integer", $TYPE_MH, '['~$TYPE_OBJ, $TYPE_CF ));
3536
$saver.append($ATHROW);
3538
$resume.append(JAST::Instruction.new( :op('aload'), 'resume' ));
3539
$resume.append(JAST::Instruction.new( :op('invokevirtual'),
3540
$TYPE_RESUME, 'resumeNextSave', 'Void' ));
3542
$resume.append(JAST::Instruction.new( :op('aload'), 'resume' ));
3543
$resume.append(JAST::Instruction.new( :op('getfield'), $TYPE_RESUME, 'resumePoint', 'Integer' ));
3544
my $switch := JAST::Instruction.new( :op('tableswitch'), JAST::Label.new( :name('reenter_0') ) );
3545
my int $labelno := 0;
3546
while ($labelno < $save_sites) {
3547
$switch.push( JAST::Label.new( :name('reenter_'~$labelno) ) );
3550
$resume.append($switch);
3552
$*JMETH.append($saver);
3553
$*JMETH.append($resume);
3556
# Set exit handler flag if needed.
3557
if $node.has_exit_handler {
3558
$*JMETH.has_exit_handler(1);
3561
# Finalize method and add it to the class.
3562
$*JCLASS.add_method($*JMETH);
3565
# Now go by block type for producing a result; also need to special-case
3566
# the top-level, where we need no result.
3567
if nqp::istype((try $*STACK), StackState) {
3568
my $blocktype := $node.blocktype;
3569
if $blocktype eq '' || $blocktype eq 'declaration' || $blocktype eq 'declaration_static' {
3570
return self.as_jast(QAST::BVal.new( :value($node) ));
3572
elsif $blocktype eq 'immediate' || $blocktype eq 'immediate_static' {
3573
# Can emit a direct JVM level call. First, get self, TC,
3574
# code ref, callsite descriptor and args (both empty) onto
3576
my $il := JAST::InstructionList.new();
3577
$*STACK.spill_to_locals($il);
3578
$il.append($ALOAD_0);
3579
$il.append($ALOAD_1);
3580
$il.append($ALOAD_0);
3581
$il.append(JAST::PushIndex.new( :value(self.cuid_to_qbid($node.cuid)) ));
3582
$il.append(JAST::Instruction.new( :op('invokevirtual'),
3583
$TYPE_CU, 'lookupCodeRef', $TYPE_CR, 'I' ));
3584
$il.append(JAST::Instruction.new( :op('getstatic'),
3585
$TYPE_OPS, 'emptyCallSite', $TYPE_CSD ));
3586
$il.append(JAST::Instruction.new( :op('getstatic'),
3587
$TYPE_OPS, 'emptyArgList', "[$TYPE_OBJ" ));
3588
$il.append($ACONST_NULL);
3590
# Emit the virtual call.
3591
$il.append(savesite(JAST::Instruction.new( :op('invokestatic'),
3592
'L' ~ $*JCLASS.name ~ ';',
3593
$*CODEREFS.cuid_to_jastmethname($node.cuid),
3594
'V', $TYPE_CU, $TYPE_TC, $TYPE_CR, $TYPE_CSD, "[$TYPE_OBJ", $TYPE_RESUME )));
3596
# Load result onto the stack, unless in void context.
3597
if $*WANT != $RT_VOID {
3598
$il.append(JAST::Instruction.new( :op('aload'), 'cf' ));
3599
$il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
3600
'result_' ~ typechar($RT_OBJ), jtype($RT_OBJ), $TYPE_CF ));
3601
return result($il, $RT_OBJ)
3604
return result($il, $RT_VOID)
3607
elsif $blocktype eq 'raw' {
3608
return self.as_jast(QAST::Op.new( :op('null') ));
3611
nqp::die("Unrecognized block type '$blocktype'");
3616
multi method as_jast(QAST::Stmts $node, :$want) {
3617
self.compile_all_the_stmts($node.list, $node.resultchild, :node($node.node))
3620
multi method as_jast(QAST::Stmt $node, :$want) {
3621
my $*TA := StmtTempAlloc.new();
3622
my $result := self.compile_all_the_stmts($node.list, $node.resultchild, :node($node.node));
3627
method compile_all_the_stmts(@stmts, $resultchild?, :$node) {
3629
# Empty statement list will break things.
3630
@stmts[0] := QAST::Op.new( :op('null') );
3633
my $il := JAST::InstructionList.new();
3635
my int $n := +@stmts;
3636
my $all_void := $*WANT == $RT_VOID;
3639
unless nqp::defined($resultchild) {
3640
$resultchild := $n - 1;
3645
my $node := $_.node;
3646
my $line := HLL::Compiler.lineof($node.orig(), $node.from(), :cache(1));
3647
$il.append(JAST::Annotation.new( :line($line) ));
3650
my $void := $all_void || $i != $resultchild;
3652
if nqp::istype($_, QAST::Want) {
3653
$_ := want($_, 'v');
3655
$last_res := self.as_jast($_, :want('v'));
3658
$last_res := self.as_jast($_);
3660
# variables with fallback can have side effects and cannot be elided
3661
$il.append($last_res.jast)
3662
unless $void && nqp::istype($_, QAST::Var) && !nqp::istype($_, QAST::VarWithFallback);
3663
$*STACK.obtain($il, $last_res);
3664
if $resultchild == $i && $resultchild != $n - 1 {
3665
$res_type := $last_res.type;
3666
$res_temp := fresh($res_type);
3667
$il.append(JAST::Instruction.new( :op(store_ins($res_type)), $res_temp ));
3672
$il.append(JAST::Instruction.new( :op(load_ins($res_type)), $res_temp ));
3673
result($il, $res_type)
3676
result($il, $last_res.type)
3680
multi method as_jast(QAST::Op $node, :$want) {
3686
$result := QAST::OperationsJAST.compile_op(self, $hll, $node);
3687
# CATCH { $err := $! }
3690
# nqp::die("Error while compiling op " ~ $node.op ~ ": $err");
3695
multi method as_jast(QAST::VM $node, :$want) {
3696
if $node.supports('jvm') {
3697
return nqp::defined($want)
3698
?? self.as_jast($node.alternative('jvm'), :$want)
3699
!! self.as_jast($node.alternative('jvm'));
3702
nqp::die("To compile on the JVM backend, QAST::VM must have an alternative 'jvm'" ~
3703
($node.supports('pirop')
3704
?? ' (got pirop = ' ~ $node.alternative('pirop') ~ ')'
3709
multi method as_jast(QAST::Var $node, :$want) {
3710
self.compile_var($node)
3713
multi method as_jast(QAST::VarWithFallback $node, :$want) {
3715
self.compile_var($node)
3718
my $var_res := self.compile_var($node);
3719
if ($var_res.type != $RT_OBJ) {
3723
my $il := JAST::InstructionList.new();
3724
$il.append($var_res.jast);
3725
$*STACK.spill_to_locals($il);
3726
$*STACK.obtain($il, $var_res);
3728
my $lbl := JAST::Label.new(:name($node.unique('fallback')));
3730
$il.append(JAST::Instruction.new( :op('ifnonnull'), $lbl ));
3732
my $fallback_res := self.as_jast($node.fallback, :want($RT_OBJ));
3734
$il.append($fallback_res.jast);
3735
$*STACK.obtain($il, $fallback_res);
3738
result($il, $RT_OBJ);
3742
method compile_var($node) {
3743
my $scope := $node.scope;
3744
my $decl := $node.decl;
3746
# Handle any declarations; after this, we fall through to the
3749
# If it's a parameter, add it to the things we should bind
3751
if $decl eq 'param' {
3752
if $scope eq 'local' || $scope eq 'lexical' {
3753
$*BLOCK.add_param($node);
3756
nqp::die("Parameter cannot have scope '$scope'; use 'local' or 'lexical'");
3759
elsif $decl eq 'var' {
3760
if $scope eq 'local' {
3761
$*BLOCK.add_local($node);
3763
elsif $scope eq 'lexical' {
3764
$*BLOCK.add_lexical($node);
3767
nqp::die("Cannot declare variable with scope '$scope'; use 'local' or 'lexical'");
3770
elsif $decl eq 'static' {
3771
if $scope ne 'lexical' {
3772
nqp::die("Can only use 'static' decl with scope 'lexical'");
3774
$*BLOCK.add_lexical($node, :is_static);
3776
elsif $decl eq 'contvar' {
3777
if $scope ne 'lexical' {
3778
nqp::die("Can only use 'contvar' decl with scope 'lexical'");
3780
$*BLOCK.add_lexical($node, :is_cont);
3782
elsif $decl eq 'statevar' {
3783
if $scope ne 'lexical' {
3784
nqp::die("Can only use 'statevar' decl with scope 'lexical'");
3786
$*BLOCK.add_lexical($node, :is_state);
3789
nqp::die("Don't understand declaration type '$decl'");
3793
# If there's no scope, figure it out from the symbol tables if
3795
my $name := $node.name;
3797
my $cur_block := $*BLOCK;
3798
while nqp::istype($cur_block, BlockInfo) {
3799
my %sym := $cur_block.qast.symbol($name);
3801
$scope := %sym<scope>;
3802
$cur_block := NQPMu;
3805
$cur_block := $cur_block.outer();
3809
nqp::die("No scope specified or locatable in the symbol table for '$name'");
3814
if $scope eq 'local' {
3815
my $info := $*BLOCK.local_info($name);
3816
my $type := $info[1];
3817
if nqp::defined($type) {
3818
my $il := JAST::InstructionList.new();
3820
my $valres := self.as_jast_clear_bindval($*BINDVAL, :want($type));
3821
$il.append($valres.jast);
3822
$*STACK.obtain($il, $valres);
3823
$il.append(dup_ins($type));
3824
$il.append(JAST::Instruction.new( :op(store_ins($type)), $info[0] ));
3827
$il.append(JAST::Instruction.new( :op(load_ins($type)), $info[0] ));
3829
return result($il, $type);
3832
nqp::die("Cannot reference undeclared local '$name'");
3835
elsif $scope eq 'lexical' || $scope eq 'contextual' {
3836
# See if it's declared in the local scope.
3838
my int $scopes := 0;
3839
my $type := $*BLOCK.lexical_type($name);
3841
if nqp::defined($type) {
3842
# It is. Nothing more to do.
3845
elsif $scope eq 'lexical' {
3846
# Try to find it in an outer scope.
3848
my $cur_block := $*BLOCK.outer();
3849
while nqp::istype($cur_block, BlockInfo) {
3850
if $cur_block.qast<DYN_COMP_WRAPPER> {
3851
$cur_block := NQPMu;
3854
$type := $cur_block.lexical_type($name);
3855
if nqp::defined($type) {
3857
$declarer := $cur_block;
3858
$cur_block := NQPMu;
3861
$cur_block := $cur_block.outer();
3868
# If we didn't find it anywhere, it musta been explicitly marked as
3869
# lexical. Take the type from .returns and rewrite to a more dynamic
3871
unless $local || $scopes {
3872
if $scope eq 'lexical' {
3873
$type := rttype_from_typeobj($node.returns);
3874
my $char := $type == $RT_OBJ ?? '' !! '_' ~ typechar($type);
3875
my $name_sval := QAST::SVal.new( :value($name) );
3876
return self.as_jast_clear_bindval($*BINDVAL
3877
?? QAST::Op.new( :op("bindlex$char"), $name_sval, $*BINDVAL )
3878
!! QAST::Op.new( :op("getlex$char"), $name_sval ));
3881
my $il := JAST::InstructionList.new();
3883
my $valres := self.as_jast_clear_bindval($*BINDVAL, :want($RT_OBJ));
3884
$il.append($valres.jast);
3885
$*STACK.obtain($il, $valres);
3887
$il.append(JAST::PushSVal.new( :value($name) ));
3888
$il.append($ALOAD_1);
3889
$il.append($*BINDVAL
3890
?? JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
3891
"bindlexdyn", $TYPE_SMO, $TYPE_SMO, $TYPE_STR, $TYPE_TC )
3892
!! JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
3893
"getlexdyn", $TYPE_SMO, $TYPE_STR, $TYPE_TC ));
3894
return result($il, $RT_OBJ);
3898
# Map type in a couple of ways we'll need.
3899
my $jtype := jtype($type);
3900
my $c := typechar($type);
3902
# If binding, always want the thing we're binding evaluated.
3903
my $il := JAST::InstructionList.new();
3905
my $valres := self.as_jast_clear_bindval($*BINDVAL, :want($type));
3906
$il.append($valres.jast);
3907
$*STACK.obtain($il, $valres);
3910
# If it's declared in the local scope...
3912
$il.append(JAST::Instruction.new( :op('aload'), 'cf' ));
3913
$il.append(JAST::PushIndex.new( :value($*BLOCK.lexical_idx($name)) ));
3914
$il.append($*BINDVAL
3915
?? JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
3916
"bindlex_$c", $jtype, $jtype, $TYPE_CF, 'Integer' )
3917
!! JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
3918
"getlex_$c", $jtype, $TYPE_CF, 'Integer' ));
3921
# Otherwise it must be a known number of scopes out.
3923
$il.append(JAST::Instruction.new( :op('aload'), 'cf' ));
3924
$il.append(JAST::PushIndex.new( :value($declarer.lexical_idx($name)) ));
3925
$il.append(JAST::PushIndex.new( :value($scopes) ));
3926
$il.append($*BINDVAL
3927
?? JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
3928
"bindlex_{$c}_si", $jtype, $jtype, $TYPE_CF, 'Integer', 'Integer' )
3929
!! JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
3930
"getlex_{$c}_si", $jtype, $TYPE_CF, 'Integer', 'Integer' ));
3933
return result($il, $type);
3935
elsif $scope eq 'attribute' {
3936
# Ensure we have object and class handle.
3937
my @args := $node.list;
3939
nqp::die("An attribute lookup needs an object and a class handle");
3942
# Compile object, handle and name.
3943
my $il := JAST::InstructionList.new();
3944
my $obj_res := self.as_jast_clear_bindval(@args[0], :want($RT_OBJ));
3945
$il.append($obj_res.jast);
3946
my $han_res := self.as_jast_clear_bindval(@args[1], :want($RT_OBJ));
3947
$il.append($han_res.jast);
3948
my $name_res := self.as_jast_clear_bindval(QAST::SVal.new( :value($name) ), :want($RT_STR));
3949
$il.append($name_res.jast);
3951
# Get lookup hint if possible.
3953
if @args[1].has_compile_time_value {
3954
$hint := nqp::attrhintfor(@args[1].compile_time_value, $name);
3957
# Go by whether it's a bind or lookup.
3958
my $type := rttype_from_typeobj($node.returns);
3959
my $jtype := jtype($type);
3960
my $suffix := $type == $RT_OBJ ?? '' !! '_' ~ typechar($type);
3962
my $val_res := self.as_jast_clear_bindval($*BINDVAL, :want($type));
3963
$il.append($val_res.jast);
3964
$*STACK.obtain($il, $obj_res, $han_res, $name_res, $val_res);
3965
$il.append(JAST::PushIVal.new( :value($hint) ));
3966
$il.append($ALOAD_1);
3967
$il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
3968
"bindattr$suffix", $jtype, $TYPE_SMO, $TYPE_SMO, $TYPE_STR, $jtype, 'Long', $TYPE_TC ));
3971
$*STACK.obtain($il, $obj_res, $han_res, $name_res);
3972
$il.append(JAST::PushIVal.new( :value($hint) ));
3973
$il.append($ALOAD_1);
3974
$il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
3975
"getattr$suffix", $jtype, $TYPE_SMO, $TYPE_SMO, $TYPE_STR, 'Long', $TYPE_TC ));
3978
return result($il, $type);
3980
elsif $scope eq 'positional' {
3981
return self.as_jast_clear_bindval($*BINDVAL
3982
?? QAST::Op.new( :op('positional_bind'), |$node.list, $*BINDVAL)
3983
!! QAST::Op.new( :op('positional_get'), |$node.list));
3985
elsif $scope eq 'associative' {
3986
return self.as_jast_clear_bindval($*BINDVAL
3987
?? QAST::Op.new( :op('associative_bind'), |$node.list, $*BINDVAL)
3988
!! QAST::Op.new( :op('associative_get'), |$node.list));
3991
nqp::die("QAST::Var with scope '$scope' NYI");
3995
method as_jast_clear_bindval($node, :$want) {
3997
nqp::defined($want) ?? self.as_jast($node, :$want) !! self.as_jast($node)
4000
method as_jast_in_handler($node, $*HANDLER_IDX, :$want) {
4002
nqp::defined($want) ?? self.as_jast($node, :$want) !! self.as_jast($node)
4005
multi method as_jast(QAST::Want $node, :$want) {
4006
# If we're not in a coercive context, take the default.
4007
self.as_jast($node[0])
4010
multi method as_jast(QAST::IVal $node, :$want) {
4011
result(JAST::PushIVal.new( :value($node.value) ), $RT_INT)
4014
multi method as_jast(QAST::NVal $node, :$want) {
4015
result(JAST::PushNVal.new( :value($node.value) ), $RT_NUM)
4018
multi method as_jast(QAST::SVal $node, :$want) {
4019
if nqp::chars($node.value) <= 65535 {
4020
result(JAST::PushSVal.new( :value($node.value) ), $RT_STR)
4024
my $value := $node.value;
4025
while nqp::chars($value) > 65535 {
4026
nqp::push(@chunks, nqp::substr($value, 0, 65535));
4027
$value := nqp::substr($value, 65535);
4029
nqp::push(@chunks, $value);
4030
my $il := JAST::InstructionList.new();
4031
$il.append(JAST::PushIndex.new( :value(nqp::elems(@chunks)) ));
4032
$il.append(JAST::Instruction.new( :op('anewarray'), $TYPE_STR ));
4036
$il.append(JAST::PushIndex.new( :value($i++) ));
4037
$il.append(JAST::PushSVal.new( :value($_) ));
4038
$il.append($AASTORE);
4040
$il.append(JAST::Instruction.new( :op('invokestatic'),
4041
$TYPE_OPS, 'join_literal', $TYPE_STR, "[$TYPE_STR" ));
4042
result($il, $RT_STR)
4046
multi method as_jast(QAST::BVal $node, :$want) {
4047
my $il := JAST::InstructionList.new();
4048
$il.append($ALOAD_0);
4049
$il.append(JAST::PushIndex.new( :value(self.cuid_to_qbid($node.value.cuid)) ));
4050
$il.append(JAST::Instruction.new( :op('invokevirtual'),
4051
$TYPE_CU, 'lookupCodeRef', $TYPE_CR, 'I' ));
4052
result($il, $RT_OBJ)
4055
multi method as_jast(QAST::WVal $node, :$want) {
4056
my $val := $node.value;
4057
my $sc := nqp::getobjsc($val);
4058
my $handle := nqp::scgethandle($sc);
4059
my $idx := nqp::scgetobjidx($sc, $val);
4060
my $il := JAST::InstructionList.new();
4061
$il.append(JAST::PushSVal.new( :value($handle) ));
4062
$il.append(JAST::PushIndex.new( :value($idx) ));
4063
$il.append($ALOAD_1);
4064
$il.append(JAST::InvokeDynamic.new(
4065
'wval_noa', $TYPE_SMO, [$TYPE_STR, 'I', $TYPE_TC],
4066
'org/perl6/nqp/runtime/IndyBootstrap', 'wval_noa'
4068
result($il, $RT_OBJ);
4071
method coerce($res, $desired) {
4072
my $got := $res.type;
4073
if $got == $desired {
4077
my $coerced := JAST::InstructionList.new();
4078
$coerced.append($res.jast);
4079
$*STACK.obtain($coerced, $res);
4080
$coerced.append(self.coercion($res, $desired));
4081
return result($coerced, $desired);
4085
# Expects that the value in need of coercing has already been
4086
# obtained (and thus is on the stack top). Produces instructions
4087
# to coerce it. Doesn't touch the stack tracking.
4088
method coercion($res, $desired) {
4089
my $il := JAST::InstructionList.new();
4090
my $got := $res.type;
4091
if $got == $desired {
4094
elsif $desired == $RT_VOID {
4095
$il.append(pop_ins($got));
4097
elsif $desired == $RT_OBJ {
4100
return QAST::OperationsJAST.box(self, $hll, $got);
4102
elsif $got == $RT_OBJ {
4105
return QAST::OperationsJAST.unbox(self, $hll, $desired);
4107
elsif $desired == $RT_INT {
4108
if $got == $RT_NUM {
4111
elsif $got == $RT_STR {
4112
$il.append(JAST::Instruction.new( :op('invokestatic'),
4113
$TYPE_OPS, 'coerce_s2i', 'Long', $TYPE_STR ));
4116
nqp::die("Unknown coercion case for int");
4119
elsif $desired == $RT_NUM {
4120
if $got == $RT_INT {
4123
elsif $got == $RT_STR {
4124
$il.append(JAST::Instruction.new( :op('invokestatic'),
4125
$TYPE_OPS, 'coerce_s2n', 'Double', $TYPE_STR ));
4128
nqp::die("Unknown coercion case for num");
4131
elsif $desired == $RT_STR {
4132
if $got == $RT_INT {
4133
$il.append(JAST::Instruction.new( :op('invokestatic'),
4134
$TYPE_OPS, 'coerce_i2s', $TYPE_STR, 'Long' ));
4136
elsif $got == $RT_NUM {
4137
$il.append(JAST::Instruction.new( :op('invokestatic'),
4138
$TYPE_OPS, 'coerce_n2s', $TYPE_STR, 'Double' ));
4141
nqp::die("Unknown coercion case for str");
4145
nqp::die("Coercion from type '$got' to '$desired' NYI");
4150
# Checks if we have reached the correct unwind target. If not, does a
4151
# rethrow of the handler. Assumes the exception is on the stack top,
4152
# and that we will not swallow it.
4153
my $unwind_lbl := 0;
4154
method unwind_check($il, $desired) {
4155
my $lbl_i := JAST::Label.new( :name('unwind_' ~ $unwind_lbl++) );
4156
my $lbl_c := JAST::Label.new( :name('unwind_' ~ $unwind_lbl++) );
4158
$il.append(JAST::Instruction.new( :op('getfield'), $TYPE_EX_UNWIND, 'unwindTarget', 'Long' ));
4159
$il.append(JAST::PushIVal.new( :value($desired) ));
4161
$il.append(JAST::Instruction.new( :op('ifeq'), $lbl_i ));
4162
$il.append($ATHROW);
4165
$il.append(JAST::Instruction.new( :op('getfield'), $TYPE_EX_UNWIND, 'unwindCompUnit', $TYPE_CU ));
4166
$il.append($ALOAD_0);
4167
$il.append(JAST::Instruction.new( :op('if_acmpeq'), $lbl_c ));
4168
$il.append($ATHROW);
4172
# Wraps a handler with code to set/clear the current handler.
4173
method delimit_handler($wrap_il, $outer, $inner) {
4174
my $il := JAST::InstructionList.new();
4175
$il.append(JAST::Instruction.new( :op('aload'), 'cf' ));
4176
$il.append(JAST::PushIVal.new( :value($inner) ));
4177
$il.append(JAST::Instruction.new( :op('putfield'), $TYPE_CF, 'curHandler', 'Long' ));
4178
$il.append($wrap_il);
4179
$il.append(JAST::Instruction.new( :op('aload'), 'cf' ));
4180
$il.append(JAST::PushIVal.new( :value($outer) ));
4181
$il.append(JAST::Instruction.new( :op('putfield'), $TYPE_CF, 'curHandler', 'Long' ));
4185
# Emits an exception throw.
4186
sub emit_throw($il, $type = 'Ljava/lang/Exception;') {
4187
$il.append(JAST::Instruction.new( :op('new'), $type ));
4189
$il.append(JAST::Instruction.new( :op('invokespecial'), $type, '<init>', 'Void' ));
4190
$il.append($ATHROW);
4193
multi method as_jast(QAST::Regex $node, :$want) {
4194
# build the list of (unique) locals we need
4196
my $prefix := self.unique('rx') ~ '_';
4197
my $reglist := nqp::split(' ', 'start o tgt s pos i off i eos i rep i cur o curclass o bstack o cstack o restart i itemp i altmarks o subcur o');
4199
my $reg := nqp::shift($reglist);
4200
my $tc := nqp::shift($reglist);
4201
my $type := $tc eq 'i' ?? int !! $tc eq 's' ?? str !! NQPMu;
4202
%*REG{$reg} := $prefix ~ $reg;
4203
$*BLOCK.add_local(QAST::Var.new( :name($prefix ~ $reg), :scope('local'), :returns($type), :decl('var') ));
4207
my $startlabel := JAST::Label.new( :name($prefix ~ 'start') );
4208
my $endlabel := JAST::Label.new( :name($prefix ~ 'end') );
4209
my $donelabel := JAST::Label.new( :name($prefix ~ 'done') );
4210
my $restartlabel := JAST::Label.new( :name($prefix ~ 'restart') );
4211
my $faillabel := JAST::Label.new( :name($prefix ~ 'fail') );
4212
my $jumplabel := JAST::Label.new( :name($prefix ~ 'jump' ));
4213
my $cutlabel := JAST::Label.new( :name($prefix ~ 'cut') );
4214
my $cstacklabel := JAST::Label.new( :name($prefix ~ 'cstack_done') );
4215
%*REG<fail> := $faillabel;
4217
# label to index mapping, for the jump table
4220
my &*REGISTER_MARK := sub ($label) {
4221
my $idx := nqp::elems(@mark_labels);
4222
nqp::push(@mark_labels, $label);
4223
%mark_lookup{$label.name} := $idx
4225
&*REGISTER_MARK($faillabel);
4228
my $il := JAST::InstructionList.new();
4229
my $csa_res := self.as_jast(QAST::Stmt.new(
4232
QAST::Var.new( :name(%*REG<start>), :scope('local') ),
4234
:op('callmethod'), :name('!cursor_start_all'),
4235
QAST::Var.new( :name('self'), :scope('local') )
4239
QAST::Var.new( :name("\$\xa2"), :scope('lexical') ),
4242
QAST::Var.new( :name(%*REG<cur>), :scope('local') ),
4245
QAST::Var.new( :name(%*REG<start>), :scope('local') ),
4246
QAST::IVal.new( :value(0) )
4250
QAST::Var.new( :name(%*REG<pos>), :scope('local'), :returns(int) ),
4255
QAST::Var.new( :name(%*REG<start>), :scope('local') ),
4256
QAST::IVal.new( :value(2) )
4260
QAST::Var.new( :name(%*REG<curclass>), :scope('local') ),
4263
QAST::Var.new( :name(%*REG<start>), :scope('local') ),
4264
QAST::IVal.new( :value(3) )
4268
QAST::Var.new( :name(%*REG<bstack>), :scope('local') ),
4271
QAST::Var.new( :name(%*REG<start>), :scope('local') ),
4272
QAST::IVal.new( :value(4) )
4276
QAST::Var.new( :name(%*REG<altmarks>), :scope('local') ),
4277
QAST::Op.new( :op('create'), QAST::Op.new( :op('bootintarray') ) )
4281
QAST::Var.new( :name(%*REG<restart>), :scope('local'), :returns(int) ),
4286
QAST::Var.new( :name(%*REG<start>), :scope('local') ),
4287
QAST::IVal.new( :value(5) )
4291
QAST::Var.new( :name(%*REG<tgt>), :scope('local'), :returns(str) ),
4296
QAST::Var.new( :name(%*REG<start>), :scope('local') ),
4297
QAST::IVal.new( :value(1) )
4299
$il.append($csa_res.jast);
4300
$*STACK.obtain($il, $csa_res);
4301
$il.append(JAST::Instruction.new( :op('invokestatic'),
4302
$TYPE_OPS, 'chars', 'Long', $TYPE_STR ));
4303
$il.append(JAST::Instruction.new( :op('lstore'), %*REG<eos> ));
4304
$il.append($ACONST_NULL);
4305
$il.append(JAST::Instruction.new( :op('astore'), %*REG<cstack> ));
4306
$il.append($ACONST_NULL);
4307
$il.append(JAST::Instruction.new( :op('astore'), %*REG<subcur> ));
4308
$il.append($IVAL_ZERO);
4309
$il.append(JAST::Instruction.new( :op('lstore'), %*REG<rep> ));
4310
$il.append(JAST::Instruction.new( :op('lload'), %*REG<restart> ));
4312
$il.append(JAST::Instruction.new( :op('ifne'), $restartlabel ));
4313
$il.append(JAST::Instruction.new( :op('lload'), %*REG<pos> ));
4314
$il.append(JAST::Instruction.new( :op('lload'), %*REG<eos> ));
4316
$il.append(JAST::Instruction.new( :op('ifgt'), %*REG<fail> ));
4318
# Compile the regex body itself; if we make it thorugh it, we go to
4319
# the end and are finished.
4320
$il.append(self.regex_jast($node));
4321
$il.append(JAST::Instruction.new( :op('goto'), $endlabel ));
4324
$il.append($restartlabel);
4325
$il.append(JAST::Instruction.new( :op('aload'), %*REG<cur> ));
4326
$il.append(JAST::Instruction.new( :op('aload'), %*REG<curclass> ));
4327
$il.append(JAST::PushSVal.new( :value('$!cstack') ));
4328
$il.append($ALOAD_1);
4329
$il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
4330
"getattr", $TYPE_SMO, $TYPE_SMO, $TYPE_SMO, $TYPE_STR, $TYPE_TC ));
4331
$il.append(JAST::Instruction.new( :op('astore'), %*REG<cstack> ));
4333
# Failure/backtrack handling. If no bstack, we're done.
4334
$il.append($faillabel);
4335
$il.append(JAST::Instruction.new( :op('aload'), %*REG<bstack> ));
4336
$il.append($ALOAD_1);
4337
$il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
4338
"elems", 'Long', $TYPE_SMO, $TYPE_TC ));
4340
$il.append(JAST::Instruction.new( :op('ifeq'), $donelabel ));
4342
# Otherwise, start handling the cstack, if it's not empty.
4343
# The setup done here is used when we backtrack into subrules.
4344
$il.append(JAST::Instruction.new( :op('aload'), %*REG<bstack> ));
4345
$il.append($ALOAD_1);
4346
$il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
4347
"pop_i", 'Long', $TYPE_SMO, $TYPE_TC ));
4348
$il.append(JAST::Instruction.new( :op('lstore'), %*REG<itemp> ));
4349
$il.append(JAST::Instruction.new( :op('aload'), %*REG<cstack> ));
4350
$il.append($ALOAD_1);
4351
$il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
4352
"islist", 'Long', $TYPE_SMO, $TYPE_TC ));
4354
$il.append(JAST::Instruction.new( :op('ifeq'), $cstacklabel ));
4355
$il.append(JAST::Instruction.new( :op('aload'), %*REG<cstack> ));
4356
$il.append($ALOAD_1);
4357
$il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
4358
"elems", 'Long', $TYPE_SMO, $TYPE_TC ));
4360
$il.append(JAST::Instruction.new( :op('ifeq'), $cstacklabel ));
4361
$il.append(JAST::Instruction.new( :op('aload'), %*REG<cstack> ));
4362
$il.append(JAST::Instruction.new( :op('lload'), %*REG<itemp> ));
4363
$il.append($IVAL_ONE);
4365
$il.append($ALOAD_1);
4366
$il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
4367
"atpos", $TYPE_SMO, $TYPE_SMO, 'Long', $TYPE_TC ));
4368
$il.append(JAST::Instruction.new( :op('astore'), %*REG<subcur> ));
4369
$il.append($cstacklabel);
4371
# Pop rep, pos and mark off the stack and store them.
4372
$il.append(JAST::Instruction.new( :op('aload'), %*REG<bstack> ));
4373
$il.append($ALOAD_1);
4376
$il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
4377
"pop_i", 'Long', $TYPE_SMO, $TYPE_TC ));
4378
$il.append(JAST::Instruction.new( :op('lstore'), %*REG<rep> ));
4379
$il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
4380
"pop_i", 'Long', $TYPE_SMO, $TYPE_TC ));
4381
$il.append(JAST::Instruction.new( :op('lstore'), %*REG<pos> ));
4382
$il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
4383
"pop_i", 'Long', $TYPE_SMO, $TYPE_TC ));
4384
$il.append(JAST::Instruction.new( :op('lstore'), %*REG<itemp> ));
4386
# Handle position and mark special cases.
4387
$il.append(JAST::Instruction.new( :op('lload'), %*REG<pos> ));
4388
$il.append($IVAL_MINUSONE);
4390
$il.append(JAST::Instruction.new( :op('iflt'), $donelabel ));
4391
$il.append(JAST::Instruction.new( :op('lload'), %*REG<pos> ));
4392
$il.append($IVAL_ZERO);
4394
$il.append(JAST::Instruction.new( :op('iflt'), $faillabel ));
4395
$il.append(JAST::Instruction.new( :op('lload'), %*REG<itemp> ));
4396
$il.append($IVAL_ZERO);
4398
$il.append(JAST::Instruction.new( :op('ifeq'), $faillabel ));
4400
# Backtrack the cursor stack
4401
$il.append(JAST::Instruction.new( :op('aload'), %*REG<cstack> ));
4402
$il.append(JAST::Instruction.new( :op('ifnull'), $jumplabel ));
4403
$il.append(JAST::Instruction.new( :op('aload'), %*REG<cstack> ));
4404
$il.append($ALOAD_1);
4405
$il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
4406
"islist", 'Long', $TYPE_SMO, $TYPE_TC ));
4408
$il.append(JAST::Instruction.new( :op('ifeq'), $jumplabel ));
4410
$il.append(JAST::Instruction.new( :op('aload'), %*REG<cstack> ));
4411
$il.append($ALOAD_1);
4412
$il.append(JAST::Instruction.new( :op('aload'), %*REG<bstack> ));
4413
$il.append($ALOAD_1);
4414
$il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
4415
"elems", 'Long', $TYPE_SMO, $TYPE_TC ));
4418
$il.append(JAST::Instruction.new( :op('ifeq'), $cutlabel ));
4420
$il.append($IVAL_ONE);
4422
$il.append(JAST::Instruction.new( :op('aload'), %*REG<bstack> ));
4423
$il.append($DUP_X2);
4425
$il.append($ALOAD_1);
4426
$il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
4427
"atpos_i", 'Long', $TYPE_SMO, 'Long', $TYPE_TC ));
4429
$il.append($cutlabel);
4430
$il.append(JAST::Instruction.new( :op('invokevirtual'), $TYPE_SMO,
4431
"set_elems", 'Void', $TYPE_TC, 'Long' ));
4433
# Otherwise, we need to jump to the appropriate label. Emit the
4435
$il.append($jumplabel);
4436
$il.append(JAST::Instruction.new( :op('lload'), %*REG<itemp> ));
4438
my $ts := JAST::Instruction.new( :op('tableswitch'), $donelabel );
4444
# If we make it to here, we failed to match.
4445
$il.append($donelabel);
4446
my $fail_res := self.as_jast(QAST::Op.new(
4447
:op('callmethod'), :name('!cursor_fail'),
4448
QAST::Var.new( :name(%*REG<cur>), :scope('local') )
4450
$il.append($fail_res.jast);
4451
$*STACK.obtain($il, $fail_res);
4454
# Evaluate to the curosr.
4455
$il.append($endlabel);
4456
$il.append(JAST::Instruction.new( :op('aload'), %*REG<cur> ));
4457
result($il, $RT_OBJ)
4460
method regex_jast($node) {
4461
my $rxtype := $node.rxtype() || 'concat';
4462
self."$rxtype"($node);
4467
return self.altseq($node);
4470
# Calculate all the branches to try, which populates the bstack
4471
# with the options. Then immediately fail to start iterating it.
4472
my $prefix := self.unique('alt') ~ '_';
4473
my $endlabel := JAST::Label.new( :name($prefix ~ 'end') );
4474
my $il_marks := JAST::InstructionList.new();
4475
my $il_alts := JAST::InstructionList.new();
4476
$il_marks.append(JAST::Instruction.new( :op('aload'), %*REG<altmarks> ));
4477
$il_marks.append($ALOAD_1);
4478
$il_marks.append($IVAL_ZERO);
4479
$il_marks.append(JAST::Instruction.new( :op('invokevirtual'), $TYPE_SMO,
4480
"set_elems", 'Void', $TYPE_TC, 'Long' ));
4482
my $mark_endlabel := &*REGISTER_MARK($endlabel);
4483
self.regex_mark($il_alts, $mark_endlabel,
4487
my $altmeth := QAST::Op.new(
4488
:op('callmethod'), :name('!alt'),
4489
QAST::Var.new( :name(%*REG<cur>), :scope('local') ),
4490
QAST::Var.new( :name(%*REG<pos>), :scope('local'), :returns(int) ),
4491
QAST::SVal.new( :value($node.name) ),
4492
QAST::Var.new( :name(%*REG<altmarks>), :scope('local') )
4494
my $altres := self.as_jast($altmeth, :want($RT_VOID));
4495
$il_alts.append($altres.jast);
4496
$*STACK.obtain($il_alts, $altres);
4497
$il_alts.append(JAST::Instruction.new( :op('goto'), %*REG<fail> ));
4499
# Emit all the possible alternations.
4501
my $iter := nqp::iterator($node.list);
4503
my $altlabel := JAST::Label.new( :name($prefix ~ $altcount) );
4504
my $ajast := self.regex_jast(nqp::shift($iter));
4505
$il_alts.append($altlabel);
4506
$il_alts.append($ajast);
4507
$il_alts.append(JAST::Instruction.new( :op('goto'), $endlabel ));
4508
my $altmark := &*REGISTER_MARK($altlabel);
4509
$il_marks.append(JAST::Instruction.new( :op('aload'), %*REG<altmarks> ));
4510
$il_marks.append(JAST::PushIVal.new( :value($altmark) ));
4511
$il_marks.append($ALOAD_1);
4512
$il_marks.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS, 'push_i',
4513
'Long', $TYPE_SMO, 'Long', $TYPE_TC ));
4514
$il_marks.append($POP2);
4518
$il_alts.append($endlabel);
4519
self.regex_commit($il_alts, $mark_endlabel) if $node.backtrack eq 'r';
4521
my $il := JAST::InstructionList.new();
4522
$il.append($il_marks);
4523
$il.append($il_alts);
4527
method altseq($node) {
4528
my $il := JAST::InstructionList.new();
4529
my $prefix := self.unique('alt') ~ '_';
4531
my $iter := nqp::iterator($node.list);
4532
my $endlabel := JAST::Label.new( :name($prefix ~ 'end') );
4533
my $altlabel := JAST::Label.new( :name($prefix ~ $altcount) );
4534
my $ajast := self.regex_jast(nqp::shift($iter));
4536
$il.append($altlabel);
4538
$altlabel := JAST::Label.new( :name($prefix ~ $altcount) );
4539
my $mark := &*REGISTER_MARK($altlabel);
4540
self.regex_mark($il, $mark,
4541
JAST::Instruction.new( :op('lload'), %*REG<pos> ),
4544
$il.append(JAST::Instruction.new( :op('goto'), $endlabel ));
4545
$ajast := self.regex_jast(nqp::shift($iter));
4547
$il.append($altlabel);
4549
$il.append($endlabel);
4553
method anchor($node) {
4554
my $il := JAST::InstructionList.new();
4555
my $subtype := $node.subtype;
4556
my $donelabel := JAST::Label.new( :name(self.unique('rxanchor') ~ '_done') );
4557
if $subtype eq 'bos' {
4558
$il.append(JAST::Instruction.new( :op('lload'), %*REG<pos> ));
4560
$il.append(JAST::Instruction.new( :op('ifne'), %*REG<fail> ));
4562
elsif $subtype eq 'eos' {
4563
$il.append(JAST::Instruction.new( :op('lload'), %*REG<pos> ));
4564
$il.append(JAST::Instruction.new( :op('lload'), %*REG<eos> ));
4566
$il.append(JAST::Instruction.new( :op('iflt'), %*REG<fail> ));
4568
elsif $subtype eq 'lwb' {
4569
$il.append(JAST::Instruction.new( :op('lload'), %*REG<pos> ));
4570
$il.append(JAST::Instruction.new( :op('lload'), %*REG<eos> ));
4572
$il.append(JAST::Instruction.new( :op('ifge'), %*REG<fail> ));
4574
$il.append(JAST::PushIVal.new( :value(nqp::const::CCLASS_WORD) ));
4575
$il.append(JAST::Instruction.new( :op('aload'), %*REG<tgt> ));
4576
$il.append(JAST::Instruction.new( :op('lload'), %*REG<pos> ));
4577
$il.append(JAST::Instruction.new( :op('invokestatic'),
4578
$TYPE_OPS, 'iscclass', 'Long', 'Long', $TYPE_STR, 'Long' ));
4580
$il.append(JAST::Instruction.new( :op('ifeq'), %*REG<fail> ));
4582
$il.append(JAST::PushIVal.new( :value(nqp::const::CCLASS_WORD) ));
4583
$il.append(JAST::Instruction.new( :op('aload'), %*REG<tgt> ));
4584
$il.append(JAST::Instruction.new( :op('lload'), %*REG<pos> ));
4585
$il.append($IVAL_ONE);
4587
$il.append(JAST::Instruction.new( :op('invokestatic'),
4588
$TYPE_OPS, 'iscclass', 'Long', 'Long', $TYPE_STR, 'Long' ));
4590
$il.append(JAST::Instruction.new( :op('ifne'), %*REG<fail> ));
4592
elsif $subtype eq 'rwb' {
4593
$il.append(JAST::Instruction.new( :op('lload'), %*REG<pos> ));
4594
$il.append($IVAL_ZERO);
4596
$il.append(JAST::Instruction.new( :op('ifle'), %*REG<fail> ));
4598
$il.append(JAST::PushIVal.new( :value(nqp::const::CCLASS_WORD) ));
4599
$il.append(JAST::Instruction.new( :op('aload'), %*REG<tgt> ));
4600
$il.append(JAST::Instruction.new( :op('lload'), %*REG<pos> ));
4601
$il.append(JAST::Instruction.new( :op('invokestatic'),
4602
$TYPE_OPS, 'iscclass', 'Long', 'Long', $TYPE_STR, 'Long' ));
4604
$il.append(JAST::Instruction.new( :op('ifne'), %*REG<fail> ));
4606
$il.append(JAST::PushIVal.new( :value(nqp::const::CCLASS_WORD) ));
4607
$il.append(JAST::Instruction.new( :op('aload'), %*REG<tgt> ));
4608
$il.append(JAST::Instruction.new( :op('lload'), %*REG<pos> ));
4609
$il.append($IVAL_ONE);
4611
$il.append(JAST::Instruction.new( :op('invokestatic'),
4612
$TYPE_OPS, 'iscclass', 'Long', 'Long', $TYPE_STR, 'Long' ));
4614
$il.append(JAST::Instruction.new( :op('ifeq'), %*REG<fail> ));
4616
elsif $subtype eq 'bol' {
4617
$il.append(JAST::Instruction.new( :op('lload'), %*REG<pos> ));
4619
$il.append(JAST::Instruction.new( :op('ifeq'), $donelabel ));
4621
$il.append(JAST::Instruction.new( :op('lload'), %*REG<pos> ));
4622
$il.append(JAST::Instruction.new( :op('lload'), %*REG<eos> ));
4624
$il.append(JAST::Instruction.new( :op('ifge'), %*REG<fail> ));
4626
$il.append(JAST::PushIVal.new( :value(nqp::const::CCLASS_NEWLINE) ));
4627
$il.append(JAST::Instruction.new( :op('aload'), %*REG<tgt> ));
4628
$il.append(JAST::Instruction.new( :op('lload'), %*REG<pos> ));
4629
$il.append($IVAL_ONE);
4631
$il.append(JAST::Instruction.new( :op('invokestatic'),
4632
$TYPE_OPS, 'iscclass', 'Long', 'Long', $TYPE_STR, 'Long' ));
4634
$il.append(JAST::Instruction.new( :op('ifeq'), %*REG<fail> ));
4636
$il.append($donelabel);
4638
elsif $subtype eq 'eol' {
4639
$il.append(JAST::PushIVal.new( :value(nqp::const::CCLASS_NEWLINE) ));
4640
$il.append(JAST::Instruction.new( :op('aload'), %*REG<tgt> ));
4641
$il.append(JAST::Instruction.new( :op('lload'), %*REG<pos> ));
4642
$il.append(JAST::Instruction.new( :op('invokestatic'),
4643
$TYPE_OPS, 'iscclass', 'Long', 'Long', $TYPE_STR, 'Long' ));
4645
$il.append(JAST::Instruction.new( :op('ifne'), $donelabel ));
4647
$il.append(JAST::Instruction.new( :op('lload'), %*REG<pos> ));
4648
$il.append(JAST::Instruction.new( :op('lload'), %*REG<eos> ));
4650
$il.append(JAST::Instruction.new( :op('ifne'), %*REG<fail> ));
4652
$il.append(JAST::Instruction.new( :op('lload'), %*REG<pos> ));
4654
$il.append(JAST::Instruction.new( :op('ifeq'), $donelabel ));
4656
$il.append(JAST::PushIVal.new( :value(nqp::const::CCLASS_NEWLINE) ));
4657
$il.append(JAST::Instruction.new( :op('aload'), %*REG<tgt> ));
4658
$il.append(JAST::Instruction.new( :op('lload'), %*REG<pos> ));
4659
$il.append($IVAL_ONE);
4661
$il.append(JAST::Instruction.new( :op('invokestatic'),
4662
$TYPE_OPS, 'iscclass', 'Long', 'Long', $TYPE_STR, 'Long' ));
4664
$il.append(JAST::Instruction.new( :op('ifne'), %*REG<fail> ));
4666
$il.append($donelabel);
4668
elsif $subtype eq 'fail' {
4669
$il.append(JAST::Instruction.new( :op('goto'), %*REG<fail> ));
4675
method concat($node) {
4676
my $il := JAST::InstructionList.new();
4678
$il.append(self.regex_jast($_))
4683
method conj($node) { self.conjseq($node) }
4685
method conjseq($node) {
4686
my $il := JAST::InstructionList.new();
4687
my $prefix := self.unique('rxconj') ~ '_';
4688
my $conjlabel := JAST::Label.new( :name($prefix ~ 'fail') );
4689
my $firstlabel := JAST::Label.new( :name($prefix ~ 'first') );
4690
my $iter := nqp::iterator($node.list);
4692
# make a mark that holds our starting position in the pos slot
4693
my $mark := &*REGISTER_MARK($conjlabel);
4694
self.regex_mark($il, $mark,
4695
JAST::Instruction.new( :op('lload'), %*REG<pos> ),
4698
$il.append(JAST::Instruction.new( :op('goto'), $firstlabel ));
4699
$il.append($conjlabel);
4700
$il.append(JAST::Instruction.new( :op('goto'), %*REG<fail> ));
4702
# call the first child
4703
$il.append($firstlabel);
4704
$il.append(self.regex_jast(nqp::shift($iter)));
4706
# use previous mark to make one with pos=start, rep=end
4707
$il.append(JAST::Instruction.new( :op('aload'), %*REG<bstack> ));
4709
$il.append(JAST::PushIVal.new( :value($mark) ));
4710
$il.append($ALOAD_1);
4711
$il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
4712
"rxpeek", 'Long', $TYPE_SMO, 'Long', $TYPE_TC ));
4713
$il.append($IVAL_ONE);
4715
$il.append($ALOAD_1);
4716
$il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
4717
"atpos_i", 'Long', $TYPE_SMO, 'Long', $TYPE_TC ));
4718
$il.append(JAST::Instruction.new( :op('lstore'), %*REG<itemp> ));
4719
self.regex_mark($il, $mark,
4720
JAST::Instruction.new( :op('lload'), %*REG<itemp> ),
4721
JAST::Instruction.new( :op('lload'), %*REG<pos> ));
4724
$il.append(JAST::Instruction.new( :op('lload'), %*REG<itemp> ));
4725
$il.append(JAST::Instruction.new( :op('lstore'), %*REG<pos> ));
4726
$il.append(self.regex_jast(nqp::shift($iter)));
4728
$il.append(JAST::Instruction.new( :op('aload'), %*REG<bstack> ));
4729
$il.append(JAST::PushIVal.new( :value($mark) ));
4730
$il.append($ALOAD_1);
4731
$il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
4732
"rxpeek", 'Long', $TYPE_SMO, 'Long', $TYPE_TC ));
4733
$il.append(JAST::Instruction.new( :op('lstore'), %*REG<itemp> ));
4735
$il.append(JAST::Instruction.new( :op('aload'), %*REG<bstack> ));
4736
$il.append(JAST::Instruction.new( :op('lload'), %*REG<itemp> ));
4737
$il.append(JAST::PushIVal.new( :value(2) ));
4739
$il.append($ALOAD_1);
4740
$il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
4741
"atpos_i", 'Long', $TYPE_SMO, 'Long', $TYPE_TC ));
4742
$il.append(JAST::Instruction.new( :op('lload'), %*REG<pos> ));
4744
$il.append(JAST::Instruction.new( :op('ifne'), %*REG<fail> ));
4746
$il.append(JAST::Instruction.new( :op('aload'), %*REG<bstack> ));
4747
$il.append(JAST::Instruction.new( :op('lload'), %*REG<itemp> ));
4748
$il.append($IVAL_ONE);
4750
$il.append($ALOAD_1);
4751
$il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
4752
"atpos_i", 'Long', $TYPE_SMO, 'Long', $TYPE_TC ));
4753
$il.append(JAST::Instruction.new( :op('lstore'), %*REG<itemp> ));
4756
if $node.subtype eq 'zerowidth' {
4757
$il.append(JAST::Instruction.new( :op('lload'), %*REG<itemp> ));
4758
$il.append(JAST::Instruction.new( :op('lstore'), %*REG<pos> ));
4766
# Codes match constants in Ops.java.
4767
%cclass_code<.> := nqp::const::CCLASS_ANY;
4768
%cclass_code<d> := nqp::const::CCLASS_NUMERIC;
4769
%cclass_code<s> := nqp::const::CCLASS_WHITESPACE;
4770
%cclass_code<w> := nqp::const::CCLASS_WORD;
4771
%cclass_code<n> := nqp::const::CCLASS_NEWLINE;
4774
method cclass($node) {
4775
my $il := JAST::InstructionList.new();
4777
$il.append(JAST::Instruction.new( :op('lload'), %*REG<pos> ));
4778
$il.append(JAST::Instruction.new( :op('lload'), %*REG<eos> ));
4780
$il.append(JAST::Instruction.new( :op('ifge'), %*REG<fail> ));
4782
my $subtype := nqp::lc($node.name);
4783
nqp::die("Unrecognized subtype '$subtype' in QAST::Regex cclass")
4784
unless nqp::existskey(%cclass_code, $subtype);
4785
my $cclass := %cclass_code{$subtype};
4786
if $subtype ne '.' {
4787
$il.append(JAST::PushIVal.new( :value($cclass) ));
4788
$il.append(JAST::Instruction.new( :op('aload'), %*REG<tgt> ));
4789
$il.append(JAST::Instruction.new( :op('lload'), %*REG<pos> ));
4790
$il.append(JAST::Instruction.new( :op('invokestatic'),
4791
$TYPE_OPS, 'iscclass', 'Long', 'Long', $TYPE_STR, 'Long' ));
4793
$il.append(JAST::Instruction.new( :op($node.negate ?? 'ifne' !! 'ifeq'), %*REG<fail> ));
4795
if $cclass == nqp::const::CCLASS_NEWLINE && !$node.negate {
4796
$il.append(JAST::Instruction.new( :op('aload'), %*REG<tgt> ));
4797
$il.append(JAST::Instruction.new( :op('lload'), %*REG<pos> ));
4798
$il.append(JAST::Instruction.new( :op('lload'), %*REG<eos> ));
4799
$il.append(JAST::Instruction.new( :op('invokestatic'),
4800
$TYPE_OPS, 'checkcrlf', 'Long', $TYPE_STR, 'Long', 'Long' ));
4801
$il.append(JAST::Instruction.new( :op('lstore'), %*REG<pos> ));
4805
unless $node.subtype eq 'zerowidth' {
4806
$il.append(JAST::Instruction.new( :op('lload'), %*REG<pos> ));
4807
$il.append($IVAL_ONE);
4809
$il.append(JAST::Instruction.new( :op('lstore'), %*REG<pos> ));
4816
my $qast := QAST::Op.new(
4817
:op('callmethod'), :name('!dba'),
4818
QAST::Var.new( :name(%*REG<cur>), :scope('local') ),
4819
QAST::Var.new( :name(%*REG<pos>), :scope('local'), :returns(int) ),
4820
QAST::SVal.new( :value($node.name()) )
4822
my $res := self.as_jast($qast, :want($RT_VOID));
4823
$*STACK.obtain(NQPMu, $res);
4827
method enumcharlist($node) {
4828
my $il := JAST::InstructionList.new();
4830
$il.append(JAST::Instruction.new( :op('lload'), %*REG<pos> ));
4831
$il.append(JAST::Instruction.new( :op('lload'), %*REG<eos> ));
4833
$il.append(JAST::Instruction.new( :op('ifge'), %*REG<fail> ));
4835
$il.append(JAST::PushSVal.new( :value($node[0]) ));
4836
$il.append(JAST::Instruction.new( :op('aload'), %*REG<tgt> ));
4837
$il.append(JAST::Instruction.new( :op('lload'), %*REG<pos> ));
4839
$il.append(JAST::Instruction.new( :op('invokevirtual'),
4840
$TYPE_STR, 'charAt', 'Char', 'Integer' ));
4841
$il.append(JAST::Instruction.new( :op('invokevirtual'),
4842
$TYPE_STR, 'indexOf', 'Integer', 'Integer' ));
4843
$il.append(JAST::Instruction.new( :op($node.negate ?? 'ifge' !! 'iflt'), %*REG<fail> ));
4845
unless $node.subtype eq 'zerowidth' {
4846
$il.append(JAST::Instruction.new( :op('lload'), %*REG<pos> ));
4847
$il.append($IVAL_ONE);
4849
$il.append(JAST::Instruction.new( :op('lstore'), %*REG<pos> ));
4855
method literal($node) {
4856
my $il := JAST::InstructionList.new();
4857
my $litconst := $node[0];
4858
my $litlen := nqp::chars($litconst);
4860
$il.append(JAST::Instruction.new( :op('lload'), %*REG<pos> ));
4861
$il.append(JAST::PushIVal.new( :value($litlen) ));
4863
$il.append(JAST::Instruction.new( :op('lload'), %*REG<eos> ));
4865
$il.append(JAST::Instruction.new( :op('ifgt'), %*REG<fail> ));
4867
$il.append(JAST::Instruction.new( :op('aload'), %*REG<tgt> ));
4868
$il.append(JAST::PushIndex.new(
4869
:value($node.subtype eq 'ignorecase' ?? 1 !! 0) ));
4870
$il.append(JAST::Instruction.new( :op('lload'), %*REG<pos> ));
4872
$il.append(JAST::PushSVal.new( :value($litconst) ));
4873
$il.append(JAST::PushIndex.new( :value(0) ));
4874
$il.append(JAST::PushIndex.new( :value($litlen) ));
4875
$il.append(JAST::Instruction.new( :op('invokevirtual'),
4876
$TYPE_STR, 'regionMatches', 'Z', 'Z', 'Integer', $TYPE_STR, 'Integer', 'Integer' ));
4877
$il.append(JAST::Instruction.new( :op($node.negate ?? 'ifne' !! 'ifeq'), %*REG<fail> ));
4879
$il.append(JAST::Instruction.new( :op('lload'), %*REG<pos> ));
4880
$il.append(JAST::PushIVal.new( :value($litlen) ));
4882
$il.append(JAST::Instruction.new( :op('lstore'), %*REG<pos> ));
4887
method pass($node) {
4888
my $qast := QAST::Op.new(
4889
:op('callmethod'), :name('!cursor_pass'),
4890
QAST::Var.new( :name(%*REG<cur>), :scope('local') ),
4891
QAST::Var.new( :name(%*REG<pos>), :scope('local'), :returns(int) )
4894
$qast.push(QAST::SVal.new( :value($node.name()) ));
4896
elsif +@($node) == 1 {
4897
$qast.push($node[0]);
4899
if $node.backtrack ne 'r' {
4900
$qast.push(QAST::IVal.new( :value(1), :named('backtrack') ));
4902
my $res := self.as_jast($qast, :want($RT_VOID));
4903
$*STACK.obtain(NQPMu, $res);
4907
method qastnode($node) {
4908
my $il := JAST::InstructionList.new();
4910
$il.append(JAST::PushSVal.new( :value("\$\xa2") ));
4911
$il.append(JAST::Instruction.new( :op('aload'), %*REG<cur> ));
4913
$il.append(JAST::Instruction.new( :op('aload'), %*REG<curclass> ));
4914
$il.append(JAST::PushSVal.new( :value('$!pos') ));
4915
$il.append(JAST::Instruction.new( :op('lload'), %*REG<pos> ));
4916
$il.append($ALOAD_1);
4917
$il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
4918
"bindattr_i", 'Long', $TYPE_SMO, $TYPE_SMO, $TYPE_STR, 'Long', $TYPE_TC ));
4920
$il.append($ALOAD_1);
4921
$il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
4922
"bindlex", $TYPE_SMO, $TYPE_STR, $TYPE_SMO, $TYPE_TC ));
4925
my $node_res := self.as_jast($node[0], :want($RT_OBJ));
4926
$il.append($node_res.jast);
4927
$*STACK.obtain($il, $node_res);
4929
if $node.subtype eq 'zerowidth' {
4930
$il.append($ALOAD_1);
4931
$il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
4932
"istrue", 'Long', $TYPE_SMO, $TYPE_TC ));
4934
$il.append(JAST::Instruction.new( :op($node.negate ?? 'ifne' !! 'ifeq'), %*REG<fail> ));
4943
method quant($node) {
4944
my $il := JAST::InstructionList.new();
4945
my $backtrack := $node.backtrack || 'g';
4946
my $sep := $node[1];
4947
my $prefix := self.unique('rxquant' ~ $backtrack);
4948
my $looplabel := JAST::Label.new( :name($prefix ~ '_loop') );
4949
my $donelabel := JAST::Label.new( :name($prefix ~ '_done') );
4950
my $min := $node.min;
4951
my $max := $node.max;
4952
my $needrep := $min > 1 || $max > 1;
4953
my $needmark := $needrep || $backtrack eq 'r';
4955
if $min == 0 && $max == 0 {
4956
# Nothing to do, and nothing to backtrack into.
4958
elsif $backtrack eq 'f' {
4959
my $seplabel := JAST::Label.new( :name($prefix ~ '_sep') );
4960
my $mark := &*REGISTER_MARK($looplabel);
4962
$il.append($IVAL_ZERO);
4963
$il.append(JAST::Instruction.new( :op('lstore'), %*REG<rep> ));
4965
self.regex_mark($il, $mark,
4966
JAST::Instruction.new( :op('lload'), %*REG<pos> ),
4967
JAST::Instruction.new( :op('lload'), %*REG<rep> ));
4968
$il.append(JAST::Instruction.new( :op('goto'), $donelabel ));
4970
$il.append(JAST::Instruction.new( :op('goto'), $seplabel )) if $sep;
4971
$il.append($looplabel);
4972
$il.append(JAST::Instruction.new( :op('lload'), %*REG<rep> ));
4973
$il.append(JAST::Instruction.new( :op('lstore'), %*REG<itemp> ));
4974
$il.append(self.regex_jast($sep)) if $sep;
4975
$il.append($seplabel) if $sep;
4976
$il.append(self.regex_jast($node[0]));
4977
$il.append(JAST::Instruction.new( :op('lload'), %*REG<itemp> ));
4978
$il.append($IVAL_ONE);
4980
$il.append(JAST::Instruction.new( :op('lstore'), %*REG<rep> ));
4983
$il.append(JAST::Instruction.new( :op('lload'), %*REG<rep> ));
4984
$il.append(JAST::PushIVal.new( :value($min) ));
4986
$il.append(JAST::Instruction.new( :op('iflt'), $looplabel ));
4989
$il.append(JAST::Instruction.new( :op('lload'), %*REG<rep> ));
4990
$il.append(JAST::PushIVal.new( :value($max) ));
4992
$il.append(JAST::Instruction.new( :op('ifge'), $donelabel ));
4995
self.regex_mark($il, $mark,
4996
JAST::Instruction.new( :op('lload'), %*REG<pos> ),
4997
JAST::Instruction.new( :op('lload'), %*REG<rep> ));
5000
$il.append($donelabel);
5003
my $mark := &*REGISTER_MARK($donelabel);
5006
self.regex_mark($il, $mark,
5007
JAST::Instruction.new( :op('lload'), %*REG<pos> ),
5011
self.regex_mark($il, $mark,
5016
$il.append($looplabel);
5017
$il.append(self.regex_jast($node[0]));
5020
$il.append(JAST::Instruction.new( :op('aload'), %*REG<bstack> ));
5022
$il.append(JAST::PushIVal.new( :value($mark) ));
5023
$il.append($ALOAD_1);
5024
$il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
5025
"rxpeek", 'Long', $TYPE_SMO, 'Long', $TYPE_TC ));
5026
$il.append(JAST::PushIVal.new( :value(2) ));
5028
$il.append($ALOAD_1);
5029
$il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
5030
"atpos_i", 'Long', $TYPE_SMO, 'Long', $TYPE_TC ));
5031
$il.append(JAST::Instruction.new( :op('lstore'), %*REG<rep> ));
5033
if $backtrack eq 'r' {
5034
self.regex_commit($il, $mark);
5037
$il.append(JAST::Instruction.new( :op('lload'), %*REG<rep> ));
5038
$il.append($IVAL_ONE);
5040
$il.append(JAST::Instruction.new( :op('lstore'), %*REG<rep> ));
5043
$il.append(JAST::Instruction.new( :op('lload'), %*REG<rep> ));
5044
$il.append(JAST::PushIVal.new( :value($node.max) ));
5046
$il.append(JAST::Instruction.new( :op('ifge'), $donelabel ));
5051
self.regex_mark($il, $mark,
5052
JAST::Instruction.new( :op('lload'), %*REG<pos> ),
5053
JAST::Instruction.new( :op('lload'), %*REG<rep> ));
5054
$il.append(self.regex_jast($sep)) if $sep;
5055
$il.append(JAST::Instruction.new( :op('goto'), $looplabel ));
5058
$il.append($donelabel);
5060
$il.append(JAST::Instruction.new( :op('lload'), %*REG<rep> ));
5061
$il.append(JAST::PushIVal.new( :value(+$node.min) ));
5063
$il.append(JAST::Instruction.new( :op('iflt'), %*REG<fail> ));
5070
method scan($node) {
5071
my $il := JAST::InstructionList.new();
5073
my $prefix := self.unique('rxscan');
5074
my $looplabel := JAST::Label.new( :name($prefix ~ '_loop') );
5075
my $scanlabel := JAST::Label.new( :name($prefix ~ '_scan') );
5076
my $donelabel := JAST::Label.new( :name($prefix ~ '_done') );
5078
$il.append(JAST::Instruction.new( :op('aload'), 'self' ));
5079
$il.append(JAST::Instruction.new( :op('aload'), %*REG<curclass> ));
5080
$il.append(JAST::PushSVal.new( :value('$!from') ));
5081
$il.append($ALOAD_1);
5082
$il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
5083
"getattr_i", 'Long', $TYPE_SMO, $TYPE_SMO, $TYPE_STR, $TYPE_TC ));
5084
$il.append($IVAL_MINUSONE);
5086
$il.append(JAST::Instruction.new( :op('ifne'), $donelabel ));
5087
$il.append(JAST::Instruction.new( :op('goto'), $scanlabel ));
5089
$il.append($looplabel);
5090
$il.append(JAST::Instruction.new( :op('lload'), %*REG<pos> ));
5091
$il.append($IVAL_ONE);
5094
$il.append(JAST::Instruction.new( :op('lstore'), %*REG<pos> ));
5095
$il.append(JAST::Instruction.new( :op('lload'), %*REG<eos> ));
5097
$il.append(JAST::Instruction.new( :op('ifgt'), %*REG<fail> ));
5098
$il.append(JAST::Instruction.new( :op('aload'), %*REG<cur> ));
5099
$il.append(JAST::Instruction.new( :op('aload'), %*REG<curclass> ));
5100
$il.append(JAST::PushSVal.new( :value('$!from') ));
5101
$il.append(JAST::Instruction.new( :op('lload'), %*REG<pos> ));
5102
$il.append($ALOAD_1);
5103
$il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
5104
"bindattr_i", 'Long', $TYPE_SMO, $TYPE_SMO, $TYPE_STR, 'Long', $TYPE_TC ));
5107
$il.append($scanlabel);
5109
my $mark := &*REGISTER_MARK($looplabel);
5110
self.regex_mark($il, $mark,
5111
JAST::Instruction.new( :op('lload'), %*REG<pos> ),
5113
$il.append($donelabel);
5118
method subcapture($node) {
5119
my $il := JAST::InstructionList.new();
5120
my $prefix := self.unique('rxcap');
5121
my $donelabel := JAST::Label.new( :name($prefix ~ '_done') );
5122
my $faillabel := JAST::Label.new( :name($prefix ~ '_fail') );
5124
my $mark := &*REGISTER_MARK($faillabel);
5125
self.regex_mark($il, $mark,
5126
JAST::Instruction.new( :op('lload'), %*REG<pos> ),
5128
$il.append(self.regex_jast($node[0]));
5129
$il.append(JAST::Instruction.new( :op('aload'), %*REG<bstack> ));
5131
$il.append(JAST::PushIVal.new( :value($mark) ));
5132
$il.append($ALOAD_1);
5133
$il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
5134
"rxpeek", 'Long', $TYPE_SMO, 'Long', $TYPE_TC ));
5135
$il.append($IVAL_ONE);
5137
$il.append($ALOAD_1);
5138
$il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
5139
"atpos_i", 'Long', $TYPE_SMO, 'Long', $TYPE_TC ));
5140
$il.append(JAST::Instruction.new( :op('lstore'), %*REG<itemp> ));
5142
my $temp := QAST::Node.unique('rx_subcapture_cur_');
5143
my $methqast := QAST::Stmts.new(
5146
QAST::Var.new( :name(%*REG<cur>), :scope('local') ),
5147
QAST::Var.new( :name(%*REG<curclass>), :scope('local') ),
5148
QAST::SVal.new( :value('$!pos') ),
5149
QAST::Var.new( :name(%*REG<pos>), :scope('local'), :returns(int) )
5153
QAST::Var.new( :name($temp), :scope('local'), :decl('var') ),
5155
:op('callmethod'), :name('!cursor_start_subcapture'),
5156
QAST::Var.new( :name(%*REG<cur>), :scope('local') ),
5157
QAST::Var.new( :name(%*REG<itemp>), :scope('local'), :returns(int) )
5160
:op('callmethod'), :name('!cursor_pass'),
5161
QAST::Var.new( :name($temp), :scope('local') ),
5162
QAST::Var.new( :name(%*REG<pos>), :scope('local'), :returns(int) )
5166
QAST::Var.new( :name(%*REG<cstack>), :scope('local') ),
5168
:op('callmethod'), :name('!cursor_capture'),
5169
QAST::Var.new( :name(%*REG<cur>), :scope('local') ),
5170
QAST::Var.new( :name($temp), :scope('local') ),
5171
QAST::SVal.new( :value($node.name) )
5173
my $methres := self.as_jast($methqast, :want($RT_VOID));
5174
$il.append($methres.jast);
5175
$*STACK.obtain($il, $methres);
5177
$il.append(JAST::Instruction.new( :op('goto'), $donelabel ));
5178
$il.append($faillabel);
5179
$il.append(JAST::Instruction.new( :op('goto'), %*REG<fail> ));
5180
$il.append($donelabel);
5185
method subrule($node) {
5186
my $il := JAST::InstructionList.new();
5187
my $name := nqp::defined($node.name) ?? $node.name !! '';
5188
my $subtype := $node.subtype;
5191
my $callqast := QAST::Stmts.new(
5194
QAST::Var.new( :name(%*REG<cur>), :scope('local') ),
5195
QAST::Var.new( :name(%*REG<curclass>), :scope('local') ),
5196
QAST::SVal.new( :value('$!pos') ),
5197
QAST::Var.new( :name(%*REG<pos>), :scope('local'), :returns(int) )
5199
if nqp::istype($node[0][0], QAST::SVal) {
5201
my @callargs := nqp::clone($node[0].list);
5202
my $name := @callargs.shift().value;
5203
$callqast.push(QAST::Op.new(
5204
:op('callmethod'), :name($name),
5205
QAST::Var.new( :name(%*REG<cur>), :scope('local') ),
5210
# Normal invocation (probably positional capture).
5211
my @callargs := nqp::clone($node[0].list);
5212
my $target := @callargs.shift();
5213
$callqast.push(QAST::Op.new(
5216
QAST::Var.new( :name(%*REG<cur>), :scope('local') ),
5220
my $invres := self.as_jast($callqast, :want($RT_OBJ));
5221
$il.append($invres.jast);
5222
$*STACK.obtain($il, $invres);
5224
$il.append(JAST::Instruction.new( :op('astore'), %*REG<subcur> ));
5225
$il.append(JAST::Instruction.new( :op('aload'), %*REG<curclass> ));
5226
$il.append(JAST::PushSVal.new( :value('$!pos') ));
5227
$il.append($ALOAD_1);
5228
$il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
5229
"getattr_i", 'Long', $TYPE_SMO, $TYPE_SMO, $TYPE_STR, $TYPE_TC ));
5230
$il.append($IVAL_ZERO);
5232
$il.append(JAST::Instruction.new( :op($node.negate ?? 'ifge' !! 'iflt'), %*REG<fail> ));
5234
if $subtype ne 'zerowidth' {
5235
my $rxname := self.unique('rxsubrule');
5236
my $passlabel := JAST::Label.new( :name($rxname ~ '_pass') );
5237
if $node.backtrack eq 'r' {
5238
unless $subtype eq 'method' {
5239
my $mark := &*REGISTER_MARK($passlabel);
5240
self.regex_mark($il, $mark,
5243
$il.append($passlabel);
5247
my $backlabel := JAST::Label.new( :name($rxname ~ '_back') );
5248
$il.append(JAST::Instruction.new( :op('goto'), $passlabel ));
5250
$il.append($backlabel);
5251
my $nextres := self.as_jast(QAST::Op.new(
5252
:op('callmethod'), :name('!cursor_next'),
5253
QAST::Var.new( :name(%*REG<subcur>), :scope('local') )
5255
$il.append($nextres.jast);
5256
$*STACK.obtain($il, $nextres);
5258
$il.append(JAST::Instruction.new( :op('astore'), %*REG<subcur> ));
5259
$il.append(JAST::Instruction.new( :op('aload'), %*REG<curclass> ));
5260
$il.append(JAST::PushSVal.new( :value('$!pos') ));
5261
$il.append($ALOAD_1);
5262
$il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
5263
"getattr_i", 'Long', $TYPE_SMO, $TYPE_SMO, $TYPE_STR, $TYPE_TC ));
5264
$il.append($IVAL_ZERO);
5266
$il.append(JAST::Instruction.new( :op($node.negate ?? 'ifge' !! 'iflt'), %*REG<fail> ));
5268
$il.append($passlabel);
5269
if $subtype eq 'capture' {
5270
my $capres := self.as_jast(QAST::Op.new(
5271
:op('callmethod'), :name('!cursor_capture'),
5272
QAST::Var.new( :name(%*REG<cur>), :scope('local') ),
5273
QAST::Var.new( :name(%*REG<subcur>), :scope('local') ),
5274
QAST::SVal.new( :value($name) )
5276
$il.append($capres.jast);
5277
$*STACK.obtain($il, $capres);
5278
$il.append(JAST::Instruction.new( :op('astore'), %*REG<cstack> ));
5282
my $pushres := self.as_jast(QAST::Op.new(
5283
:op('callmethod'), :name('!cursor_push_cstack'),
5284
QAST::Var.new( :name(%*REG<cur>), :scope('local') ),
5285
QAST::Var.new( :name(%*REG<subcur>), :scope('local') ),
5287
$il.append($pushres.jast);
5288
$*STACK.obtain($il, $pushres);
5289
$il.append(JAST::Instruction.new( :op('astore'), %*REG<cstack> ));
5292
my $mark := &*REGISTER_MARK($backlabel);
5293
$il.append(JAST::Instruction.new( :op('aload'), %*REG<bstack> ));
5296
$il.append(JAST::PushIVal.new( :value($mark) ));
5297
$il.append($ALOAD_1);
5298
$il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS, 'push_i',
5299
'Long', $TYPE_SMO, 'Long', $TYPE_TC ));
5301
$il.append($IVAL_ZERO);
5302
$il.append($ALOAD_1);
5303
$il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS, 'push_i',
5304
'Long', $TYPE_SMO, 'Long', $TYPE_TC ));
5306
$il.append(JAST::Instruction.new( :op('lload'), %*REG<pos> ));
5307
$il.append($ALOAD_1);
5308
$il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS, 'push_i',
5309
'Long', $TYPE_SMO, 'Long', $TYPE_TC ));
5311
$il.append(JAST::Instruction.new( :op('aload'), %*REG<cstack> ));
5312
$il.append($ALOAD_1);
5313
$il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS, 'elems',
5314
'Long', $TYPE_SMO, $TYPE_TC ));
5315
$il.append($ALOAD_1);
5316
$il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS, 'push_i',
5317
'Long', $TYPE_SMO, 'Long', $TYPE_TC ));
5322
if !$captured && $subtype eq 'capture' {
5323
my $capres := self.as_jast(QAST::Op.new(
5324
:op('callmethod'), :name('!cursor_capture'),
5325
QAST::Var.new( :name(%*REG<cur>), :scope('local') ),
5326
QAST::Var.new( :name(%*REG<subcur>), :scope('local') ),
5327
QAST::SVal.new( :value($name) )
5329
$il.append($capres.jast);
5330
$*STACK.obtain($il, $capres);
5331
$il.append(JAST::Instruction.new( :op('astore'), %*REG<cstack> ));
5334
unless $subtype eq 'zerowidth' {
5335
$il.append(JAST::Instruction.new( :op('aload'), %*REG<subcur> ));
5336
$il.append(JAST::Instruction.new( :op('aload'), %*REG<curclass> ));
5337
$il.append(JAST::PushSVal.new( :value('$!pos') ));
5338
$il.append($ALOAD_1);
5339
$il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
5340
"getattr_i", 'Long', $TYPE_SMO, $TYPE_SMO, $TYPE_STR, $TYPE_TC ));
5341
$il.append(JAST::Instruction.new( :op('lstore'), %*REG<pos> ));
5347
method uniprop($node) {
5348
my $il := JAST::InstructionList.new();
5350
$il.append(JAST::PushSVal.new( :value($node[0]) ));
5351
$il.append(JAST::Instruction.new( :op('aload'), %*REG<tgt> ));
5352
$il.append(JAST::Instruction.new( :op('lload'), %*REG<pos> ));
5353
$il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
5354
"ischarprop", 'Long', $TYPE_STR, $TYPE_STR, 'Long' ));
5356
$il.append(JAST::Instruction.new( :op($node.negate ?? 'ifne' !! 'ifeq'), %*REG<fail> ));
5358
unless $node.subtype eq 'zerowidth' {
5359
$il.append(JAST::Instruction.new( :op('lload'), %*REG<pos> ));
5360
$il.append($IVAL_ONE);
5362
$il.append(JAST::Instruction.new( :op('lstore'), %*REG<pos> ));
5368
# a :rxtype<ws> node is a normal subrule call
5369
method ws($node) { self.subrule($node) }
5371
method regex_mark($il, $mark, $pos, $rep) {
5372
$il.append(JAST::Instruction.new( :op('aload'), %*REG<bstack> ));
5373
$il.append(JAST::PushIVal.new( :value($mark) ));
5376
$il.append($ALOAD_1);
5377
$il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
5378
"rxmark", 'Void', $TYPE_SMO, 'Long', 'Long', 'Long', $TYPE_TC ));
5381
method regex_commit($il, $mark) {
5382
$il.append(JAST::Instruction.new( :op('aload'), %*REG<bstack> ));
5383
$il.append(JAST::PushIVal.new( :value($mark) ));
5384
$il.append($ALOAD_1);
5385
$il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
5386
"rxcommit", 'Void', $TYPE_SMO, 'Long', $TYPE_TC ));
5389
multi method as_jast($unknown, :$want) {
5390
nqp::die("Unknown QAST node type " ~ $unknown.HOW.name($unknown));
5393
method result($il, $type) { result($il, $type) }
5395
method operations() { QAST::OperationsJAST }
5398
# Register as the QAST compiler.
5399
if nqp::isnull(nqp::getcomp('QAST')) {
5400
nqp::bindcomp('QAST', QAST::CompilerJAST);