1
my $MVM_operand_literal := 0;
2
my $MVM_operand_read_reg := 1;
3
my $MVM_operand_write_reg := 2;
4
my $MVM_operand_read_lex := 3;
5
my $MVM_operand_write_lex := 4;
6
my $MVM_operand_rw_mask := 7;
8
my $MVM_operand_int8 := ($MVM_reg_int8 * 8);
9
my $MVM_operand_int16 := ($MVM_reg_int16 * 8);
10
my $MVM_operand_int32 := ($MVM_reg_int32 * 8);
11
my $MVM_operand_int64 := ($MVM_reg_int64 * 8);
12
my $MVM_operand_num32 := ($MVM_reg_num32 * 8);
13
my $MVM_operand_num64 := ($MVM_reg_num64 * 8);
14
my $MVM_operand_str := ($MVM_reg_str * 8);
15
my $MVM_operand_obj := ($MVM_reg_obj * 8);
16
my $MVM_operand_ins := (9 * 8);
17
my $MVM_operand_type_var := (10 * 8);
18
my $MVM_operand_lex_outer := (11 * 8);
19
my $MVM_operand_coderef := (12 * 8);
20
my $MVM_operand_callsite := (13 * 8);
21
my $MVM_operand_type_mask := (15 * 8);
23
# This is used as a return value from all of the various compilation routines.
24
# It groups together a set of instructions along with a result register and a
25
# result kind. It also tracks the source filename and line number.
26
class MAST::InstructionList {
29
has int $!result_kind;
33
method new(@instructions, $result_reg, $result_kind, :$filename = '<anon>', :$lineno = 0) {
34
my $obj := nqp::create(self);
35
nqp::bindattr($obj, MAST::InstructionList, '@!instructions', @instructions);
36
nqp::bindattr($obj, MAST::InstructionList, '$!result_reg', $result_reg);
37
nqp::bindattr_i($obj, MAST::InstructionList, '$!result_kind', $result_kind);
38
nqp::bindattr_s($obj, MAST::InstructionList, '$!filename', $filename);
39
nqp::bindattr_i($obj, MAST::InstructionList, '$!lineno', $lineno);
43
method instructions() { @!instructions }
44
method result_reg() { $!result_reg }
45
method result_kind() { $!result_kind }
46
method filename() { $!filename }
47
method lineno() { $!lineno }
49
method append(MAST::InstructionList $other) {
50
push_ilist(@!instructions, $other);
51
$!result_reg := $other.result_reg;
52
$!result_kind := $other.result_kind;
56
# Marker object for void.
59
class QAST::MASTOperations {
61
# Maps operations to code that will handle them. Hash of code.
64
# Maps HLL-specific operations to code that will handle them.
65
# Hash of hash of code.
68
# Mapping of how to box/unbox by HLL.
72
# Compiles an operation to MAST.
73
method compile_op($qastcomp, $hll, $op) {
75
if ($hll && %hll_ops{$hll} && %hll_ops{$hll}{$name})
76
|| %core_ops{$name} -> $mapper {
77
return $mapper($qastcomp, $op);
79
nqp::die("No registered operation handler for '$name'");
82
my @kind_names := ['VOID','int8','int16','int32','int','num32','num','str','obj'];
83
my @kind_types := [0,1,1,1,1,2,2,3,4];
85
my @operands_offsets := MAST::Ops.WHO<@offsets>;
86
my @operands_counts := MAST::Ops.WHO<@counts>;
87
my @operands_values := MAST::Ops.WHO<@values>;
88
my %op_codes := MAST::Ops.WHO<%codes>;
89
method compile_mastop($qastcomp, $op, @args, :$returnarg = -1, :$opname = 'none', :$want) {
90
#$op := $op.name if nqp::istype($op, QAST::Op);
92
my $op_num := %op_codes{$op};
93
my $num_args := +@args;
94
my $num_operands := nqp::atpos_i(@operands_counts, $op_num);
95
my $operands_offset := nqp::atpos_i(@operands_offsets, $op_num);
97
my $result_kind := $MVM_reg_void;
98
my $result_reg := MAST::VOID;
100
my $type_var_kind := 0;
107
# if the op has operands, and the first operand is a write register,
108
# and the number of args provided is one less than the number of operands needed,
109
# mark that we need to generate a result register at the end, and
110
# advance to the second operand.
112
&& (nqp::atpos_i(@operands_values, $operands_offset) +& $MVM_operand_rw_mask) == $MVM_operand_write_reg
113
# allow the QASTree to define its own write register
114
&& $num_args == $num_operands - 1) {
119
if ($num_args != $num_operands - $operand_num) {
120
nqp::die("Arg count $num_args doesn't equal required operand count "~($num_operands - $operand_num)~" for op '$op'");
123
if ($op eq 'return') {
124
$*BLOCK.return_kind($MVM_reg_void);
128
# Compile provided args.
130
my $operand := nqp::atpos_i(@operands_values, $operands_offset + $operand_num++);
131
my $operand_kind := ($operand +& $MVM_operand_type_mask);
132
my $constant_operand := !($operand +& $MVM_operand_rw_mask);
133
my $arg := $operand_kind == $MVM_operand_type_var
134
?? $qastcomp.as_mast($_)
135
!! $qastcomp.as_mast($_, :want($operand_kind/8));
136
my $arg_kind := $arg.result_kind;
138
if $arg_num == 0 && nqp::substr($op, 0, 7) eq 'return_' {
139
$*BLOCK.return_kind($arg.result_kind);
142
# args cannot be void
143
if $arg_kind == $MVM_reg_void {
144
nqp::die("Cannot use a void register as an argument to op '$op'");
147
if ($operand_kind == $MVM_operand_type_var) {
148
# handle ops that have type-variables as operands
149
if ($type_var_kind) {
150
# if we've already seen a type-var
151
if ($arg_kind != $type_var_kind) {
152
# the arg types must match
153
nqp::die("variable-type op requires same-typed args");
157
# set this variable-type op's typecode
158
$type_var_kind := $arg_kind;
160
} # allow nums and ints to be bigger than their destination width
161
elsif (@kind_types[$arg_kind] != @kind_types[$operand_kind/8]) {
162
$qastcomp.coerce($arg, $operand_kind/8);
163
$arg_kind := $operand_kind/8;
164
# the arg typecode left shifted 3 must match the operand typecode
165
# nqp::die("arg type {@kind_names[$arg_kind]} does not match operand type {@kind_names[$operand_kind/8]} to op '$op'");
168
# if this is the write register, get the result reg and type from it
169
if ($operand +& $MVM_operand_rw_mask) == $MVM_operand_write_reg
170
|| ($operand +& $MVM_operand_rw_mask) == $MVM_operand_write_lex
171
|| $returnarg != -1 && $returnarg == $arg_num {
172
$result_reg := $arg.result_reg;
173
$result_kind := $arg_kind;
175
# otherwise it's a read register, so it can be released if it's an
178
# if it's not a write register, queue it to be released it to the allocator
179
nqp::push(@release_regs, $arg.result_reg);
180
nqp::push(@release_kinds, $arg_kind);
183
# put the arg exression's generation code in the instruction list
184
nqp::splice(@all_ins, $arg.instructions, +@all_ins, 0)
185
unless $constant_operand;
186
nqp::push(@arg_regs, $constant_operand
187
?? $qastcomp.as_mast_constant($_)
193
# release the registers to the allocator. See comment there.
195
$*REGALLOC.release_register($_, @release_kinds[$release_i++]) for @release_regs;
197
# unshift in a generated write register arg if it needs one
199
# do this after the args to possibly reuse a register,
200
# and so we know the type of result register for ops with type_var operands.
202
$result_kind := (nqp::atpos_i(@operands_values, $operands_offset) +& $MVM_operand_type_mask) / 8;
204
# fixup the variable typecode if there is one
205
if ($type_var_kind && $result_kind == $MVM_operand_type_var / 8) {
206
$result_kind := $type_var_kind;
209
$result_reg := $*REGALLOC.fresh_register($result_kind);
211
nqp::unshift(@arg_regs, $result_reg);
214
# Add operation node.
215
nqp::push(@all_ins, MAST::Op.new(
219
# Build instruction list.
221
?? $qastcomp.coerce(MAST::InstructionList.new(@all_ins, $result_reg, $result_kind), $want)
222
!! MAST::InstructionList.new(@all_ins, $result_reg, $result_kind);
225
# Adds a core op handler.
226
method add_core_op($op, $handler) {
227
%core_ops{$op} := $handler;
230
# Adds a HLL op handler.
231
method add_hll_op($hll, $op, $handler) {
232
%hll_ops{$hll} := {} unless %hll_ops{$hll};
233
%hll_ops{$hll}{$op} := $handler;
236
# Adds a core op that maps to a Moar op.
237
method add_core_moarop_mapping($op, $moarop, $ret = -1, :$mapper?) {
238
my $moarop_mapper := $mapper
239
?? $mapper(self, $moarop, $ret)
240
!! self.moarop_mapper($moarop, $ret);
241
%core_ops{$op} := -> $qastcomp, $op {
242
$moarop_mapper($qastcomp, $op.op, $op.list)
246
# Adds a HLL op that maps to a Moar op.
247
method add_hll_moarop_mapping($hll, $op, $moarop, $ret = -1, :$mapper?) {
248
my $moarop_mapper := $mapper
249
?? $mapper(self, $moarop, $ret)
250
!! self.moarop_mapper($moarop, $ret);
251
%hll_ops{$hll} := {} unless %hll_ops{$hll};
252
%hll_ops{$hll}{$op} := -> $qastcomp, $op {
253
$moarop_mapper($qastcomp, $op.op, $op.list)
257
# Returns a mapper closure for turning an operation into a Moar op.
258
# $ret is the 0-based index of which arg to use as the result when
259
# the moarop is void.
260
method moarop_mapper($moarop, $ret) {
261
# do a little checking of input values
266
my $op_num := %op_codes{$moarop};
267
my $num_operands := nqp::atpos_i(@operands_counts, $op_num);
268
my $operands_offset := nqp::atpos_i(@operands_offsets, $op_num);
269
nqp::die("moarop $moarop return arg index out of range")
270
if $ret < -1 || $ret >= $num_operands;
271
nqp::die("moarop $moarop is not void")
272
if $num_operands && (nqp::atpos_i(@operands_values, $operands_offset) +& $MVM_operand_rw_mask) ==
273
$MVM_operand_write_reg;
276
-> $qastcomp, $op_name, @op_args {
277
$self.compile_mastop($qastcomp, $moarop, @op_args,
278
:returnarg($ret), :opname($op_name))
282
# Adds a HLL box handler.
283
method add_hll_box($hll, $type, $handler) {
284
unless $type == $MVM_reg_int64 || $type == $MVM_reg_num64 || $type == $MVM_reg_str || $type == $MVM_reg_void {
285
nqp::die("Unknown box type '$type'");
287
%hll_box{$hll} := {} unless nqp::existskey(%hll_box, $hll);
288
%hll_box{$hll}{$type} := $handler;
291
# Adds a HLL unbox handler.
292
method add_hll_unbox($hll, $type, $handler) {
293
unless $type == $MVM_reg_int64 || $type == $MVM_reg_num64 || $type == $MVM_reg_str {
294
nqp::die("Unknown unbox type '$type'");
296
%hll_unbox{$hll} := {} unless nqp::existskey(%hll_unbox, $hll);
297
%hll_unbox{$hll}{$type} := $handler;
300
# Generates instructions to box the result in reg.
301
method box($qastcomp, $hll, $type, $reg) {
302
(%hll_box{$hll}{$type} // %hll_box{''}{$type})($qastcomp, $reg)
305
# Generates instructions to unbox the result in reg.
306
method unbox($qastcomp, $hll, $type, $reg) {
307
(%hll_unbox{$hll}{$type} // %hll_unbox{''}{$type})($qastcomp, $reg)
311
# Set of sequential statements
312
QAST::MASTOperations.add_core_op('stmts', -> $qastcomp, $op {
313
$qastcomp.as_mast(QAST::Stmts.new( |@($op) ))
317
QAST::MASTOperations.add_core_op('list', -> $qastcomp, $op {
318
# Just desugar to create the empty list.
319
my $arr := $qastcomp.as_mast(QAST::Op.new(
321
QAST::Op.new( :op('hlllist') )
324
my $arr_reg := $arr.result_reg;
325
# Push things to the list.
327
my $item := $qastcomp.as_mast($_, :want($MVM_reg_obj));
328
my $item_reg := $item.result_reg;
330
push_op($arr.instructions, 'push_o', $arr_reg, $item_reg);
331
$*REGALLOC.release_register($item_reg, $MVM_reg_obj);
333
my $newer := MAST::InstructionList.new(nqp::list(), $arr_reg, $MVM_reg_obj);
338
QAST::MASTOperations.add_core_op('list_i', -> $qastcomp, $op {
339
# Just desugar to create the empty list.
340
my $arr := $qastcomp.as_mast(QAST::Op.new(
342
QAST::Op.new( :op('bootintarray') )
345
my $arr_reg := $arr.result_reg;
346
# Push things to the list.
348
my $item := $qastcomp.as_mast($_, :want($MVM_reg_int64));
349
my $item_reg := $item.result_reg;
351
push_op($arr.instructions, 'push_i', $arr_reg, $item_reg);
352
$*REGALLOC.release_register($item_reg, $MVM_reg_int64);
354
my $newer := MAST::InstructionList.new(nqp::list(), $arr_reg, $MVM_reg_obj);
359
QAST::MASTOperations.add_core_op('list_n', -> $qastcomp, $op {
360
# Just desugar to create the empty list.
361
my $arr := $qastcomp.as_mast(QAST::Op.new(
363
QAST::Op.new( :op('bootnumarray') )
366
my $arr_reg := $arr.result_reg;
367
# Push things to the list.
369
my $item := $qastcomp.as_mast($_, :want($MVM_reg_num64));
370
my $item_reg := $item.result_reg;
372
push_op($arr.instructions, 'push_n', $arr_reg, $item_reg);
373
$*REGALLOC.release_register($item_reg, $MVM_reg_num64);
375
my $newer := MAST::InstructionList.new(nqp::list(), $arr_reg, $MVM_reg_obj);
380
QAST::MASTOperations.add_core_op('list_s', -> $qastcomp, $op {
381
# Just desugar to create the empty list.
382
my $arr := $qastcomp.as_mast(QAST::Op.new(
384
QAST::Op.new( :op('bootstrarray') )
387
my $arr_reg := $arr.result_reg;
388
# Push things to the list.
390
my $item := $qastcomp.as_mast($_, :want($MVM_reg_str));
391
my $item_reg := $item.result_reg;
393
push_op($arr.instructions, 'push_s', $arr_reg, $item_reg);
394
$*REGALLOC.release_register($item_reg, $MVM_reg_str);
396
my $newer := MAST::InstructionList.new(nqp::list(), $arr_reg, $MVM_reg_obj);
401
QAST::MASTOperations.add_core_op('list_b', -> $qastcomp, $op {
402
# Just desugar to create the empty list.
403
my $arr := $qastcomp.as_mast(QAST::Op.new(
405
QAST::Op.new( :op('bootarray') )
408
my $arr_reg := $arr.result_reg;
409
# Push things to the list.
411
nqp::die("list_b must have a list of blocks")
412
unless nqp::istype($_, QAST::Block);
413
my $cuid := $_.cuid();
414
my $frame := %*MAST_FRAMES{$cuid};
415
my $item_reg := $*REGALLOC.fresh_register($MVM_reg_obj);
416
push_op($arr.instructions, 'getcode', $item_reg, $frame);
417
push_op($arr.instructions, 'push_o', $arr_reg, $item_reg);
418
$*REGALLOC.release_register($item_reg, $MVM_reg_obj);
420
my $newer := MAST::InstructionList.new(nqp::list(), $arr_reg, $MVM_reg_obj);
425
QAST::MASTOperations.add_core_op('qlist', -> $qastcomp, $op {
426
$qastcomp.as_mast(QAST::Op.new( :op('list'), |@($op) ))
428
QAST::MASTOperations.add_core_op('hash', -> $qastcomp, $op {
429
# Just desugar to create the empty hash.
430
my $hash := $qastcomp.as_mast(QAST::Op.new(
432
QAST::Op.new( :op('hllhash') )
435
my $hash_reg := $hash.result_reg;
436
for $op.list -> $key, $val {
437
my $key_mast := $qastcomp.as_mast($key, :want($MVM_reg_str));
438
my $val_mast := $qastcomp.as_mast($val, :want($MVM_reg_obj));
439
my $key_reg := $key_mast.result_reg;
440
my $val_reg := $val_mast.result_reg;
441
$hash.append($key_mast);
442
$hash.append($val_mast);
443
push_op($hash.instructions, 'bindkey_o', $hash_reg, $key_reg, $val_reg);
444
$*REGALLOC.release_register($key_reg, $MVM_reg_str);
445
$*REGALLOC.release_register($val_reg, $MVM_reg_obj);
447
my $newer := MAST::InstructionList.new(nqp::list(), $hash_reg, $MVM_reg_obj);
448
$hash.append($newer);
454
for <if unless> -> $op_name {
455
QAST::MASTOperations.add_core_op($op_name, -> $qastcomp, $op {
456
# Check operand count.
457
my $operands := +$op.list;
458
nqp::die("Operation '$op_name' needs either 2 or 3 operands")
459
if $operands < 2 || $operands > 3;
462
my $if_id := $qastcomp.unique($op_name);
463
my $else_lbl := MAST::Label.new(:name($if_id ~ '_else'));
464
my $end_lbl := MAST::Label.new(:name($if_id ~ '_end'));
466
# Compile each of the children, handling any that want the conditional
467
# value to be passed.
469
sub needs_cond_passed($n) {
470
nqp::istype($n, QAST::Block) && $n.arity > 0 &&
471
($n.blocktype eq 'immediate' || $n.blocktype eq 'immediate_static')
473
my $cond_temp_lbl := needs_cond_passed($op[1]) || needs_cond_passed($op[2])
474
?? $qastcomp.unique('__im_cond_')
477
@comp_ops[0] := $qastcomp.as_mast(QAST::Op.new(
479
QAST::Var.new( :name($cond_temp_lbl), :scope('local'), :decl('var') ),
482
@comp_ops[0] := $qastcomp.as_mast($op[0]);
484
if needs_cond_passed($op[1]) {
485
$op[1].blocktype('declaration');
486
@comp_ops[1] := $qastcomp.as_mast(QAST::Op.new(
489
QAST::Var.new( :name($cond_temp_lbl), :scope('local') )));
492
@comp_ops[1] := $qastcomp.as_mast($op[1]);
494
if needs_cond_passed($op[2]) {
495
$op[2].blocktype('declaration');
496
@comp_ops[2] := $qastcomp.as_mast(QAST::Op.new(
499
QAST::Var.new( :name($cond_temp_lbl), :scope('local') )));
502
@comp_ops[2] := $qastcomp.as_mast($op[2]);
505
if (@comp_ops[0].result_kind == $MVM_reg_void) {
506
nqp::die("operation '$op_name' condition cannot be void");
511
my $is_void := nqp::defined($*WANT) && $*WANT == $MVM_reg_void;
513
$res_reg := MAST::VOID;
516
$res_kind := $operands == 3
517
?? (@comp_ops[1].result_kind == @comp_ops[2].result_kind
518
&& @comp_ops[1].result_kind != $MVM_reg_void
519
?? @comp_ops[1].result_kind
521
!! (@comp_ops[0].result_kind == @comp_ops[1].result_kind
522
?? @comp_ops[0].result_kind
524
$res_reg := $*REGALLOC.fresh_register($res_kind);
529
# Evaluate the condition first; store result if needed.
530
push_ilist(@ins, @comp_ops[0]);
531
if $operands == 2 && !$is_void {
532
my $il := MAST::InstructionList.new(@ins, @comp_ops[0].result_reg, @comp_ops[0].result_kind);
533
$qastcomp.coerce($il, $res_kind);
534
push_op(@ins, 'set', $res_reg, $il.result_reg);
539
resolve_condition_op(@comp_ops[0].result_kind, $op_name eq 'if'),
540
@comp_ops[0].result_reg,
541
($operands == 3 ?? $else_lbl !! $end_lbl)
544
# Emit the then, stash the result
545
push_ilist(@ins, @comp_ops[1]);
546
if (!$is_void && @comp_ops[1].result_kind != $res_kind) {
547
my $coercion := $qastcomp.coercion(@comp_ops[1],
548
(nqp::defined($*WANT) ?? $*WANT !! $MVM_reg_obj));
549
push_ilist(@ins, $coercion);
550
$*REGALLOC.release_register($res_reg, $res_kind);
551
$res_reg := $*REGALLOC.fresh_register($coercion.result_kind);
552
push_op(@ins, 'set', $res_reg, $coercion.result_reg);
553
$res_kind := $coercion.result_kind;
556
push_op(@ins, 'set', $res_reg, @comp_ops[1].result_reg);
558
$*REGALLOC.release_register(@comp_ops[1].result_reg, @comp_ops[1].result_kind);
560
# Handle else branch (coercion of condition result if 2-arg).
561
push_op(@ins, 'goto', $end_lbl);
562
nqp::push(@ins, $else_lbl);
564
push_ilist(@ins, @comp_ops[2]);
566
if @comp_ops[2].result_kind != $res_kind {
567
my $coercion := $qastcomp.coercion(@comp_ops[2], $res_kind);
568
push_ilist(@ins, $coercion);
569
push_op(@ins, 'set', $res_reg, $coercion.result_reg);
572
push_op(@ins, 'set', $res_reg, @comp_ops[2].result_reg);
575
$*REGALLOC.release_register(@comp_ops[2].result_reg, @comp_ops[2].result_kind);
578
if !$is_void && @comp_ops[0].result_kind != $res_kind {
579
my $coercion := $qastcomp.coercion(@comp_ops[0], $res_kind);
580
push_ilist(@ins, $coercion);
581
push_op(@ins, 'set', $res_reg, $coercion.result_reg);
584
$*REGALLOC.release_register(@comp_ops[0].result_reg, @comp_ops[0].result_kind);
585
nqp::push(@ins, $end_lbl);
587
MAST::InstructionList.new(@ins, $res_reg, $res_kind)
591
QAST::MASTOperations.add_core_op('defor', -> $qastcomp, $op {
593
nqp::die("Operation 'defor' needs 2 operands");
596
# Compile the expression.
597
my $res_reg := $*REGALLOC.fresh_o();
598
my $expr := $qastcomp.as_mast($op[0], :want($MVM_reg_obj));
600
# Emit defined check.
601
my $def_reg := $*REGALLOC.fresh_i();
602
my $lbl := MAST::Label.new(:name($qastcomp.unique('defor')));
603
push_op($expr.instructions, 'set', $res_reg, $expr.result_reg);
604
push_op($expr.instructions, 'isconcrete', $def_reg, $res_reg);
605
push_op($expr.instructions, 'if_i', $def_reg, $lbl);
606
$*REGALLOC.release_register($def_reg, $MVM_reg_int64);
609
my $then := $qastcomp.as_mast($op[1], :want($MVM_reg_obj));
610
$*REGALLOC.release_register($expr.result_reg, $MVM_reg_obj);
612
push_op($expr.instructions, 'set', $res_reg, $then.result_reg);
613
nqp::push($expr.instructions, $lbl);
614
$*REGALLOC.release_register($then.result_reg, $MVM_reg_obj);
615
my $newer := MAST::InstructionList.new(nqp::list(), $res_reg, $MVM_reg_obj);
616
$expr.append($newer);
621
QAST::MASTOperations.add_core_op('ifnull', -> $qastcomp, $op {
623
nqp::die("The 'ifnull' op expects two children");
626
# Compile the expression.
627
my $res_reg := $*REGALLOC.fresh_o();
628
my $expr := $qastcomp.as_mast($op[0], :want($MVM_reg_obj));
631
my $lbl := MAST::Label.new(:name($qastcomp.unique('ifnull')));
632
push_op($expr.instructions, 'set', $res_reg, $expr.result_reg);
633
push_op($expr.instructions, 'ifnonnull', $expr.result_reg, $lbl);
636
my $then := $qastcomp.as_mast($op[1], :want($MVM_reg_obj));
637
$*REGALLOC.release_register($expr.result_reg, $MVM_reg_obj);
639
push_op($expr.instructions, 'set', $res_reg, $then.result_reg);
640
nqp::push($expr.instructions, $lbl);
641
$*REGALLOC.release_register($then.result_reg, $MVM_reg_obj);
642
my $newer := MAST::InstructionList.new(nqp::list(), $res_reg, $MVM_reg_obj);
643
$expr.append($newer);
649
for ('', 'repeat_') -> $repness {
650
for <while until> -> $op_name {
651
QAST::MASTOperations.add_core_op("$repness$op_name", -> $qastcomp, $op {
653
my $while_id := $qastcomp.unique($op_name);
654
my $test_lbl := MAST::Label.new(:name($while_id ~ '_test'));
655
my $next_lbl := MAST::Label.new(:name($while_id ~ '_next'));
656
my $redo_lbl := MAST::Label.new(:name($while_id ~ '_redo'));
657
my $done_lbl := MAST::Label.new(:name($while_id ~ '_done'));
659
# Compile each of the children; we'll need to look at the result
660
# types and pick an overall result type if in non-void context.
666
if $_.named eq 'nohandler' { $handler := 0; }
668
my $*HAVE_IMM_ARG := $_.arity > 0 && $_ =:= $op.list[1];
669
my $comp := $qastcomp.as_mast($_);
670
@comp_ops.push($comp);
671
@comp_types.push($comp.result_kind);
672
if $*HAVE_IMM_ARG && !$*IMM_ARG {
673
nqp::die("$op_name block expects an argument, but there's no immediate block to take it");
677
my $res_kind := @comp_types[0] == @comp_types[1]
680
my $res_reg := $*REGALLOC.fresh_register($res_kind);
682
# Check operand count.
683
my $operands := +@comp_ops;
684
nqp::die("Operation '$repness$op_name' needs 2 or 3 operands")
685
if $operands != 2 && $operands != 3;
687
# Test the condition and jump to the loop end if it's
690
my $coerced := $qastcomp.coerce(@comp_ops[0], $res_kind);
692
# It's a repeat_ variant, need to go straight into the
693
# loop body unconditionally. Be sure to set the register
694
# for the result to something first.
695
if $res_kind == $MVM_reg_obj {
696
push_op(@loop_il, 'null', $res_reg);
698
elsif $res_kind == $MVM_reg_str {
699
push_op(@loop_il, 'null_s', $res_reg);
701
elsif $res_kind == $MVM_reg_num64 {
702
push_op(@loop_il, 'const_n64', $res_reg,
703
MAST::NVal.new( :value(0.0) ));
706
push_op(@loop_il, 'const_i64', $res_reg,
707
MAST::IVal.new( :value(0) ));
709
push_op(@loop_il, 'goto', $redo_lbl);
711
nqp::push(@loop_il, $test_lbl);
712
push_ilist(@loop_il, $coerced);
713
push_op(@loop_il, 'set', $res_reg, $coerced.result_reg);
715
resolve_condition_op(@comp_ops[0].result_kind, $op_name eq 'while'),
716
@comp_ops[0].result_reg,
720
# Handle immediate blocks wanting the value as an arg.
725
# Emit the loop body; stash the result.
726
my $body := $qastcomp.coerce(@comp_ops[1], $res_kind);
727
nqp::push(@loop_il, $redo_lbl);
728
push_ilist(@loop_il, $body);
729
push_op(@loop_il, 'set', $res_reg, $body.result_reg);
731
# If there's a third child, evaluate it as part of the
734
nqp::push(@loop_il, $next_lbl);
735
push_ilist(@loop_il, @comp_ops[2]);
738
# Emit the iteration jump.
739
push_op(@loop_il, 'goto', $test_lbl);
741
# Emit postlude, with exception handlers if needed. Note that we
742
# don't actually need to emit a bunch of handlers; since a handler
743
# scope will happily throw control to a label of our choosing, we
744
# just have the goto label be the place the control exception
745
# needs to send control to.
747
my @redo_il := [MAST::HandlerScope.new(
748
:instructions(@loop_il),
749
:category_mask($HandlerCategory::redo),
750
:action($HandlerAction::unwind_and_goto),
753
my @next_il := [MAST::HandlerScope.new(
754
:instructions(@redo_il),
755
:category_mask($HandlerCategory::next),
756
:action($HandlerAction::unwind_and_goto),
757
:goto($operands == 3 ?? $next_lbl !! $test_lbl)
759
my @last_il := [MAST::HandlerScope.new(
760
:instructions(@next_il),
761
:category_mask($HandlerCategory::last),
762
:action($HandlerAction::unwind_and_goto),
765
nqp::push(@last_il, $done_lbl);
766
MAST::InstructionList.new(@last_il, $res_reg, $res_kind)
769
nqp::push(@loop_il, $done_lbl);
770
MAST::InstructionList.new(@loop_il, $res_reg, $res_kind)
776
QAST::MASTOperations.add_core_op('for', -> $qastcomp, $op {
780
if $_.named eq 'nohandler' { $handler := 0; }
781
else { @operands.push($_) }
785
nqp::die("Operation 'for' needs 2 operands");
787
unless nqp::istype(@operands[1], QAST::Block) {
788
nqp::die("Operation 'for' expects a block as its second operand");
790
if @operands[1].blocktype eq 'immediate' {
791
@operands[1].blocktype('declaration');
793
elsif @operands[1].blocktype eq 'immediate_static' {
794
@operands[1].blocktype('declaration_static');
797
# Create result temporary if we'll need one.
798
my $res := $*WANT == $MVM_reg_void ?? 0 !! $*REGALLOC.fresh_o();
800
# Evaluate the thing we'll iterate over, get the iterator and
801
# store it in a temporary.
803
my $list_il := $qastcomp.as_mast(@operands[0], :want($MVM_reg_obj));
804
push_ilist($il, $list_il);
806
push_op($il, 'set', $res, $list_il.result_reg);
808
my $iter_tmp := $*REGALLOC.fresh_o();
809
push_op($il, 'iter', $iter_tmp, $list_il.result_reg);
811
# Do similar for the block.
812
my $block_res := $qastcomp.as_mast(@operands[1], :want($MVM_reg_obj));
813
push_ilist($il, $block_res);
815
# Some labels we'll need.
816
my $for_id := $qastcomp.unique('for');
817
my $lbl_next := MAST::Label.new( :name($for_id ~ 'next') );
818
my $lbl_redo := MAST::Label.new( :name($for_id ~ 'redo') );
819
my $lbl_done := MAST::Label.new( :name($for_id ~ 'done') );
823
nqp::push($loop_il, $lbl_next);
824
push_op($loop_il, 'unless_o', $iter_tmp, $lbl_done);
825
$loop_il := MAST::InstructionList.new($loop_il, MAST::VOID, $MVM_reg_void);
827
# Fetch values into temporaries (on the stack ain't enough in case
832
my $arity := @operands[1].arity || 1;
834
my $tmp := $*REGALLOC.fresh_o();
835
push_op($val_il, 'shift_o', $tmp, $iter_tmp);
836
nqp::push(@val_temps, $tmp);
837
nqp::push(@arg_flags, $Arg::obj);
838
$arity := $arity - 1;
840
nqp::push($val_il, $lbl_redo);
841
$val_il := MAST::InstructionList.new($val_il, MAST::VOID, $MVM_reg_void);
843
# Now do block invocation.
846
:target($block_res.result_reg),
852
:target($block_res.result_reg),
856
$inv_il := MAST::InstructionList.new([$inv_il], MAST::VOID, $MVM_reg_void);
857
push_ilist($val_il.instructions, $inv_il);
860
push_ilist($loop_il.instructions, $val_il);
861
push_op($loop_il.instructions, 'goto', $lbl_next );
863
# Emit postlude, wrapping in handlers if needed.
865
my @ins_wrap := $loop_il.instructions;
866
@ins_wrap := [MAST::HandlerScope.new(
867
:instructions(@ins_wrap),
868
:category_mask($HandlerCategory::redo),
869
:action($HandlerAction::unwind_and_goto),
872
@ins_wrap := [MAST::HandlerScope.new(
873
:instructions(@ins_wrap),
874
:category_mask($HandlerCategory::next),
875
:action($HandlerAction::unwind_and_goto),
878
nqp::push($il, MAST::HandlerScope.new(
879
:instructions(@ins_wrap),
880
:category_mask($HandlerCategory::last),
881
:action($HandlerAction::unwind_and_goto),
886
push_ilist($il, $loop_il);
888
nqp::push($il, $lbl_done);
891
my $result := $res ?? MAST::InstructionList.new($il, $res, $*WANT) !! MAST::InstructionList.new($il, MAST::VOID, $MVM_reg_void);
892
$*REGALLOC.release_register($list_il.result_reg, $list_il.result_kind);
893
$*REGALLOC.release_register($block_res.result_reg, $block_res.result_kind);
894
for @val_temps { $*REGALLOC.release_register($_, $MVM_reg_obj) }
895
$*REGALLOC.release_register($inv_il.result_reg, $inv_il.result_kind);
900
my @kind_to_args := [0,
901
$Arg::int, # $MVM_reg_int8 := 1;
902
$Arg::int, # $MVM_reg_int16 := 2;
903
$Arg::int, # $MVM_reg_int32 := 3;
904
$Arg::int, # $MVM_reg_int64 := 4;
905
$Arg::num, # $MVM_reg_num32 := 5;
906
$Arg::num, # $MVM_reg_num64 := 6;
907
$Arg::str, # $MVM_reg_str := 7;
908
$Arg::obj # $MVM_reg_obj := 8;
911
sub handle_arg($arg, $qastcomp, @ins, @arg_regs, @arg_flags, @arg_kinds) {
912
# generate the code for the arg expression
913
my $arg_mast := $qastcomp.as_mast($arg);
915
nqp::die("arg expression cannot be void")
916
if $arg_mast.result_kind == $MVM_reg_void;
918
nqp::die("arg code did not result in a MAST::Local")
919
unless $arg_mast.result_reg && $arg_mast.result_reg ~~ MAST::Local;
921
nqp::push(@arg_kinds, $arg_mast.result_kind);
923
# append the code to the main instruction list
924
push_ilist(@ins, $arg_mast);
926
# build up the typeflag
927
my $result_typeflag := @kind_to_args[$arg_mast.result_kind];
928
if nqp::can($arg, 'flat') && $arg.flat {
930
$result_typeflag := $result_typeflag +| $Arg::flatnamed;
933
$result_typeflag := $result_typeflag +| $Arg::flat;
936
elsif nqp::can($arg, 'named') && $arg.named -> $name {
937
# add in the extra arg for the name
938
nqp::push(@arg_regs, MAST::SVal.new( value => $name ));
940
$result_typeflag := $result_typeflag +| $Arg::named;
943
# stash the result register and result typeflag
944
nqp::push(@arg_regs, $arg_mast.result_reg);
945
nqp::push(@arg_flags, $result_typeflag);
948
sub arrange_args(@in) {
952
nqp::push(((nqp::can($_, 'named') && $_.named && (!nqp::can($_, 'flat') || !$_.flat)) ?? @named !! @posit), $_);
954
for @named { nqp::push(@posit, $_) }
958
QAST::MASTOperations.add_core_op('call', sub ($qastcomp, $op) {
959
# Cheat for __MVM__ => nqp::foo
960
if nqp::substr($op.name, 0, 8) eq '&__MVM__' {
961
my $realname := nqp::substr($op.name, 8);
962
return $qastcomp.as_mast(QAST::Op.new( :op($realname), |$op.list ));
965
# Work out what callee is.
967
my @args := $op.list;
969
$callee := $qastcomp.as_mast(QAST::Var.new( :name($op.name), :scope('lexical') ));
972
@args := nqp::clone(@args);
973
$callee := $qastcomp.as_mast(@args.shift());
976
nqp::die("No name for call and empty children list");
978
@args := arrange_args(@args);
980
nqp::die("callee expression must be an object")
981
unless $callee.result_kind == $MVM_reg_obj;
983
nqp::die("callee code did not result in a MAST::Local")
984
unless $callee.result_reg && $callee.result_reg ~~ MAST::Local;
986
# main instruction list
987
my @ins := nqp::list();
988
# the result MAST::Locals of the arg expressions
989
my @arg_regs := nqp::list();
990
# the result kind codes of the arg expressions
991
my @arg_kinds := nqp::list();
992
# the args' flags in the protocol the MAST compiler expects
993
my @arg_flags := nqp::list();
995
# Append the code to evaluate the callee expression
996
push_ilist(@ins, $callee);
1000
handle_arg($_, $qastcomp, @ins, @arg_regs, @arg_flags, @arg_kinds);
1003
# Release the callee's result register
1004
$*REGALLOC.release_register($callee.result_reg, $MVM_reg_obj);
1006
# Release each arg's result register
1008
for @arg_regs -> $reg {
1009
if $reg ~~ MAST::Local {
1010
$*REGALLOC.release_register($reg, @arg_kinds[$arg_num]);
1015
# Figure out result register type
1016
my $res_kind := $qastcomp.type_to_register_kind($op.returns);
1018
# and allocate a register for it. Probably reuse an arg's or the callee's.
1019
my $res_reg := $*REGALLOC.fresh_register($res_kind);
1022
nqp::push(@ins, MAST::Call.new(
1023
:target($callee.result_reg),
1029
MAST::InstructionList.new(@ins, $res_reg, $res_kind)
1032
QAST::MASTOperations.add_core_op('callmethod', -> $qastcomp, $op {
1033
my @args := nqp::clone($op.list);
1035
nqp::die('Method call node requires at least one child');
1037
my $invocant := $qastcomp.as_mast(@args.shift(), :want($MVM_reg_obj));
1038
my $methodname_expr;
1043
$methodname_expr := @args.shift();
1046
nqp::die("Method call must either supply a name or have a child node that evaluates to the name");
1048
@args := arrange_args(@args);
1050
nqp::die("invocant expression must be an object")
1051
unless $invocant.result_kind == $MVM_reg_obj;
1053
nqp::die("invocant code did not result in a MAST::Local")
1054
unless $invocant.result_reg && $invocant.result_reg ~~ MAST::Local;
1056
# main instruction list
1058
# the result MAST::Locals of the arg expressions
1059
my @arg_regs := [$invocant.result_reg];
1060
# the result kind codes of the arg expressions
1061
my @arg_kinds := [$MVM_reg_obj];
1062
# the args' flags in the protocol the MAST compiler expects
1063
my @arg_flags := [$Arg::obj];
1065
# evaluate the invocant expression
1066
push_ilist(@ins, $invocant);
1068
# Process arguments.
1070
handle_arg($_, $qastcomp, @ins, @arg_regs, @arg_flags, @arg_kinds);
1073
# generate and emit findmethod code
1074
my $callee_reg := $*REGALLOC.fresh_o();
1076
# This will hold the 3rd argument to findmeth(_s) - the method name
1077
# either a MAST::SVal or an $MVM_reg_str
1080
$method_name := MAST::SVal.new( :value($op.name) );
1083
my $method_name_ilist := $qastcomp.as_mast($methodname_expr, :want($MVM_reg_str));
1084
push_ilist(@ins, $method_name_ilist);
1085
$method_name := $method_name_ilist.result_reg;
1088
# push the op that finds the method based on either the provided name
1089
# or the provided name-producing expression.
1090
push_op(@ins, ($op.name ?? 'findmeth' !! 'findmeth_s'),
1091
$callee_reg, $invocant.result_reg, $method_name);
1093
# release the method name register if we used one
1094
$*REGALLOC.release_register($method_name, $MVM_reg_str) unless $op.name;
1096
# release the callee register
1097
$*REGALLOC.release_register($callee_reg, $MVM_reg_obj);
1099
# Release the invocant's and each arg's result registers
1101
for @arg_regs -> $reg {
1102
if $reg ~~ MAST::Local {
1103
$*REGALLOC.release_register($reg, @arg_kinds[$arg_num]);
1108
# Figure out expected result register type
1109
my $res_kind := $qastcomp.type_to_register_kind($op.returns);
1111
# and allocate a register for it. Probably reuse an arg's or the invocant's.
1112
my $res_reg := $*REGALLOC.fresh_register($res_kind);
1115
nqp::push(@ins, MAST::Call.new(
1116
:target($callee_reg),
1122
MAST::InstructionList.new(@ins, $res_reg, $res_kind)
1125
QAST::MASTOperations.add_core_op('lexotic', -> $qastcomp, $op {
1126
my $lex_label := MAST::Label.new( :name($qastcomp.unique('lexotic_')) );
1127
my $end_label := MAST::Label.new( :name($qastcomp.unique('lexotic_end_')) );
1129
# Create new lexotic and install it lexically.
1131
my $lex_tmp := $*REGALLOC.fresh_register($MVM_reg_obj);
1132
$*BLOCK.add_lexical(QAST::Var.new( :name($op.name), :scope('lexical'), :decl('var') ));
1133
push_op(@ins, 'newlexotic', $lex_tmp, $lex_label);
1134
push_op(@ins, 'bindlex', $*BLOCK.lexical($op.name), $lex_tmp);
1136
# Emit the body, and go to the end of the lexotic code; the body's result
1138
my $body := $qastcomp.compile_all_the_stmts($op.list, :want($MVM_reg_obj));
1139
nqp::push(@ins, MAST::HandlerScope.new(
1140
:instructions($body.instructions),
1141
:category_mask($HandlerCategory::return),
1142
:action($HandlerAction::unwind_and_goto),
1145
push_op(@ins, 'goto', $end_label);
1147
# Finally, emit the lexotic handler.
1148
nqp::push(@ins, $lex_label);
1149
push_op(@ins, 'lexoticresult', $body.result_reg, $lex_tmp);
1150
nqp::push(@ins, $end_label);
1152
$*REGALLOC.release_register($lex_tmp, $MVM_reg_obj);
1154
MAST::InstructionList.new(@ins, $body.result_reg, $MVM_reg_obj)
1158
QAST::MASTOperations.add_core_op('bind', -> $qastcomp, $op {
1160
my @children := $op.list;
1161
if +@children != 2 {
1162
nqp::die("A 'bind' op must have exactly two children");
1164
unless nqp::istype(@children[0], QAST::Var) {
1165
nqp::die("First child of a 'bind' op must be a QAST::Var");
1168
# Set the QAST of the think we're to bind, then delegate to
1169
# the compilation of the QAST::Var to handle the rest.
1170
my $*BINDVAL := @children[1];
1171
$qastcomp.as_mast(@children[0])
1174
# Exception handling/munging.
1175
QAST::MASTOperations.add_core_moarop_mapping('die', 'die');
1176
QAST::MASTOperations.add_core_moarop_mapping('die_s', 'die');
1177
QAST::MASTOperations.add_core_moarop_mapping('exception', 'exception');
1178
QAST::MASTOperations.add_core_moarop_mapping('getextype', 'getexcategory');
1179
QAST::MASTOperations.add_core_moarop_mapping('setextype', 'bindexcategory', 1);
1180
QAST::MASTOperations.add_core_moarop_mapping('getpayload', 'getexpayload');
1181
QAST::MASTOperations.add_core_moarop_mapping('setpayload', 'bindexpayload', 1);
1182
QAST::MASTOperations.add_core_moarop_mapping('getmessage', 'getexmessage');
1183
QAST::MASTOperations.add_core_moarop_mapping('setmessage', 'bindexmessage', 1);
1184
QAST::MASTOperations.add_core_moarop_mapping('newexception', 'newexception');
1185
QAST::MASTOperations.add_core_moarop_mapping('backtracestrings', 'backtracestrings');
1187
QAST::MASTOperations.add_core_moarop_mapping('throw', 'throwdyn');
1188
QAST::MASTOperations.add_core_moarop_mapping('rethrow', 'rethrow');
1189
QAST::MASTOperations.add_core_moarop_mapping('resume', 'resume');
1191
my %handler_names := nqp::hash(
1192
'CATCH', $HandlerCategory::catch,
1193
'CONTROL', $HandlerCategory::control,
1194
'NEXT', $HandlerCategory::next,
1195
'LAST', $HandlerCategory::last,
1196
'REDO', $HandlerCategory::redo,
1197
'TAKE', $HandlerCategory::take,
1198
'WARN', $HandlerCategory::warn,
1199
'PROCEED', $HandlerCategory::proceed,
1200
'SUCCEED', $HandlerCategory::succeed,
1202
QAST::MASTOperations.add_core_op('handle', sub ($qastcomp, $op) {
1203
my @children := nqp::clone($op.list());
1205
nqp::die("The 'handle' op requires at least one child");
1208
# If there's exactly one child, then there's nothing protecting
1209
# it; just compile it and we're done.
1210
my $protected := @children.shift();
1212
return $qastcomp.as_mast($protected);
1215
# Otherwise, we need to generate and install a handler block, which will
1216
# decide that to do by category.
1218
my $hblock := QAST::Block.new(
1221
QAST::Var.new( :name('__category__'), :scope('local'), :decl('var') ),
1224
QAST::Op.new( :op('exception') )
1226
my $push_target := $hblock;
1227
for @children -> $type, $handler {
1228
# Get the category mask.
1229
unless nqp::existskey(%handler_names, $type) {
1230
nqp::die("Invalid handler type '$type'");
1232
my $cat_mask := %handler_names{$type};
1234
# Chain in this handler.
1235
my $check := QAST::Op.new(
1239
QAST::Var.new( :name('__category__'), :scope('local') ),
1240
QAST::IVal.new( :value($cat_mask) )
1244
$push_target.push($check);
1245
$push_target := $check;
1248
$mask := nqp::bitor_i($mask, $cat_mask);
1251
# Add a local and store the handler block into it.
1252
my $hblocal := MAST::Local.new(:index($*MAST_FRAME.add_local(NQPMu)));
1253
my $il := nqp::list();
1254
my $hbmast := $qastcomp.as_mast($hblock, :want($MVM_reg_obj));
1255
push_ilist($il, $hbmast);
1256
push_op($il, 'set', $hblocal, $hbmast.result_reg);
1257
$*REGALLOC.release_register($hbmast.result_reg, $MVM_reg_obj);
1259
# Wrap instructions to try up in a handler and evaluate to the result
1260
# of the protected code of the exception handler.
1261
my $protil := $qastcomp.as_mast($protected, :want($MVM_reg_obj));
1262
my $uwlbl := MAST::Label.new( :name($qastcomp.unique('handle_unwind_')) );
1263
my $endlbl := MAST::Label.new( :name($qastcomp.unique('handle_end_')) );
1264
push_op($protil.instructions, 'goto', $endlbl);
1265
nqp::push($il, MAST::HandlerScope.new(
1266
:instructions($protil.instructions), :goto($uwlbl), :block($hblocal),
1267
:category_mask($mask), :action($HandlerAction::invoke_and_we'll_see)));
1268
nqp::push($il, $uwlbl);
1269
push_op($il, 'takehandlerresult', $protil.result_reg);
1270
nqp::push($il, $endlbl);
1272
MAST::InstructionList.new($il, $protil.result_reg, $MVM_reg_obj)
1275
# Control exception throwing.
1276
my %control_map := nqp::hash(
1277
'next', $HandlerCategory::next,
1278
'last', $HandlerCategory::last,
1279
'redo', $HandlerCategory::redo
1281
QAST::MASTOperations.add_core_op('control', -> $qastcomp, $op {
1282
my $name := $op.name;
1283
if nqp::existskey(%control_map, $name) {
1284
my $il := nqp::list();
1285
my $res := $*REGALLOC.fresh_register($MVM_reg_obj);
1286
push_op($il, 'throwcatdyn', $res,
1287
MAST::IVal.new( :value(%control_map{$name}) ));
1288
MAST::InstructionList.new($il, $res, $MVM_reg_obj)
1291
nqp::die("Unknown control exception type '$name'");
1295
# Default ways to box/unbox (for no particular HLL).
1296
QAST::MASTOperations.add_hll_unbox('', $MVM_reg_int64, -> $qastcomp, $reg {
1297
my $il := nqp::list();
1298
my $a := $*REGALLOC.fresh_register($MVM_reg_num64);
1299
my $b := $*REGALLOC.fresh_register($MVM_reg_int64);
1300
push_op($il, 'smrt_numify', $a, $reg);
1301
push_op($il, 'coerce_ni', $b, $a);
1302
$*REGALLOC.release_register($a, $MVM_reg_num64);
1303
$*REGALLOC.release_register($reg, $MVM_reg_obj);
1304
MAST::InstructionList.new($il, $b, $MVM_reg_int64)
1306
QAST::MASTOperations.add_hll_unbox('', $MVM_reg_num64, -> $qastcomp, $reg {
1307
my $il := nqp::list();
1308
my $res_reg := $*REGALLOC.fresh_register($MVM_reg_num64);
1309
push_op($il, 'smrt_numify', $res_reg, $reg);
1310
$*REGALLOC.release_register($reg, $MVM_reg_obj);
1311
MAST::InstructionList.new($il, $res_reg, $MVM_reg_num64)
1313
QAST::MASTOperations.add_hll_unbox('', $MVM_reg_str, -> $qastcomp, $reg {
1314
my $il := nqp::list();
1315
my $res_reg := $*REGALLOC.fresh_register($MVM_reg_str);
1316
push_op($il, 'smrt_strify', $res_reg, $reg);
1317
$*REGALLOC.release_register($reg, $MVM_reg_obj);
1318
MAST::InstructionList.new($il, $res_reg, $MVM_reg_str)
1320
sub boxer($kind, $type_op, $op) {
1321
-> $qastcomp, $reg {
1322
my $il := nqp::list();
1323
my $res_reg := $*REGALLOC.fresh_register($MVM_reg_obj);
1324
push_op($il, $type_op, $res_reg);
1325
push_op($il, $op, $res_reg, $reg, $res_reg);
1326
$*REGALLOC.release_register($reg, $kind);
1327
MAST::InstructionList.new($il, $res_reg, $MVM_reg_obj)
1330
QAST::MASTOperations.add_hll_box('', $MVM_reg_int64, boxer($MVM_reg_int64, 'hllboxtype_i', 'box_i'));
1331
QAST::MASTOperations.add_hll_box('', $MVM_reg_num64, boxer($MVM_reg_num64, 'hllboxtype_n', 'box_n'));
1332
QAST::MASTOperations.add_hll_box('', $MVM_reg_str, boxer($MVM_reg_str, 'hllboxtype_s', 'box_s'));
1333
QAST::MASTOperations.add_hll_box('', $MVM_reg_void, -> $qastcomp, $reg {
1334
my $il := nqp::list();
1335
my $res_reg := $*REGALLOC.fresh_register($MVM_reg_obj);
1336
push_op($il, 'null', $res_reg);
1337
MAST::InstructionList.new($il, $res_reg, $MVM_reg_obj)
1340
# Context introspection
1341
QAST::MASTOperations.add_core_moarop_mapping('ctx', 'ctx');
1342
QAST::MASTOperations.add_core_moarop_mapping('ctxouter', 'ctxouter');
1343
QAST::MASTOperations.add_core_moarop_mapping('ctxcaller', 'ctxcaller');
1344
QAST::MASTOperations.add_core_moarop_mapping('curcode', 'curcode');
1345
QAST::MASTOperations.add_core_moarop_mapping('callercode', 'callercode');
1346
QAST::MASTOperations.add_core_moarop_mapping('ctxlexpad', 'ctxlexpad');
1347
QAST::MASTOperations.add_core_moarop_mapping('curlexpad', 'ctx');
1348
QAST::MASTOperations.add_core_moarop_mapping('lexprimspec', 'lexprimspec');
1350
# Argument capture processing, for writing things like multi-dispatchers in
1351
# high level languages.
1352
QAST::MASTOperations.add_core_moarop_mapping('usecapture', 'usecapture');
1353
QAST::MASTOperations.add_core_moarop_mapping('savecapture', 'savecapture');
1354
QAST::MASTOperations.add_core_moarop_mapping('captureposelems', 'captureposelems');
1355
QAST::MASTOperations.add_core_moarop_mapping('captureposarg', 'captureposarg');
1356
QAST::MASTOperations.add_core_moarop_mapping('captureposarg_i', 'captureposarg_i');
1357
QAST::MASTOperations.add_core_moarop_mapping('captureposarg_n', 'captureposarg_n');
1358
QAST::MASTOperations.add_core_moarop_mapping('captureposarg_s', 'captureposarg_s');
1359
QAST::MASTOperations.add_core_moarop_mapping('captureposprimspec', 'captureposprimspec');
1360
QAST::MASTOperations.add_core_moarop_mapping('objprimspec', 'objprimspec');
1362
# Multiple dispatch related.
1363
QAST::MASTOperations.add_core_moarop_mapping('invokewithcapture', 'invokewithcapture');
1364
QAST::MASTOperations.add_core_moarop_mapping('multicacheadd', 'multicacheadd');
1365
QAST::MASTOperations.add_core_moarop_mapping('multicachefind', 'multicachefind');
1368
my %const_map := nqp::hash(
1369
'CCLASS_ANY', 65535,
1370
'CCLASS_UPPERCASE', 1,
1371
'CCLASS_LOWERCASE', 2,
1372
'CCLASS_ALPHABETIC', 4,
1373
'CCLASS_NUMERIC', 8,
1374
'CCLASS_HEXADECIMAL', 16,
1375
'CCLASS_WHITESPACE', 32,
1376
'CCLASS_PRINTING', 64,
1377
'CCLASS_BLANK', 256,
1378
'CCLASS_CONTROL', 512,
1379
'CCLASS_PUNCTUATION', 1024,
1380
'CCLASS_ALPHANUMERIC', 2048,
1381
'CCLASS_NEWLINE', 4096,
1382
'CCLASS_WORD', 8192,
1388
'HLL_ROLE_ARRAY', 4,
1396
'CONTROL_SUCCEED', 128,
1397
'CONTROL_PROCEED', 256,
1405
'STAT_CREATETIME', 5,
1406
'STAT_ACCESSTIME', 6,
1407
'STAT_MODIFYTIME', 7,
1408
'STAT_CHANGETIME', 8,
1409
'STAT_BACKUPTIME', 9,
1413
'STAT_PLATFORM_DEV', -1,
1414
'STAT_PLATFORM_INODE', -2,
1415
'STAT_PLATFORM_MODE', -3,
1416
'STAT_PLATFORM_NLINKS', -4,
1417
'STAT_PLATFORM_DEVTYPE', -5,
1418
'STAT_PLATFORM_BLOCKSIZE', -6,
1419
'STAT_PLATFORM_BLOCKS', -7,
1421
QAST::MASTOperations.add_core_op('const', -> $qastcomp, $op {
1422
if nqp::existskey(%const_map, $op.name) {
1423
$qastcomp.as_mast(QAST::IVal.new( :value(%const_map{$op.name}) ))
1426
nqp::die("Unknown constant '" ~ $op.name ~ "'");
1430
# Default way to do positional and associative lookups.
1431
QAST::MASTOperations.add_core_moarop_mapping('positional_get', 'atpos_o');
1432
QAST::MASTOperations.add_core_moarop_mapping('positional_bind', 'bindpos_o', 2);
1433
QAST::MASTOperations.add_core_moarop_mapping('associative_get', 'atkey_o');
1434
QAST::MASTOperations.add_core_moarop_mapping('associative_bind', 'bindkey_o', 2);
1437
QAST::MASTOperations.add_core_moarop_mapping('say', 'say', 0);
1438
QAST::MASTOperations.add_core_moarop_mapping('print', 'print', 0);
1439
QAST::MASTOperations.add_core_moarop_mapping('stat', 'stat');
1440
QAST::MASTOperations.add_core_moarop_mapping('open', 'open_fh');
1441
QAST::MASTOperations.add_core_moarop_mapping('flushfh', 'sync_fh');
1442
QAST::MASTOperations.add_core_moarop_mapping('getstdin', 'getstdin');
1443
QAST::MASTOperations.add_core_moarop_mapping('getstdout', 'getstdout');
1444
QAST::MASTOperations.add_core_moarop_mapping('getstderr', 'getstderr');
1445
QAST::MASTOperations.add_core_moarop_mapping('setencoding', 'setencoding');
1446
QAST::MASTOperations.add_core_moarop_mapping('tellfh', 'tell_fh');
1447
QAST::MASTOperations.add_core_moarop_mapping('printfh', 'write_fhs');
1448
# QAST::MASTOperations.add_core_moarop_mapping('sayfh', ?);
1449
QAST::MASTOperations.add_core_moarop_mapping('readlinefh', 'readline_fh');
1450
QAST::MASTOperations.add_core_moarop_mapping('readlineintfh', 'readlineint_fh');
1451
QAST::MASTOperations.add_core_moarop_mapping('readallfh', 'readall_fh');
1452
QAST::MASTOperations.add_core_moarop_mapping('eoffh', 'eof_fh');
1453
QAST::MASTOperations.add_core_moarop_mapping('closefh', 'close_fh', 0);
1455
QAST::MASTOperations.add_core_moarop_mapping('chmod', 'chmod_f', 0);
1456
QAST::MASTOperations.add_core_moarop_mapping('unlink', 'delete_f', 0);
1457
QAST::MASTOperations.add_core_moarop_mapping('rmdir', 'rmdir', 0);
1458
QAST::MASTOperations.add_core_moarop_mapping('cwd', 'cwd');
1459
QAST::MASTOperations.add_core_moarop_mapping('chdir', 'chdir', 0);
1460
QAST::MASTOperations.add_core_moarop_mapping('mkdir', 'mkdir', 0);
1461
QAST::MASTOperations.add_core_moarop_mapping('rename', 'rename_f', 0);
1462
QAST::MASTOperations.add_core_moarop_mapping('copy', 'copy_f', 0);
1463
# QAST::MASTOperations.add_core_moarop_mapping('symlink', ?);
1464
# QAST::MASTOperations.add_core_moarop_mapping('link', ?);
1465
QAST::MASTOperations.add_core_op('sprintf', -> $qastcomp, $op {
1466
my @operands := $op.list;
1473
QAST::SVal.new( :value('nqp') ),
1474
QAST::SVal.new( :value('sprintf') )
1479
QAST::MASTOperations.add_core_op('sprintfaddargumenthandler', -> $qastcomp, $op {
1480
my @operands := $op.list;
1487
QAST::SVal.new( :value('nqp') ),
1488
QAST::SVal.new( :value('sprintfaddargumenthandler') )
1495
QAST::MASTOperations.add_core_moarop_mapping('time_i', 'time_i');
1496
QAST::MASTOperations.add_core_moarop_mapping('time_n', 'time_n');
1499
QAST::MASTOperations.add_core_moarop_mapping('add_i', 'add_i');
1500
QAST::MASTOperations.add_core_moarop_mapping('add_I', 'add_I');
1501
QAST::MASTOperations.add_core_moarop_mapping('add_n', 'add_n');
1502
QAST::MASTOperations.add_core_moarop_mapping('sub_i', 'sub_i');
1503
QAST::MASTOperations.add_core_moarop_mapping('sub_I', 'sub_I');
1504
QAST::MASTOperations.add_core_moarop_mapping('sub_n', 'sub_n');
1505
QAST::MASTOperations.add_core_moarop_mapping('mul_i', 'mul_i');
1506
QAST::MASTOperations.add_core_moarop_mapping('mul_I', 'mul_I');
1507
QAST::MASTOperations.add_core_moarop_mapping('mul_n', 'mul_n');
1508
QAST::MASTOperations.add_core_moarop_mapping('div_i', 'div_i');
1509
QAST::MASTOperations.add_core_moarop_mapping('div_I', 'div_I');
1510
QAST::MASTOperations.add_core_moarop_mapping('div_In', 'div_In');
1511
QAST::MASTOperations.add_core_moarop_mapping('div_n', 'div_n');
1512
QAST::MASTOperations.add_core_moarop_mapping('mod_i', 'mod_i');
1513
QAST::MASTOperations.add_core_moarop_mapping('mod_I', 'mod_I');
1514
QAST::MASTOperations.add_core_moarop_mapping('expmod_I', 'expmod_I');
1515
QAST::MASTOperations.add_core_moarop_mapping('mod_n', 'mod_n');
1516
QAST::MASTOperations.add_core_moarop_mapping('neg_i', 'neg_i');
1517
QAST::MASTOperations.add_core_moarop_mapping('neg_I', 'neg_I');
1518
QAST::MASTOperations.add_core_moarop_mapping('neg_n', 'neg_n');
1519
QAST::MASTOperations.add_core_moarop_mapping('pow_n', 'pow_n');
1520
QAST::MASTOperations.add_core_moarop_mapping('pow_I', 'pow_I');
1521
QAST::MASTOperations.add_core_moarop_mapping('abs_i', 'abs_i');
1522
QAST::MASTOperations.add_core_moarop_mapping('abs_I', 'abs_I');
1523
QAST::MASTOperations.add_core_moarop_mapping('abs_n', 'abs_n');
1524
QAST::MASTOperations.add_core_moarop_mapping('ceil_n', 'ceil_n');
1525
QAST::MASTOperations.add_core_moarop_mapping('floor_n', 'floor_n');
1526
QAST::MASTOperations.add_core_moarop_mapping('ln_n', 'log_n'); # looks like this one is never used
1527
QAST::MASTOperations.add_core_moarop_mapping('sqrt_n', 'sqrt_n');
1528
QAST::MASTOperations.add_core_moarop_mapping('base_I', 'base_I');
1529
QAST::MASTOperations.add_core_moarop_mapping('isbig_I', 'isbig_I');
1530
QAST::MASTOperations.add_core_moarop_mapping('radix', 'radix');
1531
QAST::MASTOperations.add_core_moarop_mapping('radix_I', 'radix_I');
1532
QAST::MASTOperations.add_core_moarop_mapping('log_n', 'log_n');
1533
QAST::MASTOperations.add_core_moarop_mapping('exp_n', 'exp_n');
1534
#QAST::MASTOperations.add_core_moarop_mapping('isnanorinf', 'is_inf_or_nan', 'In');
1535
QAST::MASTOperations.add_core_moarop_mapping('isprime_I', 'isprime_I');
1536
QAST::MASTOperations.add_core_moarop_mapping('rand_I', 'rand_I');
1538
# bigint <-> string/num conversions
1539
QAST::MASTOperations.add_core_moarop_mapping('tostr_I', 'coerce_Is');
1540
QAST::MASTOperations.add_core_moarop_mapping('fromstr_I', 'coerce_sI');
1541
QAST::MASTOperations.add_core_moarop_mapping('tonum_I', 'coerce_In');
1542
QAST::MASTOperations.add_core_moarop_mapping('fromnum_I', 'coerce_nI');
1545
QAST::MASTOperations.add_core_moarop_mapping('sin_n', 'sin_n');
1546
QAST::MASTOperations.add_core_moarop_mapping('asin_n', 'asin_n');
1547
QAST::MASTOperations.add_core_moarop_mapping('cos_n', 'cos_n');
1548
QAST::MASTOperations.add_core_moarop_mapping('acos_n', 'acos_n');
1549
QAST::MASTOperations.add_core_moarop_mapping('tan_n', 'tan_n');
1550
QAST::MASTOperations.add_core_moarop_mapping('atan_n', 'atan_n');
1551
QAST::MASTOperations.add_core_moarop_mapping('atan2_n', 'atan2_n');
1552
QAST::MASTOperations.add_core_moarop_mapping('sec_n', 'sec_n');
1553
QAST::MASTOperations.add_core_moarop_mapping('asec_n', 'asec_n');
1554
QAST::MASTOperations.add_core_moarop_mapping('asin_n', 'asin_n');
1555
QAST::MASTOperations.add_core_moarop_mapping('sinh_n', 'sinh_n');
1556
QAST::MASTOperations.add_core_moarop_mapping('cosh_n', 'cosh_n');
1557
QAST::MASTOperations.add_core_moarop_mapping('tanh_n', 'tanh_n');
1558
QAST::MASTOperations.add_core_moarop_mapping('sech_n', 'sech_n');
1560
# esoteric math opcodes
1561
QAST::MASTOperations.add_core_moarop_mapping('gcd_i', 'gcd_i');
1562
QAST::MASTOperations.add_core_moarop_mapping('gcd_I', 'gcd_I');
1563
QAST::MASTOperations.add_core_moarop_mapping('lcm_i', 'lcm_i');
1564
QAST::MASTOperations.add_core_moarop_mapping('lcm_I', 'lcm_I');
1567
QAST::MASTOperations.add_core_moarop_mapping('chars', 'chars');
1568
QAST::MASTOperations.add_core_moarop_mapping('uc', 'uc');
1569
QAST::MASTOperations.add_core_moarop_mapping('lc', 'lc');
1570
QAST::MASTOperations.add_core_moarop_mapping('tc', 'tc');
1571
QAST::MASTOperations.add_core_moarop_mapping('x', 'repeat_s');
1572
QAST::MASTOperations.add_core_moarop_mapping('iscclass', 'iscclass');
1573
QAST::MASTOperations.add_core_moarop_mapping('findcclass', 'findcclass');
1574
QAST::MASTOperations.add_core_moarop_mapping('findnotcclass', 'findnotcclass');
1575
QAST::MASTOperations.add_core_moarop_mapping('escape', 'escape');
1576
QAST::MASTOperations.add_core_moarop_mapping('flip', 'flip');
1577
QAST::MASTOperations.add_core_moarop_mapping('concat', 'concat_s');
1578
QAST::MASTOperations.add_core_moarop_mapping('join', 'join');
1579
QAST::MASTOperations.add_core_moarop_mapping('split', 'split');
1580
QAST::MASTOperations.add_core_moarop_mapping('chr', 'chr');
1581
QAST::MASTOperations.add_core_moarop_mapping('ordfirst', 'ordfirst');
1582
QAST::MASTOperations.add_core_moarop_mapping('ordat', 'ordat');
1583
QAST::MASTOperations.add_core_moarop_mapping('index_s', 'index_s');
1584
QAST::MASTOperations.add_core_moarop_mapping('rindexfrom', 'rindexfrom');
1585
QAST::MASTOperations.add_core_moarop_mapping('substr_s', 'substr_s');
1586
QAST::MASTOperations.add_core_moarop_mapping('codepointfromname', 'getcpbyname');
1587
QAST::MASTOperations.add_core_moarop_mapping('encode', 'encode');
1588
QAST::MASTOperations.add_core_moarop_mapping('decode', 'decode');
1590
QAST::MASTOperations.add_core_op('substr', -> $qastcomp, $op {
1591
my @operands := $op.list;
1592
if +@operands == 2 { nqp::push(@operands, QAST::IVal.new( :value(-1) )) }
1593
$qastcomp.as_mast(QAST::Op.new( :op('substr_s'), |@operands ));
1596
QAST::MASTOperations.add_core_op('ord', -> $qastcomp, $op {
1597
my @operands := $op.list;
1598
$qastcomp.as_mast(+@operands == 1
1599
?? QAST::Op.new( :op('ordfirst'), |@operands )
1600
!! QAST::Op.new( :op('ordat'), |@operands ));
1603
QAST::MASTOperations.add_core_op('index', -> $qastcomp, $op {
1604
my @operands := $op.list;
1605
$qastcomp.as_mast(+@operands == 2
1606
?? QAST::Op.new( :op('index_s'), |@operands, QAST::IVal.new( :value(0)) )
1607
!! QAST::Op.new( :op('index_s'), |@operands ));
1610
QAST::MASTOperations.add_core_op('rindex', -> $qastcomp, $op {
1611
my @operands := $op.list;
1612
$qastcomp.as_mast(+@operands == 2
1613
?? QAST::Op.new( :op('rindexfrom'), |@operands, QAST::IVal.new( :value(-1) ) )
1614
!! QAST::Op.new( :op('rindexfrom'), |@operands ));
1617
# serialization context opcodes
1618
QAST::MASTOperations.add_core_moarop_mapping('sha1', 'sha1');
1619
QAST::MASTOperations.add_core_moarop_mapping('createsc', 'createsc');
1620
QAST::MASTOperations.add_core_moarop_mapping('scsetobj', 'scsetobj', 2);
1621
QAST::MASTOperations.add_core_moarop_mapping('scsetcode', 'scsetcode', 2);
1622
QAST::MASTOperations.add_core_moarop_mapping('scgetobj', 'scgetobj');
1623
QAST::MASTOperations.add_core_moarop_mapping('scgethandle', 'scgethandle');
1624
QAST::MASTOperations.add_core_moarop_mapping('scgetdesc', 'scgetdesc');
1625
QAST::MASTOperations.add_core_moarop_mapping('scgetobjidx', 'scgetobjidx');
1626
QAST::MASTOperations.add_core_moarop_mapping('scsetdesc', 'scsetdesc', 1);
1627
QAST::MASTOperations.add_core_moarop_mapping('scobjcount', 'scobjcount');
1628
QAST::MASTOperations.add_core_moarop_mapping('setobjsc', 'setobjsc', 0);
1629
QAST::MASTOperations.add_core_moarop_mapping('getobjsc', 'getobjsc');
1630
QAST::MASTOperations.add_core_moarop_mapping('serialize', 'serialize');
1631
QAST::MASTOperations.add_core_moarop_mapping('deserialize', 'deserialize', 0);
1632
QAST::MASTOperations.add_core_moarop_mapping('scwbdisable', 'scwbdisable');
1633
QAST::MASTOperations.add_core_moarop_mapping('scwbenable', 'scwbenable');
1634
QAST::MASTOperations.add_core_moarop_mapping('pushcompsc', 'pushcompsc', 0);
1635
QAST::MASTOperations.add_core_moarop_mapping('popcompsc', 'popcompsc');
1638
QAST::MASTOperations.add_core_moarop_mapping('bitor_i', 'bor_i');
1639
QAST::MASTOperations.add_core_moarop_mapping('bitxor_i', 'bxor_i');
1640
QAST::MASTOperations.add_core_moarop_mapping('bitand_i', 'band_i');
1641
QAST::MASTOperations.add_core_moarop_mapping('bitshiftl_i', 'blshift_i');
1642
QAST::MASTOperations.add_core_moarop_mapping('bitshiftr_i', 'brshift_i');
1643
QAST::MASTOperations.add_core_moarop_mapping('bitneg_i', 'bnot_i');
1645
QAST::MASTOperations.add_core_moarop_mapping('bitor_I', 'bor_I');
1646
QAST::MASTOperations.add_core_moarop_mapping('bitxor_I', 'bxor_I');
1647
QAST::MASTOperations.add_core_moarop_mapping('bitand_I', 'band_I');
1648
QAST::MASTOperations.add_core_moarop_mapping('bitneg_I', 'bnot_I');
1649
QAST::MASTOperations.add_core_moarop_mapping('bitshiftl_I', 'blshift_I');
1650
QAST::MASTOperations.add_core_moarop_mapping('bitshiftr_I', 'brshift_I');
1652
# relational opcodes
1653
QAST::MASTOperations.add_core_moarop_mapping('cmp_i', 'cmp_i');
1654
QAST::MASTOperations.add_core_moarop_mapping('iseq_i', 'eq_i');
1655
QAST::MASTOperations.add_core_moarop_mapping('isne_i', 'ne_i');
1656
QAST::MASTOperations.add_core_moarop_mapping('islt_i', 'lt_i');
1657
QAST::MASTOperations.add_core_moarop_mapping('isle_i', 'le_i');
1658
QAST::MASTOperations.add_core_moarop_mapping('isgt_i', 'gt_i');
1659
QAST::MASTOperations.add_core_moarop_mapping('isge_i', 'ge_i');
1661
QAST::MASTOperations.add_core_moarop_mapping('cmp_n', 'cmp_n');
1662
QAST::MASTOperations.add_core_moarop_mapping('not_i', 'not_i');
1663
QAST::MASTOperations.add_core_moarop_mapping('iseq_n', 'eq_n');
1664
QAST::MASTOperations.add_core_moarop_mapping('isne_n', 'ne_n');
1665
QAST::MASTOperations.add_core_moarop_mapping('islt_n', 'lt_n');
1666
QAST::MASTOperations.add_core_moarop_mapping('isle_n', 'le_n');
1667
QAST::MASTOperations.add_core_moarop_mapping('isgt_n', 'gt_n');
1668
QAST::MASTOperations.add_core_moarop_mapping('isge_n', 'ge_n');
1670
QAST::MASTOperations.add_core_moarop_mapping('cmp_s', 'cmp_s');
1671
QAST::MASTOperations.add_core_moarop_mapping('iseq_s', 'eq_s');
1672
QAST::MASTOperations.add_core_moarop_mapping('isne_s', 'ne_s');
1673
QAST::MASTOperations.add_core_moarop_mapping('islt_s', 'lt_s');
1674
QAST::MASTOperations.add_core_moarop_mapping('isle_s', 'le_s');
1675
QAST::MASTOperations.add_core_moarop_mapping('isgt_s', 'gt_s');
1676
QAST::MASTOperations.add_core_moarop_mapping('isge_s', 'ge_s');
1678
QAST::MASTOperations.add_core_moarop_mapping('bool_I', 'bool_I');
1679
QAST::MASTOperations.add_core_moarop_mapping('cmp_I', 'cmp_I');
1680
QAST::MASTOperations.add_core_moarop_mapping('iseq_I', 'eq_I');
1681
QAST::MASTOperations.add_core_moarop_mapping('isne_I', 'ne_I');
1682
QAST::MASTOperations.add_core_moarop_mapping('islt_I', 'lt_I');
1683
QAST::MASTOperations.add_core_moarop_mapping('isle_I', 'le_I');
1684
QAST::MASTOperations.add_core_moarop_mapping('isgt_I', 'gt_I');
1685
QAST::MASTOperations.add_core_moarop_mapping('isge_I', 'ge_I');
1688
QAST::MASTOperations.add_core_moarop_mapping('atpos', 'atpos_o');
1689
QAST::MASTOperations.add_core_moarop_mapping('atpos_i', 'atpos_i');
1690
QAST::MASTOperations.add_core_moarop_mapping('atpos_n', 'atpos_n');
1691
QAST::MASTOperations.add_core_moarop_mapping('atpos_s', 'atpos_s');
1692
QAST::MASTOperations.add_core_moarop_mapping('atkey', 'atkey_o');
1693
QAST::MASTOperations.add_core_moarop_mapping('atkey_i', 'atkey_i');
1694
QAST::MASTOperations.add_core_moarop_mapping('atkey_n', 'atkey_n');
1695
QAST::MASTOperations.add_core_moarop_mapping('atkey_s', 'atkey_s');
1696
QAST::MASTOperations.add_core_moarop_mapping('bindpos', 'bindpos_o', 2);
1697
QAST::MASTOperations.add_core_moarop_mapping('bindpos_i', 'bindpos_i', 2);
1698
QAST::MASTOperations.add_core_moarop_mapping('bindpos_n', 'bindpos_n', 2);
1699
QAST::MASTOperations.add_core_moarop_mapping('bindpos_s', 'bindpos_s', 2);
1700
QAST::MASTOperations.add_core_moarop_mapping('bindkey', 'bindkey_o', 2);
1701
QAST::MASTOperations.add_core_moarop_mapping('bindkey_i', 'bindkey_i', 2);
1702
QAST::MASTOperations.add_core_moarop_mapping('bindkey_n', 'bindkey_n', 2);
1703
QAST::MASTOperations.add_core_moarop_mapping('bindkey_s', 'bindkey_s', 2);
1704
QAST::MASTOperations.add_core_moarop_mapping('existskey', 'existskey');
1705
QAST::MASTOperations.add_core_moarop_mapping('deletekey', 'deletekey');
1706
QAST::MASTOperations.add_core_moarop_mapping('elems', 'elems');
1707
QAST::MASTOperations.add_core_moarop_mapping('setelems', 'setelemspos', 0);
1708
QAST::MASTOperations.add_core_moarop_mapping('existspos', 'existspos');
1709
QAST::MASTOperations.add_core_moarop_mapping('push', 'push_o', 1);
1710
QAST::MASTOperations.add_core_moarop_mapping('push_i', 'push_i', 1);
1711
QAST::MASTOperations.add_core_moarop_mapping('push_n', 'push_n', 1);
1712
QAST::MASTOperations.add_core_moarop_mapping('push_s', 'push_s', 1);
1713
QAST::MASTOperations.add_core_moarop_mapping('pop', 'pop_o');
1714
QAST::MASTOperations.add_core_moarop_mapping('pop_i', 'pop_i');
1715
QAST::MASTOperations.add_core_moarop_mapping('pop_n', 'pop_n');
1716
QAST::MASTOperations.add_core_moarop_mapping('pop_s', 'pop_s');
1717
QAST::MASTOperations.add_core_moarop_mapping('unshift', 'unshift_o', 1);
1718
QAST::MASTOperations.add_core_moarop_mapping('unshift_i', 'unshift_i', 1);
1719
QAST::MASTOperations.add_core_moarop_mapping('unshift_n', 'unshift_n', 1);
1720
QAST::MASTOperations.add_core_moarop_mapping('unshift_s', 'unshift_s', 1);
1721
QAST::MASTOperations.add_core_moarop_mapping('shift', 'shift_o');
1722
QAST::MASTOperations.add_core_moarop_mapping('shift_i', 'shift_i');
1723
QAST::MASTOperations.add_core_moarop_mapping('shift_n', 'shift_n');
1724
QAST::MASTOperations.add_core_moarop_mapping('shift_s', 'shift_s');
1725
QAST::MASTOperations.add_core_moarop_mapping('splice', 'splice');
1726
QAST::MASTOperations.add_core_moarop_mapping('isint', 'isint');
1727
QAST::MASTOperations.add_core_moarop_mapping('isnum', 'isnum');
1728
QAST::MASTOperations.add_core_moarop_mapping('isstr', 'isstr');
1729
QAST::MASTOperations.add_core_moarop_mapping('islist', 'islist');
1730
QAST::MASTOperations.add_core_moarop_mapping('ishash', 'ishash');
1731
QAST::MASTOperations.add_core_moarop_mapping('iterator', 'iter');
1732
QAST::MASTOperations.add_core_moarop_mapping('iterkey_s', 'iterkey_s');
1733
QAST::MASTOperations.add_core_moarop_mapping('iterval', 'iterval');
1736
QAST::MASTOperations.add_core_moarop_mapping('null', 'null');
1737
QAST::MASTOperations.add_core_moarop_mapping('null_s', 'null_s');
1738
QAST::MASTOperations.add_core_moarop_mapping('what', 'getwhat');
1739
QAST::MASTOperations.add_core_moarop_mapping('how', 'gethow');
1740
QAST::MASTOperations.add_core_moarop_mapping('who', 'getwho');
1741
QAST::MASTOperations.add_core_moarop_mapping('where', 'getwhere');
1742
QAST::MASTOperations.add_core_moarop_mapping('findmethod', 'findmeth_s');
1743
QAST::MASTOperations.add_core_moarop_mapping('setwho', 'setwho');
1744
QAST::MASTOperations.add_core_moarop_mapping('rebless', 'rebless');
1745
QAST::MASTOperations.add_core_moarop_mapping('knowhow', 'knowhow');
1746
QAST::MASTOperations.add_core_moarop_mapping('knowhowattr', 'knowhowattr');
1747
QAST::MASTOperations.add_core_moarop_mapping('bootint', 'bootint');
1748
QAST::MASTOperations.add_core_moarop_mapping('bootnum', 'bootnum');
1749
QAST::MASTOperations.add_core_moarop_mapping('bootstr', 'bootstr');
1750
QAST::MASTOperations.add_core_moarop_mapping('bootarray', 'bootarray');
1751
QAST::MASTOperations.add_core_moarop_mapping('bootintarray', 'bootintarray');
1752
QAST::MASTOperations.add_core_moarop_mapping('bootnumarray', 'bootnumarray');
1753
QAST::MASTOperations.add_core_moarop_mapping('bootstrarray', 'bootstrarray');
1754
QAST::MASTOperations.add_core_moarop_mapping('boothash', 'boothash');
1755
QAST::MASTOperations.add_core_moarop_mapping('hlllist', 'hlllist');
1756
QAST::MASTOperations.add_core_moarop_mapping('hllhash', 'hllhash');
1757
QAST::MASTOperations.add_core_moarop_mapping('create', 'create');
1758
QAST::MASTOperations.add_core_moarop_mapping('clone', 'clone');
1759
QAST::MASTOperations.add_core_moarop_mapping('isconcrete', 'isconcrete');
1760
QAST::MASTOperations.add_core_moarop_mapping('iscont', 'iscont');
1761
QAST::MASTOperations.add_core_moarop_mapping('decont', 'decont');
1762
QAST::MASTOperations.add_core_moarop_mapping('isnull', 'isnull');
1763
QAST::MASTOperations.add_core_moarop_mapping('isnull_s', 'isnull_s');
1764
QAST::MASTOperations.add_core_moarop_mapping('istrue', 'istrue');
1765
QAST::MASTOperations.add_core_moarop_mapping('isfalse', 'isfalse');
1766
QAST::MASTOperations.add_core_moarop_mapping('istype', 'istype');
1767
QAST::MASTOperations.add_core_moarop_mapping('eqaddr', 'eqaddr');
1768
QAST::MASTOperations.add_core_moarop_mapping('getattr', 'getattrs_o');
1769
QAST::MASTOperations.add_core_moarop_mapping('getattr_i', 'getattrs_i');
1770
QAST::MASTOperations.add_core_moarop_mapping('getattr_n', 'getattrs_n');
1771
QAST::MASTOperations.add_core_moarop_mapping('getattr_s', 'getattrs_s');
1772
QAST::MASTOperations.add_core_moarop_mapping('attrinited', 'attrinited');
1773
QAST::MASTOperations.add_core_moarop_mapping('bindattr', 'bindattrs_o', 3);
1774
QAST::MASTOperations.add_core_moarop_mapping('bindattr_i', 'bindattrs_i', 3);
1775
QAST::MASTOperations.add_core_moarop_mapping('bindattr_n', 'bindattrs_n', 3);
1776
QAST::MASTOperations.add_core_moarop_mapping('bindattr_s', 'bindattrs_s', 3);
1777
QAST::MASTOperations.add_core_moarop_mapping('unbox_i', 'unbox_i');
1778
QAST::MASTOperations.add_core_moarop_mapping('unbox_n', 'unbox_n');
1779
QAST::MASTOperations.add_core_moarop_mapping('unbox_s', 'unbox_s');
1780
QAST::MASTOperations.add_core_moarop_mapping('box_i', 'box_i');
1781
QAST::MASTOperations.add_core_moarop_mapping('box_n', 'box_n');
1782
QAST::MASTOperations.add_core_moarop_mapping('box_s', 'box_s');
1783
QAST::MASTOperations.add_core_moarop_mapping('can', 'can_s');
1784
QAST::MASTOperations.add_core_moarop_mapping('reprname', 'reprname');
1785
QAST::MASTOperations.add_core_moarop_mapping('newtype', 'newtype');
1786
QAST::MASTOperations.add_core_moarop_mapping('composetype', 'composetype');
1787
QAST::MASTOperations.add_core_moarop_mapping('setboolspec', 'setboolspec', 0);
1788
QAST::MASTOperations.add_core_moarop_mapping('setmethcache', 'setmethcache', 0);
1789
QAST::MASTOperations.add_core_moarop_mapping('setmethcacheauth', 'setmethcacheauth', 0);
1790
QAST::MASTOperations.add_core_moarop_mapping('settypecache', 'settypecache', 0);
1791
QAST::MASTOperations.add_core_moarop_mapping('isinvokable', 'isinvokable');
1792
QAST::MASTOperations.add_core_moarop_mapping('setinvokespec', 'setinvokespec', 0);
1793
QAST::MASTOperations.add_core_moarop_mapping('setcontspec', 'setcontspec', 0);
1794
QAST::MASTOperations.add_core_moarop_mapping('assign', 'assign', 0);
1795
QAST::MASTOperations.add_core_moarop_mapping('assignunchecked', 'assignunchecked', 0);
1797
# defined - overridden by HLL, but by default same as .DEFINITE.
1798
QAST::MASTOperations.add_core_moarop_mapping('defined', 'isconcrete');
1800
# lexical related opcodes
1801
QAST::MASTOperations.add_core_moarop_mapping('getlex', 'getlex_no');
1802
QAST::MASTOperations.add_core_moarop_mapping('getlex_i', 'getlex_ni');
1803
QAST::MASTOperations.add_core_moarop_mapping('getlex_n', 'getlex_nn');
1804
QAST::MASTOperations.add_core_moarop_mapping('getlex_s', 'getlex_ns');
1805
QAST::MASTOperations.add_core_moarop_mapping('bindlex', 'bindlex_no', 1);
1806
QAST::MASTOperations.add_core_moarop_mapping('bindlex_i', 'bindlex_ni', 1);
1807
QAST::MASTOperations.add_core_moarop_mapping('bindlex_n', 'bindlex_nn', 1);
1808
QAST::MASTOperations.add_core_moarop_mapping('bindlex_s', 'bindlex_ns', 1);
1809
QAST::MASTOperations.add_core_moarop_mapping('getlexdyn', 'getdynlex');
1810
QAST::MASTOperations.add_core_moarop_mapping('bindlexdyn', 'binddynlex');
1811
QAST::MASTOperations.add_core_op('locallifetime', -> $qastcomp, $op {
1812
# TODO: take advantage of this info for code-gen, if possible.
1813
$qastcomp.as_mast($op[0])
1816
# code object related opcodes
1817
# XXX explicit takeclosure will go away under new model; for now, no-op it.
1818
QAST::MASTOperations.add_core_op('takeclosure', -> $qastcomp, $op {
1819
unless +@($op) == 1 {
1820
nqp::die('takeclosure op requires one argument');
1822
$qastcomp.as_mast($op[0])
1824
QAST::MASTOperations.add_core_moarop_mapping('getcodeobj', 'getcodeobj');
1825
QAST::MASTOperations.add_core_moarop_mapping('setcodeobj', 'setcodeobj', 0);
1826
QAST::MASTOperations.add_core_moarop_mapping('getcodename', 'getcodename');
1827
QAST::MASTOperations.add_core_moarop_mapping('setcodename', 'setcodename', 0);
1828
QAST::MASTOperations.add_core_moarop_mapping('forceouterctx', 'forceouterctx', 0);
1829
QAST::MASTOperations.add_core_op('setup_blv', -> $qastcomp, $op {
1830
if +@($op) != 1 || !nqp::ishash($op[0]) {
1831
nqp::die('setup_blv requires one hash operand');
1836
my $frame := %*MAST_FRAMES{$_.key};
1837
my $block_reg := $*REGALLOC.fresh_register($MVM_reg_obj);
1838
push_op(@ops, 'getcode', $block_reg, $frame);
1839
for $_.value -> @lex {
1840
my $valres := $qastcomp.as_mast(QAST::WVal.new( :value(@lex[1]) ));
1841
push_ilist(@ops, $valres);
1842
push_op(@ops, 'setlexvalue', $block_reg, MAST::SVal.new( :value(@lex[0]) ),
1843
$valres.result_reg, MAST::IVal.new( :value(@lex[2]) ));
1844
$*REGALLOC.release_register($valres.result_reg, $MVM_reg_obj);
1846
$*REGALLOC.release_register($block_reg, $MVM_reg_obj);
1849
MAST::InstructionList.new(@ops, $*REGALLOC.fresh_o(), $MVM_reg_obj)
1851
QAST::MASTOperations.add_core_moarop_mapping('freshcoderef', 'freshcoderef');
1852
QAST::MASTOperations.add_core_moarop_mapping('iscoderef', 'iscoderef');
1853
QAST::MASTOperations.add_core_moarop_mapping('markcodestatic', 'markcodestatic');
1854
QAST::MASTOperations.add_core_moarop_mapping('markcodestub', 'markcodestub');
1855
QAST::MASTOperations.add_core_moarop_mapping('getstaticcode', 'getstaticcode');
1856
QAST::MASTOperations.add_core_moarop_mapping('getcodecuid', 'getcodecuid');
1858
# language/compiler ops
1859
QAST::MASTOperations.add_core_moarop_mapping('getcomp', 'getcomp');
1860
QAST::MASTOperations.add_core_moarop_mapping('bindcomp', 'bindcomp');
1861
QAST::MASTOperations.add_core_moarop_mapping('gethllsym', 'gethllsym');
1862
QAST::MASTOperations.add_core_moarop_mapping('bindhllsym', 'bindhllsym', 2);
1863
QAST::MASTOperations.add_core_moarop_mapping('getcurhllsym', 'getcurhllsym');
1864
QAST::MASTOperations.add_core_moarop_mapping('bindcurhllsym', 'bindcurhllsym');
1865
QAST::MASTOperations.add_core_moarop_mapping('sethllconfig', 'sethllconfig');
1866
QAST::MASTOperations.add_core_moarop_mapping('loadbytecode', 'loadbytecode');
1867
QAST::MASTOperations.add_core_moarop_mapping('settypehll', 'settypehll', 0);
1868
QAST::MASTOperations.add_core_moarop_mapping('settypehllrole', 'settypehllrole', 0);
1869
QAST::MASTOperations.add_core_moarop_mapping('usecompileehllconfig', 'usecompileehllconfig');
1870
QAST::MASTOperations.add_core_moarop_mapping('usecompilerhllconfig', 'usecompilerhllconfig');
1871
QAST::MASTOperations.add_core_moarop_mapping('hllize', 'hllize');
1872
QAST::MASTOperations.add_core_moarop_mapping('hllizefor', 'hllizefor');
1874
# regex engine related opcodes
1875
QAST::MASTOperations.add_core_moarop_mapping('nfafromstatelist', 'nfafromstatelist');
1876
QAST::MASTOperations.add_core_moarop_mapping('nfarunproto', 'nfarunproto');
1877
QAST::MASTOperations.add_core_moarop_mapping('nfarunalt', 'nfarunalt', 0);
1879
# process related opcodes
1880
QAST::MASTOperations.add_core_moarop_mapping('exit', 'exit', 0);
1881
QAST::MASTOperations.add_core_moarop_mapping('sleep', 'sleep', 0);
1882
QAST::MASTOperations.add_core_moarop_mapping('getenvhash', 'getenvhash');
1883
QAST::MASTOperations.add_core_moarop_mapping('shell', 'shell');
1884
QAST::MASTOperations.add_core_moarop_mapping('rand_i', 'rand_i');
1885
QAST::MASTOperations.add_core_moarop_mapping('rand_n', 'rand_n');
1886
QAST::MASTOperations.add_core_moarop_mapping('seed', 'seed');
1888
# MoarVM-specific compilation ops
1889
QAST::MASTOperations.add_core_moarop_mapping('masttofile', 'masttofile', 2);
1890
QAST::MASTOperations.add_core_moarop_mapping('masttocu', 'masttocu');
1891
QAST::MASTOperations.add_core_moarop_mapping('iscompunit', 'iscompunit');
1892
QAST::MASTOperations.add_core_moarop_mapping('compunitmainline', 'compunitmainline');
1893
QAST::MASTOperations.add_core_moarop_mapping('compunitcodes', 'compunitcodes');
1895
sub resolve_condition_op($kind, $negated) {
1897
$kind == $MVM_reg_int64 ?? 'unless_i' !!
1898
$kind == $MVM_reg_num64 ?? 'unless_n' !!
1899
$kind == $MVM_reg_str ?? 'unless_s0' !!
1900
$kind == $MVM_reg_obj ?? 'unless_o' !!
1901
nqp::die("unhandled kind $kind")
1902
!! $kind == $MVM_reg_int64 ?? 'if_i' !!
1903
$kind == $MVM_reg_num64 ?? 'if_n' !!
1904
$kind == $MVM_reg_str ?? 'if_s0' !!
1905
$kind == $MVM_reg_obj ?? 'if_o' !!
1906
nqp::die("unhandled kind $kind")
1909
sub push_op(@dest, $op, *@args) {
1910
#$op := $op.name if nqp::istype($op, QAST::Op);
1911
nqp::push(@dest, MAST::Op.new(
1917
sub push_ilist(@dest, $src) is export {
1918
nqp::splice(@dest, $src.instructions, +@dest, 0);