~ubuntu-branches/ubuntu/vivid/nqp/vivid-proposed

« back to all changes in this revision

Viewing changes to src/vm/jvm/QAST/Compiler.nqp

  • Committer: Package Import Robot
  • Author(s): Alessandro Ghedini
  • Date: 2013-11-01 12:09:18 UTC
  • mfrom: (1.1.4)
  • Revision ID: package-import@ubuntu.com-20131101120918-kx51sl0sxl3exsxi
Tags: 2013.10-1
* New upstream release
* Bump versioned (Build-)Depends on parrot
* Update patches
* Install new README.pod
* Fix vcs-field-not-canonical
* Do not install rubyish examples
* Do not Depends on parrot-devel anymore
* Add 07_disable-serialization-tests.patch

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
use JASTNodes;
 
2
use QASTNode;
 
3
use NQPHLL;
 
4
 
 
5
# Instruction constants for argument-less ops.
 
6
my $ACONST_NULL := JAST::Instruction.new( :op('aconst_null') );
 
7
my $ALOAD_0     := JAST::Instruction.new( :op('aload_0') );
 
8
my $ALOAD_1     := JAST::Instruction.new( :op('aload_1') );
 
9
my $IASTORE     := JAST::Instruction.new( :op('iastore') );
 
10
my $LASTORE     := JAST::Instruction.new( :op('lastore') );
 
11
my $AALOAD      := JAST::Instruction.new( :op('aaload') );
 
12
my $AASTORE     := JAST::Instruction.new( :op('aastore') );
 
13
my $BASTORE     := JAST::Instruction.new( :op('bastore') );
 
14
my $POP         := JAST::Instruction.new( :op('pop') );
 
15
my $POP2        := JAST::Instruction.new( :op('pop2') );
 
16
my $DUP         := JAST::Instruction.new( :op('dup') );
 
17
my $DUP_X2      := JAST::Instruction.new( :op('dup_x2') );
 
18
my $DUP2        := JAST::Instruction.new( :op('dup2') );
 
19
my $SWAP        := JAST::Instruction.new( :op('swap') );
 
20
my $IADD        := JAST::Instruction.new( :op('iadd') );
 
21
my $LADD        := JAST::Instruction.new( :op('ladd') );
 
22
my $LSUB        := JAST::Instruction.new( :op('lsub') );
 
23
my $IAND        := JAST::Instruction.new( :op('iand') );
 
24
my $I2L         := JAST::Instruction.new( :op('i2l') );
 
25
my $I2B         := JAST::Instruction.new( :op('i2b') );
 
26
my $L2I         := JAST::Instruction.new( :op('l2i') );
 
27
my $L2D         := JAST::Instruction.new( :op('l2d') );
 
28
my $D2L         := JAST::Instruction.new( :op('d2l') );
 
29
my $LCMP        := JAST::Instruction.new( :op('lcmp') );
 
30
my $DCMPL       := JAST::Instruction.new( :op('dcmpl') );
 
31
my $RETURN      := JAST::Instruction.new( :op('return') );
 
32
my $ARETURN     := JAST::Instruction.new( :op('areturn') );
 
33
my $IRETURN     := JAST::Instruction.new( :op('ireturn') );
 
34
my $ATHROW      := JAST::Instruction.new( :op('athrow') );
 
35
 
 
36
# Common constant loads.
 
37
my $IVAL_ZERO     := JAST::PushIVal.new( :value(0) );
 
38
my $IVAL_ONE      := JAST::PushIVal.new( :value(1) );
 
39
my $IVAL_MINUSONE := JAST::PushIVal.new( :value(-1) );
 
40
my $NVAL_ZERO     := JAST::PushNVal.new( :value(0.0) );
 
41
 
 
42
# Some common types we'll need.
 
43
my $TYPE_TC         := 'Lorg/perl6/nqp/runtime/ThreadContext;';
 
44
my $TYPE_CU         := 'Lorg/perl6/nqp/runtime/CompilationUnit;';
 
45
my $TYPE_CR         := 'Lorg/perl6/nqp/runtime/CodeRef;';
 
46
my $TYPE_CF         := 'Lorg/perl6/nqp/runtime/CallFrame;';
 
47
my $TYPE_OPS        := 'Lorg/perl6/nqp/runtime/Ops;';
 
48
my $TYPE_NATIVE_OPS := 'Lorg/perl6/nqp/runtime/NativeCallOps;';
 
49
my $TYPE_CSD        := 'Lorg/perl6/nqp/runtime/CallSiteDescriptor;';
 
50
my $TYPE_SMO        := 'Lorg/perl6/nqp/sixmodel/SixModelObject;';
 
51
my $TYPE_STR        := 'Ljava/lang/String;';
 
52
my $TYPE_OBJ        := 'Ljava/lang/Object;';
 
53
my $TYPE_MATH       := 'Ljava/lang/Math;';
 
54
my $TYPE_MH         := 'Ljava/lang/invoke/MethodHandle;';
 
55
my $TYPE_MT         := 'Ljava/lang/invoke/MethodType;';
 
56
my $TYPE_MHS        := 'Ljava/lang/invoke/MethodHandles;';
 
57
my $TYPE_MHL        := 'Ljava/lang/invoke/MethodHandles$Lookup;';
 
58
my $TYPE_CLASS      := 'Ljava/lang/Class;';
 
59
my $TYPE_LONG       := 'Ljava/lang/Long;';
 
60
my $TYPE_DOUBLE     := 'Ljava/lang/Double;';
 
61
my $TYPE_EH         := 'Lorg/perl6/nqp/runtime/ExceptionHandling;';
 
62
my $TYPE_EX_LEX     := 'Lorg/perl6/nqp/runtime/LexoticException;';
 
63
my $TYPE_EX_UNWIND  := 'Lorg/perl6/nqp/runtime/UnwindException;';
 
64
my $TYPE_EX_CONT    := 'Lorg/perl6/nqp/runtime/ControlException;';
 
65
my $TYPE_EX_RT      := 'Ljava/lang/RuntimeException;';
 
66
my $TYPE_EX_SAVE    := 'Lorg/perl6/nqp/runtime/SaveStackException;';
 
67
my $TYPE_THROWABLE  := 'Ljava/lang/Throwable;';
 
68
my $TYPE_RESUME     := 'Lorg/perl6/nqp/runtime/ResumeStatus$Frame;';
 
69
 
 
70
# Exception handler categories.
 
71
my $EX_CAT_CATCH   := 1;
 
72
my $EX_CAT_NEXT    := 4;
 
73
my $EX_CAT_REDO    := 8;
 
74
my $EX_CAT_LAST    := 16;
 
75
my $EX_CAT_TAKE    := 32;
 
76
my $EX_CAT_WARN    := 64;
 
77
my $EX_CAT_SUCCEED := 128;
 
78
my $EX_CAT_PROCEED := 256;
 
79
my $EX_CAT_CONTROL := $EX_CAT_NEXT +| $EX_CAT_REDO +| $EX_CAT_LAST +|
 
80
                      $EX_CAT_TAKE +| $EX_CAT_WARN +|
 
81
                      $EX_CAT_SUCCEED +| $EX_CAT_PROCEED;
 
82
 
 
83
# Exception handler kinds.
 
84
my $EX_UNWIND_SIMPLE := 0;
 
85
my $EX_UNWIND_OBJECT := 1;
 
86
my $EX_BLOCK         := 2;
 
87
 
 
88
# Represents the result of turning some QAST into JAST. That includes any
 
89
# instructions, but also some metadata that goes with them.
 
90
my $RT_OBJ  := 0;
 
91
my $RT_INT  := 1;
 
92
my $RT_NUM  := 2;
 
93
my $RT_STR  := 3;
 
94
my $RT_VOID := -1;
 
95
my class Result {
 
96
    has $!jast;         # The JAST
 
97
    has int $!type;     # Result type (obj/int/num/str)
 
98
    has str $!local;    # Local where the result is; if empty, it's on the stack
 
99
    
 
100
    method jast()  { $!jast }
 
101
    method type()  { $!type }
 
102
    method local() { $!local }
 
103
    
 
104
    method set_local($local) { $!local := $local }
 
105
}
 
106
sub result($jast, int $type) {
 
107
    my $r := nqp::create(Result);
 
108
    nqp::bindattr($r, Result, '$!jast', $jast);
 
109
    nqp::bindattr_i($r, Result, '$!type', $type);
 
110
    nqp::bindattr_s($r, Result, '$!local', '');
 
111
    $*STACK.push($r);
 
112
    $r
 
113
}
 
114
sub result_from_cf($il, $rtype) {
 
115
    if $*WANT != $RT_VOID {
 
116
        $il.append(JAST::Instruction.new( :op('aload'), 'cf' ));
 
117
        $il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
 
118
            'result_' ~ typechar($rtype), jtype($rtype), $TYPE_CF ));
 
119
        result($il, $rtype)
 
120
    }
 
121
    else {
 
122
        result($il, $RT_VOID)
 
123
    }
 
124
}
 
125
my @jtypes := [$TYPE_SMO, 'Long', 'Double', $TYPE_STR];
 
126
sub jtype($type_idx) { @jtypes[$type_idx] }
 
127
my @rttypes := [$RT_OBJ, $RT_INT, $RT_NUM, $RT_STR];
 
128
sub rttype_from_typeobj($typeobj) {
 
129
    @rttypes[nqp::objprimspec($typeobj)]
 
130
}
 
131
my @typeobjs := [NQPMu, int, num, str];
 
132
sub typeobj_from_rttype($rttype) {
 
133
    @typeobjs[$rttype]
 
134
}
 
135
my @typechars := ['o', 'i', 'n', 's'];
 
136
sub typechar($type_idx) { @typechars[$type_idx] }
 
137
 
 
138
# Various typed instructions.
 
139
my @store_ins := ['astore', 'lstore', 'dstore', 'astore'];
 
140
sub store_ins($type) {
 
141
    @store_ins[$type]
 
142
}
 
143
my @load_ins := ['aload', 'lload', 'dload', 'aload'];
 
144
sub load_ins($type) {
 
145
    @load_ins[$type]
 
146
}
 
147
my @dup_ins := [
 
148
    $DUP,
 
149
    $DUP2,
 
150
    $DUP2,
 
151
    $DUP
 
152
];
 
153
sub dup_ins($type) {
 
154
    @dup_ins[$type]
 
155
}
 
156
my @pop_ins := [
 
157
    $POP,
 
158
    $POP2,
 
159
    $POP2,
 
160
    $POP
 
161
];
 
162
sub pop_ins($type) {
 
163
    @pop_ins[$type]
 
164
}
 
165
 
 
166
# Mapping of QAST::Want type identifiers to $RT_*.
 
167
my %WANTMAP := nqp::hash(
 
168
    'v', $RT_VOID,
 
169
    'I', $RT_INT, 'i', $RT_INT,
 
170
    'N', $RT_NUM, 'n', $RT_NUM,
 
171
    'S', $RT_STR, 's', $RT_STR,
 
172
    'P', $RT_OBJ, 'p', $RT_OBJ
 
173
);
 
174
 
 
175
# Utility for getting a fresh temporary by type.
 
176
my @fresh_methods := ["fresh_o", "fresh_i", "fresh_n", "fresh_s"];
 
177
sub fresh($type) {
 
178
    my $meth := @fresh_methods[$type];
 
179
    $*TA."$meth"()
 
180
}
 
181
sub bfresh($type) {
 
182
    my $meth := @fresh_methods[$type];
 
183
    $*BLOCK_TA."$meth"()
 
184
}
 
185
 
 
186
# Argument flags.
 
187
my $ARG_OBJ   := 0;
 
188
my $ARG_INT   := 1;
 
189
my $ARG_NUM   := 2;
 
190
my $ARG_STR   := 4;
 
191
my $ARG_NAMED := 8;
 
192
my $ARG_FLAT  := 16;
 
193
my @arg_types := [$ARG_OBJ, $ARG_INT, $ARG_NUM, $ARG_STR];
 
194
sub arg_type($t) { @arg_types[$t] }
 
195
 
 
196
class QAST::OperationsJAST {
 
197
    # Maps operations to code that will handle them. Hash of code.
 
198
    my %core_ops;
 
199
    
 
200
    # Maps HLL-specific operations to code that will handle them.
 
201
    # Hash of hash of code.
 
202
    my %hll_ops;
 
203
    
 
204
    # Mapping of how to box/unbox by HLL.
 
205
    my %hll_box;
 
206
    my %hll_unbox;
 
207
    
 
208
    # What we know about inlinability.
 
209
    my %core_inlinability;
 
210
    my %hll_inlinability;
 
211
    
 
212
    # What we know about op native results types.
 
213
    my %core_result_type;
 
214
    my %hll_result_type;
 
215
    
 
216
    # Compiles an operation.
 
217
    method compile_op($qastcomp, $hll, $op) {
 
218
        my $name := $op.op;
 
219
        if $hll {
 
220
            if %hll_ops{$hll} && %hll_ops{$hll}{$name} -> $mapper {
 
221
                return $mapper($qastcomp, $op);
 
222
            }
 
223
        }
 
224
        if %core_ops{$name} -> $mapper {
 
225
            return $mapper($qastcomp, $op);
 
226
        }
 
227
        nqp::die("No registered operation handler for '$name'");
 
228
    }
 
229
    
 
230
    # Adds a core op handler.
 
231
    method add_core_op($op, $handler, :$inlinable = 1) {
 
232
        %core_ops{$op} := $handler;
 
233
        self.set_core_op_inlinability($op, $inlinable);
 
234
    }
 
235
    
 
236
    # Adds a HLL op handler.
 
237
    method add_hll_op($hll, $op, $handler, :$inlinable = 1) {
 
238
        %hll_ops{$hll} := {} unless nqp::existskey(%hll_ops, $hll);
 
239
        %hll_ops{$hll}{$op} := $handler;
 
240
        self.set_hll_op_inlinability($hll, $op, $inlinable);
 
241
    }
 
242
    
 
243
    # Sets op inlinability at a core level.
 
244
    method set_core_op_inlinability($op, $inlinable) {
 
245
        %core_inlinability{$op} := $inlinable;
 
246
    }
 
247
    
 
248
    # Sets op inlinability at a HLL level. (Can override at HLL level whether
 
249
    # or not the HLL overrides the op itself.)
 
250
    method set_hll_op_inlinability($hll, $op, $inlinable) {
 
251
        %hll_inlinability{$hll} := {} unless nqp::existskey(%hll_inlinability, $hll);
 
252
        %hll_inlinability{$hll}{$op} := $inlinable;
 
253
    }
 
254
    
 
255
    # Checks if an op is considered inlinable.
 
256
    method is_inlinable($hll, $op) {
 
257
        if nqp::existskey(%hll_inlinability, $hll) {
 
258
            if nqp::existskey(%hll_inlinability{$hll}, $op) {
 
259
                return %hll_inlinability{$hll}{$op};
 
260
            }
 
261
        }
 
262
        return %core_inlinability{$op} // 0;
 
263
    }
 
264
    
 
265
    # Adds a core nqp:: op provided directly by a JVM op.
 
266
    method map_jvm_core_op($op, $jvm_op, @stack_in, $stack_out) {
 
267
        my $ins := JAST::Instruction.new( :op($jvm_op) );
 
268
        self.add_core_op($op, op_mapper($op, $ins, @stack_in, $stack_out));
 
269
        self.set_core_op_result_type($op, $stack_out);
 
270
    }
 
271
    
 
272
    # Adds a HLL nqp:: op provided directly by a JVM op.
 
273
    method map_jvm_hll_op($hll, $op, $jvm_op, @stack_in, $stack_out) {
 
274
        my $ins := JAST::Instruction.new( :op($jvm_op) );
 
275
        self.add_hll_op($hll, $op, op_mapper($op, $ins, @stack_in, $stack_out));
 
276
        self.set_hll_op_result_type($hll, $op, $stack_out);
 
277
    }
 
278
    
 
279
    # Adds a core nqp:: op provided by a static method in the
 
280
    # class library.
 
281
    method map_classlib_core_op($op, $class, $method, @stack_in, $stack_out, :$tc, :$cont, :$inlinable = 1) {
 
282
        my @jtypes_in;
 
283
        for @stack_in {
 
284
            nqp::push(@jtypes_in, jtype($_));
 
285
        }
 
286
        nqp::push(@jtypes_in, $TYPE_TC) if $tc;
 
287
        my $ins := JAST::Instruction.new( :op('invokestatic'),
 
288
            $class, $method, $cont ?? 'Void' !! jtype($stack_out), |@jtypes_in );
 
289
        self.add_core_op($op, op_mapper($op, $ins, @stack_in, $stack_out, :$tc, :$cont));
 
290
        self.set_core_op_inlinability($op, $inlinable);
 
291
        self.set_core_op_result_type($op, $stack_out);
 
292
    }
 
293
    
 
294
    # Adds a core nqp:: op provided by a static method in the
 
295
    # class library.
 
296
    method map_classlib_hll_op($hll, $op, $class, $method, @stack_in, $stack_out, :$tc, :$cont, :$inlinable = 1) {
 
297
        my @jtypes_in;
 
298
        for @stack_in {
 
299
            nqp::push(@jtypes_in, jtype($_));
 
300
        }
 
301
        nqp::push(@jtypes_in, $TYPE_TC) if $tc;
 
302
        my $ins := JAST::Instruction.new( :op('invokestatic'),
 
303
            $class, $method, $cont ?? 'Void' !! jtype($stack_out), |@jtypes_in );
 
304
        self.add_hll_op($hll, $op, op_mapper($op, $ins, @stack_in, $stack_out, :$tc, :$cont));
 
305
        self.set_core_op_inlinability($op, $inlinable);
 
306
        self.set_hll_op_result_type($hll, $op, $stack_out);
 
307
    }
 
308
    
 
309
    # Generates an operation mapper. Covers a range of operations,
 
310
    # including those provided by calling a method and those that are
 
311
    # just JVM op invocations.
 
312
    sub op_mapper($op, $instruction, @stack_in, $stack_out, :$tc = 0, :$cont = 0) {
 
313
        my int $expected_args := +@stack_in;
 
314
        return -> $qastcomp, $node {
 
315
            if +@($node) != $expected_args {
 
316
                nqp::die("Operation '$op' requires $expected_args operands");
 
317
            }
 
318
 
 
319
            # Emit operands.
 
320
            my $il := JAST::InstructionList.new();
 
321
            my int $i := 0;
 
322
            my @arg_res;
 
323
            while $i < $expected_args {
 
324
                my $type := @stack_in[$i];
 
325
                my $operand := $node[$i];
 
326
                my $operand_res := $qastcomp.as_jast($node[$i], :want($type));
 
327
                $il.append($operand_res.jast);
 
328
                $i++;
 
329
                nqp::push(@arg_res, $operand_res);
 
330
            }
 
331
            
 
332
            # Emit operation.
 
333
            $*STACK.spill_to_locals($il) if $cont;
 
334
            $*STACK.obtain($il, |@arg_res) if @arg_res;
 
335
            if $tc {
 
336
                $il.append($ALOAD_1);
 
337
            }
 
338
            if $cont {
 
339
                $il.append(savesite($instruction));
 
340
                result_from_cf($il, $stack_out);
 
341
            } else {
 
342
                $il.append($instruction);
 
343
                result($il, $stack_out)
 
344
            }
 
345
        }
 
346
    }
 
347
    
 
348
    # Sets op native result type at a core level.
 
349
    method set_core_op_result_type($op, $type) {
 
350
        if $type == $RT_INT {
 
351
            %core_result_type{$op} := int;
 
352
        }
 
353
        elsif $type == $RT_NUM {
 
354
            %core_result_type{$op} := num;
 
355
        }
 
356
        elsif $type == $RT_STR {
 
357
            %core_result_type{$op} := str;
 
358
        }
 
359
    }
 
360
    
 
361
    # Sets op inlinability at a HLL level. (Can override at HLL level whether
 
362
    # or not the HLL overrides the op itself.)
 
363
    method set_hll_op_result_type($hll, $op, $type) {
 
364
        %hll_result_type{$hll} := {} unless nqp::existskey(%hll_result_type, $hll);
 
365
        if $type == $RT_INT {
 
366
            %hll_result_type{$hll}{$op} := int;
 
367
        }
 
368
        elsif $type == $RT_NUM {
 
369
            %hll_result_type{$hll}{$op} := num;
 
370
        }
 
371
        elsif $type == $RT_STR {
 
372
            %hll_result_type{$hll}{$op} := str;
 
373
        }
 
374
    }
 
375
    
 
376
    # Sets returns on an op node if we it has a native result type.
 
377
    method attach_result_type($hll, $node) {
 
378
        my $op := $node.op;
 
379
        if nqp::existskey(%hll_result_type, $hll) {
 
380
            if nqp::existskey(%hll_result_type{$hll}, $op) {
 
381
                $node.returns(%hll_result_type{$hll}{$op});
 
382
                return 1;
 
383
            }
 
384
        }
 
385
        if nqp::existskey(%core_result_type, $op) {
 
386
            $node.returns(%core_result_type{$op});
 
387
        }
 
388
    }
 
389
 
 
390
    # Adds a HLL box handler.
 
391
    method add_hll_box($hll, $type, $handler) {
 
392
        unless $type == $RT_INT || $type == $RT_NUM || $type == $RT_STR {
 
393
            nqp::die("Unknown box type '$type'");
 
394
        }
 
395
        %hll_box{$hll} := {} unless nqp::existskey(%hll_box, $hll);
 
396
        %hll_box{$hll}{$type} := $handler;
 
397
    }
 
398
 
 
399
    # Adds a HLL unbox handler.
 
400
    method add_hll_unbox($hll, $type, $handler) {
 
401
        unless $type == $RT_INT || $type == $RT_NUM || $type == $RT_STR {
 
402
            nqp::die("Unknown unbox type '$type'");
 
403
        }
 
404
        %hll_unbox{$hll} := {} unless nqp::existskey(%hll_unbox, $hll);
 
405
        %hll_unbox{$hll}{$type} := $handler;
 
406
    }
 
407
 
 
408
    # Generates instructions to box what's currently on the stack top.
 
409
    method box($qastcomp, $hll, $type) {
 
410
        (%hll_box{$hll} // %hll_box{''}){$type}($qastcomp)
 
411
    }
 
412
 
 
413
    # Generates instructions to unbox what's currently on the stack top.
 
414
    method unbox($qastcomp, $hll, $type) {
 
415
        (%hll_unbox{$hll} // %hll_unbox{''}){$type}($qastcomp)
 
416
    }
 
417
    
 
418
    # Builds a result; helper method for extensions to the ops from outside
 
419
    # of this file.
 
420
    method result($jast, int $type) {
 
421
        result($jast, $type)
 
422
    }
 
423
}
 
424
 
 
425
sub savesite($il) {
 
426
    my $index   := $*BLOCK.alloc_save_site;
 
427
    my $reenter := JAST::Label.new( :name( "reenter_"~$index ) );
 
428
    my $saver   := JAST::Label.new( :name( "SAVER" ) );
 
429
    my $try     := JAST::InstructionList.new();
 
430
    my $catch   := JAST::InstructionList.new();
 
431
 
 
432
    $try.append($il);
 
433
    $try.append($reenter);
 
434
 
 
435
    $catch.append(JAST::PushIndex.new( :value($index) ));
 
436
    $catch.append(JAST::Instruction.new( :op('goto'), $saver ));
 
437
 
 
438
    JAST::TryCatch.new( :try($try), :catch($catch), :type($TYPE_EX_SAVE) );
 
439
}
 
440
 
 
441
# Chaining.
 
442
QAST::OperationsJAST.add_core_op('chain', -> $qastcomp, $op {
 
443
    # First, we build up the list of nodes in the chain
 
444
    my @clist;
 
445
    my $cpast := $op;
 
446
    while nqp::istype($cpast, QAST::Op) && $cpast.op eq 'chain' {
 
447
        nqp::push(@clist, $cpast);
 
448
        $cpast := $cpast[0];
 
449
    }
 
450
 
 
451
    my $il       := JAST::InstructionList.new();
 
452
    my $result   := $*TA.fresh_o();
 
453
    my $endlabel := JAST::Label.new(:name($qastcomp.unique('chain_end_')));
 
454
 
 
455
    $cpast := nqp::pop(@clist);
 
456
    my $apast := $cpast[0];
 
457
    my $ares  := $qastcomp.as_jast($apast, :want($RT_OBJ));
 
458
    my $atmp  := $*TA.fresh_o();
 
459
    $il.append($ares.jast);
 
460
    $*STACK.obtain($il, $ares);
 
461
    $il.append(JAST::Instruction.new( :op('astore'), $atmp ));
 
462
 
 
463
    my $more := 1;
 
464
    while $more {
 
465
        my $bpast := $cpast[1];
 
466
        my $bres  := $qastcomp.as_jast($bpast, :want($RT_OBJ));
 
467
        my $btmp  := $*TA.fresh_o();
 
468
        $il.append($bres.jast);
 
469
        $*STACK.obtain($il, $bres);
 
470
        $il.append(JAST::Instruction.new( :op('astore'), $btmp ));
 
471
 
 
472
        $*STACK.spill_to_locals($il);
 
473
        my $cs_idx := $*CODEREFS.get_callsite_idx([$ARG_OBJ, $ARG_OBJ], []);
 
474
        $il.append(JAST::PushSVal.new( :value($cpast.name) )),
 
475
        $il.append(JAST::PushIndex.new( :value($cs_idx) )),
 
476
        $il.append($ALOAD_1);
 
477
        $il.append(JAST::Instruction.new( :op('aload'), $atmp ));
 
478
        $il.append(JAST::Instruction.new( :op('aload'), $btmp ));
 
479
        $il.append(savesite(JAST::InvokeDynamic.new(
 
480
            'subcall_noa', 'V', [$TYPE_STR, 'I', $TYPE_TC, $TYPE_SMO, $TYPE_SMO],
 
481
            'org/perl6/nqp/runtime/IndyBootstrap', 'subcall_noa',
 
482
        )));
 
483
        $il.append(JAST::Instruction.new( :op('aload'), 'cf' ));
 
484
        $il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
 
485
            'result_o', $TYPE_SMO, $TYPE_CF ));
 
486
        $il.append(JAST::Instruction.new( :op('astore'), $result ));
 
487
 
 
488
        if @clist {
 
489
            $il.append(JAST::Instruction.new( :op('aload'), $result ));
 
490
            $il.append($ALOAD_1);
 
491
            $il.append(JAST::Instruction.new( :op('invokestatic'),
 
492
                $TYPE_OPS, 'istrue', 'Long', $TYPE_SMO, $TYPE_TC ));
 
493
            $il.append($IVAL_ZERO);
 
494
            $il.append($LCMP);
 
495
            $il.append(JAST::Instruction.new( :op('ifeq'), $endlabel ));
 
496
            $cpast := nqp::pop(@clist);
 
497
            $atmp := $btmp;
 
498
        }
 
499
        else {
 
500
            $more := 0;
 
501
        }
 
502
    }
 
503
 
 
504
    $il.append($endlabel);
 
505
    $il.append(JAST::Instruction.new( :op('aload'), $result ));
 
506
    result($il, $RT_OBJ)
 
507
});
 
508
 
 
509
# Set of sequential statements
 
510
QAST::OperationsJAST.add_core_op('stmts', -> $qastcomp, $op {
 
511
    $qastcomp.as_jast(QAST::Stmts.new( |@($op) ))
 
512
});
 
513
 
 
514
# Data structures
 
515
QAST::OperationsJAST.add_core_op('list', -> $qastcomp, $op {
 
516
    # Just desugar to create the empty list.
 
517
    my $arr := $qastcomp.as_jast(QAST::Op.new(
 
518
        :op('create'),
 
519
        QAST::Op.new( :op('hlllist') )
 
520
    ));
 
521
    if +$op.list {
 
522
        # Put list into a temporary so we can push to it.
 
523
        my $il := JAST::InstructionList.new();
 
524
        $il.append($arr.jast);
 
525
        $*STACK.obtain($il, $arr);
 
526
        my $list_tmp := $*TA.fresh_o();
 
527
        $il.append(JAST::Instruction.new( :op('astore'), $list_tmp ));
 
528
        
 
529
        # Push things to the list.
 
530
        for $op.list {
 
531
            my $item := $qastcomp.as_jast($_, :want($RT_OBJ));
 
532
            $il.append($item.jast);
 
533
            $*STACK.obtain($il, $item);
 
534
            $il.append(JAST::Instruction.new( :op('aload'), $list_tmp ));
 
535
            $il.append($SWAP);
 
536
            $il.append($ALOAD_1);
 
537
            $il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS, 'push',
 
538
                $TYPE_SMO, $TYPE_SMO, $TYPE_SMO, $TYPE_TC ));
 
539
            $il.append($POP);
 
540
        }
 
541
        
 
542
        $il.append(JAST::Instruction.new( :op('aload'), $list_tmp ));
 
543
        result($il, $RT_OBJ);
 
544
    }
 
545
    else {
 
546
        $arr
 
547
    }
 
548
});
 
549
QAST::OperationsJAST.add_core_op('list_i', -> $qastcomp, $op {
 
550
    # Just desugar to create the empty list.
 
551
    my $arr := $qastcomp.as_jast(QAST::Op.new(
 
552
        :op('create'),
 
553
        QAST::Op.new( :op('bootintarray') )
 
554
    ));
 
555
    if +$op.list {
 
556
        # Put list into a temporary so we can push to it.
 
557
        my $il := JAST::InstructionList.new();
 
558
        $il.append($arr.jast);
 
559
        $*STACK.obtain($il, $arr);
 
560
        my $list_tmp := $*TA.fresh_o();
 
561
        $il.append(JAST::Instruction.new( :op('astore'), $list_tmp ));
 
562
        
 
563
        # Push things to the list.
 
564
        for $op.list {
 
565
            my $item := $qastcomp.as_jast($_, :want($RT_INT));
 
566
            $il.append($item.jast);
 
567
            $*STACK.obtain($il, $item);
 
568
            $il.append(JAST::Instruction.new( :op('aload'), $list_tmp ));
 
569
            $il.append($DUP_X2);
 
570
            $il.append($POP);
 
571
            $il.append($ALOAD_1);
 
572
            $il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS, 'push_i',
 
573
                'Long', $TYPE_SMO, 'Long', $TYPE_TC ));
 
574
            $il.append($POP2);
 
575
        }
 
576
        
 
577
        $il.append(JAST::Instruction.new( :op('aload'), $list_tmp ));
 
578
        result($il, $RT_OBJ);
 
579
    }
 
580
    else {
 
581
        $arr
 
582
    }
 
583
});
 
584
QAST::OperationsJAST.add_core_op('list_n', -> $qastcomp, $op {
 
585
    # Just desugar to create the empty list.
 
586
    my $arr := $qastcomp.as_jast(QAST::Op.new(
 
587
        :op('create'),
 
588
        QAST::Op.new( :op('bootnumarray') )
 
589
    ));
 
590
    if +$op.list {
 
591
        # Put list into a temporary so we can push to it.
 
592
        my $il := JAST::InstructionList.new();
 
593
        $il.append($arr.jast);
 
594
        $*STACK.obtain($il, $arr);
 
595
        my $list_tmp := $*TA.fresh_o();
 
596
        $il.append(JAST::Instruction.new( :op('astore'), $list_tmp ));
 
597
        
 
598
        # Push things to the list.
 
599
        for $op.list {
 
600
            my $item := $qastcomp.as_jast($_, :want($RT_NUM));
 
601
            $il.append($item.jast);
 
602
            $*STACK.obtain($il, $item);
 
603
            $il.append(JAST::Instruction.new( :op('aload'), $list_tmp ));
 
604
            $il.append($DUP_X2);
 
605
            $il.append($POP);
 
606
            $il.append($ALOAD_1);
 
607
            $il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS, 'push_n',
 
608
                'Double', $TYPE_SMO, 'Double', $TYPE_TC ));
 
609
            $il.append($POP2);
 
610
        }
 
611
        
 
612
        $il.append(JAST::Instruction.new( :op('aload'), $list_tmp ));
 
613
        result($il, $RT_OBJ);
 
614
    }
 
615
    else {
 
616
        $arr
 
617
    }
 
618
});
 
619
QAST::OperationsJAST.add_core_op('list_s', -> $qastcomp, $op {
 
620
    # Just desugar to create the empty list.
 
621
    my $arr := $qastcomp.as_jast(QAST::Op.new(
 
622
        :op('create'),
 
623
        QAST::Op.new( :op('bootstrarray') )
 
624
    ));
 
625
    if +$op.list {
 
626
        # Put list into a temporary so we can push to it.
 
627
        my $il := JAST::InstructionList.new();
 
628
        $il.append($arr.jast);
 
629
        $*STACK.obtain($il, $arr);
 
630
        my $list_tmp := $*TA.fresh_o();
 
631
        $il.append(JAST::Instruction.new( :op('astore'), $list_tmp ));
 
632
        
 
633
        # Push things to the list.
 
634
        for $op.list {
 
635
            my $item := $qastcomp.as_jast($_, :want($RT_STR));
 
636
            $il.append($item.jast);
 
637
            $*STACK.obtain($il, $item);
 
638
            $il.append(JAST::Instruction.new( :op('aload'), $list_tmp ));
 
639
            $il.append($SWAP);
 
640
            $il.append($ALOAD_1);
 
641
            $il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS, 'push_s',
 
642
                $TYPE_STR, $TYPE_SMO, $TYPE_STR, $TYPE_TC ));
 
643
            $il.append($POP);
 
644
        }
 
645
        
 
646
        $il.append(JAST::Instruction.new( :op('aload'), $list_tmp ));
 
647
        result($il, $RT_OBJ);
 
648
    }
 
649
    else {
 
650
        $arr
 
651
    }
 
652
});
 
653
QAST::OperationsJAST.add_core_op('qlist', -> $qastcomp, $op {
 
654
    $qastcomp.as_jast(QAST::Op.new( :op('list'), |@($op) ))
 
655
});
 
656
QAST::OperationsJAST.add_core_op('hash', -> $qastcomp, $op {
 
657
    # Just desugar to create the empty hash.
 
658
    my $hash := $qastcomp.as_jast(QAST::Op.new(
 
659
        :op('create'),
 
660
        QAST::Op.new( :op('hllhash') )
 
661
    ));
 
662
    if +$op.list {
 
663
        # Put hash into a temporary so we can add the items to it.
 
664
        my $il := JAST::InstructionList.new();
 
665
        $il.append($hash.jast);
 
666
        $*STACK.obtain($il, $hash);
 
667
        my $hash_tmp := $*TA.fresh_o();
 
668
        $il.append(JAST::Instruction.new( :op('astore'), $hash_tmp ));
 
669
        
 
670
        my $key_tmp := $*TA.fresh_s();
 
671
        my $val_tmp := $*TA.fresh_o();
 
672
        for $op.list -> $key, $val {
 
673
            my $key_res := $qastcomp.as_jast($key, :want($RT_STR));
 
674
            $il.append($key_res.jast);
 
675
            $*STACK.obtain($il, $key_res);
 
676
            $il.append(JAST::Instruction.new( :op('astore'), $key_tmp ));
 
677
            
 
678
            my $val_res := $qastcomp.as_jast($val, :want($RT_OBJ));
 
679
            $il.append($val_res.jast);
 
680
            $*STACK.obtain($il, $val_res);
 
681
            $il.append(JAST::Instruction.new( :op('astore'), $val_tmp ));
 
682
            
 
683
            $il.append(JAST::Instruction.new( :op('aload'), $hash_tmp ));
 
684
            $il.append(JAST::Instruction.new( :op('aload'), $key_tmp ));
 
685
            $il.append(JAST::Instruction.new( :op('aload'), $val_tmp ));
 
686
            $il.append($ALOAD_1);
 
687
            $il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS, 'bindkey',
 
688
                $TYPE_SMO, $TYPE_SMO, $TYPE_STR, $TYPE_SMO, $TYPE_TC ));
 
689
            $il.append($POP);
 
690
        }
 
691
        
 
692
        $il.append(JAST::Instruction.new( :op('aload'), $hash_tmp ));
 
693
        result($il, $RT_OBJ);
 
694
    }
 
695
    else {
 
696
        $hash
 
697
    }
 
698
});
 
699
 
 
700
# Conditionals.
 
701
sub boolify_instructions($il, $cond_type) {
 
702
    if $cond_type == $RT_INT {
 
703
        $il.append($IVAL_ZERO);
 
704
        $il.append($LCMP);
 
705
    }
 
706
    elsif $cond_type == $RT_NUM {
 
707
        $il.append($NVAL_ZERO);
 
708
        $il.append($DCMPL);
 
709
    }
 
710
    elsif $cond_type == $RT_STR {
 
711
        $il.append(JAST::Instruction.new( :op('invokestatic'),
 
712
            $TYPE_OPS, 'istrue_s', 'Long', $TYPE_STR ));
 
713
        $il.append($IVAL_ZERO);
 
714
        $il.append($LCMP);
 
715
    }
 
716
    else {
 
717
        $il.append($ALOAD_1);
 
718
        $il.append(JAST::Instruction.new( :op('invokestatic'),
 
719
            $TYPE_OPS, 'istrue', 'Long', $TYPE_SMO, $TYPE_TC ));
 
720
        $il.append($IVAL_ZERO);
 
721
        $il.append($LCMP);
 
722
    }
 
723
}
 
724
for <if unless> -> $op_name {
 
725
    QAST::OperationsJAST.add_core_op($op_name, -> $qastcomp, $op {
 
726
        # Check operand count.
 
727
        my $operands := +$op.list;
 
728
        nqp::die("Operation '$op_name' needs either 2 or 3 operands")
 
729
            if $operands < 2 || $operands > 3;
 
730
            
 
731
        # See if any immediate block wants to be passed the condition.
 
732
        my $im_then := nqp::istype($op[1], QAST::Block) && 
 
733
                       ($op[1].blocktype eq 'immediate' || $op[1].blocktype eq 'immediate_static') &&
 
734
                       $op[1].arity > 0;
 
735
        my $im_else := $operands == 3 &&
 
736
                       nqp::istype($op[2], QAST::Block) && 
 
737
                       ($op[2].blocktype eq 'immediate' || $op[2].blocktype eq 'immediate_static') &&
 
738
                       $op[2].arity > 0;
 
739
        
 
740
        # Create labels and a place to store the overall result.
 
741
        my $if_id    := $qastcomp.unique($op_name);
 
742
        my $else_lbl := JAST::Label.new(:name($if_id ~ '_else'));
 
743
        my $end_lbl  := JAST::Label.new(:name($if_id ~ '_end'));
 
744
        my $res_temp;
 
745
        my $res_type;
 
746
        
 
747
        # Compile conditional expression and saving of it if we need to.
 
748
        my $il := JAST::InstructionList.new();
 
749
        $*STACK.spill_to_locals($il);
 
750
        my $cond := $qastcomp.as_jast($op[0]);
 
751
        $il.append($cond.jast);
 
752
        $*STACK.obtain($il, $cond);
 
753
        if $im_then || $im_else {
 
754
            my $im_local := QAST::Node.unique('__IM_');
 
755
            $*BLOCK.add_local(QAST::Var.new(
 
756
                :name($im_local),
 
757
                :returns(typeobj_from_rttype($cond.type))
 
758
            ));
 
759
            if $im_then {
 
760
                $op[1].blocktype('declaration');
 
761
                $op[1] := QAST::Op.new(
 
762
                    :op('call'), $op[1],
 
763
                    QAST::Var.new( :name($im_local), :scope('local') )
 
764
                );
 
765
            }
 
766
            if $im_else {
 
767
                $op[2].blocktype('declaration');
 
768
                $op[2] := QAST::Op.new(
 
769
                    :op('call'), $op[2],
 
770
                    QAST::Var.new( :name($im_local), :scope('local') )
 
771
                );
 
772
            }
 
773
            $il.append(dup_ins($cond.type));
 
774
            $il.append(JAST::Instruction.new( :op(store_ins($cond.type)), $im_local ));
 
775
        }
 
776
        unless $*WANT == $RT_VOID || $operands == 3 {
 
777
            $il.append(dup_ins($cond.type));
 
778
            $res_type := $cond.type;
 
779
            $res_temp := fresh($res_type);
 
780
            $il.append(JAST::Instruction.new( :op(store_ins($res_type)), $res_temp ));
 
781
        }
 
782
        
 
783
        # Emit test.
 
784
        boolify_instructions($il, $cond.type);
 
785
        $il.append(JAST::Instruction.new($else_lbl,
 
786
            :op($op_name eq 'if' ?? 'ifeq' !! 'ifne')));
 
787
        
 
788
        # Compile the "then".
 
789
        my $then := $qastcomp.as_jast($op[1]);
 
790
        $il.append($then.jast);
 
791
        
 
792
        # What comes next depends on whether there's an else.
 
793
        if $operands == 3 {
 
794
            # A little care needed here; we make sure we obtain the
 
795
            # result of the then, but before we actually use it we
 
796
            # compile the else branch so we can see what result type
 
797
            # is needed. It's fine as we don't append the else JAST
 
798
            # until later.
 
799
            $*STACK.obtain($il, $then);
 
800
            my $else := $qastcomp.as_jast($op[2]);
 
801
            if $*WANT == $RT_VOID {
 
802
                $il.append(pop_ins($then.type));
 
803
            }
 
804
            else {
 
805
                $res_type := $then.type == $else.type ?? $then.type !! $RT_OBJ;
 
806
                $res_temp := fresh($res_type);
 
807
                $il.append($qastcomp.coercion($then, $res_type));
 
808
                $il.append(JAST::Instruction.new( :op(store_ins($res_type)), $res_temp ));
 
809
            }
 
810
            
 
811
            # Then branch needs to go to the loop end.
 
812
            $il.append(JAST::Instruction.new( :op('goto'), $end_lbl ));
 
813
            
 
814
            # Emit the else branch.
 
815
            $il.append($else_lbl);
 
816
            $il.append($else.jast);
 
817
            $*STACK.obtain($il, $else);
 
818
            if $*WANT == $RT_VOID {
 
819
                $il.append(pop_ins($else.type));
 
820
            }
 
821
            else {
 
822
                $il.append($qastcomp.coercion($else, $res_type));
 
823
                $il.append(JAST::Instruction.new( :op(store_ins($res_type)), $res_temp ));
 
824
            }
 
825
        }
 
826
        else {
 
827
            # If void context, just pop the result and we're done.
 
828
            # Otherwise, need to find a common type between it and
 
829
            # the condition.
 
830
            $*STACK.obtain($il, $then);
 
831
            if $*WANT == $RT_VOID {
 
832
                $il.append(pop_ins($then.type));
 
833
                $il.append($else_lbl);
 
834
            }
 
835
            elsif $then.type == $res_type {
 
836
                # Already have a common type.
 
837
                $il.append(JAST::Instruction.new( :op(store_ins($res_type)), $res_temp ));
 
838
                $il.append($else_lbl);
 
839
            }
 
840
            else {
 
841
                # Need a new result, and to coerce both condition and
 
842
                # result of then to it as needed (basically, add an else
 
843
                # that handles coercion).
 
844
                my $old_res_type := $res_type;
 
845
                my $old_res_temp := $res_temp;
 
846
                $res_type := $RT_OBJ;
 
847
                $res_temp := fresh($res_type);
 
848
                $il.append($qastcomp.coercion($then, $res_type));
 
849
                $il.append(JAST::Instruction.new( :op(store_ins($res_type)), $res_temp ));
 
850
                $il.append(JAST::Instruction.new( :op('goto'), $end_lbl ));
 
851
                $il.append($else_lbl);
 
852
                $il.append(JAST::Instruction.new( :op(load_ins($old_res_type)), $old_res_temp ));
 
853
                $il.append($qastcomp.coercion($cond, $res_type));
 
854
                $il.append(JAST::Instruction.new( :op(store_ins($res_type)), $res_temp ));
 
855
            }
 
856
        }
 
857
        
 
858
        # Add final label and load result if neded.
 
859
        $il.append($end_lbl);
 
860
        if $res_temp {
 
861
            $il.append(JAST::Instruction.new( :op(load_ins($res_type)), $res_temp ));
 
862
            result($il, $res_type);
 
863
        }
 
864
        else {
 
865
            result($il, $RT_VOID);
 
866
        }
 
867
    });
 
868
}
 
869
 
 
870
QAST::OperationsJAST.add_core_op('defor', -> $qastcomp, $op {
 
871
    if +$op.list != 2 {
 
872
        nqp::die("Operation 'defor' needs 2 operands");
 
873
    }
 
874
    my $tmp := $op.unique('defined');
 
875
    $qastcomp.as_jast(QAST::Stmts.new(
 
876
        QAST::Op.new(
 
877
            :op('bind'),
 
878
            QAST::Var.new( :name($tmp), :scope('local'), :decl('var') ),
 
879
            $op[0]
 
880
        ),
 
881
        QAST::Op.new(
 
882
            :op('if'),
 
883
            QAST::Op.new(
 
884
                :op('defined'),
 
885
                QAST::Var.new( :name($tmp), :scope('local') )
 
886
            ),
 
887
            QAST::Var.new( :name($tmp), :scope('local') ),
 
888
            $op[1]
 
889
        )))
 
890
});
 
891
 
 
892
QAST::OperationsJAST.add_core_op('xor', -> $qastcomp, $op {
 
893
    my $prefix     := $op.unique('xor');
 
894
    my $falselabel := JAST::Label.new(:name($prefix ~ '_false'));
 
895
    my $endlabel   := JAST::Label.new(:name($prefix ~ '_end'));
 
896
 
 
897
    my @childlist;
 
898
    my $fpast;
 
899
    for $op.list {
 
900
        if $_.named eq 'false' {
 
901
            $fpast := $_;
 
902
        }
 
903
        else {
 
904
            nqp::push(@childlist, $_);
 
905
        }
 
906
    }
 
907
 
 
908
    my $r := $*TA.fresh_o();
 
909
    my $b := $*TA.fresh_o();
 
910
    my $i := $*TA.fresh_i();
 
911
    my $t := $*TA.fresh_i();
 
912
    my $u := $*TA.fresh_i();
 
913
 
 
914
    my $il    := JAST::InstructionList.new();
 
915
    my $apast := nqp::shift(@childlist);
 
916
    my $ares := $qastcomp.as_jast($apast, :want($RT_OBJ));
 
917
    $il.append($ares.jast);
 
918
    $*STACK.obtain($il, $ares);
 
919
    $il.append($DUP);
 
920
    $il.append(JAST::Instruction.new( :op('astore'), $r ));
 
921
    $il.append($ALOAD_1);
 
922
    $il.append(JAST::Instruction.new( :op('invokestatic'),
 
923
        $TYPE_OPS, 'istrue', 'Long', $TYPE_SMO, $TYPE_TC ));
 
924
    $il.append(JAST::Instruction.new( :op('lstore'), $t ));
 
925
 
 
926
    my $have_middle_child := 1;
 
927
    my $bres;
 
928
    while $have_middle_child {
 
929
        my $bpast := nqp::shift(@childlist);
 
930
        $bres := $qastcomp.as_jast($bpast, :want($RT_OBJ));
 
931
        $il.append($bres.jast);
 
932
        $*STACK.obtain($il, $bres);
 
933
        $il.append($DUP);
 
934
        $il.append(JAST::Instruction.new( :op('astore'), $b ));
 
935
        $il.append($ALOAD_1);
 
936
        $il.append(JAST::Instruction.new( :op('invokestatic'),
 
937
            $TYPE_OPS, 'istrue', 'Long', $TYPE_SMO, $TYPE_TC ));
 
938
        $il.append($DUP2);
 
939
        $il.append(JAST::Instruction.new( :op('lstore'), $u ));
 
940
        $il.append($L2I);
 
941
        $il.append(JAST::Instruction.new( :op('lload'), $t ));
 
942
        $il.append($L2I);
 
943
        $il.append($IAND);
 
944
        $il.append(JAST::Instruction.new( :op('ifne'), $falselabel ));
 
945
 
 
946
        if @childlist {
 
947
            my $truelabel := JAST::Label.new(:name($op.unique('xor_true')));
 
948
            $il.append(JAST::Instruction.new( :op('lload'), $t ));
 
949
            $il.append($L2I);
 
950
            $il.append(JAST::Instruction.new( :op('ifne'), $truelabel ));
 
951
            $il.append(JAST::Instruction.new( :op('aload'), $b ));
 
952
            $il.append(JAST::Instruction.new( :op('astore'), $r ));
 
953
            $il.append(JAST::Instruction.new( :op('lload'), $u ));
 
954
            $il.append(JAST::Instruction.new( :op('lstore'), $t ));
 
955
            $il.append($truelabel);
 
956
        }
 
957
        else {
 
958
            $have_middle_child := 0;
 
959
        }
 
960
    }
 
961
 
 
962
    $il.append(JAST::Instruction.new( :op('lload'), $t ));
 
963
    $il.append($L2I);
 
964
    $il.append(JAST::Instruction.new( :op('ifne'), $endlabel ));
 
965
    $il.append(JAST::Instruction.new( :op('aload'), $b ));
 
966
    $il.append(JAST::Instruction.new( :op('astore'), $r ));
 
967
    $il.append(JAST::Instruction.new( :op('goto'), $endlabel ));
 
968
    $il.append($falselabel);
 
969
 
 
970
    if $fpast {
 
971
        my $fres := $qastcomp.as_jast($fpast, :want($RT_OBJ));
 
972
        $il.append($fres.jast);
 
973
        $*STACK.obtain($il, $fres);
 
974
        $il.append(JAST::Instruction.new( :op('astore'), $r ));
 
975
    }
 
976
    else {
 
977
        $il.append($ACONST_NULL);
 
978
        $il.append(JAST::Instruction.new( :op('astore'), $r ));
 
979
    }
 
980
 
 
981
    $il.append($endlabel);
 
982
    $il.append(JAST::Instruction.new( :op('aload'), $r ));
 
983
    result($il, $RT_OBJ)
 
984
});
 
985
 
 
986
QAST::OperationsJAST.add_core_op('ifnull', -> $qastcomp, $op {
 
987
    if +$op.list != 2 {
 
988
        nqp::die("The 'ifnull' op expects two children");
 
989
    }
 
990
    
 
991
    # Compile the expression.
 
992
    my $il   := JAST::InstructionList.new();
 
993
    $*STACK.spill_to_locals($il);
 
994
    my $expr := $qastcomp.as_jast($op[0], :want($RT_OBJ));
 
995
    $il.append($expr.jast);
 
996
    
 
997
    # Emit null check.
 
998
    my $lbl := JAST::Label.new( :name($qastcomp.unique('ifnull_')) );
 
999
    $*STACK.obtain($il, $expr);
 
1000
    $il.append($DUP);
 
1001
    $il.append(JAST::Instruction.new( :op('ifnonnull'), $lbl ));
 
1002
    
 
1003
    # Emit "then" part.
 
1004
    $il.append($POP);
 
1005
    my $then := $qastcomp.as_jast($op[1], :want($RT_OBJ));
 
1006
    $il.append($then.jast);
 
1007
    $*STACK.obtain($il, $then);
 
1008
    $il.append($lbl);
 
1009
    
 
1010
    result($il, $RT_OBJ);
 
1011
});
 
1012
 
 
1013
# Loops.
 
1014
for ('', 'repeat_') -> $repness {
 
1015
    for <while until> -> $op_name {
 
1016
        QAST::OperationsJAST.add_core_op("$repness$op_name", -> $qastcomp, $op {
 
1017
            # Check if we need a handler and operand count.
 
1018
            my $handler := 1;
 
1019
            my @operands;
 
1020
            for $op.list {
 
1021
                if $_.named eq 'nohandler' { $handler := 0; }
 
1022
                else { @operands.push($_) }
 
1023
            }
 
1024
            if +@operands != 2 && +@operands != 3 {
 
1025
                nqp::die("Operation '$repness$op_name' needs 2 or 3 operands");
 
1026
            }
 
1027
            
 
1028
            # See if there's an immediate block wanting to be passed the condition.
 
1029
            my $has_im := nqp::istype(@operands[1], QAST::Block) && 
 
1030
                          (@operands[1].blocktype eq 'immediate' || @operands[1].blocktype eq 'immediate_static') &&
 
1031
                          @operands[1].arity > 0;
 
1032
            
 
1033
            # Create labels.
 
1034
            my $while_id := $qastcomp.unique($op_name);
 
1035
            my $test_lbl := JAST::Label.new( :name($while_id ~ '_test') );
 
1036
            my $next_lbl := JAST::Label.new( :name($while_id ~ '_next') );
 
1037
            my $redo_lbl := JAST::Label.new( :name($while_id ~ '_redo') );
 
1038
            my $done_lbl := JAST::Label.new( :name($while_id ~ '_done') );
 
1039
            
 
1040
            # If we need handlers, produce them.
 
1041
            my $l_handler_id;
 
1042
            my $nr_handler_id;
 
1043
            if $handler {
 
1044
                $l_handler_id  := &*REGISTER_UNWIND_HANDLER($*HANDLER_IDX, $EX_CAT_LAST);
 
1045
                $nr_handler_id := &*REGISTER_UNWIND_HANDLER($l_handler_id, $EX_CAT_NEXT + $EX_CAT_REDO)
 
1046
            }
 
1047
            
 
1048
            # Emit loop prelude, evaluating condition. 
 
1049
            my $testil := JAST::InstructionList.new();
 
1050
            $*STACK.spill_to_locals($testil);
 
1051
            if $repness {
 
1052
                # It's a repeat_ variant, need to go straight into the
 
1053
                # loop body unconditionally.
 
1054
                $testil.append(JAST::Instruction.new( :op('goto'), $redo_lbl ));
 
1055
            }
 
1056
            $testil.append($test_lbl);
 
1057
            my $cond_res := $qastcomp.as_jast_in_handler(@operands[0], $l_handler_id || $*HANDLER_IDX);
 
1058
            $testil.append($cond_res.jast);
 
1059
            $*STACK.obtain($testil, $cond_res);
 
1060
            if $has_im {
 
1061
                my $im_local := QAST::Node.unique('__IM_');
 
1062
                $*BLOCK.add_local(QAST::Var.new(
 
1063
                    :name($im_local),
 
1064
                    :returns(typeobj_from_rttype($cond_res.type))
 
1065
                ));
 
1066
                @operands[1].blocktype('declaration');
 
1067
                @operands[1] := QAST::Op.new(
 
1068
                    :op('call'), @operands[1],
 
1069
                    QAST::Var.new( :name($im_local), :scope('local') )
 
1070
                );
 
1071
                $testil.append(dup_ins($cond_res.type));
 
1072
                $testil.append(JAST::Instruction.new( :op(store_ins($cond_res.type)), $im_local ));
 
1073
            }
 
1074
            
 
1075
            # Compile loop body, then do any analysis of result type if
 
1076
            # in non-void context.
 
1077
            my $body_res := $qastcomp.as_jast_in_handler(@operands[1], $nr_handler_id || $*HANDLER_IDX);
 
1078
            my $res;
 
1079
            my $res_type;
 
1080
            if $*WANT != $RT_VOID {
 
1081
                $res_type := $cond_res.type == $body_res.type
 
1082
                    ?? $cond_res.type
 
1083
                    !! $RT_OBJ;
 
1084
                $res := $*TA."fresh_{typechar($res_type)}"();
 
1085
            }
 
1086
            
 
1087
            # If we're non-void, store the condition's evaluation as a
 
1088
            # result.
 
1089
            if $res {
 
1090
                $testil.append(dup_ins($cond_res.type));
 
1091
                $testil.append($qastcomp.coercion($cond_res, $res_type));
 
1092
                $testil.append(JAST::Instruction.new( :op(store_ins($res_type)), $res ));
 
1093
            }
 
1094
            
 
1095
            # Emit test.
 
1096
            boolify_instructions($testil, $cond_res.type);
 
1097
            $testil.append(JAST::Instruction.new($done_lbl,
 
1098
                :op($op_name eq 'while' ?? 'ifeq' !! 'ifne')));
 
1099
 
 
1100
            # Emit the loop body; stash the result if needed.
 
1101
            my $il := JAST::InstructionList.new();
 
1102
            $il.append($redo_lbl);
 
1103
            my $body_il := JAST::InstructionList.new();
 
1104
            $body_il.append($body_res.jast);
 
1105
            $*STACK.obtain($body_il, $body_res);
 
1106
            if $res {
 
1107
                $body_il.append($qastcomp.coercion($body_res, $res_type));
 
1108
                $body_il.append(JAST::Instruction.new( :op(store_ins($res_type)), $res ));
 
1109
            }
 
1110
            else {
 
1111
                $body_il.append(pop_ins($body_res.type));
 
1112
            }
 
1113
            
 
1114
            # Add redo and next handler if needed.
 
1115
            if $handler {
 
1116
                my $catch := JAST::InstructionList.new();
 
1117
                $qastcomp.unwind_check($catch, $nr_handler_id);
 
1118
                $catch.append(JAST::Instruction.new( :op('getfield'), $TYPE_EX_UNWIND, 'category', 'Long' ));
 
1119
                $catch.append(JAST::PushIVal.new( :value($EX_CAT_REDO) ));
 
1120
                $catch.append($LCMP);
 
1121
                $catch.append(JAST::Instruction.new( :op('ifeq'), $redo_lbl ));
 
1122
                $body_il := $qastcomp.delimit_handler(
 
1123
                    JAST::TryCatch.new( :try($body_il), :$catch, :type($TYPE_EX_UNWIND) ),
 
1124
                    $l_handler_id, $nr_handler_id);
 
1125
            }
 
1126
            $il.append($body_il);
 
1127
            
 
1128
            # If there's a third child, evaluate it as part of the
 
1129
            # "next".
 
1130
            if +@operands == 3 {
 
1131
                my $next_res := $qastcomp.as_jast_in_handler(@operands[2],
 
1132
                    $l_handler_id || $*HANDLER_IDX, :want($RT_VOID));
 
1133
                $il.append($next_res.jast);
 
1134
                $*STACK.obtain($il, $next_res);
 
1135
            }
 
1136
            
 
1137
            # Emit the iteration jump and end label.
 
1138
            $il.append(JAST::Instruction.new( :op('goto'), $test_lbl ));
 
1139
            $il.append($done_lbl);
 
1140
            
 
1141
            # If needed, wrap the whole thing in a last exception handler.
 
1142
            if $handler {
 
1143
                my $catch := JAST::InstructionList.new();
 
1144
                $qastcomp.unwind_check($catch, $l_handler_id);
 
1145
                $catch.append($POP);
 
1146
                $il := $qastcomp.delimit_handler(
 
1147
                    JAST::TryCatch.new( :try($il), :catch($catch), :type($TYPE_EX_UNWIND) ),
 
1148
                    $*HANDLER_IDX, $l_handler_id);
 
1149
            }
 
1150
 
 
1151
            my $res_il := JAST::InstructionList.new();
 
1152
            $res_il.append($testil);
 
1153
            $res_il.append($il);
 
1154
            if $res {
 
1155
                $res_il.append(JAST::Instruction.new( :op(load_ins($res_type)), $res ));
 
1156
                result($res_il, $res_type)
 
1157
            }
 
1158
            else {
 
1159
                result($res_il, $RT_VOID)
 
1160
            }
 
1161
        });
 
1162
    }
 
1163
}
 
1164
 
 
1165
QAST::OperationsJAST.add_core_op('for', -> $qastcomp, $op {
 
1166
    my $handler := 1;
 
1167
    my @operands;
 
1168
    for $op.list {
 
1169
        if $_.named eq 'nohandler' { $handler := 0; }
 
1170
        else { @operands.push($_) }
 
1171
    }
 
1172
    
 
1173
    if +@operands != 2 {
 
1174
        nqp::die("Operation 'for' needs 2 operands");
 
1175
    }
 
1176
    unless nqp::istype(@operands[1], QAST::Block) {
 
1177
        nqp::die("Operation 'for' expects a block as its second operand");
 
1178
    }
 
1179
    if @operands[1].blocktype eq 'immediate' {
 
1180
        @operands[1].blocktype('declaration');
 
1181
    }
 
1182
    elsif @operands[1].blocktype eq 'immediate_static' {
 
1183
        @operands[1].blocktype('declaration_static');
 
1184
    }
 
1185
    
 
1186
    # Create result temporary if we'll need one.
 
1187
    my $res := $*WANT == $RT_VOID ?? 0 !! $*TA.fresh_o();
 
1188
    
 
1189
    # If we need handlers, produce them.
 
1190
    my $l_handler_id;
 
1191
    my $n_handler_id;
 
1192
    my $r_handler_id;
 
1193
    if $handler {
 
1194
        $l_handler_id  := &*REGISTER_UNWIND_HANDLER($*HANDLER_IDX, $EX_CAT_LAST);
 
1195
        $n_handler_id := &*REGISTER_UNWIND_HANDLER($l_handler_id, $EX_CAT_NEXT);
 
1196
        $r_handler_id := &*REGISTER_UNWIND_HANDLER($n_handler_id, $EX_CAT_REDO);
 
1197
    }
 
1198
    
 
1199
    # Evaluate the thing we'll iterate over, get the iterator and
 
1200
    # store it in a temporary.
 
1201
    my $il := JAST::InstructionList.new();
 
1202
    $*STACK.spill_to_locals($il);
 
1203
    my $list_res := $qastcomp.as_jast(@operands[0]);
 
1204
    $il.append($list_res.jast);
 
1205
    $*STACK.obtain($il, $list_res);
 
1206
    if $res {
 
1207
        $il.append($DUP);
 
1208
        $il.append(JAST::Instruction.new( :op('astore'), $res ));
 
1209
    }
 
1210
    my $iter_tmp := $*TA.fresh_o();
 
1211
    $il.append($ALOAD_1);
 
1212
    $il.append(JAST::Instruction.new( :op('invokestatic'),
 
1213
        $TYPE_OPS, 'iter', $TYPE_SMO, $TYPE_SMO, $TYPE_TC ));
 
1214
    $il.append(JAST::Instruction.new( :op('astore'), $iter_tmp ));
 
1215
    
 
1216
    # Do similar for the block.
 
1217
    my $block_res := $qastcomp.as_jast(@operands[1], :want($RT_OBJ));
 
1218
    my $block_tmp := $op.unique('iterblock');
 
1219
    $*BLOCK.add_local(QAST::Var.new( :name($block_tmp), :scope('local') ));
 
1220
    $il.append($block_res.jast);
 
1221
    $*STACK.obtain($il, $block_res);
 
1222
    $il.append(JAST::Instruction.new( :op('astore'), $block_tmp ));
 
1223
    
 
1224
    # Some labels we'll need.
 
1225
    my $for_id := $qastcomp.unique('for');
 
1226
    my $lbl_next := JAST::Label.new( :name($for_id ~ 'next') );
 
1227
    my $lbl_redo := JAST::Label.new( :name($for_id ~ 'redo') );
 
1228
    my $lbl_done := JAST::Label.new( :name($for_id ~ 'done') );
 
1229
    
 
1230
    # Emit loop test.
 
1231
    my $loop_il := JAST::InstructionList.new();
 
1232
    $loop_il.append($lbl_next);
 
1233
    $loop_il.append(JAST::Instruction.new( :op('aload'), $iter_tmp ));
 
1234
    $loop_il.append($ALOAD_1);
 
1235
    $loop_il.append(JAST::Instruction.new( :op('invokestatic'),
 
1236
        $TYPE_OPS, 'istrue', 'Long', $TYPE_SMO, $TYPE_TC ));
 
1237
    $loop_il.append($L2I);
 
1238
    $loop_il.append(JAST::Instruction.new( :op('ifeq'), $lbl_done ));
 
1239
    
 
1240
    # Fetch values into temporaries (on the stack ain't enough in case
 
1241
    # of redo).
 
1242
    my $val_il := JAST::InstructionList.new();
 
1243
    my @val_temps;
 
1244
    my $arity := @operands[1].arity || 1;
 
1245
    while $arity > 0 {
 
1246
        my $tmp := $op.unique('itertmp');
 
1247
        $*BLOCK.add_local(QAST::Var.new( :name($tmp), :scope('local') ));
 
1248
        $val_il.append(JAST::Instruction.new( :op('aload'), $iter_tmp ));
 
1249
        $val_il.append($ALOAD_1);
 
1250
        $val_il.append(JAST::Instruction.new( :op('invokestatic'),
 
1251
            $TYPE_OPS, 'shift', $TYPE_SMO, $TYPE_SMO, $TYPE_TC ));
 
1252
        $val_il.append(JAST::Instruction.new( :op('astore'), $tmp ));
 
1253
        nqp::push(@val_temps, $tmp);
 
1254
        $arity := $arity - 1;
 
1255
    }
 
1256
    $val_il.append($lbl_redo);
 
1257
    
 
1258
    # Now do block invocation.
 
1259
    my $inv_ast := QAST::Op.new(
 
1260
        :op('call'),
 
1261
        QAST::Var.new( :name($block_tmp), :scope('local') )
 
1262
    );
 
1263
    for @val_temps {
 
1264
        $inv_ast.push(QAST::Var.new( :name($_), :scope('local') ));
 
1265
    }
 
1266
    my $inv_res := $qastcomp.as_jast($inv_ast, :want($res ?? $RT_OBJ !! $RT_VOID));
 
1267
    my $inv_il := JAST::InstructionList.new();
 
1268
    $inv_il.append($inv_res.jast);
 
1269
    $*STACK.obtain($inv_il, $inv_res);
 
1270
    if $res {
 
1271
        $inv_il.append(JAST::Instruction.new( :op('astore'), $res ));
 
1272
    }
 
1273
 
 
1274
    # Wrap block invocation in redo handler if needed.
 
1275
    if $handler {
 
1276
        my $catch := JAST::InstructionList.new();
 
1277
        $qastcomp.unwind_check($catch, $r_handler_id);
 
1278
        $catch.append($POP);
 
1279
        $catch.append(JAST::Instruction.new( :op('goto'), $lbl_redo ));
 
1280
        $inv_il := $qastcomp.delimit_handler(
 
1281
            JAST::TryCatch.new( :try($inv_il), :$catch, :type($TYPE_EX_UNWIND) ),
 
1282
            $n_handler_id, $r_handler_id);
 
1283
    }
 
1284
    $val_il.append($inv_il);
 
1285
    
 
1286
    # Wrap value fetching and call in "next" handler if needed.
 
1287
    if $handler {
 
1288
        my $catch := JAST::InstructionList.new();
 
1289
        $qastcomp.unwind_check($catch, $n_handler_id);
 
1290
        $catch.append($POP);
 
1291
        $val_il := $qastcomp.delimit_handler(
 
1292
            JAST::TryCatch.new( :try($val_il), :$catch, :type($TYPE_EX_UNWIND) ),
 
1293
            $l_handler_id, $n_handler_id);
 
1294
    }
 
1295
    $loop_il.append($val_il);
 
1296
    $loop_il.append(JAST::Instruction.new( :op('goto'), $lbl_next ));
 
1297
    
 
1298
    # Emit postlude, wrapping in last handler if needed.
 
1299
    if $handler {
 
1300
        my $catch := JAST::InstructionList.new();
 
1301
        $qastcomp.unwind_check($catch, $l_handler_id);
 
1302
        $catch.append($POP);
 
1303
        $catch.append(JAST::Instruction.new( :op('goto'), $lbl_done ));
 
1304
        $loop_il := $qastcomp.delimit_handler(
 
1305
            JAST::TryCatch.new( :try($loop_il), :$catch, :type($TYPE_EX_UNWIND) ),
 
1306
            $*HANDLER_IDX, $l_handler_id);
 
1307
    }
 
1308
    $il.append($loop_il);
 
1309
    $il.append($lbl_done);
 
1310
    
 
1311
    # Result, as needed.
 
1312
    if $res {
 
1313
        $il.append(JAST::Instruction.new( :op('aload'), $res ));
 
1314
        result($il, $RT_OBJ)
 
1315
    }
 
1316
    else {
 
1317
        result($il, $RT_VOID)
 
1318
    }
 
1319
});
 
1320
 
 
1321
# Calling
 
1322
sub process_args_onto_stack($qastcomp, @children, $il, :$obj_first, :$inv_first, :$name_first, :$obj_second) {
 
1323
    # Make sure we do positionals before nameds.
 
1324
    my @pos;
 
1325
    my @named;
 
1326
    for @children {
 
1327
        nqp::push(($_.named ?? @named !! @pos), $_);
 
1328
    }
 
1329
    my @order := @pos;
 
1330
    for @named { nqp::push(@order, $_) }
 
1331
    
 
1332
    # Process the arguments, computing each of them and putting them onto the
 
1333
    # stack.
 
1334
    my @arg_results;
 
1335
    my @arg_jtypes := [$TYPE_TC];
 
1336
    my @callsite;
 
1337
    my @argnames;
 
1338
    my int $i := 0;
 
1339
    while $i < +@order {
 
1340
        my $arg_res;
 
1341
        if $i == 0 && ($obj_first || $inv_first) || $i == 1 && $obj_second {
 
1342
            $arg_res := $qastcomp.as_jast(@order[$i], :want($RT_OBJ));
 
1343
        }
 
1344
        elsif $i == 0 && $name_first {
 
1345
            $arg_res := $qastcomp.as_jast(@order[$i], :want($RT_STR));
 
1346
        }
 
1347
        else {
 
1348
            $arg_res := $qastcomp.as_jast(@order[$i]);
 
1349
        }
 
1350
        $il.append($arg_res.jast);
 
1351
        nqp::push(@arg_results, $arg_res);
 
1352
        
 
1353
        my int $type := $arg_res.type;
 
1354
        if $type == $RT_INT {
 
1355
            nqp::push(@arg_jtypes, 'J');
 
1356
        }
 
1357
        elsif $type == $RT_NUM {
 
1358
            nqp::push(@arg_jtypes, 'D');
 
1359
        }
 
1360
        else {
 
1361
            nqp::push(@arg_jtypes, jtype($arg_res.type));
 
1362
        }
 
1363
        
 
1364
        unless $i == 0 && ($inv_first || $name_first) {
 
1365
            my int $flags := 0;
 
1366
            if @order[$i].flat {
 
1367
                $flags := @order[$i].named ?? 24 !! 16;
 
1368
            }
 
1369
            elsif @order[$i].named -> $name {
 
1370
                $flags := 8;
 
1371
                nqp::push(@argnames, $name);
 
1372
            }
 
1373
            nqp::push(@callsite, arg_type($type) + $flags);
 
1374
        }
 
1375
        
 
1376
        $i++;
 
1377
    }
 
1378
 
 
1379
    # Return callsite index (which may create it if needed).
 
1380
    return [$*CODEREFS.get_callsite_idx(@callsite, @argnames), @arg_results, @arg_jtypes];
 
1381
}
 
1382
QAST::OperationsJAST.add_core_op('call', :!inlinable, sub ($qastcomp, $node) {
 
1383
    my $il := JAST::InstructionList.new();
 
1384
    
 
1385
    # If it's a direct call, then use invokedynamic to resolve the name in
 
1386
    # the current lexical scope.
 
1387
    if $node.name ne "" {
 
1388
        # Process arguments and force them into locals.
 
1389
        my @argstuff := process_args_onto_stack($qastcomp, @($node), $il);
 
1390
        my $cs_idx := @argstuff[0];
 
1391
        $*STACK.spill_to_locals($il);
 
1392
        
 
1393
        # Emit the call. Note, name passed as extra arg as some valid names in
 
1394
        # Perl 6 are not valid method names on the JVM. We use the fact that
 
1395
        # the stack was spilled to sneak the ThreadContext arg in.
 
1396
        nqp::unshift(@argstuff[2], 'I');
 
1397
        nqp::unshift(@argstuff[2], $TYPE_STR);
 
1398
        $il.append(JAST::PushSVal.new( :value($node.name) ));
 
1399
        $il.append(JAST::PushIndex.new( :value($cs_idx) ));
 
1400
        $il.append($ALOAD_1);
 
1401
        $*STACK.obtain($il, |@argstuff[1]) if @argstuff[1];
 
1402
        $il.append(savesite(JAST::InvokeDynamic.new(
 
1403
            'subcall_noa', 'V', @argstuff[2],
 
1404
            'org/perl6/nqp/runtime/IndyBootstrap', 'subcall_noa'
 
1405
        )));
 
1406
    }
 
1407
    
 
1408
    # Otherwise, it's an indirect call.
 
1409
    else {
 
1410
        # Ensure we have a thing to invoke.
 
1411
        nqp::die("A 'call' node must have a name or at least one child") unless +@($node) >= 1;
 
1412
        
 
1413
        # Proces arguments, making sure first one is an object (since that is
 
1414
        # the thing to invoke).
 
1415
        my @argstuff := process_args_onto_stack($qastcomp, @($node), $il, :inv_first);
 
1416
        my $cs_idx := @argstuff[0];
 
1417
        $*STACK.spill_to_locals($il);
 
1418
 
 
1419
        # Emit the call, using the same thread context trick. The first thing
 
1420
        # will be invoked.
 
1421
        nqp::unshift(@argstuff[2], 'I');
 
1422
        $il.append(JAST::PushIndex.new( :value($cs_idx) ));
 
1423
        $il.append($ALOAD_1);
 
1424
        $*STACK.obtain($il, |@argstuff[1]) if @argstuff[1];
 
1425
        $il.append(savesite(JAST::InvokeDynamic.new(
 
1426
            'indcall_noa', 'V', @argstuff[2],
 
1427
            'org/perl6/nqp/runtime/IndyBootstrap', 'indcall_noa'
 
1428
        )));
 
1429
    }
 
1430
 
 
1431
    result_from_cf($il, rttype_from_typeobj($node.returns));
 
1432
});
 
1433
QAST::OperationsJAST.add_core_op('callmethod', -> $qastcomp, $node {
 
1434
    my $il := JAST::InstructionList.new();
 
1435
    
 
1436
    # Ensure we have an invocant.
 
1437
    if +@($node) == 0 {
 
1438
        nqp::die("A 'callmethod' node must have at least one child");
 
1439
    }
 
1440
    my @children := nqp::clone(@($node));
 
1441
    
 
1442
    # If it's a direct call, we can get invokedynamic to do something smart
 
1443
    # with guard clauses for us.
 
1444
    if $node.name ne '' {
 
1445
        # Process arguments and force them into locals.
 
1446
        my @argstuff := process_args_onto_stack($qastcomp, @children, $il, :obj_first);
 
1447
        my $cs_idx := @argstuff[0];
 
1448
        $*STACK.spill_to_locals($il);
 
1449
        
 
1450
        # Emit the call. Note, name passed as extra arg as some valid names in
 
1451
        # Perl 6 are not valid method names on the JVM. We use the fact that
 
1452
        # the stack was spilled to sneak the ThreadContext arg in.
 
1453
        nqp::unshift(@argstuff[2], 'I');
 
1454
        nqp::unshift(@argstuff[2], $TYPE_STR);
 
1455
        $il.append(JAST::PushSVal.new( :value($node.name) ));
 
1456
        $il.append(JAST::PushIndex.new( :value($cs_idx) ));
 
1457
        $il.append($ALOAD_1);
 
1458
        $*STACK.obtain($il, |@argstuff[1]) if @argstuff[1];
 
1459
        $il.append(savesite(JAST::InvokeDynamic.new(
 
1460
            'methcall_noa', 'V', @argstuff[2],
 
1461
            'org/perl6/nqp/runtime/IndyBootstrap', 'methcall_noa',
 
1462
        )));
 
1463
    }
 
1464
    
 
1465
    # Otherwise, it's indirect, and we need to resolve the method each and
 
1466
    # every call. Still wire it through invokedynamic, but it can't do quite
 
1467
    # so much for us.
 
1468
    else {
 
1469
        # Ensure we have a name, and re-arrange it to come first.
 
1470
        if +@children == 1 {
 
1471
            nqp::die("Method call must either supply a name or have a child node that evaluates to the name");
 
1472
        }
 
1473
        my $inv := nqp::shift(@children);
 
1474
        my $name := nqp::shift(@children);
 
1475
        nqp::unshift(@children, $inv);
 
1476
        nqp::unshift(@children, $name);
 
1477
        
 
1478
        # Process arguments and force them into locals.
 
1479
        my @argstuff := process_args_onto_stack($qastcomp, @children, $il, :name_first, :obj_second);
 
1480
        my $cs_idx := @argstuff[0];
 
1481
        $*STACK.spill_to_locals($il);
 
1482
        
 
1483
        # Emit the call.
 
1484
        nqp::unshift(@argstuff[2], 'I');
 
1485
        $il.append(JAST::PushIndex.new( :value($cs_idx) ));
 
1486
        $il.append($ALOAD_1);
 
1487
        $*STACK.obtain($il, |@argstuff[1]) if @argstuff[1];
 
1488
        $il.append(savesite(JAST::InvokeDynamic.new(
 
1489
            'indmethcall_noa', 'V', @argstuff[2],
 
1490
            'org/perl6/nqp/runtime/IndyBootstrap', 'indmethcall_noa'
 
1491
        )));
 
1492
    }
 
1493
 
 
1494
    result_from_cf($il, rttype_from_typeobj($node.returns));
 
1495
});
 
1496
 
 
1497
my $num_lexotics := 0;
 
1498
QAST::OperationsJAST.add_core_op('lexotic', :!inlinable, -> $qastcomp, $op {
 
1499
    # Create the lexotic lexical.
 
1500
    my $target := nqp::floor_n(nqp::time_n() * 1000) * 10000 + $num_lexotics++;
 
1501
    my $il := JAST::InstructionList.new();
 
1502
    $*BLOCK.add_lexical(QAST::Var.new( :name($op.name) ));
 
1503
    $il.append(JAST::PushIVal.new( :value($target) ));
 
1504
    $il.append(JAST::Instruction.new( :op('aload'), 'tc' ));
 
1505
    $il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
 
1506
        'lexotic_tc', $TYPE_SMO, 'Long', $TYPE_TC ));
 
1507
    $il.append(JAST::Instruction.new( :op('aload'), 'cf' ));
 
1508
    $il.append(JAST::PushIndex.new( :value($*BLOCK.lexical_idx($op.name)) ));
 
1509
    $il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
 
1510
        'bindlex_o', $TYPE_SMO, $TYPE_SMO, $TYPE_CF, 'Integer' ));
 
1511
    $il.append($POP);
 
1512
    
 
1513
    # Compile the things inside the lexotic
 
1514
    my $*WANT := $RT_OBJ;
 
1515
    my $stmt_res := $qastcomp.coerce($qastcomp.compile_all_the_stmts($op.list()), $RT_OBJ);
 
1516
    $*STACK.obtain($il, $stmt_res);
 
1517
    
 
1518
    # Build up catch for the lexotic (rethrows if wrong thing).
 
1519
    my $miss_lbl := JAST::Label.new( :name($qastcomp.unique('lexotic_miss_')) );
 
1520
    my $done_lbl := JAST::Label.new( :name($qastcomp.unique('lexotic_done_')) );
 
1521
    my $catch_il := JAST::InstructionList.new();
 
1522
    $catch_il.append($DUP);
 
1523
    $catch_il.append(JAST::Instruction.new( :op('getfield'), $TYPE_EX_LEX, 'target', 'Long' ));
 
1524
    $catch_il.append(JAST::PushIVal.new( :value($target) ));
 
1525
    $catch_il.append($LCMP);
 
1526
    $catch_il.append(JAST::Instruction.new( :op('ifne'), $miss_lbl ));
 
1527
    $catch_il.append(JAST::Instruction.new( :op('getfield'), $TYPE_EX_LEX, 'payload', $TYPE_SMO ));
 
1528
    $catch_il.append(JAST::Instruction.new( :op('goto'), $done_lbl ));
 
1529
    $catch_il.append($miss_lbl);
 
1530
    $catch_il.append($ATHROW);
 
1531
    $catch_il.append($done_lbl);
 
1532
    
 
1533
    # Finally, assemble try/catch.
 
1534
    $il.append(JAST::TryCatch.new(
 
1535
        :try($stmt_res.jast),
 
1536
        :catch($catch_il),
 
1537
        :type($TYPE_EX_LEX)
 
1538
    ));
 
1539
    
 
1540
    result($il, $RT_OBJ);
 
1541
});
 
1542
 
 
1543
# Binding
 
1544
QAST::OperationsJAST.add_core_op('bind', -> $qastcomp, $op {
 
1545
    # Sanity checks.
 
1546
    my @children := $op.list;
 
1547
    if +@children != 2 {
 
1548
        nqp::die("A 'bind' op must have exactly two children");
 
1549
    }
 
1550
    unless nqp::istype(@children[0], QAST::Var) {
 
1551
        nqp::die("First child of a 'bind' op must be a QAST::Var");
 
1552
    }
 
1553
    
 
1554
    # Set the QAST of the think we're to bind, then delegate to
 
1555
    # the compilation of the QAST::Var to handle the rest.
 
1556
    my $*BINDVAL := @children[1];
 
1557
    $qastcomp.as_jast(@children[0])
 
1558
});
 
1559
 
 
1560
# Exception handling/munging.
 
1561
QAST::OperationsJAST.map_classlib_core_op('die_s', $TYPE_OPS, 'die_s_c', [$RT_STR], $RT_STR, :tc, :cont);
 
1562
QAST::OperationsJAST.map_classlib_core_op('die', $TYPE_OPS, 'die_s_c', [$RT_STR], $RT_STR, :tc, :cont);
 
1563
QAST::OperationsJAST.map_classlib_core_op('exception', $TYPE_OPS, 'exception', [], $RT_OBJ, :tc);
 
1564
QAST::OperationsJAST.map_classlib_core_op('getextype', $TYPE_OPS, 'getextype', [$RT_OBJ], $RT_INT, :tc);
 
1565
QAST::OperationsJAST.map_classlib_core_op('setextype', $TYPE_OPS, 'setextype', [$RT_OBJ, $RT_INT], $RT_INT, :tc);
 
1566
QAST::OperationsJAST.map_classlib_core_op('getpayload', $TYPE_OPS, 'getpayload', [$RT_OBJ], $RT_OBJ, :tc);
 
1567
QAST::OperationsJAST.map_classlib_core_op('setpayload', $TYPE_OPS, 'setpayload', [$RT_OBJ, $RT_OBJ], $RT_OBJ, :tc);
 
1568
QAST::OperationsJAST.map_classlib_core_op('getmessage', $TYPE_OPS, 'getmessage', [$RT_OBJ], $RT_STR, :tc);
 
1569
QAST::OperationsJAST.map_classlib_core_op('setmessage', $TYPE_OPS, 'setmessage', [$RT_OBJ, $RT_STR], $RT_STR, :tc);
 
1570
QAST::OperationsJAST.map_classlib_core_op('newexception', $TYPE_OPS, 'newexception', [], $RT_OBJ, :tc);
 
1571
QAST::OperationsJAST.map_classlib_core_op('backtrace', $TYPE_OPS, 'backtrace', [$RT_OBJ], $RT_OBJ, :tc);
 
1572
QAST::OperationsJAST.map_classlib_core_op('backtracestrings', $TYPE_OPS, 'backtracestrings', [$RT_OBJ], $RT_OBJ, :tc);
 
1573
QAST::OperationsJAST.map_classlib_core_op('throw', $TYPE_OPS, '_throw_c', [$RT_OBJ], $RT_OBJ, :tc, :cont);
 
1574
QAST::OperationsJAST.map_classlib_core_op('rethrow', $TYPE_OPS, 'rethrow_c', [$RT_OBJ], $RT_OBJ, :tc, :cont);
 
1575
QAST::OperationsJAST.map_classlib_core_op('resume', $TYPE_OPS, 'resume', [$RT_OBJ], $RT_OBJ, :tc);
 
1576
my %handler_names := nqp::hash(
 
1577
    'CATCH',   $EX_CAT_CATCH,
 
1578
    'CONTROL', $EX_CAT_CONTROL,
 
1579
    'NEXT',    $EX_CAT_NEXT,
 
1580
    'LAST',    $EX_CAT_LAST,
 
1581
    'REDO',    $EX_CAT_REDO,
 
1582
    'TAKE',    $EX_CAT_TAKE,
 
1583
    'WARN',    $EX_CAT_WARN,
 
1584
    'PROCEED', $EX_CAT_PROCEED,
 
1585
    'SUCCEED', $EX_CAT_SUCCEED,
 
1586
);
 
1587
QAST::OperationsJAST.add_core_op('handle', :!inlinable, sub ($qastcomp, $op) {
 
1588
    my @children := nqp::clone($op.list());
 
1589
    if @children == 0 {
 
1590
        nqp::die("The 'handle' op requires at least one child");
 
1591
    }
 
1592
    
 
1593
    # If there's exactly one child, then there's nothing protecting
 
1594
    # it; just compile it and we're done.
 
1595
    my $protected := @children.shift();
 
1596
    unless @children {
 
1597
        return $qastcomp.as_jast($protected);
 
1598
    }
 
1599
    
 
1600
    # Otherwise, we need to generate an install a handler block, which will
 
1601
    # decide that to do by category.
 
1602
    my $mask := 0;
 
1603
    my $hblock := QAST::Block.new(
 
1604
        QAST::Op.new(
 
1605
            :op('bind'),
 
1606
            QAST::Var.new( :name('__category__'), :scope('local'), :decl('var') ),
 
1607
            QAST::Op.new(
 
1608
                :op('getextype'),
 
1609
                QAST::Op.new( :op('exception') )
 
1610
            )));
 
1611
    my $push_target := $hblock;
 
1612
    for @children -> $type, $handler {
 
1613
        # Get the category mask.
 
1614
        unless nqp::existskey(%handler_names, $type) {
 
1615
            nqp::die("Invalid handler type '$type'");
 
1616
        }
 
1617
        my $cat_mask := %handler_names{$type};
 
1618
        
 
1619
        # Chain in this handler.
 
1620
        my $check := QAST::Op.new(
 
1621
            :op('if'),
 
1622
            QAST::Op.new(
 
1623
                :op('bitand_i'),
 
1624
                QAST::Var.new( :name('__category__'), :scope('local') ),
 
1625
                QAST::IVal.new( :value($cat_mask) )
 
1626
            ),
 
1627
            $handler
 
1628
        );
 
1629
        $push_target.push($check);
 
1630
        $push_target := $check;
 
1631
        
 
1632
        # Add to mask.
 
1633
        $mask := nqp::bitor_i($mask, $cat_mask);
 
1634
    }
 
1635
    
 
1636
    # Compile, create a lexical to put the handler in, and add it. Should
 
1637
    # also force the stack to empty.
 
1638
    my $name   := QAST::Node.unique('!HANDLER_');
 
1639
    $*BLOCK.add_lexical(QAST::Var.new( :name($name) ));
 
1640
    my $lexidx := $*BLOCK.lexical_idx($name);
 
1641
    my $il     := JAST::InstructionList.new();
 
1642
    $*STACK.spill_to_locals($il);
 
1643
    my $hb_res := $qastcomp.as_jast($hblock, :want($RT_OBJ));
 
1644
    $il.append($hb_res.jast);
 
1645
    $*STACK.obtain($il, $hb_res);
 
1646
    $il.append(JAST::Instruction.new( :op('aload'), 'cf' ));
 
1647
    $il.append(JAST::PushIndex.new( :value($lexidx) ));
 
1648
    $il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
 
1649
        'bindlex_o', $TYPE_SMO, $TYPE_SMO, $TYPE_CF, 'Integer' ));
 
1650
    $il.append($POP);
 
1651
    
 
1652
    # Register a handler.
 
1653
    my $handler := &*REGISTER_BLOCK_HANDLER($*HANDLER_IDX, $mask, $lexidx);
 
1654
    
 
1655
    # Evaluate the protected code and stash it in a temporary.
 
1656
    my $result := $*TA.fresh_o();
 
1657
    my $prores := $qastcomp.as_jast_in_handler($protected, $handler, :want($RT_OBJ));
 
1658
    my $tryil  := JAST::InstructionList.new();
 
1659
    $tryil.append($prores.jast);
 
1660
    $*STACK.obtain($tryil, $prores);
 
1661
    $tryil.append(JAST::Instruction.new( :op('astore'), $result ));
 
1662
    
 
1663
    # The catch part just handles unwind; grab the result. Also check "exit
 
1664
    # after unwind" flag, used to force this whole block to exit.
 
1665
    my $catchil := JAST::InstructionList.new();
 
1666
    my $exitlbl := JAST::Label.new( :name($qastcomp.unique('unwindexit')) );
 
1667
    $qastcomp.unwind_check($catchil, $handler);
 
1668
    $catchil.append(JAST::Instruction.new( :op('getfield'), $TYPE_EX_UNWIND, 'result', $TYPE_SMO ));
 
1669
    $catchil.append(JAST::Instruction.new( :op('astore'), $result ));
 
1670
    $catchil.append(JAST::Instruction.new( :op('aload'), 'cf' ));
 
1671
    $catchil.append(JAST::Instruction.new( :op('getfield'), $TYPE_CF, 'exitAfterUnwind', "Z" ));
 
1672
    $catchil.append(JAST::Instruction.new( :op('ifeq'), $exitlbl ));
 
1673
    $catchil.append(JAST::Instruction.new( :op('aload'), $result ));
 
1674
    $catchil.append(JAST::Instruction.new( :op('aload'), 'cf' ));
 
1675
    $catchil.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
 
1676
        'return_o', 'Void', $TYPE_SMO, $TYPE_CF ));
 
1677
    $catchil.append(JAST::Instruction.new( :op('aload'), 'cf' ));
 
1678
    $catchil.append(JAST::Instruction.new( :op('invokevirtual'),
 
1679
        $TYPE_CF, 'leave', 'Void' ));
 
1680
    $catchil.append($RETURN);
 
1681
    $catchil.append($exitlbl);
 
1682
    
 
1683
    # Wrap it all up in try/catch etc.
 
1684
    $il.append($qastcomp.delimit_handler(
 
1685
        JAST::TryCatch.new( :try($tryil), :catch($catchil), :type($TYPE_EX_UNWIND) ),
 
1686
        $*HANDLER_IDX, $handler));
 
1687
 
 
1688
    # Evaluate to the result.
 
1689
    $il.append(JAST::Instruction.new( :op('aload'), $result ));
 
1690
    result($il, $RT_OBJ);
 
1691
});
 
1692
 
 
1693
# Control exception throwing.
 
1694
my %control_map := nqp::hash(
 
1695
    'next', $EX_CAT_NEXT,
 
1696
    'last', $EX_CAT_LAST,
 
1697
    'redo', $EX_CAT_REDO
 
1698
);
 
1699
QAST::OperationsJAST.add_core_op('control', -> $qastcomp, $op {
 
1700
    my $name := $op.name;
 
1701
    if nqp::existskey(%control_map, $name) {
 
1702
        my $cat := %control_map{$name};
 
1703
        my $il := JAST::InstructionList.new();
 
1704
        $*STACK.spill_to_locals($il);
 
1705
        $il.append(JAST::PushIVal.new( :value($cat) ));
 
1706
        $il.append($ALOAD_1);
 
1707
        $il.append(savesite(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
 
1708
            'throwcatdyn_c', 'Void', 'Long', $TYPE_TC )));
 
1709
        result_from_cf($il, $RT_OBJ);
 
1710
    }
 
1711
    else {
 
1712
        nqp::die("Unknown control exception type '$name'");
 
1713
    }
 
1714
});
 
1715
 
 
1716
# Default ways to box/unbox (for no particular HLL).
 
1717
QAST::OperationsJAST.add_hll_box('', $RT_INT, -> $qastcomp {
 
1718
    my $il := JAST::InstructionList.new();
 
1719
    $il.append($ALOAD_1);
 
1720
    $il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
 
1721
        'bootint', $TYPE_SMO, $TYPE_TC ));
 
1722
    $il.append($ALOAD_1);
 
1723
    $il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
 
1724
        'box_i', $TYPE_SMO, 'Long', $TYPE_SMO, $TYPE_TC ));
 
1725
    $il
 
1726
});
 
1727
QAST::OperationsJAST.add_hll_box('', $RT_NUM, -> $qastcomp {
 
1728
    my $il := JAST::InstructionList.new();
 
1729
    $il.append($ALOAD_1);
 
1730
    $il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
 
1731
        'bootnum', $TYPE_SMO, $TYPE_TC ));
 
1732
    $il.append($ALOAD_1);
 
1733
    $il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
 
1734
        'box_n', $TYPE_SMO, 'Double', $TYPE_SMO, $TYPE_TC ));
 
1735
    $il
 
1736
});
 
1737
QAST::OperationsJAST.add_hll_box('', $RT_STR, -> $qastcomp {
 
1738
    my $il := JAST::InstructionList.new();
 
1739
    $il.append($ALOAD_1);
 
1740
    $il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
 
1741
        'bootstr', $TYPE_SMO, $TYPE_TC ));
 
1742
    $il.append($ALOAD_1);
 
1743
    $il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
 
1744
        'box_s', $TYPE_SMO, $TYPE_STR, $TYPE_SMO, $TYPE_TC ));
 
1745
    $il
 
1746
});
 
1747
QAST::OperationsJAST.add_hll_unbox('', $RT_INT, -> $qastcomp {
 
1748
    my $il := JAST::InstructionList.new();
 
1749
    $il.append($ALOAD_1);
 
1750
    $il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
 
1751
        'unbox_i', 'Long', $TYPE_SMO, $TYPE_TC ));
 
1752
    $il
 
1753
});
 
1754
QAST::OperationsJAST.add_hll_unbox('', $RT_NUM, -> $qastcomp {
 
1755
    my $il := JAST::InstructionList.new();
 
1756
    $il.append($ALOAD_1);
 
1757
    $il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
 
1758
        'unbox_n', 'Double', $TYPE_SMO, $TYPE_TC ));
 
1759
    $il
 
1760
});
 
1761
QAST::OperationsJAST.add_hll_unbox('', $RT_STR, -> $qastcomp {
 
1762
    my $il := JAST::InstructionList.new();
 
1763
    $il.append($ALOAD_1);
 
1764
    $il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
 
1765
        'unbox_s', $TYPE_STR, $TYPE_SMO, $TYPE_TC ));
 
1766
    $il
 
1767
});
 
1768
 
 
1769
# Context introspection; note that lexpads and contents are actually the same object
 
1770
# in the JVM port, which allows a little op re-use.
 
1771
QAST::OperationsJAST.map_classlib_core_op('ctx', $TYPE_OPS, 'ctx', [], $RT_OBJ, :tc, :!inlinable);
 
1772
QAST::OperationsJAST.map_classlib_core_op('ctxouter', $TYPE_OPS, 'ctxouter', [$RT_OBJ], $RT_OBJ, :tc, :!inlinable);
 
1773
QAST::OperationsJAST.map_classlib_core_op('ctxcaller', $TYPE_OPS, 'ctxcaller', [$RT_OBJ], $RT_OBJ, :tc, :!inlinable);
 
1774
QAST::OperationsJAST.map_classlib_core_op('curcode', $TYPE_OPS, 'curcode', [], $RT_OBJ, :tc, :!inlinable);
 
1775
QAST::OperationsJAST.map_classlib_core_op('callercode', $TYPE_OPS, 'callercode', [], $RT_OBJ, :tc, :!inlinable);
 
1776
QAST::OperationsJAST.map_classlib_core_op('ctxlexpad', $TYPE_OPS, 'ctxlexpad', [$RT_OBJ], $RT_OBJ, :tc, :!inlinable);
 
1777
QAST::OperationsJAST.map_classlib_core_op('curlexpad', $TYPE_OPS, 'ctx', [], $RT_OBJ, :tc, :!inlinable);
 
1778
QAST::OperationsJAST.map_classlib_core_op('lexprimspec', $TYPE_OPS, 'lexprimspec', [$RT_OBJ, $RT_STR], $RT_INT, :tc, :!inlinable);
 
1779
 
 
1780
# Argument capture processing, for writing things like multi-dispatchers in
 
1781
# high level languages.
 
1782
QAST::OperationsJAST.add_core_op('usecapture', :!inlinable, -> $qastcomp, $op {
 
1783
    my $il := JAST::InstructionList.new();
 
1784
    $il.append($ALOAD_1);
 
1785
    $il.append(JAST::Instruction.new( :op('aload'), 'csd' ));
 
1786
    $il.append(JAST::Instruction.new( :op('aload'), '__args' ));
 
1787
    $il.append(JAST::Instruction.new( :op('invokestatic'),
 
1788
        $TYPE_OPS, 'usecapture', $TYPE_SMO, $TYPE_TC, $TYPE_CSD, "[$TYPE_OBJ" ));
 
1789
    result($il, $RT_OBJ)
 
1790
});
 
1791
QAST::OperationsJAST.add_core_op('savecapture', :!inlinable, -> $qastcomp, $op {
 
1792
    my $il := JAST::InstructionList.new();
 
1793
    $il.append($ALOAD_1);
 
1794
    $il.append(JAST::Instruction.new( :op('aload'), 'csd' ));
 
1795
    $il.append(JAST::Instruction.new( :op('aload'), '__args' ));
 
1796
    $il.append(JAST::Instruction.new( :op('invokestatic'),
 
1797
        $TYPE_OPS, 'savecapture', $TYPE_SMO, $TYPE_TC, $TYPE_CSD, "[$TYPE_OBJ" ));
 
1798
    result($il, $RT_OBJ)
 
1799
});
 
1800
QAST::OperationsJAST.map_classlib_core_op('captureposelems', $TYPE_OPS, 'captureposelems', [$RT_OBJ], $RT_INT, :tc);
 
1801
QAST::OperationsJAST.map_classlib_core_op('captureposarg', $TYPE_OPS, 'captureposarg', [$RT_OBJ, $RT_INT], $RT_OBJ, :tc);
 
1802
QAST::OperationsJAST.map_classlib_core_op('captureposarg_i', $TYPE_OPS, 'captureposarg_i', [$RT_OBJ, $RT_INT], $RT_INT, :tc);
 
1803
QAST::OperationsJAST.map_classlib_core_op('captureposarg_n', $TYPE_OPS, 'captureposarg_n', [$RT_OBJ, $RT_INT], $RT_NUM, :tc);
 
1804
QAST::OperationsJAST.map_classlib_core_op('captureposarg_s', $TYPE_OPS, 'captureposarg_s', [$RT_OBJ, $RT_INT], $RT_STR, :tc);
 
1805
QAST::OperationsJAST.map_classlib_core_op('captureposprimspec', $TYPE_OPS, 'captureposprimspec', [$RT_OBJ, $RT_INT], $RT_INT, :tc);
 
1806
QAST::OperationsJAST.map_classlib_core_op('captureexistsnamed', $TYPE_OPS, 'captureexistsnamed', [$RT_OBJ, $RT_STR], $RT_INT, :tc);
 
1807
QAST::OperationsJAST.map_classlib_core_op('capturehasnameds', $TYPE_OPS, 'capturehasnameds', [$RT_OBJ], $RT_INT, :tc);
 
1808
 
 
1809
# Multiple dispatch related.
 
1810
QAST::OperationsJAST.map_classlib_core_op('invokewithcapture', $TYPE_OPS, 'invokewithcapture', [$RT_OBJ, $RT_OBJ], $RT_OBJ, :tc);
 
1811
QAST::OperationsJAST.map_classlib_core_op('multicacheadd', $TYPE_OPS, 'multicacheadd', [$RT_OBJ, $RT_OBJ, $RT_OBJ], $RT_OBJ, :tc);
 
1812
QAST::OperationsJAST.map_classlib_core_op('multicachefind', $TYPE_OPS, 'multicachefind', [$RT_OBJ, $RT_OBJ], $RT_OBJ, :tc);
 
1813
 
 
1814
# Constant mapping.
 
1815
my %const_map := nqp::hash(
 
1816
    'CCLASS_ANY',           65535,
 
1817
    'CCLASS_UPPERCASE',     1,
 
1818
    'CCLASS_LOWERCASE',     2,
 
1819
    'CCLASS_ALPHABETIC',    4,
 
1820
    'CCLASS_NUMERIC',       8,
 
1821
    'CCLASS_HEXADECIMAL',   16,
 
1822
    'CCLASS_WHITESPACE',    32,
 
1823
    'CCLASS_PRINTING',      64,
 
1824
    'CCLASS_BLANK',         256,
 
1825
    'CCLASS_CONTROL',       512,
 
1826
    'CCLASS_PUNCTUATION',   1024,
 
1827
    'CCLASS_ALPHANUMERIC',  2048,
 
1828
    'CCLASS_NEWLINE',       4096,
 
1829
    'CCLASS_WORD',          8192,
 
1830
    
 
1831
    'HLL_ROLE_NONE',        0,
 
1832
    'HLL_ROLE_INT',         1,
 
1833
    'HLL_ROLE_NUM',         2,
 
1834
    'HLL_ROLE_STR',         3,
 
1835
    'HLL_ROLE_ARRAY',       4,
 
1836
    'HLL_ROLE_HASH',        5,
 
1837
    'HLL_ROLE_CODE',        6,
 
1838
    
 
1839
    'CONTROL_TAKE',         32,
 
1840
    'CONTROL_LAST',         16,
 
1841
    'CONTROL_NEXT',         4,
 
1842
    'CONTROL_REDO',         8,
 
1843
    'CONTROL_SUCCEED',      128,
 
1844
    'CONTROL_PROCEED',      256,
 
1845
    'CONTROL_WARN',         64,
 
1846
    
 
1847
    'STAT_EXISTS',             0,
 
1848
    'STAT_FILESIZE',           1,
 
1849
    'STAT_ISDIR',              2,
 
1850
    'STAT_ISREG',              3,
 
1851
    'STAT_ISDEV',              4,
 
1852
    'STAT_CREATETIME',         5,
 
1853
    'STAT_ACCESSTIME',         6,
 
1854
    'STAT_MODIFYTIME',         7,
 
1855
    'STAT_CHANGETIME',         8,
 
1856
    'STAT_BACKUPTIME',         9,
 
1857
    'STAT_UID',                10,
 
1858
    'STAT_GID',                11,
 
1859
    'STAT_ISLNK',              12,
 
1860
    'STAT_PLATFORM_DEV',       -1,
 
1861
    'STAT_PLATFORM_INODE',     -2,
 
1862
    'STAT_PLATFORM_MODE',      -3,
 
1863
    'STAT_PLATFORM_NLINKS',    -4,
 
1864
    'STAT_PLATFORM_DEVTYPE',   -5,
 
1865
    'STAT_PLATFORM_BLOCKSIZE', -6,
 
1866
    'STAT_PLATFORM_BLOCKS',    -7,
 
1867
);
 
1868
QAST::OperationsJAST.add_core_op('const', -> $qastcomp, $op {
 
1869
    if nqp::existskey(%const_map, $op.name) {
 
1870
        $qastcomp.as_jast(QAST::IVal.new( :value(%const_map{$op.name}) ))
 
1871
    }
 
1872
    else {
 
1873
        nqp::die("Unknown constant '" ~ $op.name ~ "'");
 
1874
    }
 
1875
});
 
1876
 
 
1877
# Default way to do positional and associative lookups.
 
1878
QAST::OperationsJAST.map_classlib_core_op('positional_get', $TYPE_OPS, 'atpos', [$RT_OBJ, $RT_INT], $RT_OBJ, :tc);
 
1879
QAST::OperationsJAST.map_classlib_core_op('positional_bind', $TYPE_OPS, 'bindpos', [$RT_OBJ, $RT_INT, $RT_OBJ], $RT_OBJ, :tc);
 
1880
QAST::OperationsJAST.map_classlib_core_op('associative_get', $TYPE_OPS, 'atkey', [$RT_OBJ, $RT_STR], $RT_OBJ, :tc);
 
1881
QAST::OperationsJAST.map_classlib_core_op('associative_bind', $TYPE_OPS, 'bindkey', [$RT_OBJ, $RT_STR, $RT_OBJ], $RT_OBJ, :tc);
 
1882
 
 
1883
# I/O opcodes
 
1884
QAST::OperationsJAST.map_classlib_core_op('print', $TYPE_OPS, 'print', [$RT_STR], $RT_STR, :tc);
 
1885
QAST::OperationsJAST.map_classlib_core_op('say', $TYPE_OPS, 'say', [$RT_STR], $RT_STR, :tc);
 
1886
QAST::OperationsJAST.map_classlib_core_op('stat', $TYPE_OPS, 'stat', [$RT_STR, $RT_INT], $RT_INT);
 
1887
QAST::OperationsJAST.map_classlib_core_op('open', $TYPE_OPS, 'open', [$RT_STR, $RT_STR], $RT_OBJ, :tc);
 
1888
QAST::OperationsJAST.map_classlib_core_op('filereadable', $TYPE_OPS, 'filereadable', [$RT_STR], $RT_INT, :tc);
 
1889
QAST::OperationsJAST.map_classlib_core_op('filewritable', $TYPE_OPS, 'filewritable', [$RT_STR], $RT_INT, :tc);
 
1890
QAST::OperationsJAST.map_classlib_core_op('fileexecutable', $TYPE_OPS, 'fileexecutable', [$RT_STR], $RT_INT, :tc);
 
1891
QAST::OperationsJAST.map_classlib_core_op('fileislink', $TYPE_OPS, 'fileislink', [$RT_STR], $RT_INT, :tc);
 
1892
QAST::OperationsJAST.map_classlib_core_op('getstdin', $TYPE_OPS, 'getstdin', [], $RT_OBJ, :tc);
 
1893
QAST::OperationsJAST.map_classlib_core_op('getstdout', $TYPE_OPS, 'getstdout', [], $RT_OBJ, :tc);
 
1894
QAST::OperationsJAST.map_classlib_core_op('getstderr', $TYPE_OPS, 'getstderr', [], $RT_OBJ, :tc);
 
1895
QAST::OperationsJAST.map_classlib_core_op('setencoding', $TYPE_OPS, 'setencoding', [$RT_OBJ, $RT_STR], $RT_OBJ, :tc);
 
1896
QAST::OperationsJAST.map_classlib_core_op('setinputlinesep', $TYPE_OPS, 'setinputlinesep', [$RT_OBJ, $RT_STR], $RT_OBJ, :tc);
 
1897
QAST::OperationsJAST.map_classlib_core_op('tellfh', $TYPE_OPS, 'tellfh', [$RT_OBJ], $RT_INT, :tc);
 
1898
QAST::OperationsJAST.map_classlib_core_op('readfh', $TYPE_OPS, 'readfh', [$RT_OBJ, $RT_OBJ, $RT_INT], $RT_OBJ, :tc);
 
1899
QAST::OperationsJAST.map_classlib_core_op('writefh', $TYPE_OPS, 'writefh', [$RT_OBJ, $RT_OBJ], $RT_OBJ, :tc);
 
1900
QAST::OperationsJAST.map_classlib_core_op('printfh', $TYPE_OPS, 'printfh', [$RT_OBJ, $RT_STR], $RT_STR, :tc);
 
1901
QAST::OperationsJAST.map_classlib_core_op('sayfh', $TYPE_OPS, 'sayfh', [$RT_OBJ, $RT_STR], $RT_STR, :tc);QAST::OperationsJAST.map_classlib_core_op('sayfh', $TYPE_OPS, 'sayfh', [$RT_OBJ, $RT_STR], $RT_STR, :tc);
 
1902
QAST::OperationsJAST.map_classlib_core_op('flushfh', $TYPE_OPS, 'flushfh', [$RT_OBJ], $RT_OBJ, :tc);QAST::OperationsJAST.map_classlib_core_op('sayfh', $TYPE_OPS, 'sayfh', [$RT_OBJ, $RT_STR], $RT_STR, :tc);
 
1903
QAST::OperationsJAST.map_classlib_core_op('readlinefh', $TYPE_OPS, 'readlinefh', [$RT_OBJ], $RT_STR, :tc);
 
1904
QAST::OperationsJAST.map_classlib_core_op('readlineintfh', $TYPE_OPS, 'readlineintfh', [$RT_OBJ, $RT_STR], $RT_STR, :tc);
 
1905
QAST::OperationsJAST.map_classlib_core_op('readallfh', $TYPE_OPS, 'readallfh', [$RT_OBJ], $RT_STR, :tc);
 
1906
QAST::OperationsJAST.map_classlib_core_op('getcfh', $TYPE_OPS, 'getcfh', [$RT_OBJ], $RT_STR, :tc);
 
1907
QAST::OperationsJAST.map_classlib_core_op('eoffh', $TYPE_OPS, 'eoffh', [$RT_OBJ], $RT_INT, :tc);
 
1908
QAST::OperationsJAST.map_classlib_core_op('closefh', $TYPE_OPS, 'closefh', [$RT_OBJ], $RT_OBJ, :tc);
 
1909
 
 
1910
QAST::OperationsJAST.map_classlib_core_op('chmod', $TYPE_OPS, 'chmod', [$RT_STR, $RT_INT], $RT_INT, :tc);
 
1911
QAST::OperationsJAST.map_classlib_core_op('unlink', $TYPE_OPS, 'unlink', [$RT_STR], $RT_INT, :tc);
 
1912
QAST::OperationsJAST.map_classlib_core_op('rmdir', $TYPE_OPS, 'rmdir', [$RT_STR], $RT_INT, :tc);
 
1913
QAST::OperationsJAST.map_classlib_core_op('cwd', $TYPE_OPS, 'cwd', [], $RT_STR);
 
1914
QAST::OperationsJAST.map_classlib_core_op('chdir', $TYPE_OPS, 'chdir', [$RT_STR], $RT_STR, :tc);
 
1915
QAST::OperationsJAST.map_classlib_core_op('mkdir', $TYPE_OPS, 'mkdir', [$RT_STR, $RT_INT], $RT_INT, :tc);
 
1916
QAST::OperationsJAST.map_classlib_core_op('rename', $TYPE_OPS, 'rename', [$RT_STR, $RT_STR], $RT_INT, :tc);
 
1917
QAST::OperationsJAST.map_classlib_core_op('copy', $TYPE_OPS, 'copy', [$RT_STR, $RT_STR], $RT_INT, :tc);
 
1918
QAST::OperationsJAST.map_classlib_core_op('link', $TYPE_OPS, 'link', [$RT_STR, $RT_STR], $RT_INT, :tc);
 
1919
 
 
1920
# Two variants of shell until we deprecate shell1
 
1921
QAST::OperationsJAST.map_classlib_core_op('shell1', $TYPE_OPS, 'shell1', [$RT_STR], $RT_INT, :tc);
 
1922
QAST::OperationsJAST.map_classlib_core_op('shell3', $TYPE_OPS, 'shell3', [$RT_STR, $RT_STR, $RT_OBJ], $RT_INT, :tc);
 
1923
QAST::OperationsJAST.add_core_op('shell', -> $qastcomp, $op {
 
1924
    my @operands := $op.list;
 
1925
    $qastcomp.as_jast(+@operands == 1
 
1926
        ?? QAST::Op.new( :op('shell1'), |@operands )
 
1927
        !! QAST::Op.new( :op('shell3'), |@operands ));
 
1928
});
 
1929
QAST::OperationsJAST.map_classlib_core_op('spawn', $TYPE_OPS, 'spawn', [$RT_OBJ, $RT_STR, $RT_OBJ], $RT_INT, :tc);
 
1930
QAST::OperationsJAST.map_classlib_core_op('openpipe', $TYPE_OPS, 'openpipe', [$RT_STR, $RT_STR, $RT_OBJ, $RT_STR], $RT_OBJ, :tc);
 
1931
 
 
1932
QAST::OperationsJAST.map_classlib_core_op('symlink', $TYPE_OPS, 'symlink', [$RT_STR, $RT_STR], $RT_INT, :tc);
 
1933
 
 
1934
QAST::OperationsJAST.map_classlib_core_op('opendir', $TYPE_OPS, 'opendir', [$RT_STR], $RT_OBJ, :tc);
 
1935
QAST::OperationsJAST.map_classlib_core_op('nextfiledir', $TYPE_OPS, 'nextfiledir', [$RT_OBJ], $RT_STR, :tc);
 
1936
QAST::OperationsJAST.map_classlib_core_op('closedir', $TYPE_OPS, 'closedir', [$RT_OBJ], $RT_INT, :tc);
 
1937
 
 
1938
QAST::OperationsJAST.map_classlib_core_op('openasync', $TYPE_OPS, 'openasync', [$RT_STR, $RT_STR], $RT_OBJ, :tc);
 
1939
QAST::OperationsJAST.map_classlib_core_op('slurpasync', $TYPE_OPS, 'slurpasync', [$RT_OBJ, $RT_OBJ, $RT_OBJ, $RT_OBJ], $RT_OBJ, :tc);
 
1940
QAST::OperationsJAST.map_classlib_core_op('linesasync', $TYPE_OPS, 'linesasync', [$RT_OBJ, $RT_OBJ, $RT_INT, $RT_OBJ, $RT_OBJ, $RT_OBJ], $RT_OBJ, :tc);
 
1941
 
 
1942
QAST::OperationsJAST.map_classlib_core_op('socket', $TYPE_OPS, 'socket', [$RT_INT], $RT_OBJ, :tc);
 
1943
QAST::OperationsJAST.map_classlib_core_op('connect', $TYPE_OPS, 'connect', [$RT_OBJ, $RT_STR, $RT_INT], $RT_OBJ, :tc);
 
1944
QAST::OperationsJAST.map_classlib_core_op('bindsock', $TYPE_OPS, 'bindsock', [$RT_OBJ, $RT_STR, $RT_INT], $RT_OBJ, :tc);
 
1945
QAST::OperationsJAST.map_classlib_core_op('accept', $TYPE_OPS, 'accept', [$RT_OBJ], $RT_OBJ, :tc);
 
1946
 
 
1947
QAST::OperationsJAST.map_classlib_core_op('debugnoop', $TYPE_OPS, 'debugnoop', [$RT_OBJ], $RT_OBJ, :tc);
 
1948
 
 
1949
# terms
 
1950
QAST::OperationsJAST.map_classlib_core_op('time_i', $TYPE_OPS, 'time_i', [], $RT_INT);
 
1951
QAST::OperationsJAST.map_classlib_core_op('time_n', $TYPE_OPS, 'time_n', [], $RT_NUM);
 
1952
 
 
1953
# Arithmetic ops
 
1954
QAST::OperationsJAST.map_jvm_core_op('add_i', 'ladd', [$RT_INT, $RT_INT], $RT_INT);
 
1955
QAST::OperationsJAST.map_classlib_core_op('add_I', $TYPE_OPS, 'add_I', [$RT_OBJ, $RT_OBJ, $RT_OBJ], $RT_OBJ, :tc);
 
1956
QAST::OperationsJAST.map_jvm_core_op('add_n', 'dadd', [$RT_NUM, $RT_NUM], $RT_NUM);
 
1957
QAST::OperationsJAST.map_jvm_core_op('sub_i', 'lsub', [$RT_INT, $RT_INT], $RT_INT);
 
1958
QAST::OperationsJAST.map_classlib_core_op('sub_I', $TYPE_OPS, 'sub_I', [$RT_OBJ, $RT_OBJ, $RT_OBJ], $RT_OBJ, :tc);
 
1959
QAST::OperationsJAST.map_jvm_core_op('sub_n', 'dsub', [$RT_NUM, $RT_NUM], $RT_NUM);
 
1960
QAST::OperationsJAST.map_jvm_core_op('mul_i', 'lmul', [$RT_INT, $RT_INT], $RT_INT);
 
1961
QAST::OperationsJAST.map_classlib_core_op('mul_I', $TYPE_OPS, 'mul_I', [$RT_OBJ, $RT_OBJ, $RT_OBJ], $RT_OBJ, :tc);
 
1962
QAST::OperationsJAST.map_jvm_core_op('mul_n', 'dmul', [$RT_NUM, $RT_NUM], $RT_NUM);
 
1963
QAST::OperationsJAST.map_jvm_core_op('div_i', 'ldiv', [$RT_INT, $RT_INT], $RT_INT);
 
1964
QAST::OperationsJAST.map_classlib_core_op('div_I', $TYPE_OPS, 'div_I', [$RT_OBJ, $RT_OBJ, $RT_OBJ], $RT_OBJ, :tc);
 
1965
QAST::OperationsJAST.map_classlib_core_op('div_In', $TYPE_OPS, 'div_In', [$RT_OBJ, $RT_OBJ], $RT_NUM, :tc);
 
1966
QAST::OperationsJAST.map_jvm_core_op('div_n', 'ddiv', [$RT_NUM, $RT_NUM], $RT_NUM);
 
1967
QAST::OperationsJAST.map_jvm_core_op('mod_i', 'lrem', [$RT_INT, $RT_INT], $RT_INT);
 
1968
QAST::OperationsJAST.map_classlib_core_op('mod_I', $TYPE_OPS, 'mod_I', [$RT_OBJ, $RT_OBJ, $RT_OBJ], $RT_OBJ, :tc);
 
1969
QAST::OperationsJAST.map_classlib_core_op('expmod_I', $TYPE_OPS, 'expmod_I', [$RT_OBJ, $RT_OBJ, $RT_OBJ, $RT_OBJ], $RT_OBJ, :tc);
 
1970
QAST::OperationsJAST.map_classlib_core_op('isprime_I', $TYPE_OPS, 'isprime_I', [$RT_OBJ, $RT_INT], $RT_INT, :tc);
 
1971
QAST::OperationsJAST.map_classlib_core_op('rand_n', $TYPE_OPS, 'rand_n', [$RT_NUM], $RT_NUM, :tc);
 
1972
QAST::OperationsJAST.map_classlib_core_op('srand', $TYPE_OPS, 'srand', [$RT_INT], $RT_INT, :tc);
 
1973
QAST::OperationsJAST.map_classlib_core_op('rand_I', $TYPE_OPS, 'rand_I', [$RT_OBJ, $RT_OBJ], $RT_OBJ, :tc);
 
1974
QAST::OperationsJAST.map_classlib_core_op('mod_n', $TYPE_OPS, 'mod_n', [$RT_NUM, $RT_NUM], $RT_NUM);
 
1975
QAST::OperationsJAST.map_classlib_core_op('pow_n', $TYPE_OPS, 'pow_n', [$RT_NUM, $RT_NUM], $RT_NUM);
 
1976
QAST::OperationsJAST.map_classlib_core_op('pow_I', $TYPE_OPS, 'pow_I', [$RT_OBJ, $RT_OBJ, $RT_OBJ, $RT_OBJ], $RT_OBJ, :tc);
 
1977
QAST::OperationsJAST.map_jvm_core_op('neg_i', 'lneg', [$RT_INT], $RT_INT);
 
1978
QAST::OperationsJAST.map_classlib_core_op('neg_I', $TYPE_OPS, 'neg_I', [$RT_OBJ, $RT_OBJ], $RT_OBJ, :tc);
 
1979
QAST::OperationsJAST.map_jvm_core_op('neg_n', 'dneg', [$RT_NUM], $RT_NUM);
 
1980
QAST::OperationsJAST.map_classlib_core_op('abs_i', $TYPE_MATH, 'abs', [$RT_INT], $RT_INT);
 
1981
QAST::OperationsJAST.map_classlib_core_op('abs_I', $TYPE_OPS, 'abs_I', [$RT_OBJ, $RT_OBJ], $RT_OBJ, :tc);
 
1982
QAST::OperationsJAST.map_classlib_core_op('abs_n', $TYPE_MATH, 'abs', [$RT_NUM], $RT_NUM);
 
1983
 
 
1984
QAST::OperationsJAST.map_classlib_core_op('ceil_n', $TYPE_MATH, 'ceil', [$RT_NUM], $RT_NUM);
 
1985
QAST::OperationsJAST.map_classlib_core_op('floor_n', $TYPE_MATH, 'floor', [$RT_NUM], $RT_NUM);
 
1986
QAST::OperationsJAST.map_classlib_core_op('ln_n', $TYPE_MATH, 'log', [$RT_NUM], $RT_NUM);
 
1987
QAST::OperationsJAST.map_classlib_core_op('sqrt_n', $TYPE_MATH, 'sqrt', [$RT_NUM], $RT_NUM);
 
1988
QAST::OperationsJAST.map_classlib_core_op('log_n', $TYPE_MATH, 'log', [$RT_NUM], $RT_NUM);
 
1989
QAST::OperationsJAST.map_classlib_core_op('exp_n', $TYPE_MATH, 'exp', [$RT_NUM], $RT_NUM);
 
1990
QAST::OperationsJAST.map_classlib_core_op('isnanorinf', $TYPE_OPS, 'isnanorinf', [$RT_NUM], $RT_INT);
 
1991
QAST::OperationsJAST.map_classlib_core_op('inf', $TYPE_OPS, 'inf', [], $RT_NUM);
 
1992
QAST::OperationsJAST.map_classlib_core_op('neginf', $TYPE_OPS, 'neginf', [], $RT_NUM);
 
1993
QAST::OperationsJAST.map_classlib_core_op('nan', $TYPE_OPS, 'nan', [], $RT_NUM);
 
1994
QAST::OperationsJAST.map_classlib_core_op('radix', $TYPE_OPS, 'radix', [$RT_INT, $RT_STR, $RT_INT, $RT_INT], $RT_OBJ, :tc);
 
1995
QAST::OperationsJAST.map_classlib_core_op('radix_I', $TYPE_OPS, 'radix_I', [$RT_INT, $RT_STR, $RT_INT, $RT_INT, $RT_OBJ], $RT_OBJ, :tc);
 
1996
 
 
1997
# trig opcodes
 
1998
QAST::OperationsJAST.map_classlib_core_op('sin_n', $TYPE_MATH, 'sin', [$RT_NUM], $RT_NUM);
 
1999
QAST::OperationsJAST.map_classlib_core_op('asin_n', $TYPE_MATH, 'asin', [$RT_NUM], $RT_NUM);
 
2000
QAST::OperationsJAST.map_classlib_core_op('cos_n', $TYPE_MATH, 'cos', [$RT_NUM], $RT_NUM);
 
2001
QAST::OperationsJAST.map_classlib_core_op('acos_n', $TYPE_MATH, 'acos', [$RT_NUM], $RT_NUM);
 
2002
QAST::OperationsJAST.map_classlib_core_op('tan_n', $TYPE_MATH, 'tan', [$RT_NUM], $RT_NUM);
 
2003
QAST::OperationsJAST.map_classlib_core_op('atan_n', $TYPE_MATH, 'atan', [$RT_NUM], $RT_NUM);
 
2004
QAST::OperationsJAST.map_classlib_core_op('atan2_n', $TYPE_MATH, 'atan2', [$RT_NUM, $RT_NUM], $RT_NUM);
 
2005
QAST::OperationsJAST.map_classlib_core_op('sinh_n', $TYPE_MATH, 'sinh', [$RT_NUM], $RT_NUM);
 
2006
QAST::OperationsJAST.map_classlib_core_op('cosh_n', $TYPE_MATH, 'cosh', [$RT_NUM], $RT_NUM);
 
2007
QAST::OperationsJAST.map_classlib_core_op('tanh_n', $TYPE_MATH, 'tanh', [$RT_NUM], $RT_NUM);
 
2008
QAST::OperationsJAST.map_classlib_core_op('sec_n', $TYPE_OPS, 'sec_n', [$RT_NUM], $RT_NUM);
 
2009
QAST::OperationsJAST.map_classlib_core_op('asec_n', $TYPE_OPS, 'asec_n', [$RT_NUM], $RT_NUM);
 
2010
QAST::OperationsJAST.map_classlib_core_op('sech_n', $TYPE_OPS, 'sech_n', [$RT_NUM], $RT_NUM);
 
2011
 
 
2012
# esoteric math opcodes
 
2013
QAST::OperationsJAST.map_classlib_core_op('gcd_i', $TYPE_OPS, 'gcd_i', [$RT_INT, $RT_INT], $RT_INT);
 
2014
QAST::OperationsJAST.map_classlib_core_op('gcd_I', $TYPE_OPS, 'gcd_I', [$RT_OBJ, $RT_OBJ, $RT_OBJ], $RT_OBJ, :tc);
 
2015
QAST::OperationsJAST.map_classlib_core_op('lcm_i', $TYPE_OPS, 'lcm_i', [$RT_INT, $RT_INT], $RT_INT);
 
2016
QAST::OperationsJAST.map_classlib_core_op('lcm_I', $TYPE_OPS, 'lcm_I', [$RT_OBJ, $RT_OBJ, $RT_OBJ], $RT_OBJ, :tc);
 
2017
 
 
2018
# string bitwise ops
 
2019
QAST::OperationsJAST.map_classlib_core_op('bitor_s', $TYPE_OPS, 'bitor_s', [$RT_STR, $RT_STR], $RT_STR);
 
2020
QAST::OperationsJAST.map_classlib_core_op('bitxor_s', $TYPE_OPS, 'bitxor_s', [$RT_STR, $RT_STR], $RT_STR);
 
2021
QAST::OperationsJAST.map_classlib_core_op('bitand_s', $TYPE_OPS, 'bitand_s', [$RT_STR, $RT_STR], $RT_STR);
 
2022
 
 
2023
# string opcodes
 
2024
QAST::OperationsJAST.map_classlib_core_op('chars', $TYPE_OPS, 'chars', [$RT_STR], $RT_INT);
 
2025
QAST::OperationsJAST.map_classlib_core_op('uc', $TYPE_OPS, 'uc', [$RT_STR], $RT_STR);
 
2026
QAST::OperationsJAST.map_classlib_core_op('lc', $TYPE_OPS, 'lc', [$RT_STR], $RT_STR);
 
2027
QAST::OperationsJAST.map_classlib_core_op('x', $TYPE_OPS, 'x', [$RT_STR, $RT_INT], $RT_STR);
 
2028
QAST::OperationsJAST.map_classlib_core_op('iscclass', $TYPE_OPS, 'iscclass', [$RT_INT, $RT_STR, $RT_INT], $RT_INT);
 
2029
QAST::OperationsJAST.map_classlib_core_op('concat', $TYPE_OPS, 'concat', [$RT_STR, $RT_STR], $RT_STR);
 
2030
QAST::OperationsJAST.map_classlib_core_op('chr', $TYPE_OPS, 'chr', [$RT_INT], $RT_STR, :tc);
 
2031
QAST::OperationsJAST.map_classlib_core_op('join', $TYPE_OPS, 'join', [$RT_STR, $RT_OBJ], $RT_STR, :tc);
 
2032
QAST::OperationsJAST.map_classlib_core_op('split', $TYPE_OPS, 'split', [$RT_STR, $RT_STR], $RT_OBJ, :tc);
 
2033
QAST::OperationsJAST.map_classlib_core_op('findcclass', $TYPE_OPS, 'findcclass', [$RT_INT, $RT_STR, $RT_INT, $RT_INT], $RT_INT);
 
2034
QAST::OperationsJAST.map_classlib_core_op('findnotcclass', $TYPE_OPS, 'findnotcclass', [$RT_INT, $RT_STR, $RT_INT, $RT_INT], $RT_INT);
 
2035
QAST::OperationsJAST.add_core_op('sprintf', -> $qastcomp, $op {
 
2036
    my @operands := $op.list;
 
2037
    $qastcomp.as_jast(
 
2038
        QAST::Op.new(
 
2039
            :op('call'),
 
2040
            :returns(str),
 
2041
            QAST::Op.new(
 
2042
                :op('gethllsym'),
 
2043
                QAST::SVal.new( :value('nqp') ),
 
2044
                QAST::SVal.new( :value('sprintf') )
 
2045
            ),
 
2046
            |@operands )
 
2047
    );
 
2048
});
 
2049
QAST::OperationsJAST.add_core_op('sprintfdirectives', -> $qastcomp, $op {
 
2050
    my @operands := $op.list;
 
2051
    $qastcomp.as_jast(
 
2052
        QAST::Op.new(
 
2053
            :op('call'),
 
2054
            :returns(int),
 
2055
            QAST::Op.new(
 
2056
                :op('gethllsym'),
 
2057
                QAST::SVal.new( :value('nqp') ),
 
2058
                QAST::SVal.new( :value('sprintfdirectives') )
 
2059
            ),
 
2060
            |@operands )
 
2061
    );
 
2062
});
 
2063
QAST::OperationsJAST.add_core_op('sprintfaddargumenthandler', -> $qastcomp, $op {
 
2064
    my @operands := $op.list;
 
2065
    $qastcomp.as_jast(
 
2066
        QAST::Op.new(
 
2067
            :op('call'),
 
2068
            :returns(str),
 
2069
            QAST::Op.new(
 
2070
                :op('gethllsym'),
 
2071
                QAST::SVal.new( :value('nqp') ),
 
2072
                QAST::SVal.new( :value('sprintfaddargumenthandler') )
 
2073
            ),
 
2074
            |@operands )
 
2075
    );
 
2076
});
 
2077
QAST::OperationsJAST.map_classlib_core_op('escape', $TYPE_OPS, 'escape', [$RT_STR], $RT_STR);
 
2078
QAST::OperationsJAST.map_classlib_core_op('flip', $TYPE_OPS, 'flip', [$RT_STR], $RT_STR);
 
2079
QAST::OperationsJAST.map_classlib_core_op('replace', $TYPE_OPS, 'replace', [$RT_STR, $RT_INT, $RT_INT, $RT_STR], $RT_STR);
 
2080
 
 
2081
# substr can take 2 or 3 args, so needs special handling.
 
2082
QAST::OperationsJAST.map_classlib_core_op('substr2', $TYPE_OPS, 'substr2', [$RT_STR, $RT_INT], $RT_STR);
 
2083
QAST::OperationsJAST.map_classlib_core_op('substr3', $TYPE_OPS, 'substr3', [$RT_STR, $RT_INT, $RT_INT], $RT_STR);
 
2084
QAST::OperationsJAST.add_core_op('substr', -> $qastcomp, $op {
 
2085
    my @operands := $op.list;
 
2086
    $qastcomp.as_jast(+@operands == 2
 
2087
        ?? QAST::Op.new( :op('substr2'), |@operands )
 
2088
        !! QAST::Op.new( :op('substr3'), |@operands ));
 
2089
});
 
2090
 
 
2091
# ord can be on a the first char in a string or at a particular char.
 
2092
QAST::OperationsJAST.map_classlib_core_op('ordfirst', $TYPE_OPS, 'ordfirst', [$RT_STR], $RT_INT);
 
2093
QAST::OperationsJAST.map_classlib_core_op('ordat',    $TYPE_OPS, 'ordat',    [$RT_STR, $RT_INT], $RT_INT);
 
2094
QAST::OperationsJAST.add_core_op('ord',  -> $qastcomp, $op {
 
2095
    my @operands := $op.list;
 
2096
    $qastcomp.as_jast(+@operands == 1
 
2097
        ?? QAST::Op.new( :op('ordfirst'), |@operands )
 
2098
        !! QAST::Op.new( :op('ordat'), |@operands ));
 
2099
});
 
2100
 
 
2101
# index may or may not take a starting position
 
2102
QAST::OperationsJAST.map_classlib_core_op('indexfrom', $TYPE_OPS, 'indexfrom', [$RT_STR, $RT_STR, $RT_INT], $RT_INT);
 
2103
QAST::OperationsJAST.add_core_op('index',  -> $qastcomp, $op {
 
2104
    my @operands := $op.list;
 
2105
    $qastcomp.as_jast(+@operands == 2
 
2106
        ?? QAST::Op.new( :op('indexfrom'), |@operands, QAST::IVal.new( :value(0)) )
 
2107
        !! QAST::Op.new( :op('indexfrom'), |@operands ));
 
2108
});
 
2109
 
 
2110
# rindex may or may not take a starting position
 
2111
QAST::OperationsJAST.map_classlib_core_op('rindexfromend', $TYPE_OPS, 'rindexfromend', [$RT_STR, $RT_STR], $RT_INT);
 
2112
QAST::OperationsJAST.map_classlib_core_op('rindexfrom', $TYPE_OPS, 'rindexfrom', [$RT_STR, $RT_STR, $RT_INT], $RT_INT);
 
2113
QAST::OperationsJAST.add_core_op('rindex',  -> $qastcomp, $op {
 
2114
    my @operands := $op.list;
 
2115
    $qastcomp.as_jast(+@operands == 2
 
2116
        ?? QAST::Op.new( :op('rindexfromend'), |@operands )
 
2117
        !! QAST::Op.new( :op('rindexfrom'), |@operands ));
 
2118
});
 
2119
 
 
2120
QAST::OperationsJAST.map_classlib_core_op('codepointfromname', $TYPE_OPS, 'codepointfromname', [$RT_STR], $RT_INT);
 
2121
QAST::OperationsJAST.map_classlib_core_op('encode', $TYPE_OPS, 'encode', [$RT_STR, $RT_STR, $RT_OBJ], $RT_OBJ, :tc);
 
2122
QAST::OperationsJAST.map_classlib_core_op('decode', $TYPE_OPS, 'decode', [$RT_OBJ, $RT_STR], $RT_STR, :tc);
 
2123
 
 
2124
# serialization context opcodes
 
2125
QAST::OperationsJAST.map_classlib_core_op('sha1', $TYPE_OPS, 'sha1', [$RT_STR], $RT_STR);
 
2126
QAST::OperationsJAST.map_classlib_core_op('createsc', $TYPE_OPS, 'createsc', [$RT_STR], $RT_OBJ, :tc);
 
2127
QAST::OperationsJAST.map_classlib_core_op('scsetobj', $TYPE_OPS, 'scsetobj', [$RT_OBJ, $RT_INT, $RT_OBJ], $RT_OBJ, :tc);
 
2128
QAST::OperationsJAST.map_classlib_core_op('scsetcode', $TYPE_OPS, 'scsetcode', [$RT_OBJ, $RT_INT, $RT_OBJ], $RT_OBJ, :tc);
 
2129
QAST::OperationsJAST.map_classlib_core_op('scgetobj', $TYPE_OPS, 'scgetobj', [$RT_OBJ, $RT_INT], $RT_OBJ, :tc);
 
2130
QAST::OperationsJAST.map_classlib_core_op('scgethandle', $TYPE_OPS, 'scgethandle', [$RT_OBJ], $RT_STR, :tc);
 
2131
QAST::OperationsJAST.map_classlib_core_op('scgetdesc', $TYPE_OPS, 'scgetdesc', [$RT_OBJ], $RT_STR, :tc);
 
2132
QAST::OperationsJAST.map_classlib_core_op('scgetobjidx', $TYPE_OPS, 'scgetobjidx', [$RT_OBJ, $RT_OBJ], $RT_INT, :tc);
 
2133
QAST::OperationsJAST.map_classlib_core_op('scsetdesc', $TYPE_OPS, 'scsetdesc', [$RT_OBJ, $RT_STR], $RT_STR, :tc);
 
2134
QAST::OperationsJAST.map_classlib_core_op('scobjcount', $TYPE_OPS, 'scobjcount', [$RT_OBJ], $RT_INT, :tc);
 
2135
QAST::OperationsJAST.map_classlib_core_op('setobjsc', $TYPE_OPS, 'setobjsc', [$RT_OBJ, $RT_OBJ], $RT_OBJ, :tc);
 
2136
QAST::OperationsJAST.map_classlib_core_op('getobjsc', $TYPE_OPS, 'getobjsc', [$RT_OBJ], $RT_OBJ, :tc);
 
2137
QAST::OperationsJAST.map_classlib_core_op('serialize', $TYPE_OPS, 'serialize', [$RT_OBJ, $RT_OBJ], $RT_STR, :tc);
 
2138
QAST::OperationsJAST.map_classlib_core_op('deserialize', $TYPE_OPS, 'deserialize', [$RT_STR, $RT_OBJ, $RT_OBJ, $RT_OBJ, $RT_OBJ], $RT_STR, :tc);
 
2139
QAST::OperationsJAST.map_classlib_core_op('wval', $TYPE_OPS, 'wval', [$RT_STR, $RT_INT], $RT_OBJ, :tc);
 
2140
QAST::OperationsJAST.map_classlib_core_op('scwbdisable', $TYPE_OPS, 'scwbdisable', [], $RT_INT, :tc);
 
2141
QAST::OperationsJAST.map_classlib_core_op('scwbenable', $TYPE_OPS, 'scwbenable', [], $RT_INT, :tc);
 
2142
QAST::OperationsJAST.map_classlib_core_op('pushcompsc', $TYPE_OPS, 'pushcompsc', [$RT_OBJ], $RT_OBJ, :tc);
 
2143
QAST::OperationsJAST.map_classlib_core_op('popcompsc', $TYPE_OPS, 'popcompsc', [], $RT_OBJ, :tc);
 
2144
 
 
2145
# bitwise opcodes
 
2146
QAST::OperationsJAST.map_classlib_core_op('bitor_i', $TYPE_OPS, 'bitor_i', [$RT_INT, $RT_INT], $RT_INT);
 
2147
QAST::OperationsJAST.map_classlib_core_op('bitor_I', $TYPE_OPS, 'bitor_I', [$RT_OBJ, $RT_OBJ, $RT_OBJ], $RT_OBJ, :tc);
 
2148
QAST::OperationsJAST.map_classlib_core_op('bitxor_i', $TYPE_OPS, 'bitxor_i', [$RT_INT, $RT_INT], $RT_INT);
 
2149
QAST::OperationsJAST.map_classlib_core_op('bitxor_I', $TYPE_OPS, 'bitxor_I', [$RT_OBJ, $RT_OBJ, $RT_OBJ], $RT_OBJ, :tc);
 
2150
QAST::OperationsJAST.map_classlib_core_op('bitand_i', $TYPE_OPS, 'bitand_i', [$RT_INT, $RT_INT], $RT_INT);
 
2151
QAST::OperationsJAST.map_classlib_core_op('bitand_I', $TYPE_OPS, 'bitand_I', [$RT_OBJ, $RT_OBJ, $RT_OBJ], $RT_OBJ, :tc);
 
2152
QAST::OperationsJAST.map_classlib_core_op('bitneg_i', $TYPE_OPS, 'bitneg_i', [$RT_INT], $RT_INT);
 
2153
QAST::OperationsJAST.map_classlib_core_op('bitneg_I', $TYPE_OPS, 'bitneg_I', [$RT_OBJ, $RT_OBJ], $RT_OBJ, :tc);
 
2154
QAST::OperationsJAST.map_classlib_core_op('bitshiftl_i', $TYPE_OPS, 'bitshiftl_i', [$RT_INT, $RT_INT], $RT_INT);
 
2155
QAST::OperationsJAST.map_classlib_core_op('bitshiftl_I', $TYPE_OPS, 'bitshiftl_I', [$RT_OBJ, $RT_INT, $RT_OBJ], $RT_OBJ, :tc);
 
2156
QAST::OperationsJAST.map_classlib_core_op('bitshiftr_i', $TYPE_OPS, 'bitshiftr_i', [$RT_INT, $RT_INT], $RT_INT);
 
2157
QAST::OperationsJAST.map_classlib_core_op('bitshiftr_I', $TYPE_OPS, 'bitshiftr_I', [$RT_OBJ, $RT_INT, $RT_OBJ], $RT_OBJ, :tc);
 
2158
 
 
2159
# relational opcodes
 
2160
QAST::OperationsJAST.map_classlib_core_op('cmp_i',  $TYPE_OPS, 'cmp_i',  [$RT_INT, $RT_INT], $RT_INT);
 
2161
QAST::OperationsJAST.map_classlib_core_op('iseq_i', $TYPE_OPS, 'iseq_i', [$RT_INT, $RT_INT], $RT_INT);
 
2162
QAST::OperationsJAST.map_classlib_core_op('isne_i', $TYPE_OPS, 'isne_i', [$RT_INT, $RT_INT], $RT_INT);
 
2163
QAST::OperationsJAST.map_classlib_core_op('islt_i', $TYPE_OPS, 'islt_i', [$RT_INT, $RT_INT], $RT_INT);
 
2164
QAST::OperationsJAST.map_classlib_core_op('isle_i', $TYPE_OPS, 'isle_i', [$RT_INT, $RT_INT], $RT_INT);
 
2165
QAST::OperationsJAST.map_classlib_core_op('isgt_i', $TYPE_OPS, 'isgt_i', [$RT_INT, $RT_INT], $RT_INT);
 
2166
QAST::OperationsJAST.map_classlib_core_op('isge_i', $TYPE_OPS, 'isge_i', [$RT_INT, $RT_INT], $RT_INT);
 
2167
 
 
2168
QAST::OperationsJAST.map_classlib_core_op('bool_I', $TYPE_OPS, 'bool_I', [$RT_OBJ], $RT_INT, :tc);
 
2169
QAST::OperationsJAST.map_classlib_core_op('cmp_I', $TYPE_OPS, 'cmp_I', [$RT_OBJ, $RT_OBJ], $RT_INT, :tc);
 
2170
QAST::OperationsJAST.map_classlib_core_op('iseq_I', $TYPE_OPS, 'iseq_I', [$RT_OBJ, $RT_OBJ], $RT_INT, :tc);
 
2171
QAST::OperationsJAST.map_classlib_core_op('isne_I', $TYPE_OPS, 'isne_I', [$RT_OBJ, $RT_OBJ], $RT_INT, :tc);
 
2172
QAST::OperationsJAST.map_classlib_core_op('islt_I', $TYPE_OPS, 'islt_I', [$RT_OBJ, $RT_OBJ], $RT_INT, :tc);
 
2173
QAST::OperationsJAST.map_classlib_core_op('isle_I', $TYPE_OPS, 'isle_I', [$RT_OBJ, $RT_OBJ], $RT_INT, :tc);
 
2174
QAST::OperationsJAST.map_classlib_core_op('isgt_I', $TYPE_OPS, 'isgt_I', [$RT_OBJ, $RT_OBJ], $RT_INT, :tc);
 
2175
QAST::OperationsJAST.map_classlib_core_op('isge_I', $TYPE_OPS, 'isge_I', [$RT_OBJ, $RT_OBJ], $RT_INT, :tc);
 
2176
 
 
2177
QAST::OperationsJAST.map_classlib_core_op('cmp_n',  $TYPE_OPS, 'cmp_n',  [$RT_NUM, $RT_NUM], $RT_INT);
 
2178
QAST::OperationsJAST.map_classlib_core_op('iseq_n', $TYPE_OPS, 'iseq_n', [$RT_NUM, $RT_NUM], $RT_INT);
 
2179
QAST::OperationsJAST.map_classlib_core_op('isne_n', $TYPE_OPS, 'isne_n', [$RT_NUM, $RT_NUM], $RT_INT);
 
2180
QAST::OperationsJAST.map_classlib_core_op('islt_n', $TYPE_OPS, 'islt_n', [$RT_NUM, $RT_NUM], $RT_INT);
 
2181
QAST::OperationsJAST.map_classlib_core_op('isle_n', $TYPE_OPS, 'isle_n', [$RT_NUM, $RT_NUM], $RT_INT);
 
2182
QAST::OperationsJAST.map_classlib_core_op('isgt_n', $TYPE_OPS, 'isgt_n', [$RT_NUM, $RT_NUM], $RT_INT);
 
2183
QAST::OperationsJAST.map_classlib_core_op('isge_n', $TYPE_OPS, 'isge_n', [$RT_NUM, $RT_NUM], $RT_INT);
 
2184
 
 
2185
QAST::OperationsJAST.map_classlib_core_op('cmp_s',  $TYPE_OPS, 'cmp_s',  [$RT_STR, $RT_STR], $RT_INT);
 
2186
QAST::OperationsJAST.map_classlib_core_op('iseq_s', $TYPE_OPS, 'iseq_s', [$RT_STR, $RT_STR], $RT_INT);
 
2187
QAST::OperationsJAST.map_classlib_core_op('isne_s', $TYPE_OPS, 'isne_s', [$RT_STR, $RT_STR], $RT_INT);
 
2188
QAST::OperationsJAST.map_classlib_core_op('islt_s', $TYPE_OPS, 'islt_s', [$RT_STR, $RT_STR], $RT_INT);
 
2189
QAST::OperationsJAST.map_classlib_core_op('isle_s', $TYPE_OPS, 'isle_s', [$RT_STR, $RT_STR], $RT_INT);
 
2190
QAST::OperationsJAST.map_classlib_core_op('isgt_s', $TYPE_OPS, 'isgt_s', [$RT_STR, $RT_STR], $RT_INT);
 
2191
QAST::OperationsJAST.map_classlib_core_op('isge_s', $TYPE_OPS, 'isge_s', [$RT_STR, $RT_STR], $RT_INT);
 
2192
 
 
2193
# bigint ops
 
2194
QAST::OperationsJAST.map_classlib_core_op('fromstr_I', $TYPE_OPS, 'fromstr_I', [$RT_STR, $RT_OBJ], $RT_OBJ, :tc);
 
2195
QAST::OperationsJAST.map_classlib_core_op('tostr_I', $TYPE_OPS, 'tostr_I', [$RT_OBJ], $RT_STR, :tc);
 
2196
QAST::OperationsJAST.map_classlib_core_op('base_I', $TYPE_OPS, 'base_I', [$RT_OBJ, $RT_INT], $RT_STR, :tc);
 
2197
QAST::OperationsJAST.map_classlib_core_op('isbig_I', $TYPE_OPS, 'isbig_I', [$RT_OBJ], $RT_INT, :tc);
 
2198
QAST::OperationsJAST.map_classlib_core_op('fromnum_I', $TYPE_OPS, 'fromnum_I', [$RT_NUM, $RT_OBJ], $RT_OBJ, :tc);
 
2199
QAST::OperationsJAST.map_classlib_core_op('tonum_I', $TYPE_OPS, 'tonum_I', [$RT_OBJ], $RT_NUM, :tc);
 
2200
 
 
2201
# boolean opcodes
 
2202
QAST::OperationsJAST.map_classlib_core_op('not_i', $TYPE_OPS, 'not_i', [$RT_INT], $RT_INT);
 
2203
 
 
2204
# aggregate opcodes
 
2205
QAST::OperationsJAST.map_classlib_core_op('atpos', $TYPE_OPS, 'atpos', [$RT_OBJ, $RT_INT], $RT_OBJ, :tc);
 
2206
QAST::OperationsJAST.map_classlib_core_op('atpos_i', $TYPE_OPS, 'atpos_i', [$RT_OBJ, $RT_INT], $RT_INT, :tc);
 
2207
QAST::OperationsJAST.map_classlib_core_op('atpos_n', $TYPE_OPS, 'atpos_n', [$RT_OBJ, $RT_INT], $RT_NUM, :tc);
 
2208
QAST::OperationsJAST.map_classlib_core_op('atpos_s', $TYPE_OPS, 'atpos_s', [$RT_OBJ, $RT_INT], $RT_STR, :tc);
 
2209
QAST::OperationsJAST.map_classlib_core_op('atkey', $TYPE_OPS, 'atkey', [$RT_OBJ, $RT_STR], $RT_OBJ, :tc);
 
2210
QAST::OperationsJAST.map_classlib_core_op('atkey_i', $TYPE_OPS, 'atkey_i', [$RT_OBJ, $RT_STR], $RT_INT, :tc);
 
2211
QAST::OperationsJAST.map_classlib_core_op('atkey_n', $TYPE_OPS, 'atkey_n', [$RT_OBJ, $RT_STR], $RT_NUM, :tc);
 
2212
QAST::OperationsJAST.map_classlib_core_op('atkey_s', $TYPE_OPS, 'atkey_s', [$RT_OBJ, $RT_STR], $RT_STR, :tc);
 
2213
QAST::OperationsJAST.map_classlib_core_op('bindpos', $TYPE_OPS, 'bindpos', [$RT_OBJ, $RT_INT, $RT_OBJ], $RT_OBJ, :tc);
 
2214
QAST::OperationsJAST.map_classlib_core_op('bindpos_i', $TYPE_OPS, 'bindpos_i', [$RT_OBJ, $RT_INT, $RT_INT], $RT_INT, :tc);
 
2215
QAST::OperationsJAST.map_classlib_core_op('bindpos_n', $TYPE_OPS, 'bindpos_n', [$RT_OBJ, $RT_INT, $RT_NUM], $RT_NUM, :tc);
 
2216
QAST::OperationsJAST.map_classlib_core_op('bindpos_s', $TYPE_OPS, 'bindpos_s', [$RT_OBJ, $RT_INT, $RT_STR], $RT_STR, :tc);
 
2217
QAST::OperationsJAST.map_classlib_core_op('bindkey', $TYPE_OPS, 'bindkey', [$RT_OBJ, $RT_STR, $RT_OBJ], $RT_OBJ, :tc);
 
2218
QAST::OperationsJAST.map_classlib_core_op('bindkey_i', $TYPE_OPS, 'bindkey_i', [$RT_OBJ, $RT_STR, $RT_INT], $RT_INT, :tc);
 
2219
QAST::OperationsJAST.map_classlib_core_op('bindkey_n', $TYPE_OPS, 'bindkey_n', [$RT_OBJ, $RT_STR, $RT_NUM], $RT_NUM, :tc);
 
2220
QAST::OperationsJAST.map_classlib_core_op('bindkey_s', $TYPE_OPS, 'bindkey_s', [$RT_OBJ, $RT_STR, $RT_STR], $RT_STR, :tc);
 
2221
QAST::OperationsJAST.map_classlib_core_op('existspos', $TYPE_OPS, 'existspos', [$RT_OBJ, $RT_INT], $RT_INT, :tc);
 
2222
QAST::OperationsJAST.map_classlib_core_op('existskey', $TYPE_OPS, 'existskey', [$RT_OBJ, $RT_STR], $RT_INT, :tc);
 
2223
QAST::OperationsJAST.map_classlib_core_op('deletekey', $TYPE_OPS, 'deletekey', [$RT_OBJ, $RT_STR], $RT_OBJ, :tc);
 
2224
QAST::OperationsJAST.map_classlib_core_op('elems', $TYPE_OPS, 'elems', [$RT_OBJ], $RT_INT, :tc);
 
2225
QAST::OperationsJAST.map_classlib_core_op('setelems', $TYPE_OPS, 'setelems', [$RT_OBJ, $RT_INT], $RT_OBJ, :tc);
 
2226
QAST::OperationsJAST.map_classlib_core_op('push', $TYPE_OPS, 'push', [$RT_OBJ, $RT_OBJ], $RT_OBJ, :tc);
 
2227
QAST::OperationsJAST.map_classlib_core_op('push_i', $TYPE_OPS, 'push_i', [$RT_OBJ, $RT_INT], $RT_INT, :tc);
 
2228
QAST::OperationsJAST.map_classlib_core_op('push_n', $TYPE_OPS, 'push_n', [$RT_OBJ, $RT_NUM], $RT_NUM, :tc);
 
2229
QAST::OperationsJAST.map_classlib_core_op('push_s', $TYPE_OPS, 'push_s', [$RT_OBJ, $RT_STR], $RT_STR, :tc);
 
2230
QAST::OperationsJAST.map_classlib_core_op('pop', $TYPE_OPS, 'pop', [$RT_OBJ], $RT_OBJ, :tc);
 
2231
QAST::OperationsJAST.map_classlib_core_op('pop_i', $TYPE_OPS, 'pop_i', [$RT_OBJ], $RT_INT, :tc);
 
2232
QAST::OperationsJAST.map_classlib_core_op('pop_n', $TYPE_OPS, 'pop_n', [$RT_OBJ], $RT_NUM, :tc);
 
2233
QAST::OperationsJAST.map_classlib_core_op('pop_s', $TYPE_OPS, 'pop_s', [$RT_OBJ], $RT_STR, :tc);
 
2234
QAST::OperationsJAST.map_classlib_core_op('unshift', $TYPE_OPS, 'unshift', [$RT_OBJ, $RT_OBJ], $RT_OBJ, :tc);
 
2235
QAST::OperationsJAST.map_classlib_core_op('unshift_i', $TYPE_OPS, 'unshift_i', [$RT_OBJ, $RT_INT], $RT_INT, :tc);
 
2236
QAST::OperationsJAST.map_classlib_core_op('unshift_n', $TYPE_OPS, 'unshift_n', [$RT_OBJ, $RT_NUM], $RT_NUM, :tc);
 
2237
QAST::OperationsJAST.map_classlib_core_op('unshift_s', $TYPE_OPS, 'unshift_s', [$RT_OBJ, $RT_STR], $RT_STR, :tc);
 
2238
QAST::OperationsJAST.map_classlib_core_op('shift', $TYPE_OPS, 'shift', [$RT_OBJ], $RT_OBJ, :tc);
 
2239
QAST::OperationsJAST.map_classlib_core_op('shift_i', $TYPE_OPS, 'shift_i', [$RT_OBJ], $RT_INT, :tc);
 
2240
QAST::OperationsJAST.map_classlib_core_op('shift_n', $TYPE_OPS, 'shift_n', [$RT_OBJ], $RT_NUM, :tc);
 
2241
QAST::OperationsJAST.map_classlib_core_op('shift_s', $TYPE_OPS, 'shift_s', [$RT_OBJ], $RT_STR, :tc);
 
2242
QAST::OperationsJAST.map_classlib_core_op('splice', $TYPE_OPS, 'splice', [$RT_OBJ, $RT_OBJ, $RT_INT, $RT_INT], $RT_OBJ, :tc);
 
2243
QAST::OperationsJAST.map_classlib_core_op('isint', $TYPE_OPS, 'isint', [$RT_OBJ], $RT_INT, :tc);
 
2244
QAST::OperationsJAST.map_classlib_core_op('isnum', $TYPE_OPS, 'isnum', [$RT_OBJ], $RT_INT, :tc);
 
2245
QAST::OperationsJAST.map_classlib_core_op('isstr', $TYPE_OPS, 'isstr', [$RT_OBJ], $RT_INT, :tc);
 
2246
QAST::OperationsJAST.map_classlib_core_op('islist', $TYPE_OPS, 'islist', [$RT_OBJ], $RT_INT, :tc);
 
2247
QAST::OperationsJAST.map_classlib_core_op('ishash', $TYPE_OPS, 'ishash', [$RT_OBJ], $RT_INT, :tc);
 
2248
QAST::OperationsJAST.map_classlib_core_op('iterator', $TYPE_OPS, 'iter', [$RT_OBJ], $RT_OBJ, :tc);
 
2249
QAST::OperationsJAST.map_classlib_core_op('iterkey_s', $TYPE_OPS, 'iterkey_s', [$RT_OBJ], $RT_STR, :tc);
 
2250
QAST::OperationsJAST.map_classlib_core_op('iterval', $TYPE_OPS, 'iterval', [$RT_OBJ], $RT_OBJ, :tc);
 
2251
 
 
2252
(-> {
 
2253
# object opcodes
 
2254
QAST::OperationsJAST.map_jvm_core_op('null', 'aconst_null', [], $RT_OBJ);
 
2255
QAST::OperationsJAST.map_jvm_core_op('null_s', 'aconst_null', [], $RT_STR);
 
2256
QAST::OperationsJAST.map_classlib_core_op('what', $TYPE_OPS, 'what', [$RT_OBJ], $RT_OBJ, :tc);
 
2257
QAST::OperationsJAST.map_classlib_core_op('how', $TYPE_OPS, 'how', [$RT_OBJ], $RT_OBJ, :tc);
 
2258
QAST::OperationsJAST.map_classlib_core_op('who', $TYPE_OPS, 'who', [$RT_OBJ], $RT_OBJ, :tc);
 
2259
QAST::OperationsJAST.map_classlib_core_op('where', $TYPE_OPS, 'where', [$RT_OBJ], $RT_INT, :tc);
 
2260
QAST::OperationsJAST.map_classlib_core_op('findmethod', $TYPE_OPS, 'findmethod', [$RT_OBJ, $RT_STR], $RT_OBJ, :tc);
 
2261
QAST::OperationsJAST.map_classlib_core_op('setwho', $TYPE_OPS, 'setwho', [$RT_OBJ, $RT_OBJ], $RT_OBJ, :tc);
 
2262
QAST::OperationsJAST.map_classlib_core_op('rebless', $TYPE_OPS, 'rebless', [$RT_OBJ, $RT_OBJ], $RT_OBJ, :tc);
 
2263
QAST::OperationsJAST.map_classlib_core_op('knowhow', $TYPE_OPS, 'knowhow', [], $RT_OBJ, :tc);
 
2264
QAST::OperationsJAST.map_classlib_core_op('knowhowattr', $TYPE_OPS, 'knowhowattr', [], $RT_OBJ, :tc);
 
2265
QAST::OperationsJAST.map_classlib_core_op('bootint', $TYPE_OPS, 'bootint', [], $RT_OBJ, :tc);
 
2266
QAST::OperationsJAST.map_classlib_core_op('bootnum', $TYPE_OPS, 'bootnum', [], $RT_OBJ, :tc);
 
2267
QAST::OperationsJAST.map_classlib_core_op('bootstr', $TYPE_OPS, 'bootstr', [], $RT_OBJ, :tc);
 
2268
QAST::OperationsJAST.map_classlib_core_op('bootarray', $TYPE_OPS, 'bootarray', [], $RT_OBJ, :tc);
 
2269
QAST::OperationsJAST.map_classlib_core_op('bootintarray', $TYPE_OPS, 'bootintarray', [], $RT_OBJ, :tc);
 
2270
QAST::OperationsJAST.map_classlib_core_op('bootnumarray', $TYPE_OPS, 'bootnumarray', [], $RT_OBJ, :tc);
 
2271
QAST::OperationsJAST.map_classlib_core_op('bootstrarray', $TYPE_OPS, 'bootstrarray', [], $RT_OBJ, :tc);
 
2272
QAST::OperationsJAST.map_classlib_core_op('boothash', $TYPE_OPS, 'boothash', [], $RT_OBJ, :tc);
 
2273
QAST::OperationsJAST.map_classlib_core_op('hlllist', $TYPE_OPS, 'hlllist', [], $RT_OBJ, :tc);
 
2274
QAST::OperationsJAST.map_classlib_core_op('hllhash', $TYPE_OPS, 'hllhash', [], $RT_OBJ, :tc);
 
2275
QAST::OperationsJAST.map_classlib_core_op('create', $TYPE_OPS, 'create', [$RT_OBJ], $RT_OBJ, :tc);
 
2276
QAST::OperationsJAST.map_classlib_core_op('clone', $TYPE_OPS, 'clone', [$RT_OBJ], $RT_OBJ, :tc);
 
2277
QAST::OperationsJAST.map_classlib_core_op('isconcrete', $TYPE_OPS, 'isconcrete', [$RT_OBJ], $RT_INT, :tc);
 
2278
QAST::OperationsJAST.map_classlib_core_op('isnull', $TYPE_OPS, 'isnull', [$RT_OBJ], $RT_INT);
 
2279
QAST::OperationsJAST.map_classlib_core_op('isnull_s', $TYPE_OPS, 'isnull_s', [$RT_STR], $RT_INT);
 
2280
QAST::OperationsJAST.map_classlib_core_op('istrue', $TYPE_OPS, 'istrue', [$RT_OBJ], $RT_INT, :tc);
 
2281
QAST::OperationsJAST.map_classlib_core_op('isfalse', $TYPE_OPS, 'isfalse', [$RT_OBJ], $RT_INT, :tc);
 
2282
QAST::OperationsJAST.map_classlib_core_op('istype', $TYPE_OPS, 'istype', [$RT_OBJ, $RT_OBJ], $RT_INT, :tc);
 
2283
QAST::OperationsJAST.map_classlib_core_op('eqaddr', $TYPE_OPS, 'eqaddr', [$RT_OBJ, $RT_OBJ], $RT_INT);
 
2284
QAST::OperationsJAST.map_classlib_core_op('getattr', $TYPE_OPS, 'getattr', [$RT_OBJ, $RT_OBJ, $RT_STR], $RT_OBJ, :tc);
 
2285
QAST::OperationsJAST.map_classlib_core_op('getattr_i', $TYPE_OPS, 'getattr_i', [$RT_OBJ, $RT_OBJ, $RT_STR], $RT_INT, :tc);
 
2286
QAST::OperationsJAST.map_classlib_core_op('getattr_n', $TYPE_OPS, 'getattr_n', [$RT_OBJ, $RT_OBJ, $RT_STR], $RT_NUM, :tc);
 
2287
QAST::OperationsJAST.map_classlib_core_op('getattr_s', $TYPE_OPS, 'getattr_s', [$RT_OBJ, $RT_OBJ, $RT_STR], $RT_STR, :tc);
 
2288
QAST::OperationsJAST.map_classlib_core_op('bindattr', $TYPE_OPS, 'bindattr', [$RT_OBJ, $RT_OBJ, $RT_STR, $RT_OBJ], $RT_OBJ, :tc);
 
2289
QAST::OperationsJAST.map_classlib_core_op('bindattr_i', $TYPE_OPS, 'bindattr_i', [$RT_OBJ, $RT_OBJ, $RT_STR, $RT_INT], $RT_INT, :tc);
 
2290
QAST::OperationsJAST.map_classlib_core_op('bindattr_n', $TYPE_OPS, 'bindattr_n', [$RT_OBJ, $RT_OBJ, $RT_STR, $RT_NUM], $RT_NUM, :tc);
 
2291
QAST::OperationsJAST.map_classlib_core_op('bindattr_s', $TYPE_OPS, 'bindattr_s', [$RT_OBJ, $RT_OBJ, $RT_STR, $RT_STR], $RT_STR, :tc);
 
2292
QAST::OperationsJAST.map_classlib_core_op('attrinited', $TYPE_OPS, 'attrinited', [$RT_OBJ, $RT_OBJ, $RT_STR], $RT_INT, :tc);
 
2293
QAST::OperationsJAST.map_classlib_core_op('attrhintfor', $TYPE_OPS, 'attrhintfor', [$RT_OBJ, $RT_STR], $RT_INT, :tc);
 
2294
QAST::OperationsJAST.map_classlib_core_op('unbox_i', $TYPE_OPS, 'unbox_i', [$RT_OBJ], $RT_INT, :tc);
 
2295
QAST::OperationsJAST.map_classlib_core_op('unbox_n', $TYPE_OPS, 'unbox_n', [$RT_OBJ], $RT_NUM, :tc);
 
2296
QAST::OperationsJAST.map_classlib_core_op('unbox_s', $TYPE_OPS, 'unbox_s', [$RT_OBJ], $RT_STR, :tc);
 
2297
QAST::OperationsJAST.map_classlib_core_op('box_i', $TYPE_OPS, 'box_i', [$RT_INT, $RT_OBJ], $RT_OBJ, :tc);
 
2298
QAST::OperationsJAST.map_classlib_core_op('box_n', $TYPE_OPS, 'box_n', [$RT_NUM, $RT_OBJ], $RT_OBJ, :tc);
 
2299
QAST::OperationsJAST.map_classlib_core_op('box_s', $TYPE_OPS, 'box_s', [$RT_STR, $RT_OBJ], $RT_OBJ, :tc);
 
2300
QAST::OperationsJAST.map_classlib_core_op('can', $TYPE_OPS, 'can', [$RT_OBJ, $RT_STR], $RT_INT, :tc);
 
2301
QAST::OperationsJAST.map_classlib_core_op('reprname', $TYPE_OPS, 'reprname', [$RT_OBJ], $RT_STR);
 
2302
QAST::OperationsJAST.map_classlib_core_op('newtype', $TYPE_OPS, 'newtype', [$RT_OBJ, $RT_STR], $RT_OBJ, :tc);
 
2303
QAST::OperationsJAST.map_classlib_core_op('composetype', $TYPE_OPS, 'composetype', [$RT_OBJ, $RT_OBJ], $RT_OBJ, :tc);
 
2304
QAST::OperationsJAST.map_classlib_core_op('setboolspec', $TYPE_OPS, 'setboolspec', [$RT_OBJ, $RT_INT, $RT_OBJ], $RT_OBJ, :tc);
 
2305
QAST::OperationsJAST.map_classlib_core_op('setmethcache', $TYPE_OPS, 'setmethcache', [$RT_OBJ, $RT_OBJ], $RT_OBJ, :tc);
 
2306
QAST::OperationsJAST.map_classlib_core_op('setmethcacheauth', $TYPE_OPS, 'setmethcacheauth', [$RT_OBJ, $RT_INT], $RT_OBJ, :tc);
 
2307
QAST::OperationsJAST.map_classlib_core_op('settypecache', $TYPE_OPS, 'settypecache', [$RT_OBJ, $RT_OBJ], $RT_OBJ, :tc);
 
2308
QAST::OperationsJAST.map_classlib_core_op('settypecheckmode', $TYPE_OPS, 'settypecheckmode', [$RT_OBJ, $RT_INT], $RT_OBJ, :tc);
 
2309
QAST::OperationsJAST.map_classlib_core_op('objprimspec', $TYPE_OPS, 'objprimspec', [$RT_OBJ], $RT_INT, :tc);
 
2310
QAST::OperationsJAST.map_classlib_core_op('isinvokable', $TYPE_OPS, 'isinvokable', [$RT_OBJ], $RT_INT, :tc);
 
2311
QAST::OperationsJAST.map_classlib_core_op('setinvokespec', $TYPE_OPS, 'setinvokespec', [$RT_OBJ, $RT_OBJ, $RT_STR, $RT_OBJ], $RT_OBJ, :tc);
 
2312
})();
 
2313
 
 
2314
# defined - overridden by HLL, but by default same as .DEFINITE.
 
2315
QAST::OperationsJAST.map_classlib_core_op('defined', $TYPE_OPS, 'isconcrete', [$RT_OBJ], $RT_INT, :tc);
 
2316
 
 
2317
# container related
 
2318
QAST::OperationsJAST.map_classlib_core_op('setcontspec', $TYPE_OPS, 'setcontspec', [$RT_OBJ, $RT_STR, $RT_OBJ], $RT_OBJ, :tc);
 
2319
QAST::OperationsJAST.map_classlib_core_op('iscont', $TYPE_OPS, 'iscont', [$RT_OBJ], $RT_INT);
 
2320
QAST::OperationsJAST.map_classlib_core_op('decont', $TYPE_OPS, 'decont', [$RT_OBJ], $RT_OBJ, :tc);
 
2321
QAST::OperationsJAST.map_classlib_core_op('assign', $TYPE_OPS, 'assign', [$RT_OBJ, $RT_OBJ], $RT_OBJ, :tc);
 
2322
QAST::OperationsJAST.map_classlib_core_op('assignunchecked', $TYPE_OPS, 'assignunchecked', [$RT_OBJ, $RT_OBJ], $RT_OBJ, :tc);
 
2323
 
 
2324
# lexical related opcodes
 
2325
QAST::OperationsJAST.map_classlib_core_op('getlex', $TYPE_OPS, 'getlex', [$RT_STR], $RT_OBJ, :tc);
 
2326
QAST::OperationsJAST.map_classlib_core_op('getlex_i', $TYPE_OPS, 'getlex_i', [$RT_STR], $RT_INT, :tc);
 
2327
QAST::OperationsJAST.map_classlib_core_op('getlex_n', $TYPE_OPS, 'getlex_n', [$RT_STR], $RT_NUM, :tc);
 
2328
QAST::OperationsJAST.map_classlib_core_op('getlex_s', $TYPE_OPS, 'getlex_s', [$RT_STR], $RT_STR, :tc);
 
2329
QAST::OperationsJAST.map_classlib_core_op('bindlex', $TYPE_OPS, 'bindlex', [$RT_STR, $RT_OBJ], $RT_OBJ, :tc);
 
2330
QAST::OperationsJAST.map_classlib_core_op('bindlex_i', $TYPE_OPS, 'bindlex_i', [$RT_STR, $RT_INT], $RT_INT, :tc);
 
2331
QAST::OperationsJAST.map_classlib_core_op('bindlex_n', $TYPE_OPS, 'bindlex_n', [$RT_STR, $RT_NUM], $RT_NUM, :tc);
 
2332
QAST::OperationsJAST.map_classlib_core_op('bindlex_s', $TYPE_OPS, 'bindlex_s', [$RT_STR, $RT_STR], $RT_STR, :tc);
 
2333
QAST::OperationsJAST.map_classlib_core_op('getlexdyn', $TYPE_OPS, 'getlexdyn', [$RT_STR], $RT_OBJ, :tc);
 
2334
QAST::OperationsJAST.map_classlib_core_op('bindlexdyn', $TYPE_OPS, 'bindlexdyn', [$RT_STR, $RT_OBJ], $RT_OBJ, :tc);
 
2335
QAST::OperationsJAST.map_classlib_core_op('getlexcaller', $TYPE_OPS, 'getlexcaller', [$RT_STR], $RT_OBJ, :tc);
 
2336
QAST::OperationsJAST.map_classlib_core_op('getlexouter', $TYPE_OPS, 'getlexouter', [$RT_STR], $RT_OBJ, :tc);
 
2337
QAST::OperationsJAST.map_classlib_core_op('getlexrel', $TYPE_OPS, 'getlexrel', [$RT_OBJ, $RT_STR], $RT_OBJ, :tc);
 
2338
QAST::OperationsJAST.map_classlib_core_op('getlexreldyn', $TYPE_OPS, 'getlexreldyn', [$RT_OBJ, $RT_STR], $RT_OBJ, :tc);
 
2339
QAST::OperationsJAST.map_classlib_core_op('getlexrelcaller', $TYPE_OPS, 'getlexrelcaller', [$RT_OBJ, $RT_STR], $RT_OBJ, :tc);
 
2340
QAST::OperationsJAST.add_core_op('locallifetime', -> $qastcomp, $op {
 
2341
    my @children := nqp::clone($op.list());
 
2342
    if @children == 0 {
 
2343
        nqp::die('locallifetime requires at least one child');
 
2344
    }
 
2345
    my $arg := @children.shift();
 
2346
    my $ta := $qastcomp.new_temp_allocator;
 
2347
 
 
2348
    $*BLOCK.tempify($ta, @children);
 
2349
    my $res := $qastcomp.as_jast($op[0]);
 
2350
    $*BLOCK.untempify($ta, @children);
 
2351
 
 
2352
    $res;
 
2353
});
 
2354
 
 
2355
# code object related opcodes
 
2356
QAST::OperationsJAST.map_classlib_core_op('takeclosure', $TYPE_OPS, 'takeclosure', [$RT_OBJ], $RT_OBJ, :tc);
 
2357
QAST::OperationsJAST.map_classlib_core_op('getcodeobj', $TYPE_OPS, 'getcodeobj', [$RT_OBJ], $RT_OBJ, :tc);
 
2358
QAST::OperationsJAST.map_classlib_core_op('setcodeobj', $TYPE_OPS, 'setcodeobj', [$RT_OBJ, $RT_OBJ], $RT_OBJ, :tc);
 
2359
QAST::OperationsJAST.map_classlib_core_op('getcodename', $TYPE_OPS, 'getcodename', [$RT_OBJ], $RT_STR, :tc);
 
2360
QAST::OperationsJAST.map_classlib_core_op('setcodename', $TYPE_OPS, 'setcodename', [$RT_OBJ, $RT_STR], $RT_OBJ, :tc);
 
2361
QAST::OperationsJAST.map_classlib_core_op('getcodecuid', $TYPE_OPS, 'getcodecuid', [$RT_OBJ], $RT_STR, :tc);
 
2362
QAST::OperationsJAST.map_classlib_core_op('forceouterctx', $TYPE_OPS, 'forceouterctx', [$RT_OBJ, $RT_OBJ], $RT_OBJ, :tc);
 
2363
QAST::OperationsJAST.map_classlib_core_op('freshcoderef', $TYPE_OPS, 'freshcoderef', [$RT_OBJ], $RT_OBJ, :tc);
 
2364
QAST::OperationsJAST.map_classlib_core_op('markcodestatic', $TYPE_OPS, 'markcodestatic', [$RT_OBJ], $RT_OBJ, :tc);
 
2365
QAST::OperationsJAST.map_classlib_core_op('markcodestub', $TYPE_OPS, 'markcodestub', [$RT_OBJ], $RT_OBJ, :tc);
 
2366
QAST::OperationsJAST.map_classlib_core_op('getstaticcode', $TYPE_OPS, 'getstaticcode', [$RT_OBJ], $RT_OBJ, :tc);
 
2367
QAST::OperationsJAST.add_core_op('setdispatcher', -> $qastcomp, $op {
 
2368
    if +@($op) != 1 {
 
2369
        nqp::die('setdispatcher requires one operand');
 
2370
    }
 
2371
    my $il := JAST::InstructionList.new();
 
2372
    my $dispres := $qastcomp.as_jast($op[0], :want($RT_OBJ));
 
2373
    $il.append($dispres.jast);
 
2374
    $*STACK.obtain($il, $dispres);
 
2375
    $il.append($DUP);
 
2376
    $il.append($ALOAD_1);
 
2377
    $il.append($SWAP);
 
2378
    $il.append(JAST::Instruction.new( :op('putfield'), $TYPE_TC, 'currentDispatcher', $TYPE_SMO ));
 
2379
    result($il, $RT_OBJ);
 
2380
});
 
2381
QAST::OperationsJAST.add_core_op('takedispatcher', -> $qastcomp, $op {
 
2382
    if +@($op) != 1 || !nqp::istype($op[0], QAST::SVal) {
 
2383
        nqp::die('takedispatcher requires one string literal operand');
 
2384
    }
 
2385
    my $name := $op[0].value;
 
2386
    my $idx := $*BLOCK.lexical_type($name);
 
2387
    unless nqp::defined($idx) {
 
2388
        nqp::die('takedispatcher used with non-existing lexical');
 
2389
    }
 
2390
    my $il := JAST::InstructionList.new();
 
2391
    $il.append(JAST::PushIndex.new( :value($*BLOCK.lexical_idx($name)) ));
 
2392
    $il.append($ALOAD_1);
 
2393
    $il.append(JAST::Instruction.new( :op('invokestatic'),
 
2394
        $TYPE_OPS, 'takedispatcher', 'V', 'I', $TYPE_TC ));
 
2395
    result($il, $RT_VOID);
 
2396
});
 
2397
QAST::OperationsJAST.add_core_op('setup_blv', -> $qastcomp, $op {
 
2398
    if +@($op) != 1 || !nqp::ishash($op[0]) {
 
2399
        nqp::die('setup_blv requires one hash operand');
 
2400
    }
 
2401
 
 
2402
    my $il := JAST::InstructionList.new();
 
2403
    for $op[0] {
 
2404
        my $cuid := $_.key;
 
2405
        my @bits;
 
2406
        for $_.value -> @lex {
 
2407
            nqp::push(@bits, @lex[0]);
 
2408
            my $sc := nqp::getobjsc(@lex[1]);
 
2409
            nqp::push(@bits, nqp::scgethandle($sc));
 
2410
            nqp::push(@bits, ~nqp::scgetobjidx($sc, @lex[1]));
 
2411
            nqp::push(@bits, ~@lex[2]);
 
2412
        }
 
2413
        $il.append($ALOAD_0);
 
2414
        $il.append($ALOAD_1);
 
2415
        $il.append(JAST::PushIndex.new( :value($qastcomp.cuid_to_qbid($cuid)) ));
 
2416
        $il.append(JAST::PushSVal.new( :value(nqp::join("\0", @bits)) ));
 
2417
        $il.append(JAST::Instruction.new( :op('invokevirtual'),
 
2418
            $TYPE_CU, 'setLexValues', 'Void', $TYPE_TC, 'I', $TYPE_STR ));
 
2419
    }
 
2420
    
 
2421
    $il.append($ACONST_NULL);
 
2422
    result($il, $RT_OBJ)
 
2423
});
 
2424
 
 
2425
# language/compiler ops
 
2426
QAST::OperationsJAST.map_classlib_core_op('getcomp', $TYPE_OPS, 'getcomp', [$RT_STR], $RT_OBJ, :tc);
 
2427
QAST::OperationsJAST.map_classlib_core_op('bindcomp', $TYPE_OPS, 'bindcomp', [$RT_STR, $RT_OBJ], $RT_OBJ, :tc);
 
2428
QAST::OperationsJAST.map_classlib_core_op('getcurhllsym', $TYPE_OPS, 'getcurhllsym', [$RT_STR], $RT_OBJ, :tc);
 
2429
QAST::OperationsJAST.map_classlib_core_op('bindcurhllsym', $TYPE_OPS, 'bindcurhllsym', [$RT_STR, $RT_OBJ], $RT_OBJ, :tc);
 
2430
QAST::OperationsJAST.map_classlib_core_op('gethllsym', $TYPE_OPS, 'gethllsym', [$RT_STR, $RT_STR], $RT_OBJ, :tc);
 
2431
QAST::OperationsJAST.map_classlib_core_op('bindhllsym', $TYPE_OPS, 'bindhllsym', [$RT_STR, $RT_STR, $RT_OBJ], $RT_OBJ, :tc);
 
2432
QAST::OperationsJAST.map_classlib_core_op('sethllconfig', $TYPE_OPS, 'sethllconfig', [$RT_STR, $RT_OBJ], $RT_OBJ, :tc);
 
2433
QAST::OperationsJAST.map_classlib_core_op('loadbytecode', $TYPE_OPS, 'loadbytecode', [$RT_STR], $RT_STR, :tc);
 
2434
QAST::OperationsJAST.map_classlib_core_op('usecompilerhllconfig', $TYPE_OPS, 'usecompilerhllconfig', [], $RT_INT, :tc);
 
2435
QAST::OperationsJAST.map_classlib_core_op('usecompileehllconfig', $TYPE_OPS, 'usecompileehllconfig', [], $RT_INT, :tc);
 
2436
QAST::OperationsJAST.map_classlib_core_op('settypehll', $TYPE_OPS, 'settypehll', [$RT_OBJ, $RT_STR], $RT_OBJ, :tc);
 
2437
QAST::OperationsJAST.map_classlib_core_op('settypehllrole', $TYPE_OPS, 'settypehllrole', [$RT_OBJ, $RT_INT], $RT_OBJ, :tc);
 
2438
QAST::OperationsJAST.map_classlib_core_op('hllize', $TYPE_OPS, 'hllize', [$RT_OBJ], $RT_OBJ, :tc);
 
2439
QAST::OperationsJAST.map_classlib_core_op('hllizefor', $TYPE_OPS, 'hllizefor', [$RT_OBJ, $RT_STR], $RT_OBJ, :tc);
 
2440
 
 
2441
# regex engine related opcodes
 
2442
QAST::OperationsJAST.map_classlib_core_op('nfafromstatelist', $TYPE_OPS, 'nfafromstatelist', [$RT_OBJ, $RT_OBJ], $RT_OBJ, :tc);
 
2443
QAST::OperationsJAST.map_classlib_core_op('nfatostatelist', $TYPE_OPS, 'nfatostatelist', [$RT_OBJ], $RT_OBJ, :tc);
 
2444
QAST::OperationsJAST.map_classlib_core_op('nfarunproto', $TYPE_OPS, 'nfarunproto', [$RT_OBJ, $RT_STR, $RT_INT], $RT_OBJ, :tc);
 
2445
QAST::OperationsJAST.map_classlib_core_op('nfarunalt', $TYPE_OPS, 'nfarunalt', [$RT_OBJ, $RT_STR, $RT_INT, $RT_OBJ, $RT_OBJ, $RT_OBJ], $RT_OBJ, :tc);
 
2446
 
 
2447
# process related opcodes
 
2448
QAST::OperationsJAST.map_classlib_core_op('exit', $TYPE_OPS, 'exit', [$RT_INT], $RT_INT, :tc);
 
2449
QAST::OperationsJAST.map_classlib_core_op('sleep', $TYPE_OPS, 'sleep', [$RT_NUM], $RT_NUM);
 
2450
QAST::OperationsJAST.map_classlib_core_op('getenvhash', $TYPE_OPS, 'getenvhash', [], $RT_OBJ, :tc);
 
2451
QAST::OperationsJAST.map_classlib_core_op('getpid', $TYPE_OPS, 'getpid', [], $RT_INT, :tc);
 
2452
QAST::OperationsJAST.map_classlib_core_op('jvmgetproperties', $TYPE_OPS, 'jvmgetproperties', [], $RT_OBJ, :tc);
 
2453
 
 
2454
# JVM-specific ops for compilation unit handling
 
2455
QAST::OperationsJAST.map_classlib_core_op('compilejastlines', $TYPE_OPS, 'compilejastlines', [$RT_OBJ], $RT_OBJ, :tc);
 
2456
QAST::OperationsJAST.map_classlib_core_op('compilejastlinestofile', $TYPE_OPS, 'compilejastlinestofile', [$RT_OBJ, $RT_STR], $RT_OBJ, :tc);
 
2457
QAST::OperationsJAST.map_classlib_core_op('loadcompunit', $TYPE_OPS, 'loadcompunit', [$RT_OBJ, $RT_INT], $RT_OBJ, :tc);
 
2458
QAST::OperationsJAST.map_classlib_core_op('iscompunit', $TYPE_OPS, 'iscompunit', [$RT_OBJ], $RT_INT, :tc);
 
2459
QAST::OperationsJAST.map_classlib_core_op('compunitmainline', $TYPE_OPS, 'compunitmainline', [$RT_OBJ], $RT_OBJ, :tc);
 
2460
QAST::OperationsJAST.map_classlib_core_op('compunitcodes', $TYPE_OPS, 'compunitcodes', [$RT_OBJ], $RT_OBJ, :tc);
 
2461
QAST::OperationsJAST.map_classlib_core_op('jvmclasspaths', $TYPE_OPS, 'jvmclasspaths', [], $RT_OBJ, :tc);
 
2462
 
 
2463
# JVM-specific ops for continuation handling
 
2464
# The three main continuation ops are fudgy because they need to be called partially like subs
 
2465
QAST::OperationsJAST.map_classlib_core_op('continuationclone', $TYPE_OPS, 'continuationclone', [$RT_OBJ], $RT_OBJ, :tc);
 
2466
QAST::OperationsJAST.map_classlib_core_op('continuationreset', $TYPE_OPS, 'continuationreset', [$RT_OBJ, $RT_OBJ], $RT_OBJ, :tc, :cont);
 
2467
QAST::OperationsJAST.map_classlib_core_op('continuationcontrol', $TYPE_OPS, 'continuationcontrol', [$RT_INT, $RT_OBJ, $RT_OBJ], $RT_OBJ, :tc, :cont);
 
2468
QAST::OperationsJAST.map_classlib_core_op('continuationinvoke', $TYPE_OPS, 'continuationinvoke', [$RT_OBJ, $RT_OBJ], $RT_OBJ, :tc, :cont);
 
2469
 
 
2470
# JVM interop ops
 
2471
QAST::OperationsJAST.map_classlib_core_op('jvmeqaddr', $TYPE_OPS, 'jvmeqaddr', [$RT_OBJ, $RT_OBJ], $RT_INT, :tc);
 
2472
QAST::OperationsJAST.map_classlib_core_op('jvmisnull', $TYPE_OPS, 'jvmisnull', [$RT_OBJ], $RT_INT, :tc);
 
2473
QAST::OperationsJAST.map_classlib_core_op('jvmbootinterop', $TYPE_OPS, 'jvmbootinterop', [], $RT_OBJ, :tc);
 
2474
QAST::OperationsJAST.map_classlib_core_op('jvmgetconfig', $TYPE_OPS, 'jvmgetconfig', [], $RT_OBJ, :tc);
 
2475
 
 
2476
# Native call ops
 
2477
QAST::OperationsJAST.map_classlib_core_op('initnativecall', $TYPE_NATIVE_OPS, 'init', [], $RT_INT);
 
2478
QAST::OperationsJAST.map_classlib_core_op('buildnativecall', $TYPE_NATIVE_OPS, 'build', [$RT_OBJ, $RT_STR, $RT_STR, $RT_STR, $RT_OBJ, $RT_OBJ], $RT_INT, :tc);
 
2479
QAST::OperationsJAST.map_classlib_core_op('nativecall', $TYPE_NATIVE_OPS, 'call', [$RT_OBJ, $RT_OBJ, $RT_OBJ], $RT_OBJ, :tc);
 
2480
QAST::OperationsJAST.map_classlib_core_op('nativecallrefresh', $TYPE_NATIVE_OPS, 'refresh', [$RT_OBJ], $RT_INT);
 
2481
 
 
2482
class QAST::CompilerJAST {
 
2483
    # Responsible for handling issues around code references, building the
 
2484
    # switch statement dispatcher, etc.
 
2485
    my class CodeRefBuilder {
 
2486
        has int $!cur_idx;
 
2487
        has %!cuid_to_idx;
 
2488
        has @!jastmeth_names;
 
2489
        has @!cuids;
 
2490
        has @!callsites;
 
2491
        has %!callsite_map;
 
2492
        
 
2493
        method BUILD() {
 
2494
            $!cur_idx := 0;
 
2495
            %!cuid_to_idx := {};
 
2496
            @!jastmeth_names := [];
 
2497
            @!cuids := [];
 
2498
            @!callsites := [];
 
2499
            %!callsite_map := {};
 
2500
        }
 
2501
        
 
2502
        method register_method($jastmeth, $cuid) {
 
2503
            %!cuid_to_idx{$cuid} := $!cur_idx;
 
2504
            nqp::push(@!jastmeth_names, $jastmeth.name);
 
2505
            nqp::push(@!cuids, $cuid);
 
2506
            $!cur_idx := $!cur_idx + 1;
 
2507
        }
 
2508
        
 
2509
        method know_cuid($cuid) {
 
2510
            nqp::existskey(%!cuid_to_idx, $cuid)
 
2511
        }
 
2512
        
 
2513
        method cuid_to_idx($cuid) {
 
2514
            nqp::existskey(%!cuid_to_idx, $cuid)
 
2515
                ?? %!cuid_to_idx{$cuid}
 
2516
                !! nqp::die("Unknown CUID '$cuid'")
 
2517
        }
 
2518
        
 
2519
        method cuid_to_jastmethname($cuid) {
 
2520
            @!jastmeth_names[self.cuid_to_idx($cuid)]
 
2521
        }
 
2522
        
 
2523
        method get_callsite_idx(@arg_types, @arg_names) {
 
2524
            my $key := join("-", @arg_types) ~ ';' ~ join("\0", @arg_names);
 
2525
            if nqp::existskey(%!callsite_map, $key) {
 
2526
                return %!callsite_map{$key};
 
2527
            }
 
2528
            else {
 
2529
                my $idx := +@!callsites;
 
2530
                nqp::push(@!callsites, [@arg_types, @arg_names]);
 
2531
                %!callsite_map{$key} := $idx;
 
2532
                return $idx;
 
2533
            }
 
2534
        }
 
2535
        
 
2536
        method jastify() {
 
2537
            self.callsites();
 
2538
        }
 
2539
 
 
2540
        method callsites() {
 
2541
            my $csa := JAST::Method.new( :name('getCallSites'), :returns("[$TYPE_CSD"), :static(0) );
 
2542
            
 
2543
            # Create array.
 
2544
            $csa.append(JAST::PushIndex.new( :value(+@!callsites) ));
 
2545
            $csa.append(JAST::Instruction.new( :op('anewarray'), $TYPE_CSD ));
 
2546
            
 
2547
            # All all the callsites
 
2548
            my int $i := 0;
 
2549
            for @!callsites -> @cs {
 
2550
                my @cs_flags := @cs[0];
 
2551
                my @cs_names := @cs[1];
 
2552
                $csa.append($DUP); # Target array.
 
2553
                $csa.append(JAST::PushIndex.new( :value($i++) )); # Index.
 
2554
                $csa.append(JAST::Instruction.new( :op('new'), $TYPE_CSD ));
 
2555
                $csa.append($DUP);
 
2556
                $csa.append(JAST::PushIndex.new( :value(+@cs_flags) ));
 
2557
                $csa.append(JAST::Instruction.new( :op('newarray'), 'Byte' ));
 
2558
                my int $j := 0;
 
2559
                for @cs_flags {
 
2560
                    $csa.append($DUP);
 
2561
                    $csa.append(JAST::PushIndex.new( :value($j++) ));
 
2562
                    $csa.append(JAST::PushIndex.new( :value($_) ));
 
2563
                    $csa.append($I2B);
 
2564
                    $csa.append($BASTORE);
 
2565
                }
 
2566
                if @cs_names {
 
2567
                    $csa.append(JAST::PushIndex.new( :value(+@cs_names) ));
 
2568
                    $csa.append(JAST::Instruction.new( :op('anewarray'), $TYPE_STR ));
 
2569
                    $j := 0;
 
2570
                    for @cs_names {
 
2571
                        $csa.append($DUP);
 
2572
                        $csa.append(JAST::PushIndex.new( :value($j++) ));
 
2573
                        $csa.append(JAST::PushSVal.new( :value($_) ));
 
2574
                        $csa.append($AASTORE);
 
2575
                    }
 
2576
                }
 
2577
                else {
 
2578
                    $csa.append($ACONST_NULL);
 
2579
                }
 
2580
                $csa.append(JAST::Instruction.new( :op('invokespecial'),
 
2581
                    $TYPE_CSD, '<init>', 'Void', '[Byte', "[$TYPE_STR"));
 
2582
                $csa.append($AASTORE);
 
2583
            }
 
2584
            
 
2585
            # Return the array. Add method to class.
 
2586
            $csa.append($ARETURN);
 
2587
            $*JCLASS.add_method($csa);
 
2588
        }
 
2589
    }
 
2590
    
 
2591
    # Holds information about the QAST::Block we're currently compiling.
 
2592
    my class BlockInfo {
 
2593
        has $!qast;             # The QAST::Block
 
2594
        has $!outer;            # Outer block's BlockInfo
 
2595
        has @!params;           # QAST::Var nodes of params
 
2596
        has @!locals;           # QAST::Var nodes of declared locals
 
2597
        has @!lexicals;         # QAST::Var nodes of declared lexicals
 
2598
        has %!local_types;      # Mapping of local registers to type names
 
2599
        has %!lexical_types;    # Mapping of lexical names to types
 
2600
        has %!lexical_idxs;     # Lexical indexes (but have to know type too)
 
2601
        has @!lexical_names;    # List by type of lexial name lists
 
2602
        has int $!num_save_sites;   # Count of points where a SaveStackException handler is needed
 
2603
        has %!local2temp;       # Maps local names to temporarization info
 
2604
        
 
2605
        method new($qast, $outer) {
 
2606
            my $obj := nqp::create(self);
 
2607
            $obj.BUILD($qast, $outer);
 
2608
            $obj
 
2609
        }
 
2610
        
 
2611
        method BUILD($qast, $outer) {
 
2612
            $!qast := $qast;
 
2613
            $!outer := $outer;
 
2614
            @!params := nqp::list();
 
2615
            @!locals := nqp::list();
 
2616
            @!lexicals := nqp::list();
 
2617
            %!local_types := nqp::hash();
 
2618
            %!lexical_types := nqp::hash();
 
2619
            %!lexical_idxs := nqp::hash();
 
2620
            %!local2temp := nqp::hash();
 
2621
            @!lexical_names := nqp::list([],[],[],[]);
 
2622
        }
 
2623
        
 
2624
        method add_param($var) {
 
2625
            if $var.scope eq 'local' {
 
2626
                self.add_local($var);
 
2627
            }
 
2628
            else {
 
2629
                self.add_lexical($var);
 
2630
            }
 
2631
            @!params[+@!params] := $var;
 
2632
        }
 
2633
        
 
2634
        method add_lexical($var, :$is_static, :$is_cont, :$is_state) {
 
2635
            self.register_lexical($var);
 
2636
            if $is_static || $is_cont || $is_state {
 
2637
                my %blv := %*BLOCK_LEX_VALUES;
 
2638
                unless nqp::existskey(%blv, $!qast.cuid) {
 
2639
                    %blv{$!qast.cuid} := [];
 
2640
                }
 
2641
                my $flags := $is_static ?? 0 !!
 
2642
                             $is_cont   ?? 1 !! 2;
 
2643
                nqp::push(%blv{$!qast.cuid}, [$var.name, $var.value, $flags]);
 
2644
            }
 
2645
            @!lexicals[+@!lexicals] := $var;
 
2646
        }
 
2647
        
 
2648
        method add_local($var) {
 
2649
            my $tempify := %!local2temp{$var.name};
 
2650
            if $tempify {
 
2651
                if $tempify[0] {
 
2652
                    nqp::die("Local '"~$var.name~"' already declared");
 
2653
                }
 
2654
                my int $type  := rttype_from_typeobj($var.returns);
 
2655
                my str $tch   := typechar($type);
 
2656
                my str $local := $tempify[1]."fresh_$tch"();
 
2657
                $tempify[0] := [ $local, $type ];
 
2658
            } else {
 
2659
                self.register_local($var);
 
2660
                @!locals[+@!locals] := $var;
 
2661
            }
 
2662
        }
 
2663
 
 
2664
        method tempify($ta, @vars) {
 
2665
            for @vars -> $v {
 
2666
                %!local2temp{$v} := [ '', $ta ];
 
2667
            }
 
2668
        }
 
2669
 
 
2670
        method untempify($ta, @vars) {
 
2671
            for @vars -> $v {
 
2672
                nqp::deletekey(%!local2temp, $v);
 
2673
            }
 
2674
            $ta.release();
 
2675
        }
 
2676
 
 
2677
        method register_lexical($var) {
 
2678
            my $name := $var.name;
 
2679
            my $type := rttype_from_typeobj($var.returns);
 
2680
            if nqp::existskey(%!lexical_types, $name) {
 
2681
                nqp::die("Lexical '$name' already declared");
 
2682
            }
 
2683
            %!lexical_types{$name} := $type;
 
2684
            %!lexical_idxs{$name} := +@!lexical_names[$type];
 
2685
            nqp::push(@!lexical_names[$type], $name);
 
2686
        }
 
2687
        
 
2688
        method register_local($var) {
 
2689
            my $name := $var.name;
 
2690
            if nqp::existskey(%!local_types, $name) {
 
2691
                nqp::die("Local '$name' already declared");
 
2692
            }
 
2693
            %!local_types{$name} := rttype_from_typeobj($var.returns);
 
2694
        }
 
2695
 
 
2696
        method alloc_save_site() {
 
2697
            my $index := $!num_save_sites;
 
2698
            $!num_save_sites := $index + 1;
 
2699
            $index;
 
2700
        }
 
2701
 
 
2702
        method num_save_sites() { $!num_save_sites }
 
2703
 
 
2704
        method qast() { $!qast }
 
2705
        method outer() { $!outer }
 
2706
        method params() { @!params }
 
2707
        method lexicals() { @!lexicals }
 
2708
        method locals() { @!locals }
 
2709
        
 
2710
        method local_info($name) {
 
2711
            my $tempify := %!local2temp{$name};
 
2712
            $tempify ?? $tempify[0] !! [ $name, %!local_types{$name} ]
 
2713
        }
 
2714
        method lexical_type($name) { %!lexical_types{$name} }
 
2715
        method lexical_idx($name) { %!lexical_idxs{$name} }
 
2716
        method lexical_names_by_type() { @!lexical_names }
 
2717
    }
 
2718
    
 
2719
    my class BlockTempAlloc {
 
2720
        has int $!cur_i;
 
2721
        has int $!cur_n;
 
2722
        has int $!cur_s;
 
2723
        has int $!cur_o;
 
2724
        has @!free_i;
 
2725
        has @!free_n;
 
2726
        has @!free_s;
 
2727
        has @!free_o;
 
2728
        
 
2729
        method fresh_i() {
 
2730
            @!free_i ?? nqp::pop(@!free_i) !! "__TMP_I_" ~ $!cur_i++
 
2731
        }
 
2732
        
 
2733
        method fresh_n() {
 
2734
            @!free_n ?? nqp::pop(@!free_n) !! "__TMP_N_" ~ $!cur_n++
 
2735
        }
 
2736
        
 
2737
        method fresh_s() {
 
2738
            @!free_s ?? nqp::pop(@!free_s) !! "__TMP_S_" ~ $!cur_s++
 
2739
        }
 
2740
        
 
2741
        method fresh_o() {
 
2742
            @!free_o ?? nqp::pop(@!free_o) !! "__TMP_O_" ~ $!cur_o++
 
2743
        }
 
2744
        
 
2745
        method release(@i, @n, @s, @o) {
 
2746
            for @i { nqp::push(@!free_i, $_) }
 
2747
            for @n { nqp::push(@!free_n, $_) }
 
2748
            for @s { nqp::push(@!free_s, $_) }
 
2749
            for @o { nqp::push(@!free_o, $_) }
 
2750
        }
 
2751
        
 
2752
        method add_temps_to_set($set) {
 
2753
            sub temps($prefix, $n, $type) {
 
2754
                my int $i := 0;
 
2755
                while $i < $n {
 
2756
                    nqp::push($set, ["$prefix$i", $type]);
 
2757
                    $i++;
 
2758
                }
 
2759
            }
 
2760
            temps("__TMP_I_", $!cur_i, $RT_INT);
 
2761
            temps("__TMP_N_", $!cur_n, $RT_NUM);
 
2762
            temps("__TMP_S_", $!cur_s, $RT_STR);
 
2763
            temps("__TMP_O_", $!cur_o, $RT_OBJ);
 
2764
        }
 
2765
    }
 
2766
    
 
2767
    my class StmtTempAlloc {
 
2768
        has @!used_i;
 
2769
        has @!used_n;
 
2770
        has @!used_s;
 
2771
        has @!used_o;
 
2772
        
 
2773
        method fresh_i() {
 
2774
            my $al := $*BLOCK_TA.fresh_i();
 
2775
            nqp::push(@!used_i, $al);
 
2776
            $al
 
2777
        }
 
2778
        
 
2779
        method fresh_n() {
 
2780
            my $al := $*BLOCK_TA.fresh_n();
 
2781
            nqp::push(@!used_n, $al);
 
2782
            $al
 
2783
        }
 
2784
        
 
2785
        method fresh_s() {
 
2786
            my $al := $*BLOCK_TA.fresh_s();
 
2787
            nqp::push(@!used_s, $al);
 
2788
            $al
 
2789
        }
 
2790
        
 
2791
        method fresh_o() {
 
2792
            my $al := $*BLOCK_TA.fresh_o();
 
2793
            nqp::push(@!used_o, $al);
 
2794
            $al
 
2795
        }
 
2796
        
 
2797
        method release() {
 
2798
            $*BLOCK_TA.release(@!used_i, @!used_n, @!used_s, @!used_o)
 
2799
        }
 
2800
    }
 
2801
 
 
2802
    method new_temp_allocator() { StmtTempAlloc.new }
 
2803
 
 
2804
    method jast($source, :$classname!, *%adverbs) {
 
2805
        # Wrap $source in a QAST::CompUnit if it's not already a viable root node.
 
2806
        unless nqp::istype($source, QAST::CompUnit) {
 
2807
            my $unit := $source;
 
2808
            $unit := QAST::Block.new($unit) unless nqp::istype($unit, QAST::Block);
 
2809
            $source := QAST::CompUnit.new(:hll(''), $unit);
 
2810
        }
 
2811
        
 
2812
        # Set up a JAST::Class that will hold all the blocks (which become Java
 
2813
        # methods) that we shall compile.
 
2814
        my $file := nqp::ifnull(nqp::getlexdyn('$?FILES'), "");
 
2815
        my $*JCLASS := JAST::Class.new(
 
2816
            :name($classname),
 
2817
            :super('org.perl6.nqp.runtime.CompilationUnit'),
 
2818
            :filename($file)
 
2819
        );
 
2820
        
 
2821
        # We'll also need to keep track of all the blocks we compile into Java
 
2822
        # methods; the CodeRefBuilder takes care of that.
 
2823
        my $*CODEREFS := CodeRefBuilder.new();
 
2824
        
 
2825
        # Now compile $source. By the end of this, the various data structures
 
2826
        # set up above will be fully populated.
 
2827
        self.as_jast($source);
 
2828
        
 
2829
        # Make various code-ref/dispatch related things.
 
2830
        $*CODEREFS.jastify();
 
2831
        
 
2832
        # Finally, we hand back the finished class.
 
2833
        return $*JCLASS
 
2834
    }
 
2835
    
 
2836
    # Tracks what is currently on the stack, and what things that were on the
 
2837
    # stack have been spilled to temporaries and thus will need re-instating
 
2838
    # at some point in the future.
 
2839
    my class StackState {
 
2840
        has @!stack;
 
2841
        has @!spill_locals;
 
2842
        
 
2843
        method push($result) {
 
2844
            nqp::istype($result, Result)
 
2845
                ?? nqp::push(@!stack, $result)
 
2846
                !! nqp::die("Can only push a Result onto the stack")
 
2847
        }
 
2848
        
 
2849
        method obtain($il, *@things) {
 
2850
            # Sanity checks.
 
2851
            if nqp::elems(@things) == 0 {
 
2852
                nqp::die("Should not try to obtain zero stack elements");
 
2853
            }
 
2854
            if nqp::elems(@!stack) < nqp::elems(@things) {
 
2855
                nqp::die("Cannot obtain from empty or undersized stack");
 
2856
            }
 
2857
            
 
2858
            # See if the things we need are all on the stack.
 
2859
            my int $sp        := @!stack - +@things;
 
2860
            my int $tp        := 0;
 
2861
            my int $ok        := 1;
 
2862
            my int $all_stack := 1;
 
2863
            my int $all_local := 1;
 
2864
            while $tp < +@things {
 
2865
                unless nqp::istype(@things[$tp], Result) {
 
2866
                    nqp::die("Should only look up Result objects on the stack");
 
2867
                }
 
2868
                unless nqp::eqaddr(@!stack[$sp], @things[$tp]) {
 
2869
                    $ok := 0;
 
2870
                    last;
 
2871
                }
 
2872
                if @!stack[$sp].local {
 
2873
                    $all_stack := 0;
 
2874
                }
 
2875
                else {
 
2876
                    $all_local := 0;
 
2877
                }
 
2878
                $sp++, $tp++;
 
2879
            }
 
2880
            if $ok {
 
2881
                # If they're all on the stack, easy.
 
2882
                if $all_stack {
 
2883
                    for @things { nqp::pop(@!stack) }
 
2884
                    return 1;
 
2885
                }
 
2886
                
 
2887
                # If they're all local, load them onto the stack. Also, we can
 
2888
                # re-use the stack saving temporaries.
 
2889
                elsif $all_local {
 
2890
                    for @things {
 
2891
                        my $local := $_.local;
 
2892
                        my $type  := $_.type;
 
2893
                        $il.append(JAST::Instruction.new( :op(load_ins($type)), $local ));
 
2894
                        if nqp::islist(@!spill_locals[$type]) {
 
2895
                            nqp::push(@!spill_locals[$type], $local);
 
2896
                        }
 
2897
                        else {
 
2898
                            @!spill_locals[$type] := [$local];
 
2899
                        }
 
2900
                        nqp::pop(@!stack)
 
2901
                    }
 
2902
                    return 1;
 
2903
                }
 
2904
                
 
2905
                # Mix of local and stack: just spill everything still on the
 
2906
                # stack, and try again.
 
2907
                else {
 
2908
                    self.spill_to_locals($il);
 
2909
                    return self.obtain($il, |@things);
 
2910
                }
 
2911
            }
 
2912
            
 
2913
            # Otherwise, bad access.
 
2914
            nqp::die("Out-of-order access or re-use of stack items");
 
2915
        }
 
2916
        
 
2917
        # Spills the currnet stack contents to local variables.
 
2918
        method spill_to_locals($il) {
 
2919
            sub obtain_temp($type) {
 
2920
                if $type == $RT_VOID {
 
2921
                    nqp::die("Cannot spill a stack containing a void");
 
2922
                }
 
2923
                if @!spill_locals[$type] {
 
2924
                    nqp::pop(@!spill_locals[$type])
 
2925
                }
 
2926
                else {
 
2927
                    bfresh($type);
 
2928
                }
 
2929
            }
 
2930
            
 
2931
            my $sp := nqp::elems(@!stack);
 
2932
            while $sp-- {
 
2933
                my $item := @!stack[$sp];
 
2934
                unless $item.local {
 
2935
                    my $temp := obtain_temp($item.type);
 
2936
                    $il.append(JAST::Instruction.new( :op(store_ins($item.type)), $temp ));
 
2937
                    $item.set_local($temp);
 
2938
                }
 
2939
            }
 
2940
        }
 
2941
    }
 
2942
 
 
2943
    our $serno;
 
2944
    INIT {
 
2945
        $serno := 10;
 
2946
    }
 
2947
    
 
2948
    method unique($prefix = '') { $prefix ~ $serno++ }
 
2949
 
 
2950
    proto method as_jast($node, :$want) {
 
2951
        my $*WANT;
 
2952
        if nqp::defined($want) {
 
2953
            $*WANT := %WANTMAP{$want} // $want;
 
2954
            if nqp::istype($node, QAST::Want) {
 
2955
                self.coerce(self.as_jast(want($node, $*WANT)), $*WANT)
 
2956
            }
 
2957
            else {
 
2958
                self.coerce({*}, $*WANT)
 
2959
            }
 
2960
        }
 
2961
        else {
 
2962
            {*}
 
2963
        }
 
2964
    }
 
2965
    
 
2966
    my %want_char := nqp::hash($RT_INT, 'I', $RT_NUM, 'N', $RT_STR, 'S');
 
2967
    sub want($node, $type) {
 
2968
        my @possibles := nqp::clone($node.list);
 
2969
        my $best := @possibles.shift;
 
2970
        my $char := %want_char{$type};
 
2971
        for @possibles -> $sel, $ast {
 
2972
            if nqp::index($sel, $char) >= 0 {
 
2973
                $best := $ast;
 
2974
            }
 
2975
        }
 
2976
        $best
 
2977
    }
 
2978
 
 
2979
    method cuid_to_qbid(str $cuid) {
 
2980
        my $map := %*CUID_TO_QBID;
 
2981
        nqp::existskey($map, $cuid) ?? $map{$cuid} !! ($map{$cuid} := $*NEXT_QBID++);
 
2982
    }
 
2983
    
 
2984
    multi method as_jast(QAST::CompUnit $cu, :$want) {
 
2985
        # A compilation-unit-wide source of IDs for handlers.
 
2986
        my $*EH_IDX := 1;
 
2987
        
 
2988
        # Set HLL.
 
2989
        my $*HLL := '';
 
2990
        if $cu.hll {
 
2991
            $*HLL := $cu.hll;
 
2992
        }
 
2993
        
 
2994
        # Should have a single child which is the outer block.
 
2995
        if +@($cu) != 1 || !nqp::istype($cu[0], QAST::Block) {
 
2996
            nqp::die("QAST::CompUnit should have one child that is a QAST::Block");
 
2997
        }
 
2998
 
 
2999
        my %*CUID_TO_QBID;
 
3000
        my $*NEXT_QBID := 0;
 
3001
        # Pre-seed to make sure that qbids correspond to serialization IDs
 
3002
        my $*COMP_MODE := $cu.compilation_mode;
 
3003
        if $*COMP_MODE {
 
3004
            for $cu.code_ref_blocks() -> $qblock {
 
3005
                %*CUID_TO_QBID{$qblock.cuid} := $*NEXT_QBID++;
 
3006
            }
 
3007
        }
 
3008
 
 
3009
        # Hash mapping blocks with static lexicals to an array of arrays. Each
 
3010
        # of the sub-arrays has the form [$name, $value, $flags], where flags
 
3011
        # are 0 = static lex, 1 = container, 2 = state container.
 
3012
        my %*BLOCK_LEX_VALUES;
 
3013
 
 
3014
        # Compile the block.
 
3015
        my $block_jast := self.as_jast($cu[0]);
 
3016
        
 
3017
        # If we are in compilation mode, or have pre-deserialization or
 
3018
        # post-deserialization tasks, handle those. Overall, the process
 
3019
        # is to desugar this into simpler QAST nodes, then compile those.
 
3020
        my @pre_des   := $cu.pre_deserialize;
 
3021
        my @post_des  := $cu.post_deserialize;
 
3022
        if %*BLOCK_LEX_VALUES {
 
3023
            nqp::push(@post_des, QAST::Block.new(
 
3024
                :blocktype('immediate'),
 
3025
                QAST::Op.new( :op('setup_blv'), %*BLOCK_LEX_VALUES )
 
3026
            ));
 
3027
        }
 
3028
        if $*COMP_MODE || @pre_des || @post_des {
 
3029
            # Create a block into which we'll install all of the other
 
3030
            # pieces.
 
3031
            my $block := QAST::Block.new( :blocktype('raw') );
 
3032
            
 
3033
            # Add pre-deserialization tasks, each as a QAST::Stmt.
 
3034
            for @pre_des {
 
3035
                $block.push(QAST::Stmt.new($_));
 
3036
            }
 
3037
            
 
3038
            # If we need to do deserialization, emit code for that.
 
3039
            if $*COMP_MODE {
 
3040
                $block.push(self.deserialization_code($cu.sc(), $cu.code_ref_blocks(),
 
3041
                    $cu.repo_conflict_resolver()));
 
3042
            }
 
3043
            
 
3044
            # Add post-deserialization tasks.
 
3045
            my $cur_pd_block := QAST::Block.new( :blocktype('immediate') );
 
3046
            my $i := 0;
 
3047
            for @post_des {
 
3048
                $cur_pd_block.push(QAST::Stmt.new($_));
 
3049
                $i++;
 
3050
                if $i == 2000 {
 
3051
                    $block.push($cur_pd_block);
 
3052
                    $cur_pd_block := QAST::Block.new( :blocktype('immediate') );
 
3053
                    $i := 0;
 
3054
                }
 
3055
            }
 
3056
            $block.push($cur_pd_block);
 
3057
            
 
3058
            # Compile to JAST and register this block as the deserialization
 
3059
            # handler.
 
3060
            self.as_jast($block);
 
3061
            my $des_meth := JAST::Method.new( :name('deserializeQbid'), :returns('I'), :static(0) );
 
3062
            $des_meth.append(JAST::PushIndex.new( :value(self.cuid_to_qbid($block.cuid)) ));
 
3063
            $des_meth.append($IRETURN);
 
3064
            $*JCLASS.add_method($des_meth);
 
3065
        }
 
3066
        
 
3067
        # Compile and include load-time logic, if any.
 
3068
        if nqp::defined($cu.load) {
 
3069
            my $load_block := QAST::Block.new(
 
3070
                :blocktype('raw'),
 
3071
                $cu.load,
 
3072
                QAST::Op.new( :op('null') )
 
3073
            );
 
3074
            self.as_jast($load_block);
 
3075
            my $load_meth := JAST::Method.new( :name('loadQbid'), :returns('I'), :static(0) );
 
3076
            $load_meth.append(JAST::PushIndex.new( :value(self.cuid_to_qbid($load_block.cuid)) ));
 
3077
            $load_meth.append($IRETURN);
 
3078
            $*JCLASS.add_method($load_meth);
 
3079
        }
 
3080
        
 
3081
        # Compile and include main-time logic, if any, and then add a Java
 
3082
        # main that will lead to its invocation.
 
3083
        if nqp::defined($cu.main) {
 
3084
            my $main_block := QAST::Block.new(
 
3085
                :blocktype('raw'),
 
3086
                $cu.main,
 
3087
                QAST::Op.new( :op('null') )
 
3088
            );
 
3089
            self.as_jast($main_block);
 
3090
            my $main_meth := JAST::Method.new( :name('main'), :returns('Void') );
 
3091
            $main_meth.add_argument('argv', "[$TYPE_STR");
 
3092
            $main_meth.append(JAST::PushCVal.new( :value('L' ~ $*JCLASS.name ~ ';') ));
 
3093
            $main_meth.append(JAST::PushIndex.new( :value(self.cuid_to_qbid($main_block.cuid)) ));
 
3094
            $main_meth.append($ALOAD_0);
 
3095
            $main_meth.append(JAST::Instruction.new( :op('invokestatic'),
 
3096
                $TYPE_CU, 'enterFromMain',
 
3097
                'Void', 'Ljava/lang/Class;', 'I', "[$TYPE_STR"));
 
3098
            $main_meth.append($RETURN);
 
3099
            $*JCLASS.add_method($main_meth);
 
3100
            my $entry_cuid_meth := JAST::Method.new( :name('entryQbid'), :returns('I'), :static(0) );
 
3101
            $entry_cuid_meth.append(JAST::PushIndex.new( :value(self.cuid_to_qbid($main_block.cuid)) ));
 
3102
            $entry_cuid_meth.append($IRETURN);
 
3103
            $*JCLASS.add_method($entry_cuid_meth);
 
3104
        }
 
3105
        
 
3106
        # Add method that returns HLL name.
 
3107
        my $hll_meth := JAST::Method.new( :name('hllName'), :returns($TYPE_STR), :static(0) );
 
3108
        $hll_meth.append(JAST::PushSVal.new( :value($*HLL) ));
 
3109
        $hll_meth.append($ARETURN);
 
3110
        $*JCLASS.add_method($hll_meth);
 
3111
        
 
3112
        # Add method that returns the mainline block.
 
3113
        my $mainline_meth := JAST::Method.new( :name('mainlineQbid'), :returns('I'), :static(0) );
 
3114
        $mainline_meth.append(JAST::PushIndex.new( :value(self.cuid_to_qbid($cu[0].cuid)) ));
 
3115
        $mainline_meth.append($IRETURN);
 
3116
        $*JCLASS.add_method($mainline_meth);
 
3117
        
 
3118
        return $*JCLASS;
 
3119
    }
 
3120
    
 
3121
    method deserialization_code($sc, @code_ref_blocks, $repo_conf_res) {
 
3122
        # Serialize it.
 
3123
        my $sh := nqp::list_s();
 
3124
        my $serialized := nqp::serialize($sc, $sh);
 
3125
 
 
3126
        if %*COMPILING<%?OPTIONS><target> eq 'jar' {
 
3127
            $*JCLASS.serialized($serialized);
 
3128
            $serialized := nqp::null();
 
3129
        }
 
3130
        
 
3131
        # Now it's serialized, pop this SC off the compiling SC stack.
 
3132
        nqp::popcompsc();
 
3133
        
 
3134
        # String heap QAST.
 
3135
        my $sh_ast := QAST::Op.new( :op('list_s') );
 
3136
        my $sh_elems := nqp::elems($sh);
 
3137
        my $i := 0;
 
3138
        while $i < $sh_elems {
 
3139
            $sh_ast.push(nqp::isnull_s(nqp::atpos_s($sh, $i))
 
3140
                ?? QAST::Op.new( :op('null_s') )
 
3141
                !! QAST::SVal.new( :value(nqp::atpos_s($sh, $i)) ));
 
3142
            $i := $i + 1;
 
3143
        }
 
3144
        $sh_ast := QAST::Block.new( :blocktype('immediate'), $sh_ast );
 
3145
        
 
3146
        # Handle repossession conflict resolution code, if any.
 
3147
        if $repo_conf_res {
 
3148
            $repo_conf_res.push(QAST::Var.new( :name('conflicts'), :scope('local') ));
 
3149
        }
 
3150
        else {
 
3151
            $repo_conf_res := QAST::Op.new(
 
3152
                :op('die_s'),
 
3153
                QAST::SVal.new( :value('Repossession conflicts occurred during deserialization') )
 
3154
            );
 
3155
        }
 
3156
 
 
3157
        # Which of our methods need to be serialized?
 
3158
        my $count_meth := JAST::Method.new( :name('serializedCodeRefCount'), :returns('I'), :static(0) );
 
3159
        $count_meth.append(JAST::PushIndex.new( :value(+@code_ref_blocks) ));
 
3160
        $count_meth.append($IRETURN);
 
3161
        $*JCLASS.add_method($count_meth);
 
3162
 
 
3163
        # Overall deserialization QAST.
 
3164
        QAST::Stmts.new(
 
3165
            QAST::Op.new(
 
3166
                :op('bind'),
 
3167
                QAST::Var.new( :name('cur_sc'), :scope('local'), :decl('var') ),
 
3168
                QAST::Op.new( :op('createsc'), QAST::SVal.new( :value(nqp::scgethandle($sc)) ) )
 
3169
            ),
 
3170
            QAST::Op.new(
 
3171
                :op('scsetdesc'),
 
3172
                QAST::Var.new( :name('cur_sc'), :scope('local') ),
 
3173
                QAST::SVal.new( :value(nqp::scgetdesc($sc)) )
 
3174
            ),
 
3175
            QAST::Op.new(
 
3176
                :op('bind'),
 
3177
                QAST::Var.new( :name('conflicts'), :scope('local'), :decl('var') ),
 
3178
                QAST::Op.new( :op('list') )
 
3179
            ),
 
3180
            QAST::Op.new(
 
3181
                :op('deserialize'),
 
3182
                nqp::isnull($serialized) ?? QAST::Op.new( :op('null_s') ) !! QAST::SVal.new( :value($serialized) ),
 
3183
                QAST::Var.new( :name('cur_sc'), :scope('local') ),
 
3184
                $sh_ast,
 
3185
                QAST::Op.new( :op('null') ),
 
3186
                QAST::Var.new( :name('conflicts'), :scope('local') )
 
3187
            ),
 
3188
            QAST::Op.new(
 
3189
                :op('if'),
 
3190
                QAST::Op.new(
 
3191
                    :op('elems'),
 
3192
                    QAST::Var.new( :name('conflicts'), :scope('local') )
 
3193
                ),
 
3194
                $repo_conf_res
 
3195
            )
 
3196
        )
 
3197
    }
 
3198
    
 
3199
    multi method as_jast(QAST::Block $node, :$want) {
 
3200
        # Do block compilation in a tested block, so we can produce a result based on
 
3201
        # the containing block's stack.
 
3202
        unless $*CODEREFS.know_cuid($node.cuid) {
 
3203
            # Block gets fresh BlockInfo.
 
3204
            my $*BINDVAL  := 0;
 
3205
            my $outer     := try $*BLOCK;
 
3206
            my $block     := BlockInfo.new($node, $outer);
 
3207
            
 
3208
            # This array will contain any catch/control exception handlers the
 
3209
            # block gets. A contextual lets us track nesting of handlers.
 
3210
            my @handlers;
 
3211
            my $*HANDLER_IDX := 0;
 
3212
            my &*REGISTER_UNWIND_HANDLER := sub ($outer, $category, :$ex_obj) {
 
3213
                my $unwind := $*EH_IDX++;
 
3214
                nqp::push(@handlers, [$unwind, $outer, $category,
 
3215
                    $ex_obj ?? $EX_UNWIND_OBJECT !! $EX_UNWIND_SIMPLE]);
 
3216
                $unwind
 
3217
            }
 
3218
            my &*REGISTER_BLOCK_HANDLER := sub ($outer, $category, $lexidx) {
 
3219
                my $unwind := $*EH_IDX++;
 
3220
                nqp::push(@handlers, [$unwind, $outer, $category,
 
3221
                    $EX_BLOCK, $lexidx]);
 
3222
                $unwind
 
3223
            }
 
3224
            
 
3225
            # Create JAST method and register it with the block's compilation unit
 
3226
            # unique ID and name. (Note, always void return here as return values
 
3227
            # are handled out of band).
 
3228
            my $*JMETH := JAST::Method.new( :name('qb_'~self.cuid_to_qbid($node.cuid)), :returns('Void'), :static(1) );
 
3229
            $*JMETH.cr_name($node.name);
 
3230
            $*JMETH.cr_cuid($node.cuid) unless $*COMP_MODE;
 
3231
            $*CODEREFS.register_method($*JMETH, $node.cuid);
 
3232
            
 
3233
            # Set outer if we have one.
 
3234
            if nqp::istype($outer, BlockInfo) {
 
3235
                $*JMETH.cr_outer(self.cuid_to_qbid($outer.qast.cuid));
 
3236
            } else {
 
3237
                $*JMETH.cr_outer(-1); # marks as coderef
 
3238
            }
 
3239
            
 
3240
            # Always take ThreadContext and callsite descriptor as arguments.
 
3241
            $*JMETH.add_argument('cu', $TYPE_CU);
 
3242
            $*JMETH.add_argument('tc', $TYPE_TC);
 
3243
            $*JMETH.add_argument('cr', $TYPE_CR);
 
3244
            $*JMETH.add_argument('csd', $TYPE_CSD);
 
3245
            $*JMETH.add_argument('__args', "[$TYPE_OBJ");
 
3246
            $*JMETH.add_argument('resume', $TYPE_RESUME);
 
3247
            
 
3248
            # Set up temporaries allocator.
 
3249
            my $*BLOCK_TA := BlockTempAlloc.new();
 
3250
            my $*TA := $*BLOCK_TA;
 
3251
            
 
3252
            # Compile method body.
 
3253
            my $body;
 
3254
            my $*STACK := StackState.new();
 
3255
            {
 
3256
                my $*BLOCK := $block;
 
3257
                my $*WANT;
 
3258
                $body := self.compile_all_the_stmts($node.list, :node($node.node));
 
3259
                $*STACK.obtain(NQPMu, $body);
 
3260
            }
 
3261
            
 
3262
            # Stash lexical names.
 
3263
            my @lex_names := $block.lexical_names_by_type();
 
3264
            $*JMETH.cr_olex(@lex_names[$RT_OBJ]);
 
3265
            $*JMETH.cr_ilex(@lex_names[$RT_INT]);
 
3266
            $*JMETH.cr_nlex(@lex_names[$RT_NUM]);
 
3267
            $*JMETH.cr_slex(@lex_names[$RT_STR]);
 
3268
            
 
3269
            # Unless we have custom args processing...
 
3270
            my $il := JAST::InstructionList.new();
 
3271
            unless $node.custom_args {
 
3272
                # Analyze parameters to get count of required/optional and make sure
 
3273
                # all is in order.
 
3274
                my int $pos_required := 0;
 
3275
                my int $pos_optional := 0;
 
3276
                my int $pos_slurpy   := 0;
 
3277
                for $block.params {
 
3278
                    if $_.named {
 
3279
                        # Don't count.
 
3280
                    }
 
3281
                    elsif $_.slurpy {
 
3282
                        $pos_slurpy := 1;
 
3283
                    }
 
3284
                    elsif $_.default {
 
3285
                        if $pos_slurpy {
 
3286
                            nqp::die("Optional positionals must come before all slurpy positionals");
 
3287
                        }
 
3288
                        $pos_optional++;
 
3289
                    }
 
3290
                    else {
 
3291
                        if $pos_optional {
 
3292
                            nqp::die("Required positionals must come before all optional positionals");
 
3293
                        }
 
3294
                        if $pos_slurpy {
 
3295
                            nqp::die("Required positionals must come before all slurpy positionals");
 
3296
                        }
 
3297
                        $pos_required++;
 
3298
                    }
 
3299
                }
 
3300
                
 
3301
                # Emit arity check instruction.
 
3302
                $il.append(JAST::Instruction.new( :op('aload'), 'cf' ));
 
3303
                $il.append(JAST::Instruction.new( :op('aload'), 'csd' ));
 
3304
                $il.append(JAST::Instruction.new( :op('aload'), '__args' ));
 
3305
                $il.append(JAST::PushIndex.new( :value($pos_required) ));
 
3306
                $il.append(JAST::PushIndex.new( :value($pos_slurpy ?? -1 !! $pos_required + $pos_optional) ));
 
3307
                $il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
 
3308
                    "checkarity", $TYPE_CSD, $TYPE_CF, $TYPE_CSD, "[$TYPE_OBJ", 'Integer', 'Integer' ));
 
3309
                $il.append(JAST::Instruction.new( :op('astore'), 'csd' ));
 
3310
                $il.append($ALOAD_1);
 
3311
                $il.append(JAST::Instruction.new( :op('getfield'), $TYPE_TC, 'flatArgs', "[$TYPE_OBJ" ));
 
3312
                $il.append(JAST::Instruction.new( :op('astore'), '__args' ));
 
3313
                
 
3314
                # Emit instructions to load each parameter.
 
3315
                my int $param_idx := 0;
 
3316
                for $block.params {
 
3317
                    my $type;
 
3318
                    if $_.slurpy {
 
3319
                        $type := $RT_OBJ;
 
3320
                        $il.append($ALOAD_1);
 
3321
                        $il.append(JAST::Instruction.new( :op('aload'), 'cf' ));
 
3322
                        $il.append(JAST::Instruction.new( :op('aload'), 'csd' ));
 
3323
                        $il.append(JAST::Instruction.new( :op('aload'), '__args' ));
 
3324
                        if $_.named {
 
3325
                            $il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
 
3326
                                "namedslurpy", $TYPE_SMO, $TYPE_TC, $TYPE_CF, $TYPE_CSD, "[$TYPE_OBJ" ));
 
3327
                        }
 
3328
                        else {
 
3329
                            $il.append(JAST::PushIndex.new( :value($pos_required + $pos_optional) ));
 
3330
                            $il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
 
3331
                                "posslurpy", $TYPE_SMO, $TYPE_TC, $TYPE_CF, $TYPE_CSD, "[$TYPE_OBJ", 'Integer' ));
 
3332
                        }
 
3333
                    }
 
3334
                    else {
 
3335
                        $type    := rttype_from_typeobj($_.returns);
 
3336
                        my $jt   := jtype($type);
 
3337
                        my $tc   := typechar($type);
 
3338
                        my $opt  := $_.default ?? "opt_" !! "";
 
3339
                        $il.append(JAST::Instruction.new( :op('aload'), 'cf' ));
 
3340
                        $il.append(JAST::Instruction.new( :op('aload'), 'csd' ));
 
3341
                        $il.append(JAST::Instruction.new( :op('aload'), '__args' ));
 
3342
                        if $_.named {
 
3343
                            $il.append(JAST::PushSVal.new( :value($_.named) ));
 
3344
                            $il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
 
3345
                                "namedparam_$opt$tc", $jt, $TYPE_CF, $TYPE_CSD, "[$TYPE_OBJ", $TYPE_STR ));
 
3346
                        }
 
3347
                        else {
 
3348
                            $il.append(JAST::PushIndex.new( :value($param_idx) ));
 
3349
                            $il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
 
3350
                                "posparam_$opt$tc", $jt, $TYPE_CF, $TYPE_CSD, "[$TYPE_OBJ", 'Integer' ));
 
3351
                        }
 
3352
                        if $opt {
 
3353
                            my $lbl := JAST::Label.new( :name(self.unique("opt_param")) );
 
3354
                            $il.append($ALOAD_1);
 
3355
                            $il.append(JAST::Instruction.new( :op('getfield'), $TYPE_TC,
 
3356
                                'lastParameterExisted', "Integer" ));
 
3357
                            $il.append(JAST::Instruction.new( :op('ifne'), $lbl ));
 
3358
                            $il.append(pop_ins($type));
 
3359
                            {
 
3360
                                my $*BLOCK := $block;
 
3361
                                my $default := self.as_jast($_.default, :want($type));
 
3362
                                $il.append($default.jast);
 
3363
                                $*STACK.obtain($il, $default);
 
3364
                            }
 
3365
                            $il.append($lbl);
 
3366
                        }
 
3367
                    }
 
3368
                    if $_.scope eq 'local' {
 
3369
                        $il.append(JAST::Instruction.new( :op(store_ins($type)), $_.name ));
 
3370
                    }
 
3371
                    else {
 
3372
                        my $jtype := jtype($type);
 
3373
                        $il.append(JAST::Instruction.new( :op('aload'), 'cf' ));
 
3374
                        $il.append(JAST::PushIndex.new( :value($block.lexical_idx($_.name)) ));
 
3375
                        $il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
 
3376
                            'bindlex_' ~ typechar($type), $jtype, $jtype, $TYPE_CF, 'Integer' ));
 
3377
                        $il.append(pop_ins($type));
 
3378
                    }
 
3379
                    $param_idx++;
 
3380
                }
 
3381
            }
 
3382
            
 
3383
            # Add all the locals.
 
3384
            my @all_locals;
 
3385
            for $block.locals { nqp::push(@all_locals, $block.local_info($_.name)) }
 
3386
            $*BLOCK_TA.add_temps_to_set(@all_locals);
 
3387
 
 
3388
            for @all_locals {
 
3389
                my $name := $_[0];
 
3390
                my $type := $_[1];
 
3391
                $*JMETH.add_local($name, jtype($type));
 
3392
                # use $*JMETH so it goes into the prelude section and doesn't clobber the assignments above...
 
3393
                if $type == $RT_INT {
 
3394
                    $*JMETH.append(JAST::PushIVal.new( :value(0) ));
 
3395
                }
 
3396
                elsif $type == $RT_NUM {
 
3397
                    $*JMETH.append(JAST::PushNVal.new( :value(0) ));
 
3398
                }
 
3399
                else {
 
3400
                    $*JMETH.append($ACONST_NULL);
 
3401
                }
 
3402
                $*JMETH.append(JAST::Instruction.new( :op(store_ins($type)), $name ));
 
3403
            }
 
3404
            
 
3405
            # Flatten handlers and store.
 
3406
            my @flat_handlers := [nqp::elems(@handlers)];
 
3407
            for @handlers {
 
3408
                nqp::push(@flat_handlers, nqp::elems($_));
 
3409
                for $_ { nqp::push(@flat_handlers, $_) }
 
3410
            }
 
3411
            $*JMETH.cr_handlers(@flat_handlers);
 
3412
            
 
3413
            # Add method body JAST.
 
3414
            $il.append($body.jast);
 
3415
            
 
3416
            # Store return value.
 
3417
            $il.append(JAST::Instruction.new( :op('aload'), 'cf' ));
 
3418
            $il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
 
3419
                'return_' ~ typechar($body.type), 'Void', jtype($body.type), $TYPE_CF ));
 
3420
 
 
3421
            # make sure this goes before the body
 
3422
            my int $save_sites := $block.num_save_sites;
 
3423
            if $save_sites {
 
3424
                $*JMETH.append(JAST::Instruction.new( :op('aload'), 'resume' ));
 
3425
                $*JMETH.append(JAST::Instruction.new( :op('ifnonnull'), JAST::Label.new( :name('RESUME') ) ));
 
3426
            }
 
3427
 
 
3428
            # Emit prelude (after checking for resume). This creates and stashes the CallFrame.
 
3429
            $*JMETH.add_local('cf', $TYPE_CF);
 
3430
            $*JMETH.append(JAST::Instruction.new( :op('new'), $TYPE_CF ));
 
3431
            $*JMETH.append($DUP);
 
3432
            $*JMETH.append($ALOAD_1);
 
3433
            $*JMETH.append(JAST::Instruction.new( :op('aload'), 'cr' ));
 
3434
            $*JMETH.append(JAST::Instruction.new( :op('invokespecial'), $TYPE_CF, '<init>',
 
3435
                'Void', $TYPE_TC, $TYPE_CR ));
 
3436
            $*JMETH.append(JAST::Instruction.new( :op('astore'), 'cf' ));
 
3437
            
 
3438
            # Emit the postlude. We catch any exceptions. Control ones are
 
3439
            # rethrown, after calling CallFrame.leave. Others are passed on to
 
3440
            # dieInternal. Finally, if there's no exception, we also need to
 
3441
            # call CallFrame.leave.
 
3442
            $il.append(JAST::Instruction.new( :op('aload'), 'cf' ));
 
3443
            $il.append(JAST::Instruction.new( :op('invokevirtual'),
 
3444
                $TYPE_CF, 'leave', 'Void' ));
 
3445
            my $posthan := JAST::InstructionList.new();
 
3446
            my $nclab   := JAST::Label.new( :name('non_cont_ex') );
 
3447
            $posthan.append($DUP);
 
3448
            $posthan.append(JAST::Instruction.new( :op('instanceof'), $TYPE_EX_CONT ));
 
3449
            $posthan.append(JAST::Instruction.new( :op('ifeq'), $nclab ));
 
3450
            $posthan.append(JAST::Instruction.new( :op('aload'), 'cf' ));
 
3451
            $posthan.append(JAST::Instruction.new( :op('invokevirtual'),
 
3452
                $TYPE_CF, 'leave', 'Void' ));
 
3453
            $posthan.append($ATHROW);
 
3454
            $posthan.append($nclab);
 
3455
            $posthan.append($ALOAD_1);
 
3456
            $posthan.append($SWAP);
 
3457
            $posthan.append(JAST::Instruction.new( :op('invokestatic'),
 
3458
                $TYPE_EH, 'dieInternal', $TYPE_EX_RT, $TYPE_TC, $TYPE_THROWABLE ));
 
3459
            $posthan.append($ATHROW);
 
3460
            $*JMETH.append(JAST::TryCatch.new( :try($il), :catch($posthan),
 
3461
                :type($TYPE_THROWABLE) ));
 
3462
            $*JMETH.append($RETURN);
 
3463
 
 
3464
            if $save_sites {
 
3465
                my $saver := JAST::InstructionList.new;
 
3466
                my $resume := JAST::InstructionList.new;
 
3467
 
 
3468
                $saver.append(JAST::Label.new( :name( 'SAVER' ) ));
 
3469
                $saver.append($ACONST_NULL);
 
3470
 
 
3471
                my @merged;
 
3472
                # don't save/reload the resume pointer (could get messy :p) or the thread context (restored separately since we can change threads)
 
3473
                # or the callframe (can also change)
 
3474
                # also self doesn't get saved/restored, but that's OK because the resume handle is primed with it.
 
3475
                for $*JMETH.arguments { nqp::push(@merged, $_) unless $_[0] eq 'resume' || $_[0] eq 'tc' || $_[0] eq 'cu' }
 
3476
                for $*JMETH.locals { nqp::push(@merged, $_) unless $_[0] eq 'cf' }
 
3477
 
 
3478
                my int $i := 0;
 
3479
                my int $ict := +@merged;
 
3480
 
 
3481
                $saver.append(JAST::PushIndex.new( :value(+@merged) ));
 
3482
                $saver.append(JAST::Instruction.new( :op('anewarray'), $TYPE_OBJ ));
 
3483
 
 
3484
                $resume.append(JAST::Label.new( :name( 'RESUME' ) ));
 
3485
                $resume.append(JAST::Instruction.new( :op('aload'), 'resume' ));
 
3486
                $resume.append(JAST::Instruction.new( :op('getfield'), $TYPE_RESUME, 'tc', $TYPE_TC ));
 
3487
                $resume.append(JAST::Instruction.new( :op('astore'), 'tc' ));
 
3488
                $resume.append(JAST::Instruction.new( :op('aload'), 'resume' ));
 
3489
                $resume.append(JAST::Instruction.new( :op('getfield'), $TYPE_RESUME, 'callFrame', $TYPE_CF ));
 
3490
                $resume.append(JAST::Instruction.new( :op('astore'), 'cf' ));
 
3491
                $resume.append(JAST::Instruction.new( :op('aload'), 'resume' ));
 
3492
                $resume.append(JAST::Instruction.new( :op('getfield'), $TYPE_RESUME, 'saveSpace', '['~$TYPE_OBJ ));
 
3493
 
 
3494
                for @merged {
 
3495
                    $saver.append($DUP);
 
3496
                    $saver.append(JAST::PushIndex.new( :value($i) ));
 
3497
 
 
3498
                    $resume.append($DUP) if $i+1 != $ict; # assuming @merged > 0, which is guaranteed currently
 
3499
                    $resume.append(JAST::PushIndex.new( :value($i) ));
 
3500
                    $resume.append($AALOAD);
 
3501
                    $i++;
 
3502
 
 
3503
                    # later, we might want to consolidate multiple doubles/longs into a single part of the save record
 
3504
                    if $_[1] eq 'Double' {
 
3505
                        $saver.append(JAST::Instruction.new( :op('dload'), $_[0] ));
 
3506
                        $saver.append(JAST::Instruction.new( :op('invokestatic'),
 
3507
                            $TYPE_DOUBLE, 'valueOf', $TYPE_DOUBLE, 'Double' ));
 
3508
 
 
3509
                        $resume.append(JAST::Instruction.new( :op('checkcast'), $TYPE_DOUBLE ));
 
3510
                        $resume.append(JAST::Instruction.new( :op('invokevirtual'),
 
3511
                            $TYPE_DOUBLE, 'doubleValue', 'Double' ));
 
3512
                        $resume.append(JAST::Instruction.new( :op('dstore'), $_[0] ));
 
3513
                    }
 
3514
                    elsif $_[1] eq 'Long' {
 
3515
                        $saver.append(JAST::Instruction.new( :op('lload'), $_[0] ));
 
3516
                        $saver.append(JAST::Instruction.new( :op('invokestatic'),
 
3517
                            $TYPE_LONG, 'valueOf', $TYPE_LONG, 'Long' ));
 
3518
 
 
3519
                        $resume.append(JAST::Instruction.new( :op('checkcast'), $TYPE_LONG ));
 
3520
                        $resume.append(JAST::Instruction.new( :op('invokevirtual'),
 
3521
                            $TYPE_LONG, 'longValue', 'Long' ));
 
3522
                        $resume.append(JAST::Instruction.new( :op('lstore'), $_[0] ));
 
3523
                    }
 
3524
                    else {
 
3525
                        $saver.append(JAST::Instruction.new( :op('aload'), $_[0] ));
 
3526
                        $resume.append(JAST::Instruction.new( :op('checkcast'), $_[1] ));
 
3527
                        $resume.append(JAST::Instruction.new( :op('astore'), $_[0] ));
 
3528
                    }
 
3529
 
 
3530
                    $saver.append($AASTORE);
 
3531
                }
 
3532
 
 
3533
                $saver.append(JAST::Instruction.new( :op('aload'), 'cf' ));
 
3534
                $saver.append(JAST::Instruction.new( :op('invokevirtual'),
 
3535
                    $TYPE_EX_SAVE, 'pushFrame', $TYPE_EX_SAVE, "Integer", $TYPE_MH, '['~$TYPE_OBJ, $TYPE_CF ));
 
3536
                $saver.append($ATHROW);
 
3537
 
 
3538
                $resume.append(JAST::Instruction.new( :op('aload'), 'resume' ));
 
3539
                $resume.append(JAST::Instruction.new( :op('invokevirtual'),
 
3540
                    $TYPE_RESUME, 'resumeNextSave', 'Void' ));
 
3541
 
 
3542
                $resume.append(JAST::Instruction.new( :op('aload'), 'resume' ));
 
3543
                $resume.append(JAST::Instruction.new( :op('getfield'), $TYPE_RESUME, 'resumePoint', 'Integer' ));
 
3544
                my $switch := JAST::Instruction.new( :op('tableswitch'), JAST::Label.new( :name('reenter_0') ) );
 
3545
                my int $labelno := 0;
 
3546
                while ($labelno < $save_sites) {
 
3547
                    $switch.push( JAST::Label.new( :name('reenter_'~$labelno) ) );
 
3548
                    $labelno++;
 
3549
                }
 
3550
                $resume.append($switch);
 
3551
 
 
3552
                $*JMETH.append($saver);
 
3553
                $*JMETH.append($resume);
 
3554
            }
 
3555
            
 
3556
            # Set exit handler flag if needed.
 
3557
            if $node.has_exit_handler {
 
3558
                $*JMETH.has_exit_handler(1);
 
3559
            }
 
3560
            
 
3561
            # Finalize method and add it to the class.
 
3562
            $*JCLASS.add_method($*JMETH);
 
3563
        }
 
3564
 
 
3565
        # Now go by block type for producing a result; also need to special-case
 
3566
        # the top-level, where we need no result.
 
3567
        if nqp::istype((try $*STACK), StackState) {
 
3568
            my $blocktype := $node.blocktype;
 
3569
            if $blocktype eq '' || $blocktype eq 'declaration' || $blocktype eq 'declaration_static' {
 
3570
                return self.as_jast(QAST::BVal.new( :value($node) ));
 
3571
            }
 
3572
            elsif $blocktype eq 'immediate' || $blocktype eq 'immediate_static' {
 
3573
                # Can emit a direct JVM level call. First, get self, TC,
 
3574
                # code ref, callsite descriptor and args (both empty) onto
 
3575
                # the stack.
 
3576
                my $il := JAST::InstructionList.new();
 
3577
                $*STACK.spill_to_locals($il);
 
3578
                $il.append($ALOAD_0);
 
3579
                $il.append($ALOAD_1);
 
3580
                $il.append($ALOAD_0);
 
3581
                $il.append(JAST::PushIndex.new( :value(self.cuid_to_qbid($node.cuid)) ));
 
3582
                $il.append(JAST::Instruction.new( :op('invokevirtual'),
 
3583
                    $TYPE_CU, 'lookupCodeRef', $TYPE_CR, 'I' ));
 
3584
                $il.append(JAST::Instruction.new( :op('getstatic'),
 
3585
                    $TYPE_OPS, 'emptyCallSite', $TYPE_CSD ));
 
3586
                $il.append(JAST::Instruction.new( :op('getstatic'),
 
3587
                    $TYPE_OPS, 'emptyArgList', "[$TYPE_OBJ" ));
 
3588
                $il.append($ACONST_NULL);
 
3589
                
 
3590
                # Emit the virtual call.
 
3591
                $il.append(savesite(JAST::Instruction.new( :op('invokestatic'),
 
3592
                    'L' ~ $*JCLASS.name ~ ';',
 
3593
                    $*CODEREFS.cuid_to_jastmethname($node.cuid),
 
3594
                    'V', $TYPE_CU, $TYPE_TC, $TYPE_CR, $TYPE_CSD, "[$TYPE_OBJ", $TYPE_RESUME )));
 
3595
                
 
3596
                # Load result onto the stack, unless in void context.
 
3597
                if $*WANT != $RT_VOID {
 
3598
                    $il.append(JAST::Instruction.new( :op('aload'), 'cf' ));
 
3599
                    $il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
 
3600
                        'result_' ~ typechar($RT_OBJ), jtype($RT_OBJ), $TYPE_CF ));
 
3601
                    return result($il, $RT_OBJ)
 
3602
                }
 
3603
                else {
 
3604
                    return result($il, $RT_VOID)
 
3605
                }
 
3606
            }
 
3607
            elsif $blocktype eq 'raw' {
 
3608
                return self.as_jast(QAST::Op.new( :op('null') ));
 
3609
            }
 
3610
            else {
 
3611
                nqp::die("Unrecognized block type '$blocktype'");
 
3612
            }
 
3613
        }
 
3614
    }
 
3615
    
 
3616
    multi method as_jast(QAST::Stmts $node, :$want) {
 
3617
        self.compile_all_the_stmts($node.list, $node.resultchild, :node($node.node))
 
3618
    }
 
3619
    
 
3620
    multi method as_jast(QAST::Stmt $node, :$want) {
 
3621
        my $*TA := StmtTempAlloc.new();
 
3622
        my $result := self.compile_all_the_stmts($node.list, $node.resultchild, :node($node.node));
 
3623
        $*TA.release();
 
3624
        $result
 
3625
    }
 
3626
    
 
3627
    method compile_all_the_stmts(@stmts, $resultchild?, :$node) {
 
3628
        unless @stmts {
 
3629
            # Empty statement list will break things.
 
3630
            @stmts[0] := QAST::Op.new( :op('null') );
 
3631
        }
 
3632
        my $last_res;
 
3633
        my $il := JAST::InstructionList.new();
 
3634
        my int $i := 0;
 
3635
        my int $n := +@stmts;
 
3636
        my $all_void := $*WANT == $RT_VOID;
 
3637
        my $res_temp;
 
3638
        my $res_type;
 
3639
        unless nqp::defined($resultchild) {
 
3640
            $resultchild := $n - 1;
 
3641
        }
 
3642
        
 
3643
        for @stmts {
 
3644
            if $_.node {
 
3645
                my $node := $_.node;
 
3646
                my $line := HLL::Compiler.lineof($node.orig(), $node.from(), :cache(1));            
 
3647
                $il.append(JAST::Annotation.new( :line($line) ));
 
3648
            }
 
3649
            
 
3650
            my $void := $all_void || $i != $resultchild;
 
3651
            if $void {
 
3652
                if nqp::istype($_, QAST::Want) {
 
3653
                    $_ := want($_, 'v');
 
3654
                }
 
3655
                $last_res := self.as_jast($_, :want('v'));
 
3656
            }
 
3657
            else {
 
3658
                $last_res := self.as_jast($_);
 
3659
            }
 
3660
            # variables with fallback can have side effects and cannot be elided
 
3661
            $il.append($last_res.jast)
 
3662
                unless $void && nqp::istype($_, QAST::Var) && !nqp::istype($_, QAST::VarWithFallback);
 
3663
            $*STACK.obtain($il, $last_res);
 
3664
            if $resultchild == $i && $resultchild != $n - 1 {
 
3665
                $res_type := $last_res.type;
 
3666
                $res_temp := fresh($res_type);
 
3667
                $il.append(JAST::Instruction.new( :op(store_ins($res_type)), $res_temp ));
 
3668
            }
 
3669
            $i := $i + 1;
 
3670
        }
 
3671
        if $res_temp {
 
3672
            $il.append(JAST::Instruction.new( :op(load_ins($res_type)), $res_temp ));
 
3673
            result($il, $res_type)
 
3674
        }
 
3675
        else {
 
3676
            result($il, $last_res.type)
 
3677
        }
 
3678
    }
 
3679
    
 
3680
    multi method as_jast(QAST::Op $node, :$want) {
 
3681
        my $hll := '';
 
3682
        my $result;
 
3683
        my $err;
 
3684
        try $hll := $*HLL;
 
3685
        #try {
 
3686
            $result := QAST::OperationsJAST.compile_op(self, $hll, $node);
 
3687
        #    CATCH { $err := $! }
 
3688
        #}
 
3689
        #if $err {
 
3690
        #    nqp::die("Error while compiling op " ~ $node.op ~ ": $err");
 
3691
        #}
 
3692
        $result
 
3693
    }
 
3694
    
 
3695
    multi method as_jast(QAST::VM $node, :$want) {
 
3696
        if $node.supports('jvm') {
 
3697
            return nqp::defined($want)
 
3698
                ?? self.as_jast($node.alternative('jvm'), :$want)
 
3699
                !! self.as_jast($node.alternative('jvm'));
 
3700
        }
 
3701
        else {
 
3702
            nqp::die("To compile on the JVM backend, QAST::VM must have an alternative 'jvm'" ~
 
3703
                ($node.supports('pirop')
 
3704
                    ?? ' (got pirop = ' ~ $node.alternative('pirop') ~ ')'
 
3705
                    !! ''));
 
3706
        }
 
3707
    }
 
3708
    
 
3709
    multi method as_jast(QAST::Var $node, :$want) {
 
3710
        self.compile_var($node)
 
3711
    }
 
3712
    
 
3713
    multi method as_jast(QAST::VarWithFallback $node, :$want) {
 
3714
        if $*BINDVAL {
 
3715
            self.compile_var($node)
 
3716
        }
 
3717
        else {
 
3718
            my $var_res := self.compile_var($node);
 
3719
            if ($var_res.type != $RT_OBJ) {
 
3720
                return $var_res;
 
3721
            }
 
3722
            
 
3723
            my $il := JAST::InstructionList.new();
 
3724
            $il.append($var_res.jast);
 
3725
            $*STACK.spill_to_locals($il);
 
3726
            $*STACK.obtain($il, $var_res);
 
3727
            
 
3728
            my $lbl := JAST::Label.new(:name($node.unique('fallback')));
 
3729
            $il.append($DUP);
 
3730
            $il.append(JAST::Instruction.new( :op('ifnonnull'), $lbl ));
 
3731
            
 
3732
            my $fallback_res := self.as_jast($node.fallback, :want($RT_OBJ));
 
3733
            $il.append($POP);
 
3734
            $il.append($fallback_res.jast);
 
3735
            $*STACK.obtain($il, $fallback_res);
 
3736
            $il.append($lbl);
 
3737
 
 
3738
            result($il, $RT_OBJ);
 
3739
        }
 
3740
    }
 
3741
    
 
3742
    method compile_var($node) {
 
3743
        my $scope := $node.scope;
 
3744
        my $decl  := $node.decl;
 
3745
        
 
3746
        # Handle any declarations; after this, we fall through to the
 
3747
        # lookup code.
 
3748
        if $decl {
 
3749
            # If it's a parameter, add it to the things we should bind
 
3750
            # at block entry.
 
3751
            if $decl eq 'param' {
 
3752
                if $scope eq 'local' || $scope eq 'lexical' {
 
3753
                    $*BLOCK.add_param($node);
 
3754
                }
 
3755
                else {
 
3756
                    nqp::die("Parameter cannot have scope '$scope'; use 'local' or 'lexical'");
 
3757
                }
 
3758
            }
 
3759
            elsif $decl eq 'var' {
 
3760
                if $scope eq 'local' {
 
3761
                    $*BLOCK.add_local($node);
 
3762
                }
 
3763
                elsif $scope eq 'lexical' {
 
3764
                    $*BLOCK.add_lexical($node);
 
3765
                }
 
3766
                else {
 
3767
                    nqp::die("Cannot declare variable with scope '$scope'; use 'local' or 'lexical'");
 
3768
                }
 
3769
            }
 
3770
            elsif $decl eq 'static' {
 
3771
                if $scope ne 'lexical' {
 
3772
                    nqp::die("Can only use 'static' decl with scope 'lexical'");
 
3773
                }
 
3774
                $*BLOCK.add_lexical($node, :is_static);
 
3775
            }
 
3776
            elsif $decl eq 'contvar' {
 
3777
                if $scope ne 'lexical' {
 
3778
                    nqp::die("Can only use 'contvar' decl with scope 'lexical'");
 
3779
                }
 
3780
                $*BLOCK.add_lexical($node, :is_cont);
 
3781
            }
 
3782
            elsif $decl eq 'statevar' {
 
3783
                if $scope ne 'lexical' {
 
3784
                    nqp::die("Can only use 'statevar' decl with scope 'lexical'");
 
3785
                }
 
3786
                $*BLOCK.add_lexical($node, :is_state);
 
3787
            }
 
3788
            else {
 
3789
                nqp::die("Don't understand declaration type '$decl'");
 
3790
            }
 
3791
        }
 
3792
        
 
3793
        # If there's no scope, figure it out from the symbol tables if
 
3794
        # possible.
 
3795
        my $name := $node.name;
 
3796
        if $scope eq '' {
 
3797
            my $cur_block := $*BLOCK;
 
3798
            while nqp::istype($cur_block, BlockInfo) {
 
3799
                my %sym := $cur_block.qast.symbol($name);
 
3800
                if %sym {
 
3801
                    $scope := %sym<scope>;
 
3802
                    $cur_block := NQPMu;
 
3803
                }
 
3804
                else {
 
3805
                    $cur_block := $cur_block.outer();
 
3806
                }
 
3807
            }
 
3808
            if $scope eq '' {
 
3809
                nqp::die("No scope specified or locatable in the symbol table for '$name'");
 
3810
            }
 
3811
        }
 
3812
        
 
3813
        # Now go by scope.
 
3814
        if $scope eq 'local' {
 
3815
            my $info := $*BLOCK.local_info($name);
 
3816
            my $type := $info[1];
 
3817
            if nqp::defined($type) {
 
3818
                my $il := JAST::InstructionList.new();
 
3819
                if $*BINDVAL {
 
3820
                    my $valres := self.as_jast_clear_bindval($*BINDVAL, :want($type));
 
3821
                    $il.append($valres.jast);
 
3822
                    $*STACK.obtain($il, $valres);
 
3823
                    $il.append(dup_ins($type));
 
3824
                    $il.append(JAST::Instruction.new( :op(store_ins($type)), $info[0] ));
 
3825
                }
 
3826
                else {
 
3827
                    $il.append(JAST::Instruction.new( :op(load_ins($type)), $info[0] ));
 
3828
                }
 
3829
                return result($il, $type);
 
3830
            }
 
3831
            else {
 
3832
                nqp::die("Cannot reference undeclared local '$name'");
 
3833
            }
 
3834
        }
 
3835
        elsif $scope eq 'lexical' || $scope eq 'contextual' {
 
3836
            # See if it's declared in the local scope.
 
3837
            my int $local  := 0;
 
3838
            my int $scopes := 0;
 
3839
            my $type       := $*BLOCK.lexical_type($name);
 
3840
            my $declarer;
 
3841
            if nqp::defined($type) {
 
3842
                # It is. Nothing more to do.
 
3843
                $local := 1;
 
3844
            }
 
3845
            elsif $scope eq 'lexical' {
 
3846
                # Try to find it in an outer scope.
 
3847
                my int $i := 1;
 
3848
                my $cur_block := $*BLOCK.outer();
 
3849
                while nqp::istype($cur_block, BlockInfo) {
 
3850
                    if $cur_block.qast<DYN_COMP_WRAPPER> {
 
3851
                        $cur_block := NQPMu;
 
3852
                    }
 
3853
                    else {
 
3854
                        $type := $cur_block.lexical_type($name);
 
3855
                        if nqp::defined($type) {
 
3856
                            $scopes := $i;
 
3857
                            $declarer := $cur_block;
 
3858
                            $cur_block := NQPMu;
 
3859
                        }
 
3860
                        else {
 
3861
                            $cur_block := $cur_block.outer();
 
3862
                            $i++;
 
3863
                        }
 
3864
                    }
 
3865
                }
 
3866
            }
 
3867
            
 
3868
            # If we didn't find it anywhere, it musta been explicitly marked as
 
3869
            # lexical. Take the type from .returns and rewrite to a more dynamic
 
3870
            # lookup.
 
3871
            unless $local || $scopes {
 
3872
                if $scope eq 'lexical' {
 
3873
                    $type := rttype_from_typeobj($node.returns);
 
3874
                    my $char := $type == $RT_OBJ ?? '' !! '_' ~ typechar($type);
 
3875
                    my $name_sval := QAST::SVal.new( :value($name) );
 
3876
                    return self.as_jast_clear_bindval($*BINDVAL
 
3877
                        ?? QAST::Op.new( :op("bindlex$char"), $name_sval, $*BINDVAL )
 
3878
                        !! QAST::Op.new( :op("getlex$char"), $name_sval ));
 
3879
                }
 
3880
                else {
 
3881
                    my $il := JAST::InstructionList.new();
 
3882
                    if $*BINDVAL {
 
3883
                        my $valres := self.as_jast_clear_bindval($*BINDVAL, :want($RT_OBJ));
 
3884
                        $il.append($valres.jast);
 
3885
                        $*STACK.obtain($il, $valres);
 
3886
                    }
 
3887
                    $il.append(JAST::PushSVal.new( :value($name) ));
 
3888
                    $il.append($ALOAD_1);
 
3889
                    $il.append($*BINDVAL
 
3890
                        ?? JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
 
3891
                                "bindlexdyn", $TYPE_SMO, $TYPE_SMO, $TYPE_STR, $TYPE_TC )
 
3892
                        !! JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
 
3893
                                "getlexdyn", $TYPE_SMO, $TYPE_STR, $TYPE_TC ));
 
3894
                    return result($il, $RT_OBJ);
 
3895
                }
 
3896
            }
 
3897
            
 
3898
            # Map type in a couple of ways we'll need.
 
3899
            my $jtype := jtype($type);
 
3900
            my $c     := typechar($type);
 
3901
            
 
3902
            # If binding, always want the thing we're binding evaluated.
 
3903
            my $il := JAST::InstructionList.new();
 
3904
            if $*BINDVAL {
 
3905
                my $valres := self.as_jast_clear_bindval($*BINDVAL, :want($type));
 
3906
                $il.append($valres.jast);
 
3907
                $*STACK.obtain($il, $valres);
 
3908
            }
 
3909
            
 
3910
            # If it's declared in the local scope...
 
3911
            if $local {
 
3912
                $il.append(JAST::Instruction.new( :op('aload'), 'cf' ));
 
3913
                $il.append(JAST::PushIndex.new( :value($*BLOCK.lexical_idx($name)) ));
 
3914
                $il.append($*BINDVAL
 
3915
                    ?? JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
 
3916
                            "bindlex_$c", $jtype, $jtype, $TYPE_CF, 'Integer' )
 
3917
                    !! JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
 
3918
                            "getlex_$c", $jtype, $TYPE_CF, 'Integer' ));
 
3919
            }
 
3920
            
 
3921
            # Otherwise it must be a known number of scopes out.
 
3922
            else {
 
3923
                $il.append(JAST::Instruction.new( :op('aload'), 'cf' ));
 
3924
                $il.append(JAST::PushIndex.new( :value($declarer.lexical_idx($name)) ));
 
3925
                $il.append(JAST::PushIndex.new( :value($scopes) ));
 
3926
                $il.append($*BINDVAL
 
3927
                    ?? JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
 
3928
                            "bindlex_{$c}_si", $jtype, $jtype, $TYPE_CF, 'Integer', 'Integer' )
 
3929
                    !! JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
 
3930
                            "getlex_{$c}_si", $jtype, $TYPE_CF, 'Integer', 'Integer' ));
 
3931
            }
 
3932
 
 
3933
            return result($il, $type);
 
3934
        }
 
3935
        elsif $scope eq 'attribute' {
 
3936
            # Ensure we have object and class handle.
 
3937
            my @args := $node.list;
 
3938
            if +@args != 2 {
 
3939
                nqp::die("An attribute lookup needs an object and a class handle");
 
3940
            }
 
3941
            
 
3942
            # Compile object, handle and name.
 
3943
            my $il := JAST::InstructionList.new();
 
3944
            my $obj_res := self.as_jast_clear_bindval(@args[0], :want($RT_OBJ));
 
3945
            $il.append($obj_res.jast);
 
3946
            my $han_res := self.as_jast_clear_bindval(@args[1], :want($RT_OBJ));
 
3947
            $il.append($han_res.jast);
 
3948
            my $name_res := self.as_jast_clear_bindval(QAST::SVal.new( :value($name) ), :want($RT_STR));
 
3949
            $il.append($name_res.jast);
 
3950
            
 
3951
            # Get lookup hint if possible.
 
3952
            my int $hint := -1;
 
3953
            if @args[1].has_compile_time_value {
 
3954
                $hint := nqp::attrhintfor(@args[1].compile_time_value, $name);
 
3955
            }
 
3956
            
 
3957
            # Go by whether it's a bind or lookup.
 
3958
            my $type := rttype_from_typeobj($node.returns);
 
3959
            my $jtype := jtype($type);
 
3960
            my $suffix := $type == $RT_OBJ ?? '' !! '_' ~ typechar($type);
 
3961
            if $*BINDVAL {
 
3962
                my $val_res := self.as_jast_clear_bindval($*BINDVAL, :want($type));
 
3963
                $il.append($val_res.jast);
 
3964
                $*STACK.obtain($il, $obj_res, $han_res, $name_res, $val_res);
 
3965
                $il.append(JAST::PushIVal.new( :value($hint) ));
 
3966
                $il.append($ALOAD_1);
 
3967
                $il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
 
3968
                    "bindattr$suffix", $jtype, $TYPE_SMO, $TYPE_SMO, $TYPE_STR, $jtype, 'Long', $TYPE_TC ));
 
3969
            }
 
3970
            else {
 
3971
                $*STACK.obtain($il, $obj_res, $han_res, $name_res);
 
3972
                $il.append(JAST::PushIVal.new( :value($hint) ));
 
3973
                $il.append($ALOAD_1);
 
3974
                $il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
 
3975
                    "getattr$suffix", $jtype, $TYPE_SMO, $TYPE_SMO, $TYPE_STR, 'Long', $TYPE_TC ));
 
3976
            }
 
3977
            
 
3978
            return result($il, $type);
 
3979
        }
 
3980
        elsif $scope eq 'positional' {
 
3981
            return self.as_jast_clear_bindval($*BINDVAL
 
3982
                ?? QAST::Op.new( :op('positional_bind'), |$node.list, $*BINDVAL)
 
3983
                !! QAST::Op.new( :op('positional_get'), |$node.list));
 
3984
        }
 
3985
        elsif $scope eq 'associative' {
 
3986
            return self.as_jast_clear_bindval($*BINDVAL
 
3987
                ?? QAST::Op.new( :op('associative_bind'), |$node.list, $*BINDVAL)
 
3988
                !! QAST::Op.new( :op('associative_get'), |$node.list));
 
3989
        }
 
3990
        else {
 
3991
            nqp::die("QAST::Var with scope '$scope' NYI");
 
3992
        }
 
3993
    }
 
3994
    
 
3995
    method as_jast_clear_bindval($node, :$want) {
 
3996
        my $*BINDVAL := 0;
 
3997
        nqp::defined($want) ?? self.as_jast($node, :$want) !! self.as_jast($node)
 
3998
    }
 
3999
    
 
4000
    method as_jast_in_handler($node, $*HANDLER_IDX, :$want) {
 
4001
        my $*BINDVAL := 0;
 
4002
        nqp::defined($want) ?? self.as_jast($node, :$want) !! self.as_jast($node)
 
4003
    }
 
4004
    
 
4005
    multi method as_jast(QAST::Want $node, :$want) {
 
4006
        # If we're not in a coercive context, take the default.
 
4007
        self.as_jast($node[0])
 
4008
    }
 
4009
    
 
4010
    multi method as_jast(QAST::IVal $node, :$want) {
 
4011
        result(JAST::PushIVal.new( :value($node.value) ), $RT_INT)
 
4012
    }
 
4013
    
 
4014
    multi method as_jast(QAST::NVal $node, :$want) {
 
4015
        result(JAST::PushNVal.new( :value($node.value) ), $RT_NUM)
 
4016
    }
 
4017
    
 
4018
    multi method as_jast(QAST::SVal $node, :$want) {
 
4019
        if nqp::chars($node.value) <= 65535 {
 
4020
            result(JAST::PushSVal.new( :value($node.value) ), $RT_STR)
 
4021
        }
 
4022
        else {
 
4023
            my @chunks;
 
4024
            my $value := $node.value;
 
4025
            while nqp::chars($value) > 65535 {
 
4026
                nqp::push(@chunks, nqp::substr($value, 0, 65535));
 
4027
                $value := nqp::substr($value, 65535);
 
4028
            }
 
4029
            nqp::push(@chunks, $value);
 
4030
            my $il := JAST::InstructionList.new();
 
4031
            $il.append(JAST::PushIndex.new( :value(nqp::elems(@chunks)) ));
 
4032
            $il.append(JAST::Instruction.new( :op('anewarray'), $TYPE_STR ));
 
4033
            my int $i := 0;
 
4034
            for @chunks {
 
4035
                $il.append($DUP);
 
4036
                $il.append(JAST::PushIndex.new( :value($i++) ));
 
4037
                $il.append(JAST::PushSVal.new( :value($_) ));
 
4038
                $il.append($AASTORE);
 
4039
            }
 
4040
            $il.append(JAST::Instruction.new( :op('invokestatic'),
 
4041
                $TYPE_OPS, 'join_literal', $TYPE_STR, "[$TYPE_STR" ));
 
4042
            result($il, $RT_STR)
 
4043
        }
 
4044
    }
 
4045
    
 
4046
    multi method as_jast(QAST::BVal $node, :$want) {
 
4047
        my $il := JAST::InstructionList.new();
 
4048
        $il.append($ALOAD_0);
 
4049
        $il.append(JAST::PushIndex.new( :value(self.cuid_to_qbid($node.value.cuid)) ));
 
4050
        $il.append(JAST::Instruction.new( :op('invokevirtual'),
 
4051
            $TYPE_CU, 'lookupCodeRef', $TYPE_CR, 'I' ));
 
4052
        result($il, $RT_OBJ)
 
4053
    }
 
4054
    
 
4055
     multi method as_jast(QAST::WVal $node, :$want) {
 
4056
        my $val    := $node.value;
 
4057
        my $sc     := nqp::getobjsc($val);
 
4058
        my $handle := nqp::scgethandle($sc);
 
4059
        my $idx    := nqp::scgetobjidx($sc, $val);
 
4060
        my $il     := JAST::InstructionList.new();
 
4061
        $il.append(JAST::PushSVal.new( :value($handle) ));
 
4062
        $il.append(JAST::PushIndex.new( :value($idx) ));
 
4063
        $il.append($ALOAD_1);
 
4064
        $il.append(JAST::InvokeDynamic.new(
 
4065
            'wval_noa', $TYPE_SMO, [$TYPE_STR, 'I', $TYPE_TC],
 
4066
            'org/perl6/nqp/runtime/IndyBootstrap', 'wval_noa'
 
4067
        ));
 
4068
        result($il, $RT_OBJ);
 
4069
    }
 
4070
    
 
4071
    method coerce($res, $desired) {
 
4072
        my $got := $res.type;
 
4073
        if $got == $desired {
 
4074
            return $res;
 
4075
        }
 
4076
        else {
 
4077
            my $coerced := JAST::InstructionList.new();
 
4078
            $coerced.append($res.jast);
 
4079
            $*STACK.obtain($coerced, $res);
 
4080
            $coerced.append(self.coercion($res, $desired));
 
4081
            return result($coerced, $desired);
 
4082
        }
 
4083
    }
 
4084
    
 
4085
    # Expects that the value in need of coercing has already been
 
4086
    # obtained (and thus is on the stack top). Produces instructions
 
4087
    # to coerce it. Doesn't touch the stack tracking.
 
4088
    method coercion($res, $desired) {
 
4089
        my $il := JAST::InstructionList.new();
 
4090
        my $got := $res.type;
 
4091
        if $got == $desired {
 
4092
            # Nothing to do.
 
4093
        }
 
4094
        elsif $desired == $RT_VOID {
 
4095
            $il.append(pop_ins($got));
 
4096
        }
 
4097
        elsif $desired == $RT_OBJ {
 
4098
            my $hll := '';
 
4099
            try $hll := $*HLL;
 
4100
            return QAST::OperationsJAST.box(self, $hll, $got);
 
4101
        }
 
4102
        elsif $got == $RT_OBJ {
 
4103
            my $hll := '';
 
4104
            try $hll := $*HLL;
 
4105
            return QAST::OperationsJAST.unbox(self, $hll, $desired);
 
4106
        }
 
4107
        elsif $desired == $RT_INT {
 
4108
            if $got == $RT_NUM {
 
4109
                $il.append($D2L);
 
4110
            }
 
4111
            elsif $got == $RT_STR {
 
4112
                $il.append(JAST::Instruction.new( :op('invokestatic'),
 
4113
                    $TYPE_OPS, 'coerce_s2i', 'Long', $TYPE_STR ));
 
4114
            }
 
4115
            else {
 
4116
                nqp::die("Unknown coercion case for int");
 
4117
            }
 
4118
        }
 
4119
        elsif $desired == $RT_NUM {
 
4120
            if $got == $RT_INT {
 
4121
                $il.append($L2D);
 
4122
            }
 
4123
            elsif $got == $RT_STR {
 
4124
                $il.append(JAST::Instruction.new( :op('invokestatic'),
 
4125
                    $TYPE_OPS, 'coerce_s2n', 'Double', $TYPE_STR ));
 
4126
            }
 
4127
            else {
 
4128
                nqp::die("Unknown coercion case for num");
 
4129
            }
 
4130
        }
 
4131
        elsif $desired == $RT_STR {
 
4132
            if $got == $RT_INT {
 
4133
                $il.append(JAST::Instruction.new( :op('invokestatic'),
 
4134
                    $TYPE_OPS, 'coerce_i2s', $TYPE_STR, 'Long' ));
 
4135
            }
 
4136
            elsif $got == $RT_NUM {
 
4137
                $il.append(JAST::Instruction.new( :op('invokestatic'),
 
4138
                    $TYPE_OPS, 'coerce_n2s', $TYPE_STR, 'Double' ));
 
4139
            }
 
4140
            else {
 
4141
                nqp::die("Unknown coercion case for str");
 
4142
            }
 
4143
        }
 
4144
        else {
 
4145
            nqp::die("Coercion from type '$got' to '$desired' NYI");
 
4146
        }
 
4147
        $il
 
4148
    }
 
4149
    
 
4150
    # Checks if we have reached the correct unwind target. If not, does a
 
4151
    # rethrow of the handler. Assumes the exception is on the stack top,
 
4152
    # and that we will not swallow it.
 
4153
    my $unwind_lbl := 0;
 
4154
    method unwind_check($il, $desired) {
 
4155
        my $lbl_i := JAST::Label.new( :name('unwind_' ~ $unwind_lbl++) );
 
4156
        my $lbl_c := JAST::Label.new( :name('unwind_' ~ $unwind_lbl++) );
 
4157
        $il.append($DUP);
 
4158
        $il.append(JAST::Instruction.new( :op('getfield'), $TYPE_EX_UNWIND, 'unwindTarget', 'Long' ));
 
4159
        $il.append(JAST::PushIVal.new( :value($desired) ));
 
4160
        $il.append($LCMP);
 
4161
        $il.append(JAST::Instruction.new( :op('ifeq'), $lbl_i ));
 
4162
        $il.append($ATHROW);
 
4163
        $il.append($lbl_i);
 
4164
        $il.append($DUP);
 
4165
        $il.append(JAST::Instruction.new( :op('getfield'), $TYPE_EX_UNWIND, 'unwindCompUnit', $TYPE_CU ));
 
4166
        $il.append($ALOAD_0);
 
4167
        $il.append(JAST::Instruction.new( :op('if_acmpeq'), $lbl_c ));
 
4168
        $il.append($ATHROW);
 
4169
        $il.append($lbl_c);
 
4170
    }
 
4171
    
 
4172
    # Wraps a handler with code to set/clear the current handler.
 
4173
    method delimit_handler($wrap_il, $outer, $inner) {
 
4174
        my $il := JAST::InstructionList.new();
 
4175
        $il.append(JAST::Instruction.new( :op('aload'), 'cf' ));
 
4176
        $il.append(JAST::PushIVal.new( :value($inner) ));
 
4177
        $il.append(JAST::Instruction.new( :op('putfield'), $TYPE_CF, 'curHandler', 'Long' ));
 
4178
        $il.append($wrap_il);
 
4179
        $il.append(JAST::Instruction.new( :op('aload'), 'cf' ));
 
4180
        $il.append(JAST::PushIVal.new( :value($outer) ));
 
4181
        $il.append(JAST::Instruction.new( :op('putfield'), $TYPE_CF, 'curHandler', 'Long' ));
 
4182
        $il
 
4183
    }
 
4184
 
 
4185
    # Emits an exception throw.
 
4186
    sub emit_throw($il, $type = 'Ljava/lang/Exception;') {
 
4187
        $il.append(JAST::Instruction.new( :op('new'), $type ));
 
4188
        $il.append($DUP);
 
4189
        $il.append(JAST::Instruction.new( :op('invokespecial'), $type, '<init>', 'Void' ));
 
4190
        $il.append($ATHROW);
 
4191
    }
 
4192
    
 
4193
    multi method as_jast(QAST::Regex $node, :$want) {
 
4194
        # build the list of (unique) locals we need
 
4195
        my %*REG;
 
4196
        my $prefix := self.unique('rx') ~ '_';
 
4197
        my $reglist := nqp::split(' ', 'start o tgt s pos i off i eos i rep i cur o curclass o bstack o cstack o restart i itemp i altmarks o subcur o');
 
4198
        while $reglist {
 
4199
            my $reg := nqp::shift($reglist);
 
4200
            my $tc := nqp::shift($reglist);
 
4201
            my $type := $tc eq 'i' ?? int !! $tc eq 's' ?? str !! NQPMu;
 
4202
            %*REG{$reg} := $prefix ~ $reg;
 
4203
            $*BLOCK.add_local(QAST::Var.new( :name($prefix ~ $reg), :scope('local'), :returns($type), :decl('var') ));
 
4204
        }
 
4205
 
 
4206
        # create our labels
 
4207
        my $startlabel   := JAST::Label.new( :name($prefix ~ 'start') );
 
4208
        my $endlabel     := JAST::Label.new( :name($prefix ~ 'end') );
 
4209
        my $donelabel    := JAST::Label.new( :name($prefix ~ 'done') );
 
4210
        my $restartlabel := JAST::Label.new( :name($prefix ~ 'restart') );
 
4211
        my $faillabel    := JAST::Label.new( :name($prefix ~ 'fail') );
 
4212
        my $jumplabel    := JAST::Label.new( :name($prefix ~ 'jump' ));
 
4213
        my $cutlabel     := JAST::Label.new( :name($prefix ~ 'cut') );
 
4214
        my $cstacklabel  := JAST::Label.new( :name($prefix ~ 'cstack_done') );
 
4215
        %*REG<fail>      := $faillabel;
 
4216
        
 
4217
        # label to index mapping, for the jump table
 
4218
        my @mark_labels;
 
4219
        my %mark_lookup;
 
4220
        my &*REGISTER_MARK := sub ($label) {
 
4221
            my $idx := nqp::elems(@mark_labels);
 
4222
            nqp::push(@mark_labels, $label);
 
4223
            %mark_lookup{$label.name} := $idx
 
4224
        }
 
4225
        &*REGISTER_MARK($faillabel);
 
4226
 
 
4227
        # common prologue
 
4228
        my $il := JAST::InstructionList.new();
 
4229
        my $csa_res := self.as_jast(QAST::Stmt.new(
 
4230
            QAST::Op.new(
 
4231
                :op('bind'),
 
4232
                QAST::Var.new( :name(%*REG<start>), :scope('local') ),
 
4233
                QAST::Op.new(
 
4234
                    :op('callmethod'), :name('!cursor_start_all'),
 
4235
                    QAST::Var.new( :name('self'), :scope('local') )
 
4236
                )),
 
4237
            QAST::Op.new(
 
4238
                :op('bind'),
 
4239
                QAST::Var.new( :name("\$\xa2"), :scope('lexical') ),
 
4240
                QAST::Op.new(
 
4241
                    :op('bind'),
 
4242
                    QAST::Var.new( :name(%*REG<cur>), :scope('local') ),
 
4243
                    QAST::Op.new(
 
4244
                        :op('atpos'),
 
4245
                        QAST::Var.new( :name(%*REG<start>), :scope('local') ),
 
4246
                        QAST::IVal.new( :value(0) )
 
4247
                    ))),
 
4248
            QAST::Op.new(
 
4249
                :op('bind'),
 
4250
                QAST::Var.new( :name(%*REG<pos>), :scope('local'), :returns(int) ),
 
4251
                QAST::Op.new(
 
4252
                    :op('unbox_i'),
 
4253
                    QAST::Op.new(
 
4254
                        :op('atpos'),
 
4255
                        QAST::Var.new( :name(%*REG<start>), :scope('local') ),
 
4256
                        QAST::IVal.new( :value(2) )
 
4257
                    ))),
 
4258
            QAST::Op.new(
 
4259
                :op('bind'),
 
4260
                QAST::Var.new( :name(%*REG<curclass>), :scope('local') ),
 
4261
                QAST::Op.new(
 
4262
                    :op('atpos'),
 
4263
                    QAST::Var.new( :name(%*REG<start>), :scope('local') ),
 
4264
                    QAST::IVal.new( :value(3) )
 
4265
                )),
 
4266
            QAST::Op.new(
 
4267
                :op('bind'),
 
4268
                QAST::Var.new( :name(%*REG<bstack>), :scope('local') ),
 
4269
                QAST::Op.new(
 
4270
                    :op('atpos'),
 
4271
                    QAST::Var.new( :name(%*REG<start>), :scope('local') ),
 
4272
                    QAST::IVal.new( :value(4) )
 
4273
                )),
 
4274
            QAST::Op.new(
 
4275
                :op('bind'),
 
4276
                QAST::Var.new( :name(%*REG<altmarks>), :scope('local') ),
 
4277
                QAST::Op.new( :op('create'), QAST::Op.new( :op('bootintarray') ) )
 
4278
            ),
 
4279
            QAST::Op.new(
 
4280
                :op('bind'),
 
4281
                QAST::Var.new( :name(%*REG<restart>), :scope('local'), :returns(int) ),
 
4282
                QAST::Op.new(
 
4283
                    :op('unbox_i'),
 
4284
                    QAST::Op.new(
 
4285
                        :op('atpos'),
 
4286
                        QAST::Var.new( :name(%*REG<start>), :scope('local') ),
 
4287
                        QAST::IVal.new( :value(5) )
 
4288
                    ))),
 
4289
            QAST::Op.new(
 
4290
                :op('bind'),
 
4291
                QAST::Var.new( :name(%*REG<tgt>), :scope('local'), :returns(str) ),
 
4292
                QAST::Op.new(
 
4293
                    :op('unbox_s'),
 
4294
                    QAST::Op.new(
 
4295
                        :op('atpos'),
 
4296
                        QAST::Var.new( :name(%*REG<start>), :scope('local') ),
 
4297
                        QAST::IVal.new( :value(1) )
 
4298
                    )))));
 
4299
        $il.append($csa_res.jast);
 
4300
        $*STACK.obtain($il, $csa_res);
 
4301
        $il.append(JAST::Instruction.new( :op('invokestatic'),
 
4302
            $TYPE_OPS, 'chars', 'Long', $TYPE_STR ));
 
4303
        $il.append(JAST::Instruction.new( :op('lstore'), %*REG<eos> ));
 
4304
        $il.append($ACONST_NULL);
 
4305
        $il.append(JAST::Instruction.new( :op('astore'), %*REG<cstack> ));
 
4306
        $il.append($ACONST_NULL);
 
4307
        $il.append(JAST::Instruction.new( :op('astore'), %*REG<subcur> ));
 
4308
        $il.append($IVAL_ZERO);
 
4309
        $il.append(JAST::Instruction.new( :op('lstore'), %*REG<rep> ));
 
4310
        $il.append(JAST::Instruction.new( :op('lload'), %*REG<restart> ));
 
4311
        $il.append($L2I);
 
4312
        $il.append(JAST::Instruction.new( :op('ifne'), $restartlabel ));
 
4313
        $il.append(JAST::Instruction.new( :op('lload'), %*REG<pos> ));
 
4314
        $il.append(JAST::Instruction.new( :op('lload'), %*REG<eos> ));
 
4315
        $il.append($LCMP);
 
4316
        $il.append(JAST::Instruction.new( :op('ifgt'), %*REG<fail> ));
 
4317
        
 
4318
        # Compile the regex body itself; if we make it thorugh it, we go to
 
4319
        # the end and are finished.
 
4320
        $il.append(self.regex_jast($node));
 
4321
        $il.append(JAST::Instruction.new( :op('goto'), $endlabel ));
 
4322
        
 
4323
        # Restart.
 
4324
        $il.append($restartlabel);
 
4325
        $il.append(JAST::Instruction.new( :op('aload'), %*REG<cur> ));
 
4326
        $il.append(JAST::Instruction.new( :op('aload'), %*REG<curclass> ));
 
4327
        $il.append(JAST::PushSVal.new( :value('$!cstack') ));
 
4328
        $il.append($ALOAD_1);
 
4329
        $il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
 
4330
            "getattr", $TYPE_SMO, $TYPE_SMO, $TYPE_SMO, $TYPE_STR, $TYPE_TC ));
 
4331
        $il.append(JAST::Instruction.new( :op('astore'), %*REG<cstack> ));
 
4332
        
 
4333
        # Failure/backtrack handling. If no bstack, we're done.
 
4334
        $il.append($faillabel);
 
4335
        $il.append(JAST::Instruction.new( :op('aload'), %*REG<bstack> ));
 
4336
        $il.append($ALOAD_1);
 
4337
        $il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
 
4338
                "elems", 'Long', $TYPE_SMO, $TYPE_TC ));
 
4339
        $il.append($L2I);
 
4340
        $il.append(JAST::Instruction.new( :op('ifeq'), $donelabel ));
 
4341
        
 
4342
        # Otherwise, start handling the cstack, if it's not empty.
 
4343
        # The setup done here is used when we backtrack into subrules.
 
4344
        $il.append(JAST::Instruction.new( :op('aload'), %*REG<bstack> ));
 
4345
        $il.append($ALOAD_1);
 
4346
        $il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
 
4347
                "pop_i", 'Long', $TYPE_SMO, $TYPE_TC ));
 
4348
        $il.append(JAST::Instruction.new( :op('lstore'), %*REG<itemp> ));
 
4349
        $il.append(JAST::Instruction.new( :op('aload'), %*REG<cstack> ));
 
4350
        $il.append($ALOAD_1);
 
4351
        $il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
 
4352
            "islist", 'Long', $TYPE_SMO, $TYPE_TC ));
 
4353
        $il.append($L2I);
 
4354
        $il.append(JAST::Instruction.new( :op('ifeq'), $cstacklabel ));
 
4355
        $il.append(JAST::Instruction.new( :op('aload'), %*REG<cstack> ));
 
4356
        $il.append($ALOAD_1);
 
4357
        $il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
 
4358
                "elems", 'Long', $TYPE_SMO, $TYPE_TC ));
 
4359
        $il.append($L2I);
 
4360
        $il.append(JAST::Instruction.new( :op('ifeq'), $cstacklabel ));
 
4361
        $il.append(JAST::Instruction.new( :op('aload'), %*REG<cstack> ));
 
4362
        $il.append(JAST::Instruction.new( :op('lload'), %*REG<itemp> ));
 
4363
        $il.append($IVAL_ONE);
 
4364
        $il.append($LSUB);
 
4365
        $il.append($ALOAD_1);
 
4366
        $il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
 
4367
                "atpos", $TYPE_SMO, $TYPE_SMO, 'Long', $TYPE_TC ));
 
4368
        $il.append(JAST::Instruction.new( :op('astore'), %*REG<subcur> ));
 
4369
        $il.append($cstacklabel);
 
4370
        
 
4371
        # Pop rep, pos and mark off the stack and store them.
 
4372
        $il.append(JAST::Instruction.new( :op('aload'), %*REG<bstack> ));
 
4373
        $il.append($ALOAD_1);
 
4374
        $il.append($DUP2);
 
4375
        $il.append($DUP2);
 
4376
        $il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
 
4377
                "pop_i", 'Long', $TYPE_SMO, $TYPE_TC ));
 
4378
        $il.append(JAST::Instruction.new( :op('lstore'), %*REG<rep> ));
 
4379
        $il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
 
4380
                "pop_i", 'Long', $TYPE_SMO, $TYPE_TC ));
 
4381
        $il.append(JAST::Instruction.new( :op('lstore'), %*REG<pos> ));
 
4382
        $il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
 
4383
                "pop_i", 'Long', $TYPE_SMO, $TYPE_TC ));
 
4384
        $il.append(JAST::Instruction.new( :op('lstore'), %*REG<itemp> ));
 
4385
        
 
4386
        # Handle position and mark special cases.
 
4387
        $il.append(JAST::Instruction.new( :op('lload'), %*REG<pos> ));
 
4388
        $il.append($IVAL_MINUSONE);
 
4389
        $il.append($LCMP);
 
4390
        $il.append(JAST::Instruction.new( :op('iflt'), $donelabel ));
 
4391
        $il.append(JAST::Instruction.new( :op('lload'), %*REG<pos> ));
 
4392
        $il.append($IVAL_ZERO);
 
4393
        $il.append($LCMP);
 
4394
        $il.append(JAST::Instruction.new( :op('iflt'), $faillabel ));
 
4395
        $il.append(JAST::Instruction.new( :op('lload'), %*REG<itemp> ));
 
4396
        $il.append($IVAL_ZERO);
 
4397
        $il.append($LCMP);
 
4398
        $il.append(JAST::Instruction.new( :op('ifeq'), $faillabel ));
 
4399
        
 
4400
        # Backtrack the cursor stack
 
4401
        $il.append(JAST::Instruction.new( :op('aload'), %*REG<cstack> ));
 
4402
        $il.append(JAST::Instruction.new( :op('ifnull'), $jumplabel ));
 
4403
        $il.append(JAST::Instruction.new( :op('aload'), %*REG<cstack> ));
 
4404
        $il.append($ALOAD_1);
 
4405
        $il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
 
4406
            "islist", 'Long', $TYPE_SMO, $TYPE_TC ));
 
4407
        $il.append($L2I);
 
4408
        $il.append(JAST::Instruction.new( :op('ifeq'), $jumplabel ));
 
4409
        
 
4410
        $il.append(JAST::Instruction.new( :op('aload'), %*REG<cstack> ));
 
4411
        $il.append($ALOAD_1);
 
4412
        $il.append(JAST::Instruction.new( :op('aload'), %*REG<bstack> ));
 
4413
        $il.append($ALOAD_1);
 
4414
        $il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
 
4415
            "elems", 'Long', $TYPE_SMO, $TYPE_TC ));
 
4416
        $il.append($DUP2);
 
4417
        $il.append($L2I);
 
4418
        $il.append(JAST::Instruction.new( :op('ifeq'), $cutlabel ));
 
4419
        
 
4420
        $il.append($IVAL_ONE);
 
4421
        $il.append($LSUB);
 
4422
        $il.append(JAST::Instruction.new( :op('aload'), %*REG<bstack> ));
 
4423
        $il.append($DUP_X2);
 
4424
        $il.append($POP);
 
4425
        $il.append($ALOAD_1);
 
4426
        $il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
 
4427
            "atpos_i", 'Long', $TYPE_SMO, 'Long', $TYPE_TC ));
 
4428
        
 
4429
        $il.append($cutlabel);
 
4430
        $il.append(JAST::Instruction.new( :op('invokevirtual'), $TYPE_SMO,
 
4431
            "set_elems", 'Void', $TYPE_TC, 'Long' ));
 
4432
        
 
4433
        # Otherwise, we need to jump to the appropriate label. Emit the
 
4434
        # jump table.
 
4435
        $il.append($jumplabel);
 
4436
        $il.append(JAST::Instruction.new( :op('lload'), %*REG<itemp> ));
 
4437
        $il.append($L2I);
 
4438
        my $ts := JAST::Instruction.new( :op('tableswitch'), $donelabel );
 
4439
        for @mark_labels {
 
4440
            $ts.push($_);
 
4441
        }
 
4442
        $il.append($ts);
 
4443
        
 
4444
        # If we make it to here, we failed to match.
 
4445
        $il.append($donelabel);
 
4446
        my $fail_res := self.as_jast(QAST::Op.new(
 
4447
            :op('callmethod'), :name('!cursor_fail'),
 
4448
            QAST::Var.new( :name(%*REG<cur>), :scope('local') )
 
4449
        ));
 
4450
        $il.append($fail_res.jast);
 
4451
        $*STACK.obtain($il, $fail_res);
 
4452
        $il.append($POP);
 
4453
 
 
4454
        # Evaluate to the curosr.
 
4455
        $il.append($endlabel);
 
4456
        $il.append(JAST::Instruction.new( :op('aload'), %*REG<cur> ));
 
4457
        result($il, $RT_OBJ)
 
4458
    }
 
4459
 
 
4460
    method regex_jast($node) {
 
4461
        my $rxtype := $node.rxtype() || 'concat';
 
4462
        self."$rxtype"($node);
 
4463
    }
 
4464
 
 
4465
    method alt($node) {
 
4466
        unless $node.name {
 
4467
            return self.altseq($node);
 
4468
        }
 
4469
 
 
4470
        # Calculate all the branches to try, which populates the bstack
 
4471
        # with the options. Then immediately fail to start iterating it.
 
4472
        my $prefix   := self.unique('alt') ~ '_';
 
4473
        my $endlabel := JAST::Label.new( :name($prefix ~ 'end') );
 
4474
        my $il_marks := JAST::InstructionList.new();
 
4475
        my $il_alts  := JAST::InstructionList.new();
 
4476
        $il_marks.append(JAST::Instruction.new( :op('aload'), %*REG<altmarks> ));
 
4477
        $il_marks.append($ALOAD_1);
 
4478
        $il_marks.append($IVAL_ZERO);
 
4479
        $il_marks.append(JAST::Instruction.new( :op('invokevirtual'), $TYPE_SMO,
 
4480
            "set_elems", 'Void', $TYPE_TC, 'Long' ));
 
4481
        
 
4482
        my $mark_endlabel := &*REGISTER_MARK($endlabel);
 
4483
        self.regex_mark($il_alts, $mark_endlabel,
 
4484
            $IVAL_MINUSONE,
 
4485
            $IVAL_ZERO);
 
4486
        
 
4487
        my $altmeth := QAST::Op.new(
 
4488
            :op('callmethod'), :name('!alt'),
 
4489
            QAST::Var.new( :name(%*REG<cur>), :scope('local') ),
 
4490
            QAST::Var.new( :name(%*REG<pos>), :scope('local'), :returns(int) ),
 
4491
            QAST::SVal.new( :value($node.name) ),
 
4492
            QAST::Var.new( :name(%*REG<altmarks>), :scope('local') )
 
4493
        );
 
4494
        my $altres := self.as_jast($altmeth, :want($RT_VOID));
 
4495
        $il_alts.append($altres.jast);
 
4496
        $*STACK.obtain($il_alts, $altres);
 
4497
        $il_alts.append(JAST::Instruction.new( :op('goto'), %*REG<fail> ));
 
4498
 
 
4499
        # Emit all the possible alternations.
 
4500
        my $altcount := 0;
 
4501
        my $iter     := nqp::iterator($node.list);
 
4502
        while $iter {
 
4503
            my $altlabel := JAST::Label.new( :name($prefix ~ $altcount) );
 
4504
            my $ajast    := self.regex_jast(nqp::shift($iter));
 
4505
            $il_alts.append($altlabel);
 
4506
            $il_alts.append($ajast);
 
4507
            $il_alts.append(JAST::Instruction.new( :op('goto'), $endlabel ));
 
4508
            my $altmark := &*REGISTER_MARK($altlabel);
 
4509
            $il_marks.append(JAST::Instruction.new( :op('aload'), %*REG<altmarks> ));
 
4510
            $il_marks.append(JAST::PushIVal.new( :value($altmark) ));
 
4511
            $il_marks.append($ALOAD_1);
 
4512
            $il_marks.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS, 'push_i',
 
4513
                'Long', $TYPE_SMO, 'Long', $TYPE_TC ));
 
4514
            $il_marks.append($POP2);
 
4515
            $altcount++;
 
4516
        }
 
4517
        
 
4518
        $il_alts.append($endlabel);
 
4519
        self.regex_commit($il_alts, $mark_endlabel) if $node.backtrack eq 'r';
 
4520
        
 
4521
        my $il := JAST::InstructionList.new();
 
4522
        $il.append($il_marks);
 
4523
        $il.append($il_alts);
 
4524
        $il;
 
4525
    }
 
4526
 
 
4527
    method altseq($node) {
 
4528
        my $il       := JAST::InstructionList.new();
 
4529
        my $prefix   := self.unique('alt') ~ '_';
 
4530
        my $altcount := 0;
 
4531
        my $iter     := nqp::iterator($node.list);
 
4532
        my $endlabel := JAST::Label.new( :name($prefix ~ 'end') );
 
4533
        my $altlabel := JAST::Label.new( :name($prefix ~ $altcount) );
 
4534
        my $ajast    := self.regex_jast(nqp::shift($iter));
 
4535
        while $iter {
 
4536
            $il.append($altlabel);
 
4537
            $altcount++;
 
4538
            $altlabel := JAST::Label.new( :name($prefix ~ $altcount) );
 
4539
            my $mark := &*REGISTER_MARK($altlabel);
 
4540
            self.regex_mark($il, $mark,
 
4541
                JAST::Instruction.new( :op('lload'), %*REG<pos> ),
 
4542
                $IVAL_ZERO);
 
4543
            $il.append($ajast);
 
4544
            $il.append(JAST::Instruction.new( :op('goto'), $endlabel ));
 
4545
            $ajast := self.regex_jast(nqp::shift($iter));
 
4546
        }
 
4547
        $il.append($altlabel);
 
4548
        $il.append($ajast);
 
4549
        $il.append($endlabel);
 
4550
        $il;
 
4551
    }
 
4552
    
 
4553
    method anchor($node) {
 
4554
        my $il        := JAST::InstructionList.new();
 
4555
        my $subtype   := $node.subtype;
 
4556
        my $donelabel := JAST::Label.new( :name(self.unique('rxanchor') ~ '_done') );
 
4557
        if $subtype eq 'bos' {
 
4558
            $il.append(JAST::Instruction.new( :op('lload'), %*REG<pos> ));
 
4559
            $il.append($L2I);
 
4560
            $il.append(JAST::Instruction.new( :op('ifne'), %*REG<fail> ));
 
4561
        }
 
4562
        elsif $subtype eq 'eos' {
 
4563
            $il.append(JAST::Instruction.new( :op('lload'), %*REG<pos> ));
 
4564
            $il.append(JAST::Instruction.new( :op('lload'), %*REG<eos> ));
 
4565
            $il.append($LCMP);
 
4566
            $il.append(JAST::Instruction.new( :op('iflt'), %*REG<fail> ));
 
4567
        }
 
4568
        elsif $subtype eq 'lwb' {
 
4569
            $il.append(JAST::Instruction.new( :op('lload'), %*REG<pos> ));
 
4570
            $il.append(JAST::Instruction.new( :op('lload'), %*REG<eos> ));
 
4571
            $il.append($LCMP);
 
4572
            $il.append(JAST::Instruction.new( :op('ifge'), %*REG<fail> ));
 
4573
            
 
4574
            $il.append(JAST::PushIVal.new( :value(nqp::const::CCLASS_WORD) ));
 
4575
            $il.append(JAST::Instruction.new( :op('aload'), %*REG<tgt> ));
 
4576
            $il.append(JAST::Instruction.new( :op('lload'), %*REG<pos> ));
 
4577
            $il.append(JAST::Instruction.new( :op('invokestatic'),
 
4578
                $TYPE_OPS, 'iscclass', 'Long', 'Long', $TYPE_STR, 'Long' ));
 
4579
            $il.append($L2I);
 
4580
            $il.append(JAST::Instruction.new( :op('ifeq'), %*REG<fail> ));
 
4581
            
 
4582
            $il.append(JAST::PushIVal.new( :value(nqp::const::CCLASS_WORD) ));
 
4583
            $il.append(JAST::Instruction.new( :op('aload'), %*REG<tgt> ));
 
4584
            $il.append(JAST::Instruction.new( :op('lload'), %*REG<pos> ));
 
4585
            $il.append($IVAL_ONE);
 
4586
            $il.append($LSUB);
 
4587
            $il.append(JAST::Instruction.new( :op('invokestatic'),
 
4588
                $TYPE_OPS, 'iscclass', 'Long', 'Long', $TYPE_STR, 'Long' ));
 
4589
            $il.append($L2I);
 
4590
            $il.append(JAST::Instruction.new( :op('ifne'), %*REG<fail> ));
 
4591
        }
 
4592
        elsif $subtype eq 'rwb' {
 
4593
            $il.append(JAST::Instruction.new( :op('lload'), %*REG<pos> ));
 
4594
            $il.append($IVAL_ZERO);
 
4595
            $il.append($LCMP);
 
4596
            $il.append(JAST::Instruction.new( :op('ifle'), %*REG<fail> ));
 
4597
            
 
4598
            $il.append(JAST::PushIVal.new( :value(nqp::const::CCLASS_WORD) ));
 
4599
            $il.append(JAST::Instruction.new( :op('aload'), %*REG<tgt> ));
 
4600
            $il.append(JAST::Instruction.new( :op('lload'), %*REG<pos> ));
 
4601
            $il.append(JAST::Instruction.new( :op('invokestatic'),
 
4602
                $TYPE_OPS, 'iscclass', 'Long', 'Long', $TYPE_STR, 'Long' ));
 
4603
            $il.append($L2I);
 
4604
            $il.append(JAST::Instruction.new( :op('ifne'), %*REG<fail> ));
 
4605
            
 
4606
            $il.append(JAST::PushIVal.new( :value(nqp::const::CCLASS_WORD) ));
 
4607
            $il.append(JAST::Instruction.new( :op('aload'), %*REG<tgt> ));
 
4608
            $il.append(JAST::Instruction.new( :op('lload'), %*REG<pos> ));
 
4609
            $il.append($IVAL_ONE);
 
4610
            $il.append($LSUB);
 
4611
            $il.append(JAST::Instruction.new( :op('invokestatic'),
 
4612
                $TYPE_OPS, 'iscclass', 'Long', 'Long', $TYPE_STR, 'Long' ));
 
4613
            $il.append($L2I);
 
4614
            $il.append(JAST::Instruction.new( :op('ifeq'), %*REG<fail> ));
 
4615
        }
 
4616
        elsif $subtype eq 'bol' {
 
4617
            $il.append(JAST::Instruction.new( :op('lload'), %*REG<pos> ));
 
4618
            $il.append($L2I);
 
4619
            $il.append(JAST::Instruction.new( :op('ifeq'), $donelabel ));
 
4620
            
 
4621
            $il.append(JAST::Instruction.new( :op('lload'), %*REG<pos> ));
 
4622
            $il.append(JAST::Instruction.new( :op('lload'), %*REG<eos> ));
 
4623
            $il.append($LCMP);
 
4624
            $il.append(JAST::Instruction.new( :op('ifge'), %*REG<fail> ));
 
4625
            
 
4626
            $il.append(JAST::PushIVal.new( :value(nqp::const::CCLASS_NEWLINE) ));
 
4627
            $il.append(JAST::Instruction.new( :op('aload'), %*REG<tgt> ));
 
4628
            $il.append(JAST::Instruction.new( :op('lload'), %*REG<pos> ));
 
4629
            $il.append($IVAL_ONE);
 
4630
            $il.append($LSUB);
 
4631
            $il.append(JAST::Instruction.new( :op('invokestatic'),
 
4632
                $TYPE_OPS, 'iscclass', 'Long', 'Long', $TYPE_STR, 'Long' ));
 
4633
            $il.append($L2I);
 
4634
            $il.append(JAST::Instruction.new( :op('ifeq'), %*REG<fail> ));
 
4635
            
 
4636
            $il.append($donelabel);
 
4637
        }
 
4638
        elsif $subtype eq 'eol' {
 
4639
            $il.append(JAST::PushIVal.new( :value(nqp::const::CCLASS_NEWLINE) ));
 
4640
            $il.append(JAST::Instruction.new( :op('aload'), %*REG<tgt> ));
 
4641
            $il.append(JAST::Instruction.new( :op('lload'), %*REG<pos> ));
 
4642
            $il.append(JAST::Instruction.new( :op('invokestatic'),
 
4643
                $TYPE_OPS, 'iscclass', 'Long', 'Long', $TYPE_STR, 'Long' ));
 
4644
            $il.append($L2I);
 
4645
            $il.append(JAST::Instruction.new( :op('ifne'), $donelabel ));
 
4646
            
 
4647
            $il.append(JAST::Instruction.new( :op('lload'), %*REG<pos> ));
 
4648
            $il.append(JAST::Instruction.new( :op('lload'), %*REG<eos> ));
 
4649
            $il.append($LCMP);
 
4650
            $il.append(JAST::Instruction.new( :op('ifne'), %*REG<fail> ));
 
4651
            
 
4652
            $il.append(JAST::Instruction.new( :op('lload'), %*REG<pos> ));
 
4653
            $il.append($L2I);
 
4654
            $il.append(JAST::Instruction.new( :op('ifeq'), $donelabel ));
 
4655
            
 
4656
            $il.append(JAST::PushIVal.new( :value(nqp::const::CCLASS_NEWLINE) ));
 
4657
            $il.append(JAST::Instruction.new( :op('aload'), %*REG<tgt> ));
 
4658
            $il.append(JAST::Instruction.new( :op('lload'), %*REG<pos> ));
 
4659
            $il.append($IVAL_ONE);
 
4660
            $il.append($LSUB);
 
4661
            $il.append(JAST::Instruction.new( :op('invokestatic'),
 
4662
                $TYPE_OPS, 'iscclass', 'Long', 'Long', $TYPE_STR, 'Long' ));
 
4663
            $il.append($L2I);
 
4664
            $il.append(JAST::Instruction.new( :op('ifne'), %*REG<fail> ));
 
4665
            
 
4666
            $il.append($donelabel);
 
4667
        }
 
4668
        elsif $subtype eq 'fail' {
 
4669
            $il.append(JAST::Instruction.new( :op('goto'), %*REG<fail> ));
 
4670
        }
 
4671
 
 
4672
        $il
 
4673
    }
 
4674
 
 
4675
    method concat($node) {
 
4676
        my $il := JAST::InstructionList.new();
 
4677
        for $node.list {
 
4678
            $il.append(self.regex_jast($_))
 
4679
        }
 
4680
        $il
 
4681
    }
 
4682
 
 
4683
    method conj($node) { self.conjseq($node) }
 
4684
    
 
4685
    method conjseq($node) {
 
4686
        my $il         := JAST::InstructionList.new();
 
4687
        my $prefix     := self.unique('rxconj') ~ '_';
 
4688
        my $conjlabel  := JAST::Label.new( :name($prefix ~ 'fail') );
 
4689
        my $firstlabel := JAST::Label.new( :name($prefix ~ 'first') );
 
4690
        my $iter       := nqp::iterator($node.list);
 
4691
        
 
4692
        # make a mark that holds our starting position in the pos slot
 
4693
        my $mark := &*REGISTER_MARK($conjlabel);
 
4694
        self.regex_mark($il, $mark,
 
4695
             JAST::Instruction.new( :op('lload'), %*REG<pos> ),
 
4696
             $IVAL_ZERO);
 
4697
        
 
4698
        $il.append(JAST::Instruction.new( :op('goto'), $firstlabel ));
 
4699
        $il.append($conjlabel);
 
4700
        $il.append(JAST::Instruction.new( :op('goto'), %*REG<fail> ));
 
4701
        
 
4702
        # call the first child
 
4703
        $il.append($firstlabel);
 
4704
        $il.append(self.regex_jast(nqp::shift($iter)));
 
4705
        
 
4706
        # use previous mark to make one with pos=start, rep=end
 
4707
        $il.append(JAST::Instruction.new( :op('aload'), %*REG<bstack> ));
 
4708
        $il.append($DUP);
 
4709
        $il.append(JAST::PushIVal.new( :value($mark) ));
 
4710
        $il.append($ALOAD_1);
 
4711
        $il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
 
4712
            "rxpeek", 'Long', $TYPE_SMO, 'Long', $TYPE_TC ));
 
4713
        $il.append($IVAL_ONE);
 
4714
        $il.append($LADD);
 
4715
        $il.append($ALOAD_1);
 
4716
        $il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
 
4717
            "atpos_i", 'Long', $TYPE_SMO, 'Long', $TYPE_TC ));
 
4718
        $il.append(JAST::Instruction.new( :op('lstore'), %*REG<itemp> ));
 
4719
        self.regex_mark($il, $mark,
 
4720
             JAST::Instruction.new( :op('lload'), %*REG<itemp> ),
 
4721
             JAST::Instruction.new( :op('lload'), %*REG<pos> ));
 
4722
 
 
4723
        while $iter {
 
4724
            $il.append(JAST::Instruction.new( :op('lload'), %*REG<itemp> ));
 
4725
            $il.append(JAST::Instruction.new( :op('lstore'), %*REG<pos> ));
 
4726
            $il.append(self.regex_jast(nqp::shift($iter)));
 
4727
            
 
4728
            $il.append(JAST::Instruction.new( :op('aload'), %*REG<bstack> ));
 
4729
            $il.append(JAST::PushIVal.new( :value($mark) ));
 
4730
            $il.append($ALOAD_1);
 
4731
            $il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
 
4732
                "rxpeek", 'Long', $TYPE_SMO, 'Long', $TYPE_TC ));
 
4733
            $il.append(JAST::Instruction.new( :op('lstore'), %*REG<itemp> ));
 
4734
            
 
4735
            $il.append(JAST::Instruction.new( :op('aload'), %*REG<bstack> ));
 
4736
            $il.append(JAST::Instruction.new( :op('lload'), %*REG<itemp> ));
 
4737
            $il.append(JAST::PushIVal.new( :value(2) ));
 
4738
            $il.append($LADD);
 
4739
            $il.append($ALOAD_1);
 
4740
            $il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
 
4741
                "atpos_i", 'Long', $TYPE_SMO, 'Long', $TYPE_TC ));
 
4742
            $il.append(JAST::Instruction.new( :op('lload'), %*REG<pos> ));
 
4743
            $il.append($LCMP);
 
4744
            $il.append(JAST::Instruction.new( :op('ifne'), %*REG<fail> ));
 
4745
            
 
4746
            $il.append(JAST::Instruction.new( :op('aload'), %*REG<bstack> ));
 
4747
            $il.append(JAST::Instruction.new( :op('lload'), %*REG<itemp> ));
 
4748
            $il.append($IVAL_ONE);
 
4749
            $il.append($LADD);
 
4750
            $il.append($ALOAD_1);
 
4751
            $il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
 
4752
                "atpos_i", 'Long', $TYPE_SMO, 'Long', $TYPE_TC ));
 
4753
            $il.append(JAST::Instruction.new( :op('lstore'), %*REG<itemp> ));
 
4754
        }
 
4755
        
 
4756
        if $node.subtype eq 'zerowidth' {
 
4757
            $il.append(JAST::Instruction.new( :op('lload'), %*REG<itemp> ));
 
4758
            $il.append(JAST::Instruction.new( :op('lstore'), %*REG<pos> ));
 
4759
        }
 
4760
        
 
4761
        $il
 
4762
    }
 
4763
    
 
4764
    my %cclass_code;
 
4765
    INIT {
 
4766
        # Codes match constants in Ops.java.
 
4767
        %cclass_code<.>  := nqp::const::CCLASS_ANY;
 
4768
        %cclass_code<d>  := nqp::const::CCLASS_NUMERIC;
 
4769
        %cclass_code<s>  := nqp::const::CCLASS_WHITESPACE;
 
4770
        %cclass_code<w>  := nqp::const::CCLASS_WORD;
 
4771
        %cclass_code<n>  := nqp::const::CCLASS_NEWLINE;
 
4772
    }
 
4773
 
 
4774
    method cclass($node) {
 
4775
        my $il := JAST::InstructionList.new();
 
4776
        
 
4777
        $il.append(JAST::Instruction.new( :op('lload'), %*REG<pos> ));
 
4778
        $il.append(JAST::Instruction.new( :op('lload'), %*REG<eos> ));
 
4779
        $il.append($LCMP);
 
4780
        $il.append(JAST::Instruction.new( :op('ifge'), %*REG<fail> ));
 
4781
        
 
4782
        my $subtype := nqp::lc($node.name);
 
4783
        nqp::die("Unrecognized subtype '$subtype' in QAST::Regex cclass")
 
4784
            unless nqp::existskey(%cclass_code, $subtype);
 
4785
        my $cclass := %cclass_code{$subtype};
 
4786
        if $subtype ne '.' {
 
4787
            $il.append(JAST::PushIVal.new( :value($cclass) ));
 
4788
            $il.append(JAST::Instruction.new( :op('aload'), %*REG<tgt> ));
 
4789
            $il.append(JAST::Instruction.new( :op('lload'), %*REG<pos> ));
 
4790
            $il.append(JAST::Instruction.new( :op('invokestatic'),
 
4791
                $TYPE_OPS, 'iscclass', 'Long', 'Long', $TYPE_STR, 'Long' ));
 
4792
            $il.append($L2I);
 
4793
            $il.append(JAST::Instruction.new( :op($node.negate ?? 'ifne' !! 'ifeq'), %*REG<fail> ));
 
4794
            
 
4795
            if $cclass == nqp::const::CCLASS_NEWLINE && !$node.negate {
 
4796
                $il.append(JAST::Instruction.new( :op('aload'), %*REG<tgt> ));
 
4797
                $il.append(JAST::Instruction.new( :op('lload'), %*REG<pos> ));
 
4798
                $il.append(JAST::Instruction.new( :op('lload'), %*REG<eos> ));
 
4799
                $il.append(JAST::Instruction.new( :op('invokestatic'),
 
4800
                    $TYPE_OPS, 'checkcrlf', 'Long', $TYPE_STR, 'Long', 'Long' ));
 
4801
                $il.append(JAST::Instruction.new( :op('lstore'), %*REG<pos> ));
 
4802
            } 
 
4803
        }
 
4804
        
 
4805
        unless $node.subtype eq 'zerowidth' {
 
4806
            $il.append(JAST::Instruction.new( :op('lload'), %*REG<pos> ));
 
4807
            $il.append($IVAL_ONE);
 
4808
            $il.append($LADD);
 
4809
            $il.append(JAST::Instruction.new( :op('lstore'), %*REG<pos> ));
 
4810
        }
 
4811
        
 
4812
        $il
 
4813
    }
 
4814
    
 
4815
    method dba($node) {
 
4816
        my $qast := QAST::Op.new(
 
4817
            :op('callmethod'), :name('!dba'),
 
4818
            QAST::Var.new( :name(%*REG<cur>), :scope('local') ),
 
4819
            QAST::Var.new( :name(%*REG<pos>), :scope('local'), :returns(int) ),
 
4820
            QAST::SVal.new( :value($node.name()) )
 
4821
        );
 
4822
        my $res := self.as_jast($qast, :want($RT_VOID));
 
4823
        $*STACK.obtain(NQPMu, $res);
 
4824
        $res.jast
 
4825
    }
 
4826
    
 
4827
    method enumcharlist($node) {
 
4828
        my $il := JAST::InstructionList.new();
 
4829
        
 
4830
        $il.append(JAST::Instruction.new( :op('lload'), %*REG<pos> ));
 
4831
        $il.append(JAST::Instruction.new( :op('lload'), %*REG<eos> ));
 
4832
        $il.append($LCMP);
 
4833
        $il.append(JAST::Instruction.new( :op('ifge'), %*REG<fail> ));
 
4834
        
 
4835
        $il.append(JAST::PushSVal.new( :value($node[0]) ));
 
4836
        $il.append(JAST::Instruction.new( :op('aload'), %*REG<tgt> ));
 
4837
        $il.append(JAST::Instruction.new( :op('lload'), %*REG<pos> ));
 
4838
        $il.append($L2I);
 
4839
        $il.append(JAST::Instruction.new( :op('invokevirtual'),
 
4840
            $TYPE_STR, 'charAt', 'Char', 'Integer' ));
 
4841
        $il.append(JAST::Instruction.new( :op('invokevirtual'),
 
4842
            $TYPE_STR, 'indexOf', 'Integer', 'Integer' ));
 
4843
        $il.append(JAST::Instruction.new( :op($node.negate ?? 'ifge' !! 'iflt'), %*REG<fail> ));
 
4844
        
 
4845
        unless $node.subtype eq 'zerowidth' {
 
4846
            $il.append(JAST::Instruction.new( :op('lload'), %*REG<pos> ));
 
4847
            $il.append($IVAL_ONE);
 
4848
            $il.append($LADD);
 
4849
            $il.append(JAST::Instruction.new( :op('lstore'), %*REG<pos> ));
 
4850
        }
 
4851
        
 
4852
        $il;
 
4853
    }
 
4854
    
 
4855
    method literal($node) {
 
4856
        my $il := JAST::InstructionList.new();
 
4857
        my $litconst := $node[0];
 
4858
        my $litlen := nqp::chars($litconst);
 
4859
        
 
4860
        $il.append(JAST::Instruction.new( :op('lload'), %*REG<pos> ));
 
4861
        $il.append(JAST::PushIVal.new( :value($litlen) ));
 
4862
        $il.append($LADD);
 
4863
        $il.append(JAST::Instruction.new( :op('lload'), %*REG<eos> ));
 
4864
        $il.append($LCMP);
 
4865
        $il.append(JAST::Instruction.new( :op('ifgt'), %*REG<fail> ));
 
4866
        
 
4867
        $il.append(JAST::Instruction.new( :op('aload'), %*REG<tgt> ));
 
4868
        $il.append(JAST::PushIndex.new(
 
4869
            :value($node.subtype eq 'ignorecase' ?? 1 !! 0) ));
 
4870
        $il.append(JAST::Instruction.new( :op('lload'), %*REG<pos> ));
 
4871
        $il.append($L2I);
 
4872
        $il.append(JAST::PushSVal.new( :value($litconst) ));
 
4873
        $il.append(JAST::PushIndex.new( :value(0) ));
 
4874
        $il.append(JAST::PushIndex.new( :value($litlen) ));
 
4875
        $il.append(JAST::Instruction.new( :op('invokevirtual'),
 
4876
            $TYPE_STR, 'regionMatches', 'Z', 'Z', 'Integer', $TYPE_STR, 'Integer', 'Integer' ));
 
4877
        $il.append(JAST::Instruction.new( :op($node.negate ?? 'ifne' !! 'ifeq'), %*REG<fail> ));
 
4878
        
 
4879
        $il.append(JAST::Instruction.new( :op('lload'), %*REG<pos> ));
 
4880
        $il.append(JAST::PushIVal.new( :value($litlen) ));
 
4881
        $il.append($LADD);
 
4882
        $il.append(JAST::Instruction.new( :op('lstore'), %*REG<pos> ));
 
4883
        
 
4884
        $il;
 
4885
    }
 
4886
    
 
4887
    method pass($node) {
 
4888
        my $qast := QAST::Op.new(
 
4889
            :op('callmethod'), :name('!cursor_pass'),
 
4890
            QAST::Var.new( :name(%*REG<cur>), :scope('local') ),
 
4891
            QAST::Var.new( :name(%*REG<pos>), :scope('local'), :returns(int) )
 
4892
        );
 
4893
        if $node.name() {
 
4894
            $qast.push(QAST::SVal.new( :value($node.name()) ));
 
4895
        }
 
4896
        elsif +@($node) == 1 {
 
4897
            $qast.push($node[0]);
 
4898
        }
 
4899
        if $node.backtrack ne 'r' {
 
4900
            $qast.push(QAST::IVal.new( :value(1), :named('backtrack') ));
 
4901
        }
 
4902
        my $res := self.as_jast($qast, :want($RT_VOID));
 
4903
        $*STACK.obtain(NQPMu, $res);
 
4904
        $res.jast;
 
4905
    }
 
4906
 
 
4907
    method qastnode($node) {
 
4908
        my $il := JAST::InstructionList.new();
 
4909
        
 
4910
        $il.append(JAST::PushSVal.new( :value("\$\xa2") ));
 
4911
        $il.append(JAST::Instruction.new( :op('aload'), %*REG<cur> ));
 
4912
        $il.append($DUP);
 
4913
        $il.append(JAST::Instruction.new( :op('aload'), %*REG<curclass> ));
 
4914
        $il.append(JAST::PushSVal.new( :value('$!pos') ));
 
4915
        $il.append(JAST::Instruction.new( :op('lload'), %*REG<pos> ));
 
4916
        $il.append($ALOAD_1);
 
4917
        $il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
 
4918
            "bindattr_i", 'Long', $TYPE_SMO, $TYPE_SMO, $TYPE_STR, 'Long', $TYPE_TC ));
 
4919
        $il.append($POP2);
 
4920
        $il.append($ALOAD_1);
 
4921
        $il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
 
4922
            "bindlex", $TYPE_SMO, $TYPE_STR, $TYPE_SMO, $TYPE_TC ));
 
4923
        $il.append($POP);
 
4924
 
 
4925
        my $node_res := self.as_jast($node[0], :want($RT_OBJ));
 
4926
        $il.append($node_res.jast);
 
4927
        $*STACK.obtain($il, $node_res);
 
4928
        
 
4929
        if $node.subtype eq 'zerowidth' {
 
4930
            $il.append($ALOAD_1);
 
4931
            $il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
 
4932
                "istrue", 'Long', $TYPE_SMO, $TYPE_TC ));
 
4933
            $il.append($L2I);
 
4934
            $il.append(JAST::Instruction.new( :op($node.negate ?? 'ifne' !! 'ifeq'), %*REG<fail> ));
 
4935
        }
 
4936
        else {
 
4937
            $il.append($POP);
 
4938
        }
 
4939
        
 
4940
        $il;
 
4941
    }
 
4942
 
 
4943
    method quant($node) {
 
4944
        my $il        := JAST::InstructionList.new();
 
4945
        my $backtrack := $node.backtrack || 'g';
 
4946
        my $sep       := $node[1];
 
4947
        my $prefix    := self.unique('rxquant' ~ $backtrack);
 
4948
        my $looplabel := JAST::Label.new( :name($prefix ~ '_loop') );
 
4949
        my $donelabel := JAST::Label.new( :name($prefix ~ '_done') );
 
4950
        my $min       := $node.min;
 
4951
        my $max       := $node.max;
 
4952
        my $needrep   := $min > 1 || $max > 1;
 
4953
        my $needmark  := $needrep || $backtrack eq 'r';
 
4954
 
 
4955
        if $min == 0 && $max == 0 {
 
4956
            # Nothing to do, and nothing to backtrack into.
 
4957
        }
 
4958
        elsif $backtrack eq 'f' {
 
4959
            my $seplabel := JAST::Label.new( :name($prefix ~ '_sep') );
 
4960
            my $mark     := &*REGISTER_MARK($looplabel);
 
4961
            
 
4962
            $il.append($IVAL_ZERO);
 
4963
            $il.append(JAST::Instruction.new( :op('lstore'), %*REG<rep> ));
 
4964
            if $min < 1 {
 
4965
                self.regex_mark($il, $mark,
 
4966
                    JAST::Instruction.new( :op('lload'), %*REG<pos> ),
 
4967
                    JAST::Instruction.new( :op('lload'), %*REG<rep> ));
 
4968
                $il.append(JAST::Instruction.new( :op('goto'), $donelabel ));
 
4969
            }
 
4970
            $il.append(JAST::Instruction.new( :op('goto'), $seplabel )) if $sep;
 
4971
            $il.append($looplabel);
 
4972
            $il.append(JAST::Instruction.new( :op('lload'), %*REG<rep> ));
 
4973
            $il.append(JAST::Instruction.new( :op('lstore'), %*REG<itemp> ));
 
4974
            $il.append(self.regex_jast($sep)) if $sep;
 
4975
            $il.append($seplabel) if $sep;
 
4976
            $il.append(self.regex_jast($node[0]));
 
4977
            $il.append(JAST::Instruction.new( :op('lload'), %*REG<itemp> ));
 
4978
            $il.append($IVAL_ONE);
 
4979
            $il.append($LADD);
 
4980
            $il.append(JAST::Instruction.new( :op('lstore'), %*REG<rep> ));
 
4981
            
 
4982
            if $min > 1 {
 
4983
                $il.append(JAST::Instruction.new( :op('lload'), %*REG<rep> ));
 
4984
                $il.append(JAST::PushIVal.new( :value($min) ));
 
4985
                $il.append($LCMP);
 
4986
                $il.append(JAST::Instruction.new( :op('iflt'), $looplabel ));
 
4987
            }
 
4988
            if $max > 1 {
 
4989
                $il.append(JAST::Instruction.new( :op('lload'), %*REG<rep> ));
 
4990
                $il.append(JAST::PushIVal.new( :value($max) ));
 
4991
                $il.append($LCMP);
 
4992
                $il.append(JAST::Instruction.new( :op('ifge'), $donelabel ));
 
4993
            }
 
4994
            if $max != 1 {
 
4995
                self.regex_mark($il, $mark,
 
4996
                    JAST::Instruction.new( :op('lload'), %*REG<pos> ),
 
4997
                    JAST::Instruction.new( :op('lload'), %*REG<rep> ));
 
4998
            }
 
4999
            
 
5000
            $il.append($donelabel);
 
5001
        }
 
5002
        else {
 
5003
            my $mark := &*REGISTER_MARK($donelabel);
 
5004
 
 
5005
            if $min == 0 {
 
5006
                self.regex_mark($il, $mark,
 
5007
                    JAST::Instruction.new( :op('lload'), %*REG<pos> ),
 
5008
                    $IVAL_ZERO);
 
5009
            }
 
5010
            elsif $needmark {
 
5011
                self.regex_mark($il, $mark,
 
5012
                    $IVAL_MINUSONE,
 
5013
                    $IVAL_ZERO);
 
5014
            }
 
5015
            
 
5016
            $il.append($looplabel);
 
5017
            $il.append(self.regex_jast($node[0]));
 
5018
            
 
5019
            if $needmark {
 
5020
                $il.append(JAST::Instruction.new( :op('aload'), %*REG<bstack> ));
 
5021
                $il.append($DUP);
 
5022
                $il.append(JAST::PushIVal.new( :value($mark) ));
 
5023
                $il.append($ALOAD_1);
 
5024
                $il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
 
5025
                    "rxpeek", 'Long', $TYPE_SMO, 'Long', $TYPE_TC ));
 
5026
                $il.append(JAST::PushIVal.new( :value(2) ));
 
5027
                $il.append($LADD);
 
5028
                $il.append($ALOAD_1);
 
5029
                $il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
 
5030
                    "atpos_i", 'Long', $TYPE_SMO, 'Long', $TYPE_TC ));
 
5031
                $il.append(JAST::Instruction.new( :op('lstore'), %*REG<rep> ));
 
5032
                
 
5033
                if $backtrack eq 'r' {
 
5034
                    self.regex_commit($il, $mark);
 
5035
                }
 
5036
                
 
5037
                $il.append(JAST::Instruction.new( :op('lload'), %*REG<rep> ));
 
5038
                $il.append($IVAL_ONE);
 
5039
                $il.append($LADD);
 
5040
                $il.append(JAST::Instruction.new( :op('lstore'), %*REG<rep> ));
 
5041
                
 
5042
                if $max > 1 {
 
5043
                    $il.append(JAST::Instruction.new( :op('lload'), %*REG<rep> ));
 
5044
                    $il.append(JAST::PushIVal.new( :value($node.max) ));
 
5045
                    $il.append($LCMP);
 
5046
                    $il.append(JAST::Instruction.new( :op('ifge'), $donelabel ));
 
5047
                }
 
5048
            }
 
5049
            
 
5050
            unless $max == 1 {
 
5051
                self.regex_mark($il, $mark,
 
5052
                    JAST::Instruction.new( :op('lload'), %*REG<pos> ),
 
5053
                    JAST::Instruction.new( :op('lload'), %*REG<rep> ));
 
5054
                $il.append(self.regex_jast($sep)) if $sep;
 
5055
                $il.append(JAST::Instruction.new( :op('goto'), $looplabel ));
 
5056
            }
 
5057
            
 
5058
            $il.append($donelabel);
 
5059
            if $min > 1 {
 
5060
                $il.append(JAST::Instruction.new( :op('lload'), %*REG<rep> ));
 
5061
                $il.append(JAST::PushIVal.new( :value(+$node.min) ));
 
5062
                $il.append($LCMP);
 
5063
                $il.append(JAST::Instruction.new( :op('iflt'), %*REG<fail> ));
 
5064
            }
 
5065
        }
 
5066
        
 
5067
        $il;
 
5068
    }
 
5069
    
 
5070
    method scan($node) {
 
5071
        my $il := JAST::InstructionList.new();
 
5072
        
 
5073
        my $prefix := self.unique('rxscan');
 
5074
        my $looplabel := JAST::Label.new( :name($prefix ~ '_loop') );
 
5075
        my $scanlabel := JAST::Label.new( :name($prefix ~ '_scan') );
 
5076
        my $donelabel := JAST::Label.new( :name($prefix ~ '_done') );
 
5077
        
 
5078
        $il.append(JAST::Instruction.new( :op('aload'), 'self' ));
 
5079
        $il.append(JAST::Instruction.new( :op('aload'), %*REG<curclass> ));
 
5080
        $il.append(JAST::PushSVal.new( :value('$!from') ));
 
5081
        $il.append($ALOAD_1);
 
5082
        $il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
 
5083
                "getattr_i", 'Long', $TYPE_SMO, $TYPE_SMO, $TYPE_STR, $TYPE_TC ));
 
5084
        $il.append($IVAL_MINUSONE);
 
5085
        $il.append($LCMP);
 
5086
        $il.append(JAST::Instruction.new( :op('ifne'), $donelabel ));
 
5087
        $il.append(JAST::Instruction.new( :op('goto'), $scanlabel ));
 
5088
        
 
5089
        $il.append($looplabel);
 
5090
        $il.append(JAST::Instruction.new( :op('lload'), %*REG<pos> ));
 
5091
        $il.append($IVAL_ONE);
 
5092
        $il.append($LADD);
 
5093
        $il.append($DUP2);
 
5094
        $il.append(JAST::Instruction.new( :op('lstore'), %*REG<pos> ));
 
5095
        $il.append(JAST::Instruction.new( :op('lload'), %*REG<eos> ));
 
5096
        $il.append($LCMP);
 
5097
        $il.append(JAST::Instruction.new( :op('ifgt'), %*REG<fail> ));
 
5098
        $il.append(JAST::Instruction.new( :op('aload'), %*REG<cur> ));
 
5099
        $il.append(JAST::Instruction.new( :op('aload'), %*REG<curclass> ));
 
5100
        $il.append(JAST::PushSVal.new( :value('$!from') ));
 
5101
        $il.append(JAST::Instruction.new( :op('lload'), %*REG<pos> ));
 
5102
        $il.append($ALOAD_1);
 
5103
        $il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
 
5104
                "bindattr_i", 'Long', $TYPE_SMO, $TYPE_SMO, $TYPE_STR, 'Long', $TYPE_TC ));
 
5105
        $il.append($POP2);
 
5106
        
 
5107
        $il.append($scanlabel);
 
5108
        
 
5109
        my $mark := &*REGISTER_MARK($looplabel);
 
5110
        self.regex_mark($il, $mark,
 
5111
            JAST::Instruction.new( :op('lload'), %*REG<pos> ),
 
5112
            $IVAL_ZERO);
 
5113
        $il.append($donelabel);
 
5114
        
 
5115
        $il;
 
5116
    }
 
5117
 
 
5118
    method subcapture($node) {
 
5119
        my $il        := JAST::InstructionList.new();
 
5120
        my $prefix    := self.unique('rxcap');
 
5121
        my $donelabel := JAST::Label.new( :name($prefix ~ '_done') );
 
5122
        my $faillabel := JAST::Label.new( :name($prefix ~ '_fail') );
 
5123
 
 
5124
        my $mark := &*REGISTER_MARK($faillabel);
 
5125
        self.regex_mark($il, $mark,
 
5126
            JAST::Instruction.new( :op('lload'), %*REG<pos> ),
 
5127
            $IVAL_ZERO);
 
5128
        $il.append(self.regex_jast($node[0]));
 
5129
        $il.append(JAST::Instruction.new( :op('aload'), %*REG<bstack> ));
 
5130
        $il.append($DUP);
 
5131
        $il.append(JAST::PushIVal.new( :value($mark) ));
 
5132
        $il.append($ALOAD_1);
 
5133
        $il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
 
5134
            "rxpeek", 'Long', $TYPE_SMO, 'Long', $TYPE_TC ));
 
5135
        $il.append($IVAL_ONE);
 
5136
        $il.append($LADD);
 
5137
        $il.append($ALOAD_1);
 
5138
        $il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
 
5139
                    "atpos_i", 'Long', $TYPE_SMO, 'Long', $TYPE_TC ));
 
5140
        $il.append(JAST::Instruction.new( :op('lstore'), %*REG<itemp> ));
 
5141
 
 
5142
        my $temp := QAST::Node.unique('rx_subcapture_cur_');
 
5143
        my $methqast := QAST::Stmts.new(
 
5144
            QAST::Op.new(
 
5145
                :op('bindattr_i'),
 
5146
                QAST::Var.new( :name(%*REG<cur>), :scope('local') ),
 
5147
                QAST::Var.new( :name(%*REG<curclass>), :scope('local') ),
 
5148
                QAST::SVal.new( :value('$!pos') ),
 
5149
                QAST::Var.new( :name(%*REG<pos>), :scope('local'), :returns(int) )
 
5150
            ),
 
5151
            QAST::Op.new(
 
5152
                :op('bind'),
 
5153
                QAST::Var.new( :name($temp), :scope('local'), :decl('var') ),
 
5154
                QAST::Op.new(
 
5155
                    :op('callmethod'), :name('!cursor_start_subcapture'),
 
5156
                    QAST::Var.new( :name(%*REG<cur>), :scope('local') ),
 
5157
                    QAST::Var.new( :name(%*REG<itemp>), :scope('local'), :returns(int) )
 
5158
                )),
 
5159
            QAST::Op.new(
 
5160
                :op('callmethod'), :name('!cursor_pass'),
 
5161
                QAST::Var.new( :name($temp), :scope('local') ),
 
5162
                QAST::Var.new( :name(%*REG<pos>), :scope('local'), :returns(int) )
 
5163
            ),
 
5164
            QAST::Op.new(
 
5165
                :op('bind'),
 
5166
                QAST::Var.new( :name(%*REG<cstack>), :scope('local') ),
 
5167
                QAST::Op.new(
 
5168
                    :op('callmethod'), :name('!cursor_capture'),
 
5169
                    QAST::Var.new( :name(%*REG<cur>), :scope('local') ),
 
5170
                    QAST::Var.new( :name($temp), :scope('local') ),
 
5171
                    QAST::SVal.new( :value($node.name) )
 
5172
                )));
 
5173
        my $methres := self.as_jast($methqast, :want($RT_VOID));
 
5174
        $il.append($methres.jast);
 
5175
        $*STACK.obtain($il, $methres);
 
5176
        
 
5177
        $il.append(JAST::Instruction.new( :op('goto'), $donelabel ));
 
5178
        $il.append($faillabel);
 
5179
        $il.append(JAST::Instruction.new( :op('goto'), %*REG<fail> ));
 
5180
        $il.append($donelabel);
 
5181
        
 
5182
        $il;
 
5183
    }
 
5184
 
 
5185
    method subrule($node) {
 
5186
        my $il := JAST::InstructionList.new();
 
5187
        my $name := nqp::defined($node.name) ?? $node.name !! '';
 
5188
        my $subtype := $node.subtype;
 
5189
        my $captured := 0;
 
5190
 
 
5191
        my $callqast := QAST::Stmts.new(
 
5192
            QAST::Op.new(
 
5193
                :op('bindattr_i'),
 
5194
                QAST::Var.new( :name(%*REG<cur>), :scope('local') ),
 
5195
                QAST::Var.new( :name(%*REG<curclass>), :scope('local') ),
 
5196
                QAST::SVal.new( :value('$!pos') ),
 
5197
                QAST::Var.new( :name(%*REG<pos>), :scope('local'), :returns(int) )
 
5198
            ));
 
5199
        if nqp::istype($node[0][0], QAST::SVal) {
 
5200
            # Method call.
 
5201
            my @callargs := nqp::clone($node[0].list);
 
5202
            my $name := @callargs.shift().value;
 
5203
            $callqast.push(QAST::Op.new(
 
5204
                :op('callmethod'), :name($name),
 
5205
                QAST::Var.new( :name(%*REG<cur>), :scope('local') ),
 
5206
                |@callargs
 
5207
            ));
 
5208
        }
 
5209
        else {
 
5210
            # Normal invocation (probably positional capture).
 
5211
            my @callargs := nqp::clone($node[0].list);
 
5212
            my $target := @callargs.shift();
 
5213
            $callqast.push(QAST::Op.new(
 
5214
                :op('call'),
 
5215
                $target,
 
5216
                QAST::Var.new( :name(%*REG<cur>), :scope('local') ),
 
5217
                |@callargs
 
5218
            ));
 
5219
        }
 
5220
        my $invres := self.as_jast($callqast, :want($RT_OBJ));
 
5221
        $il.append($invres.jast);
 
5222
        $*STACK.obtain($il, $invres);
 
5223
        $il.append($DUP);
 
5224
        $il.append(JAST::Instruction.new( :op('astore'), %*REG<subcur> ));
 
5225
        $il.append(JAST::Instruction.new( :op('aload'), %*REG<curclass> ));
 
5226
        $il.append(JAST::PushSVal.new( :value('$!pos') ));
 
5227
        $il.append($ALOAD_1);
 
5228
        $il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
 
5229
            "getattr_i", 'Long', $TYPE_SMO, $TYPE_SMO, $TYPE_STR, $TYPE_TC ));
 
5230
        $il.append($IVAL_ZERO);
 
5231
        $il.append($LCMP);
 
5232
        $il.append(JAST::Instruction.new( :op($node.negate ?? 'ifge' !! 'iflt'), %*REG<fail> ));
 
5233
        
 
5234
        if $subtype ne 'zerowidth' {
 
5235
            my $rxname := self.unique('rxsubrule');
 
5236
            my $passlabel := JAST::Label.new( :name($rxname ~ '_pass') );
 
5237
            if $node.backtrack eq 'r' {
 
5238
                unless $subtype eq 'method' {
 
5239
                    my $mark := &*REGISTER_MARK($passlabel);
 
5240
                    self.regex_mark($il, $mark,
 
5241
                        $IVAL_MINUSONE,
 
5242
                        $IVAL_ZERO);
 
5243
                    $il.append($passlabel);
 
5244
                }
 
5245
            }
 
5246
            else {
 
5247
                my $backlabel := JAST::Label.new( :name($rxname ~ '_back') );
 
5248
                $il.append(JAST::Instruction.new( :op('goto'), $passlabel ));
 
5249
                
 
5250
                $il.append($backlabel);
 
5251
                my $nextres := self.as_jast(QAST::Op.new(
 
5252
                    :op('callmethod'), :name('!cursor_next'),
 
5253
                    QAST::Var.new( :name(%*REG<subcur>), :scope('local') )
 
5254
                ), :want($RT_OBJ));
 
5255
                $il.append($nextres.jast);
 
5256
                $*STACK.obtain($il, $nextres);
 
5257
                $il.append($DUP);
 
5258
                $il.append(JAST::Instruction.new( :op('astore'), %*REG<subcur> ));
 
5259
                $il.append(JAST::Instruction.new( :op('aload'), %*REG<curclass> ));
 
5260
                $il.append(JAST::PushSVal.new( :value('$!pos') ));
 
5261
                $il.append($ALOAD_1);
 
5262
                $il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
 
5263
                    "getattr_i", 'Long', $TYPE_SMO, $TYPE_SMO, $TYPE_STR, $TYPE_TC ));
 
5264
                $il.append($IVAL_ZERO);
 
5265
                $il.append($LCMP);
 
5266
                $il.append(JAST::Instruction.new( :op($node.negate ?? 'ifge' !! 'iflt'), %*REG<fail> ));
 
5267
                
 
5268
                $il.append($passlabel);
 
5269
                if $subtype eq 'capture' {
 
5270
                    my $capres := self.as_jast(QAST::Op.new(
 
5271
                        :op('callmethod'), :name('!cursor_capture'),
 
5272
                        QAST::Var.new( :name(%*REG<cur>), :scope('local') ),
 
5273
                        QAST::Var.new( :name(%*REG<subcur>), :scope('local') ),
 
5274
                        QAST::SVal.new( :value($name) )
 
5275
                    ), :want($RT_OBJ));
 
5276
                    $il.append($capres.jast);
 
5277
                    $*STACK.obtain($il, $capres);
 
5278
                    $il.append(JAST::Instruction.new( :op('astore'), %*REG<cstack> ));
 
5279
                    $captured := 1;
 
5280
                }
 
5281
                else {
 
5282
                    my $pushres := self.as_jast(QAST::Op.new(
 
5283
                        :op('callmethod'), :name('!cursor_push_cstack'),
 
5284
                        QAST::Var.new( :name(%*REG<cur>), :scope('local') ),
 
5285
                        QAST::Var.new( :name(%*REG<subcur>), :scope('local') ),
 
5286
                    ), :want($RT_OBJ));
 
5287
                    $il.append($pushres.jast);
 
5288
                    $*STACK.obtain($il, $pushres);
 
5289
                    $il.append(JAST::Instruction.new( :op('astore'), %*REG<cstack> ));
 
5290
                }
 
5291
                
 
5292
                my $mark := &*REGISTER_MARK($backlabel);
 
5293
                $il.append(JAST::Instruction.new( :op('aload'), %*REG<bstack> ));
 
5294
                $il.append($DUP);
 
5295
                $il.append($DUP2);
 
5296
                $il.append(JAST::PushIVal.new( :value($mark) ));
 
5297
                $il.append($ALOAD_1);
 
5298
                $il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS, 'push_i',
 
5299
                    'Long', $TYPE_SMO, 'Long', $TYPE_TC ));
 
5300
                $il.append($POP2);
 
5301
                $il.append($IVAL_ZERO);
 
5302
                $il.append($ALOAD_1);
 
5303
                $il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS, 'push_i',
 
5304
                    'Long', $TYPE_SMO, 'Long', $TYPE_TC ));
 
5305
                $il.append($POP2);
 
5306
                $il.append(JAST::Instruction.new( :op('lload'), %*REG<pos> ));
 
5307
                $il.append($ALOAD_1);
 
5308
                $il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS, 'push_i',
 
5309
                    'Long', $TYPE_SMO, 'Long', $TYPE_TC ));
 
5310
                $il.append($POP2);
 
5311
                $il.append(JAST::Instruction.new( :op('aload'), %*REG<cstack> ));
 
5312
                $il.append($ALOAD_1);
 
5313
                $il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS, 'elems',
 
5314
                    'Long', $TYPE_SMO, $TYPE_TC ));
 
5315
                $il.append($ALOAD_1);
 
5316
                $il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS, 'push_i',
 
5317
                    'Long', $TYPE_SMO, 'Long', $TYPE_TC ));
 
5318
                $il.append($POP2);
 
5319
            }
 
5320
        }
 
5321
        
 
5322
        if !$captured && $subtype eq 'capture' {
 
5323
            my $capres := self.as_jast(QAST::Op.new(
 
5324
                :op('callmethod'), :name('!cursor_capture'),
 
5325
                QAST::Var.new( :name(%*REG<cur>), :scope('local') ),
 
5326
                QAST::Var.new( :name(%*REG<subcur>), :scope('local') ),
 
5327
                QAST::SVal.new( :value($name) )
 
5328
            ), :want($RT_OBJ));
 
5329
            $il.append($capres.jast);
 
5330
            $*STACK.obtain($il, $capres);
 
5331
            $il.append(JAST::Instruction.new( :op('astore'), %*REG<cstack> ));
 
5332
        }
 
5333
        
 
5334
        unless $subtype eq 'zerowidth' {
 
5335
            $il.append(JAST::Instruction.new( :op('aload'), %*REG<subcur> ));
 
5336
            $il.append(JAST::Instruction.new( :op('aload'), %*REG<curclass> ));
 
5337
            $il.append(JAST::PushSVal.new( :value('$!pos') ));
 
5338
            $il.append($ALOAD_1);
 
5339
            $il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
 
5340
                "getattr_i", 'Long', $TYPE_SMO, $TYPE_SMO, $TYPE_STR, $TYPE_TC ));
 
5341
            $il.append(JAST::Instruction.new( :op('lstore'), %*REG<pos> ));
 
5342
        }
 
5343
        
 
5344
        $il;
 
5345
    }
 
5346
 
 
5347
    method uniprop($node) {
 
5348
        my $il := JAST::InstructionList.new();
 
5349
        
 
5350
        $il.append(JAST::PushSVal.new( :value($node[0]) ));
 
5351
        $il.append(JAST::Instruction.new( :op('aload'), %*REG<tgt> ));
 
5352
        $il.append(JAST::Instruction.new( :op('lload'), %*REG<pos> ));
 
5353
        $il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
 
5354
            "ischarprop", 'Long', $TYPE_STR, $TYPE_STR, 'Long' ));
 
5355
        $il.append($L2I);
 
5356
        $il.append(JAST::Instruction.new( :op($node.negate ?? 'ifne' !! 'ifeq'), %*REG<fail> ));
 
5357
        
 
5358
        unless $node.subtype eq 'zerowidth' {
 
5359
            $il.append(JAST::Instruction.new( :op('lload'), %*REG<pos> ));
 
5360
            $il.append($IVAL_ONE);
 
5361
            $il.append($LADD);
 
5362
            $il.append(JAST::Instruction.new( :op('lstore'), %*REG<pos> ));
 
5363
        }
 
5364
        
 
5365
        $il
 
5366
    }
 
5367
    
 
5368
    # a :rxtype<ws> node is a normal subrule call
 
5369
    method ws($node) { self.subrule($node) }
 
5370
    
 
5371
    method regex_mark($il, $mark, $pos, $rep) {
 
5372
        $il.append(JAST::Instruction.new( :op('aload'), %*REG<bstack> ));
 
5373
        $il.append(JAST::PushIVal.new( :value($mark) ));
 
5374
        $il.append($pos);
 
5375
        $il.append($rep);
 
5376
        $il.append($ALOAD_1);
 
5377
        $il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
 
5378
            "rxmark", 'Void', $TYPE_SMO, 'Long', 'Long', 'Long', $TYPE_TC ));
 
5379
    }
 
5380
    
 
5381
    method regex_commit($il, $mark) {
 
5382
        $il.append(JAST::Instruction.new( :op('aload'), %*REG<bstack> ));
 
5383
        $il.append(JAST::PushIVal.new( :value($mark) ));
 
5384
        $il.append($ALOAD_1);
 
5385
        $il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS,
 
5386
            "rxcommit", 'Void', $TYPE_SMO, 'Long', $TYPE_TC ));
 
5387
    }
 
5388
    
 
5389
    multi method as_jast($unknown, :$want) {
 
5390
        nqp::die("Unknown QAST node type " ~ $unknown.HOW.name($unknown));
 
5391
    }
 
5392
    
 
5393
    method result($il, $type) { result($il, $type) }
 
5394
    
 
5395
    method operations() { QAST::OperationsJAST }
 
5396
}
 
5397
 
 
5398
# Register as the QAST compiler.
 
5399
if nqp::isnull(nqp::getcomp('QAST')) {
 
5400
    nqp::bindcomp('QAST', QAST::CompilerJAST);
 
5401
}