3
class QAST::Operations {
4
# Maps operations to code that will handle them. Hash of code.
7
# Maps HLL-specific operations to code that will handle them.
8
# Hash of hash of code.
11
# Cached pirop compilers.
14
# Mapping of how to box/unbox by HLL.
18
# What we know about inlinability.
19
my %core_inlinability;
22
# What we know about op native results types.
26
# Compiles an operation to POST.
27
method compile_op($qastcomp, $hll, $op) {
30
if %hll_ops{$hll} && %hll_ops{$hll}{$name} -> $mapper {
31
return $mapper($qastcomp, $op);
34
if %core_ops{$name} -> $mapper {
35
return $mapper($qastcomp, $op);
37
nqp::die("No registered operation handler for '$name'");
40
# Compiles a PIR operation.
41
method compile_pirop($qastcomp, $op_name, @op_args) {
42
if nqp::index($op_name, ' ') {
43
$op_name := nqp::join('__', nqp::split(' ', $op_name));
45
unless nqp::existskey(%cached_pirops, $op_name) {
46
my @pieces := nqp::split('__', $op_name);
47
%cached_pirops{$op_name} := pirop_mapper(@pieces[0], @pieces[1]);
49
%cached_pirops{$op_name}($qastcomp, $op_name, @op_args)
52
# Adds a core op handler.
53
method add_core_op($op, $handler, :$inlinable = 0) {
54
%core_ops{$op} := $handler;
55
self.set_core_op_inlinability($op, $inlinable);
58
# Adds a HLL op handler.
59
method add_hll_op($hll, $op, $handler, :$inlinable = 0) {
60
%hll_ops{$hll} := {} unless nqp::existskey(%hll_ops, $hll);
61
%hll_ops{$hll}{$op} := $handler;
62
self.set_hll_op_inlinability($hll, $op, $inlinable);
65
# Adds a core op that maps to a PIR op.
66
method add_core_pirop_mapping($op, $pirop, $sig, :$inlinable = 0) {
67
my $pirop_mapper := pirop_mapper($pirop, $sig);
68
%core_ops{$op} := -> $qastcomp, $op {
69
$pirop_mapper($qastcomp, $op.op, $op.list)
71
self.set_core_op_inlinability($op, $inlinable);
72
self.set_core_op_result_type($op, nqp::substr($sig, 0, 1));
75
# Adds a HLL op that maps to a PIR op.
76
method add_hll_pirop_mapping($hll, $op, $pirop, $sig, :$inlinable = 0) {
77
my $pirop_mapper := pirop_mapper($pirop, $sig);
78
%hll_ops{$hll} := {} unless nqp::existskey(%hll_ops, $hll);
79
%hll_ops{$hll}{$op} := -> $qastcomp, $op {
80
$pirop_mapper($qastcomp, $op.op, $op.list)
82
self.set_hll_op_inlinability($hll, $op, $inlinable);
83
self.set_hll_op_result_type($hll, $op, nqp::substr($sig, 0, 1));
86
# Sets op inlinability at a core level.
87
method set_core_op_inlinability($op, $inlinable) {
88
%core_inlinability{$op} := $inlinable;
91
# Sets op inlinability at a HLL level. (Can override at HLL level whether
92
# or not the HLL overrides the op itself.)
93
method set_hll_op_inlinability($hll, $op, $inlinable) {
94
%hll_inlinability{$hll} := {} unless nqp::existskey(%hll_inlinability, $hll);
95
%hll_inlinability{$hll}{$op} := $inlinable;
98
# Checks if an op is considered inlinable.
99
method is_inlinable($hll, $op) {
100
if nqp::existskey(%hll_inlinability, $hll) {
101
if nqp::existskey(%hll_inlinability{$hll}, $op) {
102
return %hll_inlinability{$hll}{$op};
105
return %core_inlinability{$op} // 0;
108
# Sets op native result type at a core level.
109
method set_core_op_result_type($op, $type_char) {
110
if $type_char eq 'I' {
111
%core_result_type{$op} := int;
113
elsif $type_char eq 'N' {
114
%core_result_type{$op} := num;
116
elsif $type_char eq 'S' {
117
%core_result_type{$op} := str;
121
# Sets op inlinability at a HLL level. (Can override at HLL level whether
122
# or not the HLL overrides the op itself.)
123
method set_hll_op_result_type($hll, $op, $type_char) {
124
%hll_result_type{$hll} := {} unless nqp::existskey(%hll_result_type, $hll);
125
if $type_char eq 'I' {
126
%hll_result_type{$hll}{$op} := int;
128
elsif $type_char eq 'N' {
129
%hll_result_type{$hll}{$op} := num;
131
elsif $type_char eq 'S' {
132
%hll_result_type{$hll}{$op} := str;
136
# Sets returns on an op node if we it has a native result type.
137
method attach_result_type($hll, $node) {
139
if nqp::existskey(%hll_result_type, $hll) {
140
if nqp::existskey(%hll_result_type{$hll}, $op) {
141
$node.returns(%hll_result_type{$hll}{$op});
145
if nqp::existskey(%core_result_type, $op) {
146
$node.returns(%core_result_type{$op});
150
# Adds a HLL box handler.
151
method add_hll_box($hll, $type, $handler) {
152
unless $type eq 'i' || $type eq 'n' || $type eq 's' {
153
nqp::die("Unknown box type '$type'");
155
%hll_box{$hll} := {} unless nqp::existskey(%hll_box, $hll);
156
%hll_box{$hll}{$type} := $handler;
159
# Adds a HLL unbox handler.
160
method add_hll_unbox($hll, $type, $handler) {
161
unless $type eq 'i' || $type eq 'n' || $type eq 's' {
162
nqp::die("Unknown unbox type '$type'");
164
%hll_unbox{$hll} := {} unless nqp::existskey(%hll_unbox, $hll);
165
%hll_unbox{$hll}{$type} := $handler;
168
# Generates a box. Takes a POST tree.
169
method box($qastcomp, $hll, $type, $post) {
170
(%hll_box{$hll}{$type} // %hll_box{'nqp'}{$type})($qastcomp, $post)
173
# Generates an unbox. Takes a POST tree.
174
method unbox($qastcomp, $hll, $type, $post) {
175
(%hll_unbox{$hll}{$type} // %hll_unbox{'nqp'}{$type})($qastcomp, $post)
178
# Returns a mapper closure for turning an operation into a PIR op.
179
# The signature argument consists of characters indicating the
180
# register types and conversions. The characters are:
181
# P,S,I,N PMC, string, int, or num register
182
# Q keyed PMC, next character indicates type of key
183
# s string register or constant
184
# i int register or constant
185
# n num register or constant
186
# r any register result
188
# 0-9 use the nth input operand as the output result of this operation
189
sub pirop_mapper($pirop, $sig) {
190
# Parse arg types out.
191
my @arg_types := nqp::split('', $sig);
192
my $ret_type := @arg_types.shift();
194
# Work out register method for return type, if any.
196
if $ret_type eq 'P' { $ret_meth := "fresh_p"; }
197
elsif $ret_type eq 'S' { $ret_meth := "fresh_s"; }
198
elsif $ret_type eq 'I' { $ret_meth := "fresh_i"; }
199
elsif $ret_type eq 'N' { $ret_meth := "fresh_n"; }
201
-> $qastcomp, $op_name, @op_args {
202
my $ops := PIRT::Ops.new();
204
# If we need a result register, create it and make it the
208
my $reg := $*REGALLOC."$ret_meth"();
213
# Build the arguments list.
214
my $num_args := +@op_args;
215
if +@arg_types != $num_args {
216
nqp::die("Operation '$op_name' requires " ~
217
+@arg_types ~ " operands, but got $num_args");
220
my $last_argtype_was_Q := 0;
222
while $i < $num_args {
223
my $arg_type := @arg_types[$i];
224
my $operand := @op_args[$i];
225
if $arg_type eq 'Q' {
226
my $post := $qastcomp.coerce($qastcomp.as_post($operand), 'P');
228
$aggregate := $post.result;
229
$last_argtype_was_Q := 1;
231
elsif $last_argtype_was_Q {
232
if $arg_type ne 'P' {
233
$operand := $qastcomp.apply_context($operand, $arg_type);
235
my $post := $qastcomp.coerce($qastcomp.as_post($operand), $arg_type);
237
@args.push("$aggregate[" ~ $post.result ~ "]");
238
$last_argtype_was_Q := 0;
241
if $arg_type ne 'P' {
242
$operand := $qastcomp.apply_context($operand, $arg_type);
244
my $post := $qastcomp.coerce($qastcomp.as_post($operand), $arg_type);
246
@args.push($post.result);
251
# If we have an integer as the return type, find the arg that
252
# becomes the result.
253
if !$ret_meth && $ret_type ne 'v' && +$ret_type eq $ret_type {
254
my $rreg := @args[+$ret_type];
255
my $brak := nqp::index($rreg, '[');
257
$rreg := nqp::substr($rreg, $brak + 1, nqp::chars($rreg) - ($brak + 2));
262
# Construct and return the op.
263
$ops.push_pirop($pirop, |@args);
270
QAST::Operations.add_core_op('list', :inlinable(1), -> $qastcomp, $op {
271
# Create register for the resulting list and make an empty one.
272
my $list_reg := $*REGALLOC.fresh_p();
273
my $ops := PIRT::Ops.new(:result($list_reg));
274
$ops.push_pirop('new', $list_reg, "'ResizablePMCArray'");
276
# Push all the things.
278
my $post := $qastcomp.coerce($qastcomp.as_post($_), 'P');
280
$ops.push_pirop('push', $list_reg, $post.result);
286
QAST::Operations.add_core_op('qlist', :inlinable(1), -> $qastcomp, $op {
287
# Create register for the resulting list and make an empty one.
288
my $list_reg := $*REGALLOC.fresh_p();
289
my $ops := PIRT::Ops.new(:result($list_reg));
290
$ops.push_pirop('new', $list_reg, "'QRPA'");
292
# Push all the things.
294
my $post := $qastcomp.coerce($qastcomp.as_post($_), 'P');
296
$ops.push_pirop('push', $list_reg, $post.result);
302
QAST::Operations.add_core_op('list_i', :inlinable(1), -> $qastcomp, $op {
303
# Create register for the resulting list and make an empty one.
304
my $list_reg := $*REGALLOC.fresh_p();
305
my $ops := PIRT::Ops.new(:result($list_reg));
306
$ops.push_pirop('new', $list_reg, "'ResizableIntegerArray'");
308
# Push all the things.
310
my $post := $qastcomp.coerce($qastcomp.as_post($_), 'i');
312
$ops.push_pirop('push', $list_reg, $post.result);
318
QAST::Operations.add_core_op('list_s', :inlinable(1), -> $qastcomp, $op {
319
# Create register for the resulting list and make an empty one.
320
my $list_reg := $*REGALLOC.fresh_p();
321
my $ops := PIRT::Ops.new(:result($list_reg));
322
$ops.push_pirop('new', $list_reg, "'ResizableStringArray'");
324
# Push all the things.
326
my $post := $qastcomp.coerce($qastcomp.as_post($_), 's');
328
$ops.push_pirop('push', $list_reg, $post.result);
334
QAST::Operations.add_core_op('list_b', :inlinable(1), -> $qastcomp, $op {
335
# Create register for the resulting list and make an empty one.
336
my $list_reg := $*REGALLOC.fresh_p();
337
my $ops := PIRT::Ops.new(:result($list_reg));
338
$ops.push_pirop('new', $list_reg, "'ResizablePMCArray'");
340
# Push all the things.
341
my $block_reg := $*REGALLOC.fresh_p();
344
$ops.push_pirop(".const 'Sub' $block_reg = \"$cuid\"");
345
$ops.push_pirop('push', $list_reg, $block_reg);
351
QAST::Operations.add_core_op('hash', :inlinable(1), -> $qastcomp, $op {
352
# Create register for the resulting hash and make an empty one.
353
my $hash_reg := $*REGALLOC.fresh_p();
354
my $ops := PIRT::Ops.new(:result($hash_reg));
355
$ops.push_pirop('new', $hash_reg, "'Hash'");
357
# Set all the values by key on the hash.
359
my @op_list := $op.list;
360
while $i < +@op_list {
361
my $kpost := $qastcomp.coerce($qastcomp.as_post(@op_list[$i]), 's');
365
my $vpost := $qastcomp.coerce($qastcomp.as_post(@op_list[$i]), 'P');
369
$ops.push_pirop('set', $hash_reg ~ '[' ~ $kpost.result ~ ']', $vpost.result);
376
QAST::Operations.add_core_op('chain', :inlinable(1), -> $qastcomp, $op {
377
# First, we build up the list of nodes in the chain
380
while $cpast ~~ QAST::Op && $cpast.op eq 'chain' {
381
nqp::push(@clist, $cpast);
385
my $ops := PIRT::Ops.new(:result($*REGALLOC.fresh_p()));
386
my $endlabel := PIRT::Label.new(:name($qastcomp.unique('chain_end_')));
388
$cpast := nqp::pop(@clist);
389
my $apast := $cpast[0];
390
my $apost := $qastcomp.coerce($qastcomp.as_post($apast), 'P');
395
my $bpast := $cpast[1];
396
my $bpost := $qastcomp.coerce($qastcomp.as_post($bpast), 'P');
399
my $name := $qastcomp.escape($cpast.name());
400
$ops.push_pirop('call', $name, $apost, $bpost, :result($ops));
403
$ops.push_pirop('unless', $ops, $endlabel);
404
$cpast := nqp::pop(@clist);
412
$ops.push($endlabel);
417
# Set of sequential statements
418
QAST::Operations.add_core_op('stmts', :inlinable(1), -> $qastcomp, $op {
419
$qastcomp.as_post(QAST::Stmts.new( |@($op) ))
423
for <if unless> -> $op_name {
424
QAST::Operations.add_core_op($op_name, :inlinable(1), -> $qastcomp, $op {
425
# Check operand count.
426
my $operands := +$op.list;
427
nqp::die("Operation '$op_name' needs either 2 or 3 operands")
428
if $operands < 2 || $operands > 3;
431
my $if_id := $qastcomp.unique($op_name);
432
my $else_lbl := PIRT::Label.new(:name($if_id ~ '_else'));
433
my $end_lbl := PIRT::Label.new(:name($if_id ~ '_end'));
435
# Compile each of the children; we'll need to look at the result
436
# types and pick an overall result type if in non-void context.
441
my $*HAVE_IMM_ARG := $_.arity > 0 && !($_ =:= $op[0]);
443
my $comp := $qastcomp.as_post($_);
444
@comp_ops.push($comp);
445
@op_types.push(nqp::uc($qastcomp.infer_type($comp.result)));
448
@im_args.push($*IMM_ARG);
451
nqp::die("$op_name block expects an argument, but there's no immediate block to take it");
458
$res_type := $operands == 3 ??
459
(@op_types[1] eq @op_types[2] ?? nqp::lc(@op_types[1]) !! 'p') !!
460
(@op_types[0] eq @op_types[1] ?? nqp::lc(@op_types[0]) !! 'p');
461
$res_reg := $*REGALLOC."fresh_$res_type"();
464
# Evaluate the condition first; store result if needed.
465
my $ops := PIRT::Ops.new();
467
if $res_reg && $operands == 2 {
468
my $coerced := $qastcomp.coerce(@comp_ops[0], $res_type);
470
$ops.push_pirop('set', $res_reg, $coerced.result);
471
$cond_result := $coerced;
474
$ops.push(@comp_ops[0]);
475
$cond_result := @comp_ops[0];
478
# If needed, set up passing condition value to blocks.
480
$_($cond_result.result);
484
$ops.push_pirop(($op_name eq 'if' ?? 'unless ' !! 'if ') ~
485
@comp_ops[0].result ~ ' goto ' ~
486
($operands == 2 ?? $end_lbl.result !! $else_lbl.result));
488
# Emit the then; stash the result.
490
my $then := $qastcomp.coerce(@comp_ops[1], $res_type);
492
$ops.push_pirop('set', $res_reg, $then.result);
495
$ops.push(@comp_ops[1]);
498
# Handle else branch if needed.
500
$ops.push_pirop('goto', $end_lbl.result);
501
$ops.push($else_lbl);
503
my $else := $qastcomp.coerce(@comp_ops[2], $res_type);
505
$ops.push_pirop('set', $res_reg, $else.result);
508
$ops.push(@comp_ops[2]);
512
# Emit end label and tag ops with result.
514
$ops.result($res_reg || 'null');
520
QAST::Operations.add_core_op('ifnull', :inlinable(1), -> $qastcomp, $op {
522
nqp::die("The 'ifnull' op expects two children");
525
my $exprpost := $qastcomp.as_post($op[0]);
526
my $vivipost := $qastcomp.coerce($qastcomp.as_post($op[1]),
527
$qastcomp.infer_type($exprpost.result));
528
my $vivlabel := PIRT::Label.new(:name($qastcomp.unique('vivi_')));
530
my $ops := PIRT::Ops.new();
531
$ops.push($exprpost);
532
$ops.push_pirop('unless_null', $exprpost, $vivlabel);
533
$ops.push($vivipost);
534
$ops.push_pirop('set', $exprpost, $vivipost);
535
$ops.push($vivlabel);
536
$ops.result($exprpost.result);
541
for ('', 'repeat_') -> $repness {
542
for <while until> -> $op_name {
543
QAST::Operations.add_core_op("$repness$op_name", :inlinable(1), -> $qastcomp, $op {
545
my $while_id := $qastcomp.unique($op_name);
546
my $test_lbl := PIRT::Label.new(:name($while_id ~ '_test'));
547
my $next_lbl := PIRT::Label.new(:name($while_id ~ '_next'));
548
my $redo_lbl := PIRT::Label.new(:name($while_id ~ '_redo'));
549
my $hand_lbl := PIRT::Label.new(:name($while_id ~ '_handlers'));
550
my $done_lbl := PIRT::Label.new(:name($while_id ~ '_done'));
552
# Compile each of the children; we'll need to look at the result
553
# types and pick an overall result type if in non-void context.
559
if $_.named eq 'nohandler' { $handler := 0; }
561
my $*HAVE_IMM_ARG := $_.arity > 0 && $_ =:= $op.list[1];
562
my $comp := $qastcomp.as_post($_);
563
@comp_ops.push($comp);
564
@comp_types.push($qastcomp.infer_type($comp.result));
565
if $*HAVE_IMM_ARG && !$*IMM_ARG {
566
nqp::die("$op_name block expects an argument, but there's no immediate block to take it");
570
my $res_type := @comp_types[0] eq @comp_types[1] ?? nqp::lc(@comp_types[0]) !! 'p';
571
my $res_reg := $*REGALLOC."fresh_$res_type"();
573
# Check operand count.
574
my $operands := +@comp_ops;
575
nqp::die("Operation '$repness$op_name' needs 2 or 3 operands")
576
if $operands != 2 && $operands != 3;
579
my $ops := PIRT::Ops.new();
580
$ops.result($res_reg);
584
$exc_reg := $*REGALLOC.fresh_p();
585
$ops.push_pirop('new', $exc_reg, "'ExceptionHandler'",
586
'[.CONTROL_LOOP_NEXT;.CONTROL_LOOP_REDO;.CONTROL_LOOP_LAST]');
587
$ops.push_pirop('set_label', $exc_reg, $hand_lbl);
588
$ops.push_pirop('push_eh', $exc_reg);
591
# Test the condition and jump to the loop end if it's
593
my $coerced := $qastcomp.coerce(@comp_ops[0], $res_type);
595
# It's a repeat_ variant, need to go straight into the
596
# loop body unconditionally. Be sure to set the register
597
# for the result to something first.
598
if $res_type eq 'p' || $res_type eq 's' {
599
$ops.push_pirop('null', $res_reg);
602
$ops.push_pirop('set', $res_reg, '0');
604
$ops.push_pirop('goto', $redo_lbl);
606
$ops.push($test_lbl);
608
$ops.push_pirop('set', $res_reg, $coerced.result);
609
$ops.push_pirop(($op_name eq 'while' ?? 'unless ' !! 'if ') ~
610
@comp_ops[0].result ~ ' goto ' ~ $done_lbl.result);
612
# Handle immediate blocks wanting the value as an arg.
617
# Emit the loop body; stash the result.
618
my $body := $qastcomp.coerce(@comp_ops[1], $res_type);
619
$ops.push($redo_lbl);
621
$ops.push_pirop('set', $res_reg, $body.result);
623
# If there's a third child, evaluate it as part of the
626
$ops.push($next_lbl);
627
$ops.push(@comp_ops[2]);
630
# Emit the iteration jump.
631
$ops.push_pirop('goto ' ~ $test_lbl.result);
633
# Emit postlude, with exception handlers.
635
$ops.push($hand_lbl);
636
$ops.push_pirop('.get_results', '(' ~ $exc_reg ~ ')');
637
$ops.push_pirop('pop_upto_eh', $exc_reg);
638
$ops.push_pirop('getattribute', $exc_reg, $exc_reg, "'type'");
639
$ops.push_pirop('eq', $exc_reg, '.CONTROL_LOOP_NEXT',
640
$operands == 3 ?? $next_lbl !! $test_lbl);
641
$ops.push_pirop('eq', $exc_reg, '.CONTROL_LOOP_REDO', $redo_lbl);
642
$ops.push($done_lbl);
643
$ops.push_pirop('pop_eh');
646
$ops.push($done_lbl);
654
QAST::Operations.add_core_op('for', :inlinable(1), -> $qastcomp, $op {
658
if $_.named eq 'nohandler' { $handler := 0; }
659
else { @operands.push($_) }
663
nqp::die("Operation 'for' needs 2 operands");
665
unless nqp::istype(@operands[1], QAST::Block) {
666
nqp::die("Operation 'for' expects a block as its second operand");
668
if @operands[1].blocktype eq 'immediate' {
669
@operands[1].blocktype('declaration');
671
elsif @operands[1].blocktype eq 'immediate_static' {
672
@operands[1].blocktype('declaration_static');
675
# Evaluate the thing we'll iterate over and the block.
676
my $res := $*REGALLOC.fresh_p();
677
my $curval := $*REGALLOC.fresh_p();
678
my $iter := $*REGALLOC.fresh_p();
679
my $ops := PIRT::Ops.new();
680
my $listpost := $qastcomp.coerce($qastcomp.as_post(@operands[0]), "P");
681
my $blockpost := $qastcomp.coerce($qastcomp.as_post(@operands[1]), "P");
682
$ops.push($listpost);
685
$ops.push_pirop('set', $res, $listpost);
686
$ops.push_pirop('iter', $iter, $listpost);
688
# Set up exception handler.
692
$exc_reg := $*REGALLOC.fresh_p();
693
$hand_lbl := PIRT::Label.new(:name('for_handlers'));
694
$ops.push_pirop('new', $exc_reg, "'ExceptionHandler'",
695
'[.CONTROL_LOOP_NEXT;.CONTROL_LOOP_REDO;.CONTROL_LOOP_LAST]');
696
$ops.push_pirop('set_label', $exc_reg, $hand_lbl);
697
$ops.push_pirop('push_eh', $exc_reg);
700
# Loop while we still have values.
701
my $lbl_next := PIRT::Label.new(:name('for_next'));
702
my $lbl_redo := PIRT::Label.new(:name('for_redo'));
703
my $lbl_done := PIRT::Label.new(:name('for_done'));
704
$ops.push($lbl_next);
705
$ops.push_pirop('unless', $iter, $lbl_done);
709
my $arity := @operands[1].arity || 1;
711
my $reg := $*REGALLOC.fresh_p();
712
$ops.push_pirop('shift', $reg, $iter);
713
nqp::push(@valreg, $reg);
714
$arity := $arity - 1;
718
$ops.push($lbl_redo);
719
$ops.push($blockpost);
720
$ops.push_pirop('call', $blockpost, |@valreg, :result($res));
723
$ops.push_pirop('goto', $lbl_next);
727
$ops.push($hand_lbl);
728
$ops.push_pirop('.get_results', '(' ~ $exc_reg ~ ')');
729
$ops.push_pirop('pop_upto_eh', $exc_reg);
730
$ops.push_pirop('getattribute', $exc_reg, $exc_reg, "'type'");
731
$ops.push_pirop('eq', $exc_reg, '.CONTROL_LOOP_NEXT', $lbl_next);
732
$ops.push_pirop('eq', $exc_reg, '.CONTROL_LOOP_REDO', $lbl_redo);
733
$ops.push($lbl_done);
734
$ops.push_pirop('pop_eh');
737
$ops.push($lbl_done);
745
QAST::Operations.add_core_op('defor', :inlinable(1), -> $qastcomp, $op {
747
nqp::die("Operation 'defor' needs 2 operands");
749
my $ops := PIRT::Ops.new();
750
my $lbl := PIRT::Label.new(:name('defor'));
751
my $dreg := $*REGALLOC.fresh_i();
752
my $rreg := $*REGALLOC.fresh_p();
753
my $test := $qastcomp.coerce($qastcomp.as_post($op[0]), 'P');
754
my $then := $qastcomp.coerce($qastcomp.as_post($op[1]), 'P');
756
$ops.push_pirop('set', $rreg, $test);
757
$ops.push_pirop('defined', $dreg, $rreg);
758
$ops.push_pirop('if', $dreg, $lbl);
760
$ops.push_pirop('set', $rreg, $then);
766
QAST::Operations.add_core_op('xor', :inlinable(1), -> $qastcomp, $op {
767
my $ops := PIRT::Ops.new();
768
$ops.result($*REGALLOC.fresh_p());
770
my $falselabel := PIRT::Label.new(:name('xor_false'));
771
my $endlabel := PIRT::Label.new(:name('xor_end'));
776
if $_.named eq 'false' {
780
nqp::push(@childlist, $_);
784
my $i := $*REGALLOC.fresh_i();
785
my $t := $*REGALLOC.fresh_i();
786
my $u := $*REGALLOC.fresh_i();
788
my $apast := nqp::shift(@childlist);
789
my $apost := $qastcomp.coerce($qastcomp.as_post($apast), 'P');
791
$ops.push_pirop('set', $ops, $apost);
792
$ops.push_pirop('istrue', $t, $apost);
794
my $have_middle_child := 1;
796
while $have_middle_child {
797
my $bpast := nqp::shift(@childlist);
798
$bpost := $qastcomp.coerce($qastcomp.as_post($bpast), 'P');
800
$ops.push_pirop('istrue', $u, $bpost);
801
$ops.push_pirop('and', $i, $t, $u);
802
$ops.push_pirop('if', $i, $falselabel);
804
my $truelabel := PIRT::Label.new(:name('xor_true'));
805
$ops.push_pirop('if', $t, $truelabel);
806
$ops.push_pirop('set', $ops, $bpost);
807
$ops.push_pirop('set', $t, $u);
808
$ops.push($truelabel);
811
$have_middle_child := 0;
815
$ops.push_pirop('if', $t, $endlabel);
816
$ops.push_pirop('set', $ops, $bpost);
817
$ops.push_pirop('goto', $endlabel);
818
$ops.push($falselabel);
821
my $fpost := $qastcomp.coerce($qastcomp.as_post($fpast), 'P');
823
$ops.push_pirop('set', $ops, $fpost);
826
$ops.push_pirop('new', $ops, '["Undef"]');
829
$ops.push($endlabel);
835
QAST::Operations.add_core_op('bind', :inlinable(1), -> $qastcomp, $op {
837
my @children := $op.list;
839
nqp::die("A 'bind' op must have exactly two children");
841
unless nqp::istype(@children[0], QAST::Var) {
842
nqp::die("First child of a 'bind' op must be a QAST::Var");
845
# Set the QAST of the think we're to bind, then delegate to
846
# the compilation of the QAST::Var to handle the rest.
847
my $*BINDVAL := @children[1];
848
$qastcomp.as_post(@children[0])
852
sub handle_arg($arg, $qastcomp, $ops, @pos_arg_results, @named_arg_results, :$coerce) {
853
my $arg_post := $qastcomp.as_post($arg);
855
$arg_post := $qastcomp.coerce($arg_post, $coerce);
857
$ops.push($arg_post);
858
my $result := $arg_post.result;
860
$result := "$result :flat";
862
$result := "$result :named";
865
elsif $arg.named -> $name {
866
$result := "$result :named(" ~ $qastcomp.escape($name) ~ ")";
869
@named_arg_results.push($result);
872
@pos_arg_results.push($result);
876
QAST::Operations.add_core_op('call', -> $qastcomp, $op {
877
# Work out what callee is.
879
my @args := nqp::clone($op.list);
881
$callee := PIRT::Ops.new(:result($qastcomp.escape($op.name)));
884
$callee := $qastcomp.as_post(@args.shift());
887
nqp::die("No name for call and empty children list");
891
my $ops := PIRT::Ops.new();
892
$ops.node($op.node) if $op.node;
894
my @named_arg_results;
896
handle_arg($_, $qastcomp, $ops, @pos_arg_results, @named_arg_results);
899
# Generate call, with a result register if we're not in void context.
902
$ops.push_pirop('call', $callee.result, |@pos_arg_results, |@named_arg_results);
905
my $res_type := $qastcomp.type_to_register_type($op.returns);
906
my $res_reg := $*REGALLOC."fresh_{nqp::lc($res_type)}"();
907
$ops.push_pirop('call', $callee.result, |@pos_arg_results, |@named_arg_results, :result($res_reg));
908
$ops.result($res_reg);
912
QAST::Operations.add_core_op('callmethod', :inlinable(1), -> $qastcomp, $op {
913
# Ensure we at least have an invocant.
914
my @args := nqp::clone($op.list);
916
nqp::die('Method call node requires at least one child');
919
# Where is the name coming from?
922
$name := PIRT::Ops.new(:result($qastcomp.escape($op.name)));
925
my $invocant := @args.shift();
926
$name := $qastcomp.coerce($qastcomp.as_post(@args.shift()), 's');
927
@args.unshift($invocant);
930
nqp::die("Method call must either supply a name or have a child node that evaluates to the name");
934
my $ops := PIRT::Ops.new();
935
$ops.node($op.node) if $op.node;
937
my @named_arg_results;
941
handle_arg($_, $qastcomp, $ops, @pos_arg_results, @named_arg_results, :coerce('P'));
945
handle_arg($_, $qastcomp, $ops, @pos_arg_results, @named_arg_results);
949
# Generate call, with a result register if we're not in void context.
952
$ops.push_pirop('callmethod', $name.result, |@pos_arg_results, |@named_arg_results);
955
my $res_type := $qastcomp.type_to_register_type($op.returns);
956
my $res_reg := $*REGALLOC."fresh_{nqp::lc($res_type)}"();
957
$ops.push_pirop('callmethod', $name.result, |@pos_arg_results, |@named_arg_results, :result($res_reg));
958
$ops.result($res_reg);
964
QAST::Operations.add_core_op('lexotic', -> $qastcomp, $op {
965
my $label1 := PIRT::Label.new(:name('lexotic_'));
966
my $label2 := PIRT::Label.new(:name('lexotic_'));
967
my $lexname := $qastcomp.escape($op.name);
969
my $ops := PIRT::Ops.new();
970
my $handler := $*BLOCK.fresh_lex_p();
971
$ops.push_pirop('root_new', $handler, "['parrot';'Continuation']");
972
$ops.push_pirop('set_label', $handler, $label1);
973
$ops.push_pirop('.lex', $lexname, $handler);
975
my $cpost := $qastcomp.coerce($qastcomp.compile_all_the_stmts($op.list()), 'P');
979
$ops.push_pirop('goto', $label2);
981
$ops.push_pirop('.get_results', '(' ~ $ops.result() ~ ')');
987
# Context introspection
988
QAST::Operations.add_core_op('ctx', -> $qastcomp, $op {
989
my $reg := $*REGALLOC.fresh_p();
990
my $ops := PIRT::Ops.new();
991
$ops.push_pirop('getinterp', $reg);
992
$ops.push_pirop('set', $reg, $reg ~ "['context']");
996
QAST::Operations.add_core_op('ctxouter', -> $qastcomp, $op {
997
my $reg := $*REGALLOC.fresh_p();
998
my $ops := PIRT::Ops.new();
999
my $ctxpost := $qastcomp.coerce($qastcomp.as_post($op[0]), 'P');
1000
$ops.push($ctxpost);
1001
$ops.push_pirop('getattribute', $reg, $ctxpost, "'outer_ctx'");
1005
QAST::Operations.add_core_op('ctxcaller', -> $qastcomp, $op {
1006
my $reg := $*REGALLOC.fresh_p();
1007
my $ops := PIRT::Ops.new();
1008
my $ctxpost := $qastcomp.coerce($qastcomp.as_post($op[0]), 'P');
1009
$ops.push($ctxpost);
1010
$ops.push_pirop('getattribute', $reg, $ctxpost, "'caller_ctx'");
1014
QAST::Operations.add_core_op('ctxlexpad', -> $qastcomp, $op {
1015
my $reg := $*REGALLOC.fresh_p();
1016
my $ops := PIRT::Ops.new();
1017
my $ctxpost := $qastcomp.coerce($qastcomp.as_post($op[0]), 'P');
1018
$ops.push($ctxpost);
1019
$ops.push_pirop('getattribute', $reg, $ctxpost, "'lex_pad'");
1023
QAST::Operations.add_core_op('curlexpad', -> $qastcomp, $op {
1024
my $reg := $*REGALLOC.fresh_p();
1025
my $ops := PIRT::Ops.new();
1026
$ops.push_pirop('getinterp', $reg);
1027
$ops.push_pirop('set', $reg, $reg ~ "['lexpad']");
1031
QAST::Operations.add_core_op('curcode', -> $qastcomp, $op {
1032
my $reg := $*REGALLOC.fresh_p();
1033
my $ops := PIRT::Ops.new();
1034
$ops.push_pirop('getinterp', $reg);
1035
$ops.push_pirop('set', $reg, $reg ~ "['sub']");
1039
QAST::Operations.add_core_op('callercode', -> $qastcomp, $op {
1040
my $reg := $*REGALLOC.fresh_p();
1041
my $ops := PIRT::Ops.new();
1042
$ops.push_pirop('getinterp', $reg);
1043
$ops.push_pirop('set', $reg, $reg ~ "['sub';1]");
1047
QAST::Operations.add_core_op('lexprimspec', -> $qastcomp, $op {
1048
unless +@($op) == 2 {
1049
nqp::die("Operation 'lexprimspec' expects two operands");
1051
$qastcomp.as_post(QAST::Op.new(
1052
:op('callmethod'), :name('get_lex_type'), :returns(int),
1057
# Argument capture processing, for writing things like multi-dispatchers in
1058
# high level languages.
1059
QAST::Operations.add_core_op('usecapture', -> $qastcomp, $op {
1060
# On Parrot, the current CallContext has the current args, so just use it.
1061
my $reg := $*REGALLOC.fresh_p();
1062
my $ops := PIRT::Ops.new();
1063
$ops.push_pirop('getinterp', $reg);
1064
$ops.push_pirop('set', $reg, $reg ~ "['context']");
1068
QAST::Operations.add_core_op('savecapture', -> $qastcomp, $op {
1069
# On Parrot, CallContext contains the args and is immutable, so we
1070
# don't need to do anything more than map this to returning the
1072
my $reg := $*REGALLOC.fresh_p();
1073
my $ops := PIRT::Ops.new();
1074
$ops.push_pirop('getinterp', $reg);
1075
$ops.push_pirop('set', $reg, $reg ~ "['context']");
1079
QAST::Operations.add_core_pirop_mapping('captureposelems', 'elements', 'IP');
1080
QAST::Operations.add_core_pirop_mapping('captureposarg', 'set', 'PQi');
1081
QAST::Operations.add_core_pirop_mapping('captureposarg_i', 'set', 'IQi');
1082
QAST::Operations.add_core_pirop_mapping('captureposarg_n', 'set', 'NQi');
1083
QAST::Operations.add_core_pirop_mapping('captureposarg_s', 'set', 'SQi');
1084
QAST::Operations.add_core_pirop_mapping('captureposprimspec', 'captureposprimspec', 'IPi');
1085
QAST::Operations.add_core_pirop_mapping('captureexistsnamed', 'exists', 'IQs');
1086
QAST::Operations.add_core_pirop_mapping('capturehasnameds', 'nqp_capturehasnameds', 'IP');
1088
# Multiple dispatch related.
1089
QAST::Operations.add_core_op('invokewithcapture', -> $qastcomp, $op {
1090
unless $op.list == 2 {
1091
nqp::die("The 'invokewithcapture' op requires two children");
1093
my $pos_reg := $*REGALLOC.fresh_p();
1094
my $nam_reg := $*REGALLOC.fresh_p();
1095
my $res_reg := $*REGALLOC.fresh_p();
1096
my $inv_post := $qastcomp.coerce($qastcomp.as_post($op[0]), 'P');
1097
my $cap_post := $qastcomp.coerce($qastcomp.as_post($op[1]), 'P');
1098
my $ops := PIRT::Ops.new();
1099
$ops.push($inv_post);
1100
$ops.push($cap_post);
1101
$ops.push_pirop('deconstruct_capture', $cap_post.result, $pos_reg, $nam_reg);
1102
$ops.push_pirop('call', $inv_post.result, $pos_reg ~ ' :flat',
1103
$nam_reg ~ ' :flat :named', :result($res_reg));
1104
$ops.result($res_reg);
1107
QAST::Operations.add_core_pirop_mapping('multicacheadd', 'multi_cache_add', 'PPPP');
1108
QAST::Operations.add_core_pirop_mapping('multicachefind', 'multi_cache_find', 'PPP');
1111
my %const_map := nqp::hash(
1112
'CCLASS_ANY', pir::const::CCLASS_ANY,
1113
'CCLASS_NUMERIC', pir::const::CCLASS_NUMERIC,
1114
'CCLASS_WHITESPACE', pir::const::CCLASS_WHITESPACE,
1115
'CCLASS_PRINTING', pir::const::CCLASS_PRINTING,
1116
'CCLASS_GRAPHICAL', pir::const::CCLASS_GRAPHICAL,
1117
'CCLASS_WORD', pir::const::CCLASS_WORD,
1118
'CCLASS_NEWLINE', pir::const::CCLASS_NEWLINE,
1119
'CCLASS_ALPHABETIC', pir::const::CCLASS_ALPHABETIC,
1120
'CCLASS_UPPERCASE', pir::const::CCLASS_UPPERCASE,
1121
'CCLASS_LOWERCASE', pir::const::CCLASS_LOWERCASE,
1122
'CCLASS_NUMERIC', pir::const::CCLASS_NUMERIC,
1123
'CCLASS_HEXADECIMAL', pir::const::CCLASS_HEXADECIMAL,
1124
'CCLASS_BLANK', pir::const::CCLASS_BLANK,
1125
'CCLASS_CONTROL', pir::const::CCLASS_CONTROL,
1126
'CCLASS_PUNCTUATION', pir::const::CCLASS_PUNCTUATION,
1127
'CCLASS_ALPHANUMERIC', pir::const::CCLASS_ALPHANUMERIC,
1133
'HLL_ROLE_ARRAY', 4,
1137
'CONTROL_TAKE', pir::const::CONTROL_TAKE,
1138
'CONTROL_LAST', pir::const::CONTROL_LOOP_LAST,
1139
'CONTROL_NEXT', pir::const::CONTROL_LOOP_NEXT,
1140
'CONTROL_REDO', pir::const::CONTROL_LOOP_REDO,
1141
'CONTROL_SUCCEED', pir::const::CONTROL_BREAK,
1142
'CONTROL_PROCEED', pir::const::CONTROL_CONTINUE,
1143
'CONTROL_WARN', pir::const::CONTROL_OK,
1145
'STAT_EXISTS', pir::const::STAT_EXISTS,
1146
'STAT_FILESIZE', pir::const::STAT_FILESIZE,
1147
'STAT_ISDIR', pir::const::STAT_ISDIR,
1148
'STAT_ISREG', pir::const::STAT_ISREG,
1149
'STAT_ISDEV', pir::const::STAT_ISDEV,
1150
'STAT_CREATETIME', pir::const::STAT_CREATETIME,
1151
'STAT_ACCESSTIME', pir::const::STAT_ACCESSTIME,
1152
'STAT_MODIFYTIME', pir::const::STAT_MODIFYTIME,
1153
'STAT_CHANGETIME', pir::const::STAT_CHANGETIME,
1154
'STAT_BACKUPTIME', pir::const::STAT_BACKUPTIME,
1155
'STAT_UID', pir::const::STAT_UID,
1156
'STAT_GID', pir::const::STAT_GID,
1157
'STAT_ISLNK', pir::const::STAT_ISLNK,
1158
'STAT_PLATFORM_DEV', pir::const::STAT_PLATFORM_DEV,
1159
'STAT_PLATFORM_INODE', pir::const::STAT_PLATFORM_INODE,
1160
'STAT_PLATFORM_MODE', pir::const::STAT_PLATFORM_MODE,
1161
'STAT_PLATFORM_NLINKS', pir::const::STAT_PLATFORM_NLINKS,
1162
'STAT_PLATFORM_DEVTYPE', pir::const::STAT_PLATFORM_DEVTYPE,
1163
'STAT_PLATFORM_BLOCKSIZE', pir::const::STAT_PLATFORM_BLOCKSIZE,
1164
'STAT_PLATFORM_BLOCKS', pir::const::STAT_PLATFORM_BLOCKS,
1166
'STAT_TYPE_UNKNOWN', pir::const::STAT_TYPE_UNKNOWN,
1167
'STAT_TYPE_FILE', pir::const::STAT_TYPE_FILE,
1168
'STAT_TYPE_DIRECTORY', pir::const::STAT_TYPE_DIRECTORY,
1169
'STAT_TYPE_PIPE', pir::const::STAT_TYPE_PIPE,
1170
'STAT_TYPE_LINK', pir::const::STAT_TYPE_LINK,
1171
'STAT_TYPE_DEVICE', pir::const::STAT_TYPE_DEVICE
1173
QAST::Operations.add_core_op('const', -> $qastcomp, $op {
1174
if nqp::existskey(%const_map, $op.name) {
1175
$qastcomp.as_post(QAST::IVal.new( :value(%const_map{$op.name}) ))
1178
nqp::die("Unknown constant '" ~ $op.name ~ "'");
1182
# Exception handling/munging.
1183
my $exc_exclude := 0;
1184
my $exc_include := 1;
1185
my %handler_names := nqp::hash(
1186
'CATCH', '.CONTROL_ALL',
1187
'CONTROL', '.CONTROL_ALL',
1188
'NEXT', '.CONTROL_LOOP_NEXT',
1189
'LAST', '.CONTROL_LOOP_LAST',
1190
'REDO', '.CONTROL_LOOP_REDO',
1191
'TAKE', '.CONTROL_TAKE',
1192
'SUCCEED', '.CONTROL_BREAK',
1193
'PROCEED', '.CONTROL_CONTINUE'
1195
QAST::Operations.add_core_op('handle', -> $qastcomp, $op {
1196
my @children := nqp::clone($op.list());
1198
nqp::die("The 'handle' op requires at least one child");
1201
# Compile the protected statements. If we've no handlers at all
1203
my $protected := @children.shift();
1204
my $procpost := $qastcomp.coerce($qastcomp.as_post($protected), 'P');
1214
for @children -> $name, $handler_code {
1215
if nqp::existskey(%handler_names, $name) {
1216
if nqp::existskey(%handlers, $name) {
1217
nqp::die("Multiple handlers for $name");
1219
%handlers{$name} := $handler_code;
1220
if $name eq 'CATCH' {
1223
elsif $name eq 'CONTROL' {
1227
nqp::push(@other, $name);
1231
nqp::die("Invalid handler type '$name'");
1240
my $skip_handler_label := PIRT::Label.new(:name($qastcomp.unique('skip_handler_')));
1241
my $ops := PIRT::Ops.new();
1242
my $reg := $*REGALLOC.fresh_p();
1244
$catch_label := PIRT::Label.new(:name($qastcomp.unique('catch_handler_')));
1245
$ops.push_pirop('new', $reg, "'ExceptionHandler'");
1246
$ops.push_pirop('set_label', $reg, $catch_label);
1247
$ops.push_pirop('callmethod', "'handle_types_except'", $reg, ".CONTROL_ALL");
1248
$ops.push_pirop('push_eh', $reg);
1249
$num_pops := $num_pops + 1;
1252
$control_label := PIRT::Label.new(:name($qastcomp.unique('catch_handler_')));
1253
$ops.push_pirop('new', $reg, "'ExceptionHandler'", "[.CONTROL_ALL]");
1254
$ops.push_pirop('set_label', $reg, $control_label);
1255
$ops.push_pirop('push_eh', $reg);
1256
$num_pops := $num_pops + 1;
1260
for @other { nqp::push(@hnames, %handler_names{$_}); }
1261
$other_label := PIRT::Label.new(:name($qastcomp.unique('catch_handler_')));
1262
$ops.push_pirop('new', $reg, "'ExceptionHandler'",
1263
"[" ~ nqp::join(", ", @hnames) ~ "]");
1264
$ops.push_pirop('set_label', $reg, $other_label);
1265
$ops.push_pirop('push_eh', $reg);
1266
$num_pops := $num_pops + 1;
1270
my $res_type := nqp::lc($qastcomp.infer_type($procpost.result));
1271
my $res_reg := $*REGALLOC."fresh_$res_type"();
1272
$ops.push($procpost);
1273
$ops.push_pirop('set', $res_reg, $procpost.result);
1275
$ops.push_pirop('pop_eh');
1276
$num_pops := $num_pops - 1;
1278
$ops.push_pirop('goto', $skip_handler_label);
1280
# Now emit the handlers.
1281
my $orig_alloc := $*REGALLOC;
1283
my $*CUR_EXCEPTION := $reg;
1284
my $*REGALLOC := $orig_alloc.handler_allocator();
1285
sub simple_handler($label, $handler_qast) {
1286
my $handler_post := $qastcomp.coerce($qastcomp.as_post($handler_qast), 'P');
1288
$ops.push_pirop(".get_results ($reg)");
1289
$ops.push($handler_post);
1290
$ops.push_pirop('finalize', $reg);
1291
$ops.push_pirop('pop_upto_eh', $reg);
1292
$ops.push_pirop('pop_eh');
1293
$ops.push_pirop('set', $res_reg, $handler_post.result);
1294
$ops.push_pirop('goto', $skip_handler_label);
1297
simple_handler($catch_label, %handlers<CATCH>);
1300
simple_handler($control_label, %handlers<CONTROL>);
1303
my $type_reg := $*REGALLOC.fresh_i();
1304
$ops.push($other_label);
1305
$ops.push_pirop(".get_results ($reg)");
1307
# Create labels for each type and emit type selection ladder.
1309
$ops.push_pirop('set', $type_reg, $reg ~ '["type"]');
1311
my $lbl := PIRT::Label.new(:name($qastcomp.unique('handle_type_')));
1312
$ops.push_pirop('eq', $type_reg, %handler_names{$_}, $lbl);
1313
%type_labels{$_} := $lbl;
1316
# Emit handler for each type.
1318
my $handler_post := $qastcomp.coerce($qastcomp.as_post(%handlers{$_}), 'P');
1319
$ops.push(%type_labels{$_});
1320
$ops.push($handler_post);
1321
$ops.push_pirop('finalize', $reg);
1322
$ops.push_pirop('pop_upto_eh', $reg);
1323
$ops.push_pirop('pop_eh');
1324
$ops.push_pirop('set', $res_reg, $handler_post.result);
1325
$ops.push_pirop('goto', $skip_handler_label);
1331
$ops.push($skip_handler_label);
1332
$ops.result($res_reg);
1336
QAST::Operations.add_core_op('exception', -> $qastcomp, $op {
1337
my $exc_reg := try $*CUR_EXCEPTION;
1339
nqp::die("Can only use 'exception' op in the context of an exception handler");
1341
my $ops := PIRT::Ops.new();
1342
$ops.result($exc_reg);
1345
QAST::Operations.add_core_op('getpayload', -> $qastcomp, $op {
1347
nqp::die("The 'getpayload' op expects one child");
1349
my $exc := $qastcomp.coerce($qastcomp.as_post($op[0]), 'P');
1350
my $reg := $*REGALLOC.fresh_p();
1351
my $ops := PIRT::Ops.new();
1353
$ops.push_pirop('getattribute', $reg, $exc.result, '"payload"');
1357
QAST::Operations.add_core_op('setpayload', -> $qastcomp, $op {
1359
nqp::die("The 'setpayload' op expects two children");
1361
my $exc := $qastcomp.coerce($qastcomp.as_post($op[0]), 'P');
1362
my $payload := $qastcomp.coerce($qastcomp.as_post($op[1]), 'P');
1363
my $ops := PIRT::Ops.new();
1365
$ops.push($payload);
1366
$ops.push_pirop('setattribute', $exc, '"payload"', $payload);
1367
$ops.result($payload.result);
1370
QAST::Operations.add_core_op('getmessage', -> $qastcomp, $op {
1372
nqp::die("The 'getmessage' op expects one child");
1374
my $exc := $qastcomp.coerce($qastcomp.as_post($op[0]), 'P');
1375
my $pmc := $*REGALLOC.fresh_p();
1376
my $reg := $*REGALLOC.fresh_s();
1377
my $ops := PIRT::Ops.new();
1379
$ops.push_pirop('getattribute', $pmc, $exc.result, '"message"');
1380
$ops.push_pirop('set', $reg, $pmc);
1384
QAST::Operations.add_core_op('setmessage', -> $qastcomp, $op {
1386
nqp::die("The 'setmessage' op expects two children");
1388
my $exc := $qastcomp.coerce($qastcomp.as_post($op[0]), 'P');
1389
my $message := $qastcomp.coerce($qastcomp.as_post($op[1]), 'S');
1390
my $pmc := $*REGALLOC.fresh_p();
1391
my $ops := PIRT::Ops.new();
1393
$ops.push($message);
1394
$ops.push_pirop('box', $pmc, $message);
1395
$ops.push_pirop('setattribute', $exc, '"message"', $pmc);
1396
$ops.result($message.result);
1399
QAST::Operations.add_core_op('getextype', -> $qastcomp, $op {
1401
nqp::die("The 'getextype' op expects one child");
1403
my $exc := $qastcomp.coerce($qastcomp.as_post($op[0]), 'P');
1404
my $pmc := $*REGALLOC.fresh_p();
1405
my $reg := $*REGALLOC.fresh_i();
1406
my $ops := PIRT::Ops.new();
1408
$ops.push_pirop('getattribute', $pmc, $exc.result, '"type"');
1409
$ops.push_pirop('set', $reg, $pmc);
1413
QAST::Operations.add_core_op('setextype', -> $qastcomp, $op {
1415
nqp::die("The 'setextype' op expects two children");
1417
my $exc := $qastcomp.coerce($qastcomp.as_post($op[0]), 'P');
1418
my $type := $qastcomp.coerce($qastcomp.as_post($op[1]), 'I');
1419
my $pmc := $*REGALLOC.fresh_p();
1420
my $ops := PIRT::Ops.new();
1423
$ops.push_pirop('box', $pmc, $type);
1424
$ops.push_pirop('setattribute', $exc, '"type"', $pmc);
1425
$ops.result($type.result);
1428
QAST::Operations.add_core_op('backtracestrings', -> $qastcomp, $op {
1430
nqp::die("The 'backtracestrings' op expects one child");
1432
$qastcomp.as_post(QAST::Op.new(
1433
:op('callmethod'), :name('backtrace_strings'),
1437
QAST::Operations.add_core_op('backtrace', -> $qastcomp, $op {
1439
nqp::die("The 'backtrace' op expects one child");
1441
$qastcomp.as_post(QAST::Op.new(
1442
:op('callmethod'), :name('backtrace'),
1446
QAST::Operations.add_core_op('newexception', -> $qastcomp, $op {
1448
nqp::die("The 'newexception' op expects no children");
1450
my $reg := $*REGALLOC.fresh_p();
1451
my $ops := PIRT::Ops.new();
1452
$ops.push_pirop('new', $reg, '["Exception"]');
1456
QAST::Operations.add_core_pirop_mapping('die_s', 'die', '0s');
1457
QAST::Operations.add_core_pirop_mapping('die', 'die', '0P');
1458
QAST::Operations.add_core_pirop_mapping('throw', 'throw', '0P');
1459
QAST::Operations.add_core_pirop_mapping('rethrow', 'rethrow', '0P');
1460
QAST::Operations.add_core_op('resume', -> $qastcomp, $op {
1462
nqp::die("The 'resume' op expects 1 child");
1464
$qastcomp.as_post(QAST::Op.new(
1469
QAST::SVal.new( :value('resume') )
1473
# Control exception throwing.
1474
my %control_map := nqp::hash(
1475
'next', '.CONTROL_LOOP_NEXT',
1476
'last', '.CONTROL_LOOP_LAST',
1477
'redo', '.CONTROL_LOOP_REDO'
1479
QAST::Operations.add_core_op('control', -> $qastcomp, $op {
1480
my $name := $op.name;
1481
if nqp::existskey(%control_map, $name) {
1482
my $ops := PIRT::Ops.new(:result('0'));
1483
$ops.push_pirop('die', '0', %control_map{$name});
1487
nqp::die("Unknown control exception type '$name'");
1493
QAST::Operations.add_hll_box('nqp', $_, -> $qastcomp, $post {
1494
my $reg := $*REGALLOC.fresh_p();
1495
my $ops := PIRT::Ops.new();
1497
$ops.push_pirop('box', $reg, $post);
1501
QAST::Operations.add_hll_unbox('nqp', $_, -> $qastcomp, $post {
1502
my $reg := $*REGALLOC."fresh_$_"();
1503
my $ops := PIRT::Ops.new();
1505
$ops.push_pirop('set', $reg, $post);
1511
# Default way to do positional and associative lookups.
1512
QAST::Operations.add_core_pirop_mapping('positional_get', 'set', 'PQi', :inlinable(1));
1513
QAST::Operations.add_core_pirop_mapping('positional_bind', 'set', '1QiP', :inlinable(1));
1514
QAST::Operations.add_core_pirop_mapping('associative_get', 'set', 'PQs', :inlinable(1));
1515
QAST::Operations.add_core_pirop_mapping('associative_bind', 'set', '1QsP', :inlinable(1));
1518
QAST::Operations.add_core_pirop_mapping('print', 'print', '0s', :inlinable(1));
1519
QAST::Operations.add_core_pirop_mapping('say', 'say', '0s', :inlinable(1));
1520
QAST::Operations.add_core_pirop_mapping('stat', 'stat', 'Isi', :inlinable(1));
1521
QAST::Operations.add_core_pirop_mapping('open', 'open', 'Pss', :inlinable(1));
1523
QAST::Operations.add_core_op('filereadable', -> $qastcomp, $op {
1525
nqp::die("The 'filereadable' op expects one child");
1527
$qastcomp.as_post(QAST::Op.new(
1530
QAST::VM.new( :pirop('new__Ps'),
1531
QAST::SVal.new( :value('OS') ) ),
1534
QAST::Operations.add_core_op('filewritable', -> $qastcomp, $op {
1536
nqp::die("The 'filewritable' op expects one child");
1538
$qastcomp.as_post(QAST::Op.new(
1541
QAST::VM.new( :pirop('new__Ps'),
1542
QAST::SVal.new( :value('OS') ) ),
1545
QAST::Operations.add_core_op('fileexecutable', -> $qastcomp, $op {
1547
nqp::die("The 'fileexecutable' op expects one child");
1549
$qastcomp.as_post(QAST::Op.new(
1551
:name('can_execute'),
1552
QAST::VM.new( :pirop('new__Ps'),
1553
QAST::SVal.new( :value('OS') ) ),
1556
QAST::Operations.add_core_op('fileislink', -> $qastcomp, $op {
1558
nqp::die("The 'fileislink' op expects one child");
1560
$qastcomp.as_post(QAST::Op.new(
1563
QAST::VM.new( :pirop('new__Ps'),
1564
QAST::SVal.new( :value('File') ) ),
1568
QAST::Operations.add_core_op('getstdin', -> $qastcomp, $op {
1570
nqp::die("The 'getstdin' op expects no operands");
1572
$qastcomp.as_post(QAST::Op.new(
1573
:op('callmethod'), :name('stdin_handle'),
1574
QAST::VM.new( :pirop('getinterp__P') )
1577
QAST::Operations.add_core_op('getstdout', -> $qastcomp, $op {
1579
nqp::die("The 'getstdout' op expects no operands");
1581
$qastcomp.as_post(QAST::Op.new(
1582
:op('callmethod'), :name('stdout_handle'),
1583
QAST::VM.new( :pirop('getinterp__P') )
1586
QAST::Operations.add_core_op('getstderr', -> $qastcomp, $op {
1588
nqp::die("The 'getstderr' op expects no operands");
1590
$qastcomp.as_post(QAST::Op.new(
1591
:op('callmethod'), :name('stderr_handle'),
1592
QAST::VM.new( :pirop('getinterp__P') )
1595
QAST::Operations.add_core_op('setencoding', -> $qastcomp, $op {
1597
nqp::die("The 'setencoding' op expects two operands");
1599
$qastcomp.as_post(QAST::Op.new(
1600
:op('callmethod'), :name('encoding'),
1604
QAST::Operations.add_core_op('tellfh', -> $qastcomp, $op {
1606
nqp::die("The 'tellfh' op expects one operand");
1608
$qastcomp.as_post(QAST::Op.new(
1609
:op('callmethod'), :name('tell'),
1613
QAST::Operations.add_core_op('printfh', -> $qastcomp, $op {
1615
nqp::die("The 'printfh' op expects two operands");
1617
$qastcomp.as_post(QAST::Op.new(
1618
:op('callmethod'), :name('print'),
1622
QAST::Operations.add_core_op('sayfh', -> $qastcomp, $op {
1624
nqp::die("The 'sayfh' op expects two operands");
1626
$qastcomp.as_post(QAST::Op.new(
1627
:op('callmethod'), :name('say'),
1631
QAST::Operations.add_core_op('flushfh', -> $qastcomp, $op {
1633
nqp::die("The 'flushfh' op expects two operands");
1635
$qastcomp.as_post(QAST::Op.new(
1636
:op('callmethod'), :name('flush'),
1640
QAST::Operations.add_core_op('readlinefh', -> $qastcomp, $op {
1642
nqp::die("The 'readlinefh' op expects one operand");
1644
$qastcomp.as_post(QAST::Op.new(
1645
:op('callmethod'), :name('readline'),
1649
QAST::Operations.add_core_op('readlineintfh', -> $qastcomp, $op {
1651
nqp::die("The 'readlineintfh' op expects two operands");
1653
$qastcomp.as_post(QAST::Op.new(
1654
:op('callmethod'), :name('readline_interactive'),
1658
QAST::Operations.add_core_op('readallfh', -> $qastcomp, $op {
1660
nqp::die("The 'readallfh' op expects one operand");
1662
$qastcomp.as_post(QAST::Op.new(
1663
:op('callmethod'), :name('readall'),
1667
QAST::Operations.add_core_op('getcfh', -> $qastcomp, $op {
1669
nqp::die("The 'getcfh' op expects one operand");
1671
$qastcomp.as_post(QAST::Op.new(
1672
:op('callmethod'), :name('read'),
1673
$op[0], QAST::IVal.new( :value(1) )
1676
QAST::Operations.add_core_op('eoffh', -> $qastcomp, $op {
1678
nqp::die("The 'eoffh' op expects one operand");
1680
$qastcomp.as_post(QAST::Op.new( :op('isfalse'), $op[0] ))
1682
QAST::Operations.add_core_op('closefh', -> $qastcomp, $op {
1684
nqp::die("The 'closefh' op expects one operand");
1686
$qastcomp.as_post(QAST::Op.new(
1687
:op('callmethod'), :name('close'),
1692
QAST::Operations.add_core_op('chmod', -> $qastcomp, $op {
1694
nqp::die("The 'chmod' op expects two operands");
1696
$qastcomp.as_post(QAST::Op.new(
1699
QAST::VM.new( :pirop('new__Ps'),
1700
QAST::SVal.new( :value('OS') ) ),
1704
QAST::Operations.add_core_pirop_mapping('unlink', 'nqp_delete_f', 'Is');
1705
QAST::Operations.add_core_op('rmdir', -> $qastcomp, $op {
1707
nqp::die("The 'rmdir' op expects one operand");
1709
$qastcomp.as_post(QAST::Op.new(
1712
QAST::VM.new( :pirop('new__Ps'),
1713
QAST::SVal.new( :value('OS') ) ),
1716
QAST::Operations.add_core_op('cwd', -> $qastcomp, $op {
1718
nqp::die("The 'cwd' op expects no operands");
1720
$qastcomp.as_post(QAST::Op.new(
1723
QAST::VM.new( :pirop('new__Ps'),
1724
QAST::SVal.new( :value('OS') ) ) ) );
1726
QAST::Operations.add_core_op('chdir', -> $qastcomp, $op {
1728
nqp::die("The 'chdir' op expects one operand");
1730
$qastcomp.as_post(QAST::Op.new(
1733
QAST::VM.new( :pirop('new__Ps'),
1734
QAST::SVal.new( :value('OS') ) ),
1737
QAST::Operations.add_core_op('mkdir', -> $qastcomp, $op {
1739
nqp::die("The 'mkdir' op expects two operands");
1741
$qastcomp.as_post(QAST::Op.new(
1744
QAST::VM.new( :pirop('new__Ps'),
1745
QAST::SVal.new( :value('OS') ) ),
1749
QAST::Operations.add_core_op('rename', -> $qastcomp, $op {
1751
nqp::die("The 'rename' op expects two operands");
1753
$qastcomp.as_post(QAST::Op.new(
1756
QAST::VM.new( :pirop('new__Ps'),
1757
QAST::SVal.new( :value('OS') ) ),
1761
QAST::Operations.add_core_op('copy', -> $qastcomp, $op {
1763
nqp::die("The 'copy' op expects two operands");
1765
$qastcomp.as_post(QAST::Op.new(
1768
QAST::VM.new( :pirop('new__Ps'),
1769
QAST::SVal.new( :value('File') ) ),
1773
QAST::Operations.add_core_op('symlink', -> $qastcomp, $op {
1775
nqp::die("The 'symlink' op expects two operands");
1777
$qastcomp.as_post(QAST::Op.new(
1780
QAST::VM.new( :pirop('new__Ps'),
1781
QAST::SVal.new( :value('OS') ) ),
1785
QAST::Operations.add_core_op('link', -> $qastcomp, $op {
1787
nqp::die("The 'link' op expects two operands");
1789
$qastcomp.as_post(QAST::Op.new(
1792
QAST::VM.new( :pirop('new__Ps'),
1793
QAST::SVal.new( :value('OS') ) ),
1799
QAST::Operations.add_core_pirop_mapping('time_i', 'time', 'I', :inlinable(1));
1800
QAST::Operations.add_core_pirop_mapping('time_n', 'time', 'N', :inlinable(1));
1802
# arithmetic opcodes
1803
QAST::Operations.add_core_pirop_mapping('add_i', 'add', 'Iii', :inlinable(1));
1804
QAST::Operations.add_core_pirop_mapping('add_I', 'nqp_bigint_add', 'PPPP', :inlinable(1));
1805
QAST::Operations.add_core_pirop_mapping('add_n', 'add', 'Nnn', :inlinable(1));
1806
QAST::Operations.add_core_pirop_mapping('sub_i', 'sub', 'Iii', :inlinable(1));
1807
QAST::Operations.add_core_pirop_mapping('sub_I', 'nqp_bigint_sub', 'PPPP', :inlinable(1));
1808
QAST::Operations.add_core_pirop_mapping('sub_n', 'sub', 'Nnn', :inlinable(1));
1809
QAST::Operations.add_core_pirop_mapping('mul_i', 'mul', 'Iii', :inlinable(1));
1810
QAST::Operations.add_core_pirop_mapping('mul_I', 'nqp_bigint_mul', 'PPPP', :inlinable(1));
1811
QAST::Operations.add_core_pirop_mapping('mul_n', 'mul', 'Nnn', :inlinable(1));
1812
QAST::Operations.add_core_pirop_mapping('div_i', 'div', 'Iii', :inlinable(1));
1813
QAST::Operations.add_core_pirop_mapping('div_I', 'nqp_bigint_div', 'PPPP', :inlinable(1));
1814
QAST::Operations.add_core_pirop_mapping('div_In', 'nqp_bigint_div_num', 'NPP', :inlinable(1));
1815
QAST::Operations.add_core_pirop_mapping('div_n', 'div', 'Nnn', :inlinable(1));
1816
QAST::Operations.add_core_pirop_mapping('mod_i', 'mod', 'Iii', :inlinable(1));
1817
QAST::Operations.add_core_pirop_mapping('mod_I', 'nqp_bigint_mod', 'PPPP', :inlinable(1));
1818
QAST::Operations.add_core_pirop_mapping('expmod_I', 'nqp_bigint_exp_mod', 'PPPPP', :inlinable(1));
1819
QAST::Operations.add_core_pirop_mapping('isprime_I', 'nqp_bigint_is_prime', 'IPi', :inlinable(1));
1820
QAST::Operations.add_core_pirop_mapping('srand', 'srand', '0i', :inlinable(1));
1821
QAST::Operations.add_core_pirop_mapping('rand_n', 'rand', 'Nn', :inlinable(1));
1822
QAST::Operations.add_core_pirop_mapping('rand_I', 'nqp_bigint_rand', 'PPP', :inlinable(1));
1823
QAST::Operations.add_core_pirop_mapping('mod_n', 'mod', 'Nnn', :inlinable(1));
1824
QAST::Operations.add_core_pirop_mapping('pow_n', 'pow', 'Nnn', :inlinable(1));
1825
QAST::Operations.add_core_pirop_mapping('pow_I', 'nqp_bigint_pow', 'PPPPP', :inlinable(1));
1826
QAST::Operations.add_core_pirop_mapping('neg_i', 'neg', 'Ii', :inlinable(1));
1827
QAST::Operations.add_core_pirop_mapping('neg_I', 'nqp_bigint_neg', 'PPP', :inlinable(1));
1828
QAST::Operations.add_core_pirop_mapping('neg_n', 'neg', 'Nn', :inlinable(1));
1829
QAST::Operations.add_core_pirop_mapping('abs_i', 'abs', 'Ii', :inlinable(1));
1830
QAST::Operations.add_core_pirop_mapping('abs_I', 'nqp_bigint_abs', 'PPP', :inlinable(1));
1831
QAST::Operations.add_core_pirop_mapping('abs_n', 'abs', 'Nn', :inlinable(1));
1833
QAST::Operations.add_core_pirop_mapping('gcd_i', 'gcd', 'Iii', :inlinable(1));
1834
QAST::Operations.add_core_pirop_mapping('gcd_I', 'nqp_bigint_gcd', 'PPPP', :inlinable(1));
1835
QAST::Operations.add_core_pirop_mapping('lcm_i', 'lcm', 'Iii', :inlinable(1));
1836
QAST::Operations.add_core_pirop_mapping('lcm_I', 'nqp_bigint_lcm', 'PPPP', :inlinable(1));
1838
QAST::Operations.add_core_pirop_mapping('ceil_n', 'ceil', 'Nn', :inlinable(1));
1839
QAST::Operations.add_core_pirop_mapping('floor_n', 'floor', 'NN', :inlinable(1));
1840
QAST::Operations.add_core_pirop_mapping('ln_n', 'ln', 'Nn', :inlinable(1));
1841
QAST::Operations.add_core_pirop_mapping('sqrt_n', 'sqrt', 'Nn', :inlinable(1));
1842
QAST::Operations.add_core_pirop_mapping('radix', 'nqp_radix', 'Pisii', :inlinable(1));
1843
QAST::Operations.add_core_pirop_mapping('radix_I', 'nqp_bigint_radix', 'PisiiP', :inlinable(1));
1844
QAST::Operations.add_core_pirop_mapping('log_n', 'ln', 'NN', :inlinable(1));
1845
QAST::Operations.add_core_pirop_mapping('exp_n', 'exp', 'Nn', :inlinable(1));
1846
QAST::Operations.add_core_pirop_mapping('isnanorinf', 'is_inf_or_nan', 'In', :inlinable(1));
1847
QAST::Operations.add_core_op('inf', :inlinable(1), -> $qastcomp, $op {
1848
$qastcomp.as_post(QAST::VM.new(
1850
QAST::SVal.new( :value('Inf') )
1853
QAST::Operations.add_core_op('neginf', :inlinable(1), -> $qastcomp, $op {
1854
$qastcomp.as_post(QAST::VM.new(
1856
QAST::SVal.new( :value('-Inf') )
1859
QAST::Operations.add_core_op('nan', :inlinable(1), -> $qastcomp, $op {
1860
$qastcomp.as_post(QAST::VM.new(
1862
QAST::SVal.new( :value('NaN') )
1867
QAST::Operations.add_core_pirop_mapping('sin_n', 'sin', 'NN', :inlinable(1));
1868
QAST::Operations.add_core_pirop_mapping('asin_n', 'asin', 'NN', :inlinable(1));
1869
QAST::Operations.add_core_pirop_mapping('cos_n', 'cos', 'NN', :inlinable(1));
1870
QAST::Operations.add_core_pirop_mapping('acos_n', 'acos', 'NN', :inlinable(1));
1871
QAST::Operations.add_core_pirop_mapping('tan_n', 'tan', 'NN', :inlinable(1));
1872
QAST::Operations.add_core_pirop_mapping('atan_n', 'atan', 'NN', :inlinable(1));
1873
QAST::Operations.add_core_pirop_mapping('atan2_n', 'atan', 'NNN', :inlinable(1));
1874
QAST::Operations.add_core_pirop_mapping('sec_n', 'sec', 'NN', :inlinable(1));
1875
QAST::Operations.add_core_pirop_mapping('asec_n', 'asec', 'NN', :inlinable(1));
1876
QAST::Operations.add_core_pirop_mapping('sin_n', 'sin', 'NN', :inlinable(1));
1877
QAST::Operations.add_core_pirop_mapping('asin_n', 'asin', 'NN', :inlinable(1));
1878
QAST::Operations.add_core_pirop_mapping('sinh_n', 'sinh', 'NN', :inlinable(1));
1879
QAST::Operations.add_core_pirop_mapping('cosh_n', 'cosh', 'NN', :inlinable(1));
1880
QAST::Operations.add_core_pirop_mapping('tanh_n', 'tanh', 'NN', :inlinable(1));
1881
QAST::Operations.add_core_pirop_mapping('sech_n', 'sech', 'NN', :inlinable(1));
1884
QAST::Operations.add_core_pirop_mapping('bitor_i', 'bor', 'Iii', :inlinable(1));
1885
QAST::Operations.add_core_pirop_mapping('bitor_I', 'nqp_bigint_bor', 'PPPP', :inlinable(1));
1886
QAST::Operations.add_core_pirop_mapping('bitxor_i', 'bxor', 'Iii', :inlinable(1));
1887
QAST::Operations.add_core_pirop_mapping('bitxor_I', 'nqp_bigint_bxor', 'PPPP', :inlinable(1));
1888
QAST::Operations.add_core_pirop_mapping('bitand_i', 'band', 'Iii', :inlinable(1));
1889
QAST::Operations.add_core_pirop_mapping('bitand_I', 'nqp_bigint_band', 'PPPP', :inlinable(1));
1890
QAST::Operations.add_core_pirop_mapping('bitneg_i', 'bnot', 'Ii', :inlinable(1));
1891
QAST::Operations.add_core_pirop_mapping('bitneg_I', 'nqp_bigint_bnot', 'PPP', :inlinable(1));
1892
QAST::Operations.add_core_pirop_mapping('bitshiftl_i', 'shl', 'Iii', :inlinable(1));
1893
QAST::Operations.add_core_pirop_mapping('bitshiftl_I', 'nqp_bigint_shl', 'PPIP', :inlinable(1));
1894
QAST::Operations.add_core_pirop_mapping('bitshiftr_i', 'shr', 'Iii', :inlinable(1));
1895
QAST::Operations.add_core_pirop_mapping('bitshiftr_I', 'nqp_bigint_shr', 'PPIP', :inlinable(1));
1897
# string bitwise ops
1898
QAST::Operations.add_core_pirop_mapping('bitor_s', 'bors', 'Sss', :inlinable(1));
1899
QAST::Operations.add_core_pirop_mapping('bitxor_s', 'bxors', 'Sss', :inlinable(1));
1900
QAST::Operations.add_core_pirop_mapping('bitand_s', 'bands', 'Sss', :inlinable(1));
1903
QAST::Operations.add_core_pirop_mapping('chars', 'length', 'Is', :inlinable(1));
1904
QAST::Operations.add_core_pirop_mapping('concat', 'concat', 'Sss', :inlinable(1));
1905
QAST::Operations.add_core_pirop_mapping('concat_s', 'concat', 'Sss', :inlinable(1));
1906
QAST::Operations.add_core_pirop_mapping('join', 'join', 'SsP', :inlinable(1));
1907
QAST::Operations.add_core_pirop_mapping('split', 'split', 'Pss', :inlinable(1));
1908
QAST::Operations.add_core_pirop_mapping('chr', 'chr', 'Si', :inlinable(1));
1909
QAST::Operations.add_core_pirop_mapping('lc', 'downcase', 'Ss', :inlinable(1));
1910
QAST::Operations.add_core_pirop_mapping('uc', 'upcase', 'Ss', :inlinable(1));
1911
QAST::Operations.add_core_pirop_mapping('x', 'repeat', 'Ssi', :inlinable(1));
1912
QAST::Operations.add_core_pirop_mapping('iscclass', 'is_cclass', 'Iisi', :inlinable(1));
1913
QAST::Operations.add_core_pirop_mapping('findcclass', 'find_cclass', 'Iisii', :inlinable(1));
1914
QAST::Operations.add_core_pirop_mapping('findnotcclass', 'find_not_cclass', 'Iisii', :inlinable(1));
1915
QAST::Operations.add_core_op('sprintf', :inlinable(1), -> $qastcomp, $op {
1916
my @operands := $op.list;
1923
QAST::SVal.new( :value('nqp') ),
1924
QAST::SVal.new( :value('sprintf') )
1929
QAST::Operations.add_core_op('sprintfdirectives', :inlinable(1), -> $qastcomp, $op {
1930
my @operands := $op.list;
1937
QAST::SVal.new( :value('nqp') ),
1938
QAST::SVal.new( :value('sprintfdirectives') )
1943
QAST::Operations.add_core_op('sprintfaddargumenthandler', :inlinable(1), -> $qastcomp, $op {
1944
my @operands := $op.list;
1951
QAST::SVal.new( :value('nqp') ),
1952
QAST::SVal.new( :value('sprintfaddargumenthandler') )
1957
QAST::Operations.add_core_pirop_mapping('escape', 'escape', 'SS', :inlinable(1));
1958
QAST::Operations.add_core_pirop_mapping('replace', 'replace', 'Ssiis', :inlinable(1));
1960
QAST::Operations.add_core_op('flip', :inlinable(1), -> $qastcomp, $op {
1962
nqp::die('flip requires one operand');
1965
QAST::VM.new( :pirop('set__SP'),
1966
QAST::Op.new( :op('callmethod'),
1968
QAST::VM.new( :pirop('box__PS'), $op[0] ) ) )
1973
# substr can take 2 or 3 args, so needs special handling.
1974
QAST::Operations.add_core_pirop_mapping('substr2', 'substr', 'Ssi', :inlinable(1));
1975
QAST::Operations.add_core_pirop_mapping('substr3', 'substr', 'Ssii', :inlinable(1));
1976
QAST::Operations.add_core_op('substr', :inlinable(1), -> $qastcomp, $op {
1977
my @operands := $op.list;
1978
$qastcomp.as_post(+@operands == 2
1979
?? QAST::Op.new( :op('substr2'), |@operands )
1980
!! QAST::Op.new( :op('substr3'), |@operands ));
1983
# ord can be on a the first char in a string or at a particular char.
1984
QAST::Operations.add_core_pirop_mapping('ordfirst', 'ord', 'Is', :inlinable(1));
1985
QAST::Operations.add_core_pirop_mapping('ordat', 'ord', 'Isi', :inlinable(1));
1986
QAST::Operations.add_core_op('ord', :inlinable(1), -> $qastcomp, $op {
1987
my @operands := $op.list;
1988
$qastcomp.as_post(+@operands == 1
1989
?? QAST::Op.new( :op('ordfirst'), |@operands )
1990
!! QAST::Op.new( :op('ordat'), |@operands ));
1993
# index may or may not take a starting position
1994
QAST::Operations.add_core_pirop_mapping('indexfrom', 'index', 'Issi', :inlinable(1));
1995
QAST::Operations.add_core_op('index', :inlinable(1), -> $qastcomp, $op {
1996
my @operands := $op.list;
1997
$qastcomp.as_post(+@operands == 2
1998
?? QAST::Op.new( :op('indexfrom'), |@operands, QAST::IVal.new( :value(0) ) )
1999
!! QAST::Op.new( :op('indexfrom'), |@operands ));
2001
QAST::Operations.add_core_pirop_mapping('rindexfrom', 'rindex', 'Issi', :inlinable(1));
2002
QAST::Operations.add_core_pirop_mapping('rindexfromend', 'rindex', 'Iss', :inlinable(1));
2003
QAST::Operations.add_core_op('rindex', :inlinable(1), -> $qastcomp, $op {
2004
my @operands := $op.list;
2005
$qastcomp.as_post(+@operands == 2
2006
?? QAST::Op.new( :op('rindexfromend'), |@operands )
2007
!! QAST::Op.new( :op('rindexfrom'), |@operands ));
2010
QAST::Operations.add_core_op('codepointfromname', :inlinable(1), -> $qastcomp, $op {
2011
my @operands := $op.list;
2012
nqp::die("codepointfromname expects a single child") unless @operands == 1;
2013
my $i_reg := $*REGALLOC.fresh_i();
2014
my $s_reg := $*REGALLOC.fresh_s();
2015
my $ops := PIRT::Ops.new();
2016
my $name := $qastcomp.coerce($qastcomp.as_post($op[0]), 'S');
2018
$ops.push_pirop('find_encoding', $i_reg, "'utf8'");
2019
$ops.push_pirop('trans_encoding', $s_reg, $name, $i_reg);
2020
$ops.push_pirop('find_codepoint', $i_reg, $s_reg);
2021
$ops.result($i_reg);
2025
QAST::Operations.add_core_pirop_mapping('encode', 'nqp_encode', 'PssP', :inlinable(1));
2026
QAST::Operations.add_core_pirop_mapping('decode', 'nqp_decode', 'SPs', :inlinable(1));
2028
# relational opcodes
2029
QAST::Operations.add_core_pirop_mapping('cmp_i', 'cmp', 'Iii', :inlinable(1));
2030
QAST::Operations.add_core_pirop_mapping('iseq_i', 'iseq', 'Iii', :inlinable(1));
2031
QAST::Operations.add_core_pirop_mapping('isne_i', 'isne', 'Iii', :inlinable(1));
2032
QAST::Operations.add_core_pirop_mapping('islt_i', 'islt', 'Iii', :inlinable(1));
2033
QAST::Operations.add_core_pirop_mapping('isle_i', 'isle', 'Iii', :inlinable(1));
2034
QAST::Operations.add_core_pirop_mapping('isgt_i', 'isgt', 'Iii', :inlinable(1));
2035
QAST::Operations.add_core_pirop_mapping('isge_i', 'isge', 'Iii', :inlinable(1));
2037
QAST::Operations.add_core_pirop_mapping('bool_I', 'nqp_bigint_bool', 'IP', :inlinable(1));
2038
QAST::Operations.add_core_pirop_mapping('cmp_I', 'nqp_bigint_cmp', 'IPP', :inlinable(1));
2039
QAST::Operations.add_core_pirop_mapping('iseq_I', 'nqp_bigint_eq', 'IPP', :inlinable(1));
2040
QAST::Operations.add_core_pirop_mapping('isne_I', 'nqp_bigint_ne', 'IPP', :inlinable(1));
2041
QAST::Operations.add_core_pirop_mapping('islt_I', 'nqp_bigint_lt', 'IPP', :inlinable(1));
2042
QAST::Operations.add_core_pirop_mapping('isle_I', 'nqp_bigint_le', 'IPP', :inlinable(1));
2043
QAST::Operations.add_core_pirop_mapping('isgt_I', 'nqp_bigint_gt', 'IPP', :inlinable(1));
2044
QAST::Operations.add_core_pirop_mapping('isge_I', 'nqp_bigint_ge', 'IPP', :inlinable(1));
2046
QAST::Operations.add_core_pirop_mapping('cmp_n', 'cmp', 'Inn', :inlinable(1));
2047
QAST::Operations.add_core_pirop_mapping('iseq_n', 'iseq', 'Inn', :inlinable(1));
2048
QAST::Operations.add_core_pirop_mapping('isne_n', 'isne', 'Inn', :inlinable(1));
2049
QAST::Operations.add_core_pirop_mapping('islt_n', 'islt', 'Inn', :inlinable(1));
2050
QAST::Operations.add_core_pirop_mapping('isle_n', 'isle', 'Inn', :inlinable(1));
2051
QAST::Operations.add_core_pirop_mapping('isgt_n', 'isgt', 'Inn', :inlinable(1));
2052
QAST::Operations.add_core_pirop_mapping('isge_n', 'isge', 'Inn', :inlinable(1));
2054
QAST::Operations.add_core_pirop_mapping('cmp_s', 'cmp', 'Iss', :inlinable(1));
2055
QAST::Operations.add_core_pirop_mapping('iseq_s', 'iseq', 'Iss', :inlinable(1));
2056
QAST::Operations.add_core_pirop_mapping('isne_s', 'isne', 'Iss', :inlinable(1));
2057
QAST::Operations.add_core_pirop_mapping('islt_s', 'islt', 'Iss', :inlinable(1));
2058
QAST::Operations.add_core_pirop_mapping('isle_s', 'isle', 'Iss', :inlinable(1));
2059
QAST::Operations.add_core_pirop_mapping('isgt_s', 'isgt', 'Iss', :inlinable(1));
2060
QAST::Operations.add_core_pirop_mapping('isge_s', 'isge', 'Iss', :inlinable(1));
2063
QAST::Operations.add_core_pirop_mapping('fromstr_I', 'nqp_bigint_from_str', 'PsP', :inlinable(1));
2064
QAST::Operations.add_core_pirop_mapping('tostr_I', 'nqp_bigint_to_str', 'SP', :inlinable(1));
2065
QAST::Operations.add_core_pirop_mapping('base_I', 'nqp_bigint_to_str_base', 'SPI', :inlinable(1));
2066
QAST::Operations.add_core_pirop_mapping('isbig_I', 'nqp_bigint_is_big', 'IP', :inlinable(1));
2067
QAST::Operations.add_core_pirop_mapping('fromnum_I', 'nqp_bigint_from_num', 'PNP', :inlinable(1));
2068
QAST::Operations.add_core_pirop_mapping('tonum_I', 'nqp_bigint_to_num', 'NP', :inlinable(1));
2071
QAST::Operations.add_core_pirop_mapping('initnativecall', 'nqp_native_call_setup', 'v');
2072
QAST::Operations.add_core_pirop_mapping('buildnativecall', 'nqp_native_call_build', 'vPsssPP');
2073
QAST::Operations.add_core_pirop_mapping('nativecall', 'nqp_native_call', 'PPPP');
2074
QAST::Operations.add_core_pirop_mapping('nativecallrefresh', 'nqp_native_call_wb', 'vP');
2075
QAST::Operations.add_core_pirop_mapping('x_posixerrno', 'nqp_posixerrno', 'I');
2078
QAST::Operations.add_core_pirop_mapping('not_i', 'not', 'Ii', :inlinable(1));
2080
# aggregate opcodes, mapping to the Parrot v-table functions
2081
QAST::Operations.add_core_pirop_mapping('atkey', 'set', 'PQs', :inlinable(1));
2082
QAST::Operations.add_core_pirop_mapping('atkey_i', 'set', 'IQs', :inlinable(1));
2083
QAST::Operations.add_core_pirop_mapping('atkey_n', 'set', 'NQs', :inlinable(1));
2084
QAST::Operations.add_core_pirop_mapping('atkey_s', 'set', 'SQs', :inlinable(1));
2085
QAST::Operations.add_core_pirop_mapping('atpos', 'set', 'PQi', :inlinable(1));
2086
QAST::Operations.add_core_pirop_mapping('atpos_i', 'set', 'IQi', :inlinable(1));
2087
QAST::Operations.add_core_pirop_mapping('atpos_n', 'set', 'NQi', :inlinable(1));
2088
QAST::Operations.add_core_pirop_mapping('atpos_s', 'set', 'SQi', :inlinable(1));
2089
QAST::Operations.add_core_pirop_mapping('bindkey', 'set', '1QsP', :inlinable(1));
2090
QAST::Operations.add_core_pirop_mapping('bindkey_i', 'set', '1QsI', :inlinable(1));
2091
QAST::Operations.add_core_pirop_mapping('bindkey_n', 'set', '1QsN', :inlinable(1));
2092
QAST::Operations.add_core_pirop_mapping('bindkey_s', 'set', '1QsS', :inlinable(1));
2093
QAST::Operations.add_core_pirop_mapping('bindpos', 'set', '1QiP', :inlinable(1));
2094
QAST::Operations.add_core_pirop_mapping('bindpos_i', 'set', '1Qii', :inlinable(1));
2095
QAST::Operations.add_core_pirop_mapping('bindpos_n', 'set', '1Qin', :inlinable(1));
2096
QAST::Operations.add_core_pirop_mapping('bindpos_s', 'set', '1Qis', :inlinable(1));
2097
QAST::Operations.add_core_pirop_mapping('deletekey', 'delete', '0Qs', :inlinable(1));
2098
QAST::Operations.add_core_pirop_mapping('existskey', 'exists', 'IQs', :inlinable(1));
2099
QAST::Operations.add_core_pirop_mapping('existspos', 'exists', 'IQi', :inlinable(1));
2100
QAST::Operations.add_core_pirop_mapping('elems', 'elements', 'IP', :inlinable(1));
2101
QAST::Operations.add_core_pirop_mapping('setelems', 'assign', '0Pi', :inlinable(1));
2102
QAST::Operations.add_core_pirop_mapping('push', 'push', '0PP', :inlinable(1));
2103
QAST::Operations.add_core_pirop_mapping('push_s', 'push', '0Ps', :inlinable(1));
2104
QAST::Operations.add_core_pirop_mapping('push_i', 'push', '0Pi', :inlinable(1));
2105
QAST::Operations.add_core_pirop_mapping('push_n', 'push', '0Pn', :inlinable(1));
2106
QAST::Operations.add_core_pirop_mapping('pop', 'pop', 'PP', :inlinable(1));
2107
QAST::Operations.add_core_pirop_mapping('pop_s', 'pop', 'SP', :inlinable(1));
2108
QAST::Operations.add_core_pirop_mapping('pop_i', 'pop', 'IP', :inlinable(1));
2109
QAST::Operations.add_core_pirop_mapping('pop_n', 'pop', 'NP', :inlinable(1));
2110
QAST::Operations.add_core_pirop_mapping('shift', 'shift', 'PP', :inlinable(1));
2111
QAST::Operations.add_core_pirop_mapping('shift_s', 'shift', 'SP', :inlinable(1));
2112
QAST::Operations.add_core_pirop_mapping('shift_i', 'shift', 'IP', :inlinable(1));
2113
QAST::Operations.add_core_pirop_mapping('shift_n', 'shift', 'NP', :inlinable(1));
2114
QAST::Operations.add_core_pirop_mapping('unshift', 'unshift', '0PP', :inlinable(1));
2115
QAST::Operations.add_core_pirop_mapping('unshift_s', 'unshift', '0Ps', :inlinable(1));
2116
QAST::Operations.add_core_pirop_mapping('unshift_i', 'unshift', '0Pi', :inlinable(1));
2117
QAST::Operations.add_core_pirop_mapping('unshift_n', 'unshift', '0Pn', :inlinable(1));
2118
QAST::Operations.add_core_pirop_mapping('splice', 'splice', '0PPii', :inlinable(1));
2119
QAST::Operations.add_core_pirop_mapping('isint', 'nqp_isint', 'IP', :inlinable(1));
2120
QAST::Operations.add_core_pirop_mapping('isnum', 'nqp_isnum', 'IP', :inlinable(1));
2121
QAST::Operations.add_core_pirop_mapping('isstr', 'nqp_isstr', 'IP', :inlinable(1));
2122
QAST::Operations.add_core_pirop_mapping('islist', 'nqp_islist', 'IP', :inlinable(1));
2123
QAST::Operations.add_core_pirop_mapping('ishash', 'nqp_ishash', 'IP', :inlinable(1));
2124
QAST::Operations.add_core_pirop_mapping('isinvokable', 'is_invokable', 'IP', :inlinable(1));
2125
QAST::Operations.add_core_pirop_mapping('iterator', 'iter', 'PP', :inlinable(1));
2126
QAST::Operations.add_core_op('iterkey_s', -> $qastcomp, $op {
2127
$qastcomp.as_post(QAST::Op.new( :op('callmethod'), :name('key'), $op[0] ))
2129
QAST::Operations.add_core_op('iterval', -> $qastcomp, $op {
2130
$qastcomp.as_post(QAST::Op.new( :op('callmethod'), :name('value'), $op[0] ))
2133
# repr-level aggregate operations
2134
QAST::Operations.add_core_pirop_mapping('r_atpos', 'repr_at_pos_obj', 'PPi', :inlinable(1));
2135
QAST::Operations.add_core_pirop_mapping('r_atpos_i', 'repr_at_pos_int', 'IPi', :inlinable(1));
2136
QAST::Operations.add_core_pirop_mapping('r_atpos_n', 'repr_at_pos_num', 'NPi', :inlinable(1));
2137
QAST::Operations.add_core_pirop_mapping('r_bindpos', 'repr_bind_pos_obj', '2PiP', :inlinable(1));
2138
QAST::Operations.add_core_pirop_mapping('r_bindpos_i', 'repr_bind_pos_int', '2Pii', :inlinable(1));
2139
QAST::Operations.add_core_pirop_mapping('r_bindpos_n', 'repr_bind_pos_num', '2Pin', :inlinable(1));
2140
QAST::Operations.add_core_pirop_mapping('r_elems', 'repr_elems', 'IP', :inlinable(1));
2142
sub str_or_want($op) {
2143
nqp::istype($op, QAST::SVal) || nqp::istype($op, QAST::Want) && +@($op)[1] eq 'Ss';
2146
sub val_from_str_or_want($op) {
2147
nqp::istype($op, QAST::SVal)
2153
QAST::Operations.add_core_pirop_mapping('bindattr', 'setattribute', '3PPsP', :inlinable(1));
2154
QAST::Operations.add_core_pirop_mapping('bindattr_i_nh', 'repr_bind_attr_int', '3PPsi', :inlinable(1));
2155
QAST::Operations.add_core_pirop_mapping('bindattr_i_h', 'repr_bind_attr_int', '3PPsii', :inlinable(1));
2156
QAST::Operations.add_core_op('bindattr_i', :inlinable(1), -> $qastcomp, $op {
2158
nqp::die('bindattr_i requires four operands');
2161
if nqp::istype($op[1], QAST::WVal) && str_or_want($op[2]) {
2162
$hint := pir::repr_hint_for__IPs($op[1].value, val_from_str_or_want($op[2]));
2165
$qastcomp.as_post(QAST::Op.new(
2166
:op('bindattr_i_h'),
2170
QAST::IVal.new(:value($hint)),
2174
$qastcomp.as_post(QAST::Op.new(
2175
:op('bindattr_i_nh'),
2183
QAST::Operations.add_core_pirop_mapping('bindattr_n', 'repr_bind_attr_num', '3PPsn', :inlinable(1));
2184
QAST::Operations.add_core_pirop_mapping('bindattr_s', 'repr_bind_attr_str', '3PPss', :inlinable(1));
2185
QAST::Operations.add_core_pirop_mapping('bindattr_s_nh', 'repr_bind_attr_str', '3PPss', :inlinable(1));
2186
QAST::Operations.add_core_pirop_mapping('bindattr_s_h', 'repr_bind_attr_str', '3PPsis', :inlinable(1));
2187
QAST::Operations.add_core_op('bindattr_s', :inlinable(1), -> $qastcomp, $op {
2189
nqp::die('bindattr_s requires four operands');
2192
if nqp::istype($op[1], QAST::WVal) && str_or_want($op[2]) {
2193
$hint := pir::repr_hint_for__IPs($op[1].value, val_from_str_or_want($op[2]));
2196
$qastcomp.as_post(QAST::Op.new(
2197
:op('bindattr_s_h'),
2201
QAST::IVal.new(:value($hint)),
2205
$qastcomp.as_post(QAST::Op.new(
2206
:op('bindattr_s_nh'),
2214
QAST::Operations.add_core_pirop_mapping('getattr', 'getattribute', 'PPPs', :inlinable(1));
2215
QAST::Operations.add_core_pirop_mapping('getattr_i_nh', 'repr_get_attr_int', 'IPPs', :inlinable(1));
2216
QAST::Operations.add_core_pirop_mapping('getattr_i_h', 'repr_get_attr_int', 'IPPsi', :inlinable(1));
2217
QAST::Operations.add_core_op('getattr_i', :inlinable(1), -> $qastcomp, $op {
2219
nqp::die('getattr_i requires three operands');
2222
if nqp::istype($op[1], QAST::WVal) && str_or_want($op[2]) {
2223
$hint := pir::repr_hint_for__IPs($op[1].value, val_from_str_or_want($op[2]));
2226
$qastcomp.as_post(QAST::Op.new(
2231
QAST::IVal.new(:value($hint))
2234
$qastcomp.as_post(QAST::Op.new(
2235
:op('getattr_i_nh'),
2242
QAST::Operations.add_core_pirop_mapping('getattr_n', 'repr_get_attr_num', 'NPPs', :inlinable(1));
2243
QAST::Operations.add_core_pirop_mapping('getattr_s_nh', 'repr_get_attr_str', 'SPPs', :inlinable(1));
2244
QAST::Operations.add_core_pirop_mapping('getattr_s_h', 'repr_get_attr_str', 'SPPsi', :inlinable(1));
2245
QAST::Operations.add_core_op('getattr_s', :inlinable(1), -> $qastcomp, $op {
2247
nqp::die('getattr_s requires three operands');
2250
if nqp::istype($op[1], QAST::WVal) && str_or_want($op[2]) {
2251
$hint := pir::repr_hint_for__IPs($op[1].value, val_from_str_or_want($op[2]));
2254
$qastcomp.as_post(QAST::Op.new(
2259
QAST::IVal.new(:value($hint))
2262
$qastcomp.as_post(QAST::Op.new(
2263
:op('getattr_s_nh'),
2270
QAST::Operations.add_core_pirop_mapping('attrinited', 'repr_is_attr_initialized', 'IPPs', :inlinable(1));
2271
QAST::Operations.add_core_pirop_mapping('create', 'repr_instance_of', 'PP', :inlinable(1));
2272
QAST::Operations.add_core_pirop_mapping('clone', 'repr_clone', 'PP', :inlinable(1));
2273
QAST::Operations.add_core_pirop_mapping('isconcrete', 'repr_defined', 'IP', :inlinable(1));
2274
QAST::Operations.add_core_pirop_mapping('isnull', 'isnull', 'IP', :inlinable(1));
2275
QAST::Operations.add_core_pirop_mapping('isnull_s', 'isnull', 'IS', :inlinable(1));
2276
QAST::Operations.add_core_pirop_mapping('istrue', 'istrue', 'IP', :inlinable(1));
2277
QAST::Operations.add_core_pirop_mapping('isfalse', 'isfalse', 'IP', :inlinable(1));
2278
QAST::Operations.add_core_pirop_mapping('istype', 'type_check', 'IPP', :inlinable(1));
2279
QAST::Operations.add_core_pirop_mapping('null', 'null', 'P', :inlinable(1));
2280
QAST::Operations.add_core_pirop_mapping('null_s', 'null', 'S', :inlinable(1));
2281
QAST::Operations.add_core_pirop_mapping('unbox_i', 'repr_unbox_int', 'IP', :inlinable(1));
2282
QAST::Operations.add_core_pirop_mapping('unbox_n', 'repr_unbox_num', 'NP', :inlinable(1));
2283
QAST::Operations.add_core_pirop_mapping('unbox_s', 'repr_unbox_str', 'SP', :inlinable(1));
2284
QAST::Operations.add_core_pirop_mapping('box_i', 'repr_box_int', 'PiP', :inlinable(1));
2285
QAST::Operations.add_core_pirop_mapping('box_n', 'repr_box_num', 'PnP', :inlinable(1));
2286
QAST::Operations.add_core_pirop_mapping('box_s', 'repr_box_str', 'PsP', :inlinable(1));
2287
QAST::Operations.add_core_pirop_mapping('what', 'get_what', 'PP', :inlinable(1));
2288
QAST::Operations.add_core_pirop_mapping('how', 'get_how', 'PP', :inlinable(1));
2289
QAST::Operations.add_core_pirop_mapping('who', 'get_who', 'PP', :inlinable(1));
2290
QAST::Operations.add_core_pirop_mapping('where', 'get_id', 'IP', :inlinable(1));
2291
QAST::Operations.add_core_pirop_mapping('findmethod', 'find_method', 'PPs', :inlinable(1));
2292
QAST::Operations.add_core_pirop_mapping('defined', 'defined', 'IP', :inlinable(1));
2293
QAST::Operations.add_core_pirop_mapping('can', 'can', 'IPs', :inlinable(1));
2294
QAST::Operations.add_core_pirop_mapping('reprname', 'repr_name', 'SP', :inlinable(1));
2295
QAST::Operations.add_core_pirop_mapping('newtype', 'repr_type_object_for', 'PPs', :inlinable(1));
2296
QAST::Operations.add_core_pirop_mapping('composetype', 'repr_compose', '0PP', :inlinable(1));
2297
QAST::Operations.add_core_pirop_mapping('setwho', 'set_who', '0PP', :inlinable(1));
2298
QAST::Operations.add_core_pirop_mapping('rebless', 'repr_change_type', '0PP', :inlinable(1));
2299
QAST::Operations.add_core_pirop_mapping('knowhow', 'get_knowhow', 'P', :inlinable(1));
2300
QAST::Operations.add_core_pirop_mapping('knowhowattr', 'get_knowhow_attribute', 'P', :inlinable(1));
2301
QAST::Operations.add_core_pirop_mapping('setboolspec', 'set_boolification_spec', '0PiP', :inlinable(1));
2302
QAST::Operations.add_core_pirop_mapping('setmethcache', 'publish_method_cache', '0PP', :inlinable(1));
2303
QAST::Operations.add_core_pirop_mapping('setmethcacheauth', 'set_method_cache_authoritativeness', '0Pi', :inlinable(1));
2304
QAST::Operations.add_core_pirop_mapping('settypecache', 'publish_type_check_cache', '0PP', :inlinable(1));
2305
QAST::Operations.add_core_pirop_mapping('settypecheckmode', 'stable_set_type_check_mode', '0Pi', :inlinable(1));
2306
QAST::Operations.add_core_pirop_mapping('objprimspec', 'repr_get_primitive_type_spec', 'IP', :inlinable(1));
2307
QAST::Operations.add_core_pirop_mapping('setinvokespec', 'set_invocation_spec', '0PPsP', :inlinable(1));
2310
QAST::Operations.add_core_pirop_mapping('setcontspec', 'set_container_spec', '0PsP', :inlinable(1));
2311
QAST::Operations.add_core_pirop_mapping('iscont', 'is_container', 'IP', :inlinable(1));
2312
QAST::Operations.add_core_pirop_mapping('decont', 'nqp_decontainerize', 'PP', :inlinable(1));
2313
QAST::Operations.add_core_pirop_mapping('assign', 'nqp_assign', '0PP', :inlinable(1));
2314
QAST::Operations.add_core_pirop_mapping('assignunchecked', 'nqp_assignunchecked', '0PP', :inlinable(1));
2315
QAST::Operations.add_core_op('eqaddr', -> $qastcomp, $op {
2316
$qastcomp.as_post(QAST::Op.new(
2318
QAST::Op.new( :op('where'), $op[0] ),
2319
QAST::Op.new( :op('where'), $op[1] )
2323
# lexical related opcodes
2324
QAST::Operations.add_core_pirop_mapping('getlex', 'find_lex', 'Ps');
2325
QAST::Operations.add_core_pirop_mapping('getlex_i', 'find_lex', 'Is');
2326
QAST::Operations.add_core_pirop_mapping('getlex_n', 'find_lex', 'Ns');
2327
QAST::Operations.add_core_pirop_mapping('getlex_s', 'find_lex', 'Ss');
2328
QAST::Operations.add_core_pirop_mapping('bindlex', 'store_lex', '1sP');
2329
QAST::Operations.add_core_pirop_mapping('bindlex_i', 'store_lex', '1si');
2330
QAST::Operations.add_core_pirop_mapping('bindlex_n', 'store_lex', '1sn');
2331
QAST::Operations.add_core_pirop_mapping('bindlex_s', 'store_lex', '1ss');
2332
QAST::Operations.add_core_pirop_mapping('getlexdyn', 'find_dynamic_lex', 'Ps');
2333
QAST::Operations.add_core_pirop_mapping('bindlexdyn', 'store_dynamic_lex', '1sP');
2334
QAST::Operations.add_core_pirop_mapping('getlexcaller', 'find_caller_lex', 'Ps');
2335
QAST::Operations.add_core_pirop_mapping('getlexouter', 'nqp_getlexouter', 'Ps');
2336
QAST::Operations.add_core_pirop_mapping('getlexrel', 'nqp_getlexrel', 'PPs');
2337
QAST::Operations.add_core_pirop_mapping('getlexreldyn', 'nqp_getlexreldyn', 'PPs');
2338
QAST::Operations.add_core_pirop_mapping('getlexrelcaller', 'nqp_getlexrelcaller', 'PPs');
2339
QAST::Operations.add_core_op('locallifetime', :inlinable(1), -> $qastcomp, $op {
2341
nqp::die('locallifetime requires at least one operand');
2344
$qastcomp.as_post( $op[0] );
2347
# code object related opcodes
2348
QAST::Operations.add_core_pirop_mapping('takeclosure', 'newclosure', 'PP');
2349
QAST::Operations.add_core_pirop_mapping('getcodeobj', 'get_sub_code_object', 'PP');
2350
QAST::Operations.add_core_pirop_mapping('setcodeobj', 'set_sub_code_object', '1PP');
2351
QAST::Operations.add_core_pirop_mapping('getcodename', 'set', 'SP');
2352
QAST::Operations.add_core_pirop_mapping('setcodename', 'assign', '1Ps');
2353
QAST::Operations.add_core_op('getcodecuid', -> $qastcomp, $op {
2355
nqp::die('getcodecuid requires one operand');
2357
$qastcomp.as_post(QAST::Op.new(
2358
:op('callmethod'), :name('get_subid'),
2362
QAST::Operations.add_core_op('forceouterctx', -> $qastcomp, $op {
2364
nqp::die('forceouterctx requires two operands');
2366
$qastcomp.as_post(QAST::Op.new(
2367
:op('callmethod'), :name('set_outer_ctx'),
2371
QAST::Operations.add_core_pirop_mapping('freshcoderef', 'nqp_fresh_stub', 'PP');
2372
QAST::Operations.add_core_pirop_mapping('replacecoderef', 'assign', '0PP');
2373
QAST::Operations.add_core_op('markcodestatic', -> $qastcomp, $op {
2375
nqp::die('markcodestatic requires one operand');
2377
my $ops := PIRT::Ops.new();
2378
my $code := $qastcomp.coerce($qastcomp.as_post($op[0]), 'P');
2380
$ops.push_pirop('setprop', $code, "'STATIC_CODE_REF'", $code);
2384
QAST::Operations.add_core_op('markcodestub', -> $qastcomp, $op {
2386
nqp::die('markcodestatic requires one operand');
2388
my $ops := PIRT::Ops.new();
2389
my $code := $qastcomp.coerce($qastcomp.as_post($op[0]), 'P');
2391
$ops.push_pirop('setprop', $code, "'COMPILER_STUB'", $code);
2395
QAST::Operations.add_core_op('getstaticcode', -> $qastcomp, $op {
2397
nqp::die('getcodecuid requires one operand');
2399
$qastcomp.as_post(QAST::Op.new(
2400
:op('callmethod'), :name('get_static_code'),
2402
:op('callmethod'), :name('get_lexinfo'),
2406
QAST::Operations.add_core_pirop_mapping('setdispatcher', 'nqp_setdispatcher', '0P');
2407
QAST::Operations.add_core_pirop_mapping('takedispatcher', 'nqp_takedispatcher', '0s');
2409
# serialization context related opcodes
2410
QAST::Operations.add_core_pirop_mapping('sha1', 'nqp_sha1', 'Ss');
2411
QAST::Operations.add_core_pirop_mapping('createsc', 'nqp_create_sc', 'Ps');
2412
QAST::Operations.add_core_pirop_mapping('scsetobj', 'set', '1QiP');
2413
QAST::Operations.add_core_pirop_mapping('scsetcode', 'nqp_add_code_ref_to_sc', '2PiP');
2414
QAST::Operations.add_core_pirop_mapping('scgetobj', 'set', 'PQi');
2415
QAST::Operations.add_core_pirop_mapping('scgetcode', 'nqp_get_sc_code_ref', 'Psi');
2416
QAST::Operations.add_core_op('scgethandle', -> $qastcomp, $op {
2417
$qastcomp.as_post(QAST::Op.new(
2418
:op('callmethod'), :name('handle'), :returns(str),
2422
QAST::Operations.add_core_op('scgetdesc', -> $qastcomp, $op {
2423
$qastcomp.as_post(QAST::Op.new(
2424
:op('callmethod'), :name('description'), :returns(str),
2428
QAST::Operations.add_core_op('scgetobjidx', -> $qastcomp, $op {
2429
$qastcomp.as_post(QAST::Op.new(
2430
:op('callmethod'), :name('slot_index_for'), :returns(int),
2434
QAST::Operations.add_core_op('scsetdesc', -> $qastcomp, $op {
2435
$qastcomp.as_post(QAST::Op.new(
2436
:op('callmethod'), :name('set_description'),
2440
QAST::Operations.add_core_op('scobjcount', -> $qastcomp, $op {
2441
$qastcomp.as_post(QAST::Op.new(
2442
:op('callmethod'), :name('elems'),
2446
QAST::Operations.add_core_pirop_mapping('setobjsc', 'nqp_set_sc_for_object', '0PP');
2447
QAST::Operations.add_core_pirop_mapping('getobjsc', 'nqp_get_sc_for_object', 'PP');
2448
QAST::Operations.add_core_pirop_mapping('serialize', 'nqp_serialize_sc', 'SPP');
2449
QAST::Operations.add_core_pirop_mapping('deserialize', 'nqp_deserialize_sc', '0sPPPP');
2450
QAST::Operations.add_core_pirop_mapping('wval', 'nqp_get_sc_object', 'Psi');
2451
QAST::Operations.add_core_op('scwbdisable', -> $qastcomp, $op {
2452
my $ops := PIRT::Ops.new();
2453
$ops.push_pirop('nqp_disable_sc_write_barrier');
2457
QAST::Operations.add_core_op('scwbenable', -> $qastcomp, $op {
2458
my $ops := PIRT::Ops.new();
2459
$ops.push_pirop('nqp_enable_sc_write_barrier');
2463
QAST::Operations.add_core_pirop_mapping('pushcompsc', 'nqp_push_compiling_sc', '0P');
2464
QAST::Operations.add_core_op('popcompsc', -> $qastcomp, $op {
2465
my $ops := PIRT::Ops.new();
2466
$ops.push_pirop('nqp_pop_compiling_sc');
2471
# hll related opcodes
2472
QAST::Operations.add_core_pirop_mapping('getcomp', 'compreg', 'Ps');
2473
QAST::Operations.add_core_pirop_mapping('bindcomp', 'compreg', '1sP');
2474
QAST::Operations.add_core_pirop_mapping('getcurhllsym', 'get_hll_global', 'Ps');
2475
QAST::Operations.add_core_pirop_mapping('bindcurhllsym', 'set_hll_global', '1sP');
2476
QAST::Operations.add_core_pirop_mapping('loadbytecode', 'load_bytecode', '0s');
2477
QAST::Operations.add_core_op('gethllsym', -> $qastcomp, $op {
2479
nqp::die('gethllsym requires two operands');
2481
$qastcomp.as_post(QAST::VM.new(
2482
:pirop('get_root_global__PPs'),
2483
QAST::Op.new( :op('list_s'), $op[0] ),
2487
QAST::Operations.add_core_op('bindhllsym', -> $qastcomp, $op {
2489
nqp::die('bindhllsym requires three operands');
2491
$qastcomp.as_post(QAST::VM.new(
2492
:pirop('set_root_global__2PsP'),
2493
QAST::Op.new( :op('list_s'), $op[0] ),
2498
QAST::Operations.add_core_pirop_mapping('sethllconfig', 'nqp_sethllconfig', 'PsP');
2499
QAST::Operations.add_core_pirop_mapping('settypehll', 'nqp_settypehll', '0Ps');
2500
QAST::Operations.add_core_pirop_mapping('settypehllrole', 'nqp_settypehllrole', '0Pi');
2501
QAST::Operations.add_core_pirop_mapping('hllize', 'nqp_hllize', 'PP');
2502
QAST::Operations.add_core_pirop_mapping('hllizefor', 'nqp_hllizefor', 'PPs');
2504
# regex engine related opcodes
2505
QAST::Operations.add_core_pirop_mapping('nfafromstatelist', 'nqp_nfa_from_statelist', 'PPP');
2506
QAST::Operations.add_core_pirop_mapping('nfatostatelist', 'nqp_nfa_to_statelist', 'PP');
2507
QAST::Operations.add_core_pirop_mapping('nfarunproto', 'nqp_nfa_run_proto', 'PPsi');
2508
QAST::Operations.add_core_pirop_mapping('nfarunalt', 'nqp_nfa_run_alt', '0PsiPPP');
2510
# process related opcodes
2511
QAST::Operations.add_core_pirop_mapping('exit', 'exit', '0i', :inlinable(1));
2512
QAST::Operations.add_core_pirop_mapping('sleep', 'sleep', '0n', :inlinable(1));
2513
QAST::Operations.add_core_pirop_mapping('shell', 'nqp_shell', 'IssP');
2514
QAST::Operations.add_core_pirop_mapping('getenvhash', 'nqp_getenvhash', 'P');
2516
QAST::Operations.add_core_op('getpid', -> $qastcomp, $op {
2518
nqp::die('getpid requires no operands');
2520
$qastcomp.as_post(QAST::Op.new(
2521
:op('callmethod'), :name('getpid'), :returns(int),
2522
QAST::VM.new( :pirop('getinterp__P') )