@@ -135,6 +135,10 @@ class QAST::OperationsTruffle {
135
135
});
136
136
}
137
137
138
+ add_simple_op(' createsc' , $ OBJ , [$ STR ]);
139
+ add_simple_op(' scsetdesc' , $ STR , [$ OBJ , $ STR ]);
140
+ add_simple_op(' deserialize' , $ STR , [$ STR , $ OBJ , $ OBJ , $ OBJ , $ OBJ ]);
141
+
138
142
add_simple_op(' die' , $ VOID , [$ STR ]);
139
143
% ops <die_s > := % ops <die >;
140
144
@@ -146,6 +150,9 @@ class QAST::OperationsTruffle {
146
150
add_simple_op(' gethllsym' , $ OBJ , [$ STR , $ STR ]);
147
151
add_simple_op(' bindhllsym' , $ OBJ , [$ STR , $ STR , $ OBJ ]);
148
152
153
+ add_simple_op(' loadbytecode' , $ STR , [$ STR ]);
154
+ add_simple_op(' forceouterctx' , $ OBJ , [$ OBJ , $ OBJ ]);
155
+
149
156
add_simple_op(' say' , $ STR , [$ STR ], : side_effects);
150
157
add_simple_op(' print' , $ STR , [$ STR ], : side_effects);
151
158
@@ -398,25 +405,10 @@ class QAST::OperationsTruffle {
398
405
$ comp . as_truffle($ node [0 ], : want($ want ));
399
406
});
400
407
401
-
402
- # TODO :$want
403
- add_op(' call' , :! inlinable, sub ($ comp , $ node , : $ want ) {
408
+ my sub compile_args ($ comp , @ args , @ trees , @ flags , @ names ) {
404
409
my int $ NAMED := 1 ;
405
410
my int $ FLAT := 2 ;
406
411
407
- my $ ret := [' call' ];
408
-
409
- my @ args := $ node . list;
410
-
411
- if $ node . name {
412
- nqp :: push ($ ret , [' get-lexical' , $ node . name ]);
413
- }
414
- else {
415
- nqp :: push ($ ret , $ comp . as_truffle(nqp :: shift (@ args ), : want($ OBJ )). tree );
416
- }
417
-
418
- my @ names ;
419
- my @ flags ;
420
412
for @ args -> $ arg {
421
413
my int $ flags := 0 ;
422
414
@@ -430,24 +422,60 @@ class QAST::OperationsTruffle {
430
422
431
423
nqp :: push (@ flags , $ flags );
432
424
433
- nqp :: push ($ ret , $ comp . as_truffle($ arg , : want($ CALL_ARG )). tree );
425
+ nqp :: push (@ trees , $ comp . as_truffle($ arg , : want($ CALL_ARG )). tree );
434
426
}
435
- nqp :: splice ( $ ret , [ @ flags , @ names ], 2 , 0 );
427
+ }
436
428
437
- TAST. new ($ OBJ , $ ret );
429
+ add_op(' callmethod' , :! inlinable, sub ($ comp , $ node , : $ want ) {
430
+ my $ call := [' callmethod' ];
431
+
432
+ my @ args := nqp :: clone ($ node . list);
433
+
434
+ nqp :: push ($ call , $ comp . as_truffle(@ args . shift , : want($ OBJ )). tree );
435
+
436
+ if $ node . name {
437
+ nqp :: push ($ call , [' sval' , $ node . name ]);
438
+ }
439
+ else {
440
+ nqp :: push ($ call , $ comp . as_truffle(@ args . shift , : want($ STR )). tree );
441
+ }
442
+
443
+ my @ flags ;
444
+ my @ names ;
445
+
446
+ compile_args($ comp , @ args , $ call , @ flags , @ names );
447
+
448
+ nqp :: splice ($ call , [@ flags , @ names ], 3 , 0 );
449
+
450
+ TAST. new ($ OBJ , $ call );
438
451
});
439
452
440
- % ops <callstatic > := % ops <call >;
441
453
442
- add_op(' callmethod' , :! inlinable, sub ($ comp , $ node , : $ want ) {
443
- # HACK till we get proper callmethod
444
- if $ node . name eq ' name' && nqp ::istype($ node [0 ], QAST ::Op) && $ node [0 ]. op eq ' callmethod' && $ node [0 ]. name eq ' backend' && nqp ::istype($ node [0 ][0 ], QAST ::Op) && $ node [0 ][0 ]. op eq ' getcomp' {
445
- TAST. new ($ STR , [' sval' , ' truffle' ])
446
- } else {
447
- $ comp . NYI(" unimplemented QAST::Op { $ node . op} " );
454
+ # TODO :$want
455
+ add_op(' call' , :! inlinable, sub ($ comp , $ node , : $ want ) {
456
+ my $ ret := [' call' ];
457
+
458
+ my @ args := $ node . list;
459
+
460
+ if $ node . name {
461
+ nqp :: push ($ ret , [' get-lexical' , $ node . name ]);
462
+ }
463
+ else {
464
+ nqp :: push ($ ret , $ comp . as_truffle(nqp :: shift (@ args ), : want($ OBJ )). tree );
448
465
}
466
+
467
+ my @ flags ;
468
+ my @ names ;
469
+
470
+ compile_args($ comp , @ args , $ ret , @ flags , @ names );
471
+
472
+ nqp :: splice ($ ret , [@ flags , @ names ], 2 , 0 );
473
+
474
+ TAST. new ($ OBJ , $ ret );
449
475
});
450
476
477
+ % ops <callstatic > := % ops <call >;
478
+
451
479
add_op(' bind' , sub ($ comp , $ node , : $ want ) {
452
480
my @ children := $ node . list;
453
481
if + @ children != 2 {
@@ -495,7 +523,45 @@ class QAST::OperationsTruffle {
495
523
}
496
524
}
497
525
498
- class QAST::TruffleCompiler {
526
+ # It only makes sense to serialize a serialization context once, so when cross compiling we cache the result
527
+ role SerializeOnce {
528
+ method serialize_sc_without_caching ($ sc ) {
529
+ # Serialize it.
530
+
531
+ # HACK - we are avoiding an MoarVM specific optimalization
532
+ # On MoarVM if an sc is on top of the compiling_scs stackthread the serialized data is stored on the thread context
533
+ # We have no way of accessing it, so we try to avoid that
534
+ # If we put a fake sc on top of the stack it won't be cached
535
+ # we avoid anything that creates a write barrier while it's on top
536
+ my $ fake_stack_top_sc := nqp ::createsc(' JS_HACK' );
537
+ nqp ::pushcompsc($ fake_stack_top_sc );
538
+
539
+ my $ sh := nqp ::list_s();
540
+ my $ serialized := nqp ::serialize($ sc , $ sh );
541
+
542
+ # HACK - now we pop our fake sc
543
+ nqp ::popcompsc();
544
+
545
+ [$ serialized ,$ sh ];
546
+ }
547
+
548
+ method serialize_sc ($ sc ) {
549
+ if % * SC_CACHE <enabled > {
550
+ my $ handle := nqp ::scgethandle($ sc );
551
+ if nqp ::existskey(% * SC_CACHE ,$ handle ) {
552
+ % * SC_CACHE {$ handle };
553
+ }
554
+ else {
555
+ % * SC_CACHE {$ handle } := self . serialize_sc_without_caching($ sc );
556
+ }
557
+ }
558
+ else {
559
+ self . serialize_sc_without_caching($ sc );
560
+ }
561
+ }
562
+ }
563
+
564
+ class QAST::TruffleCompiler does SerializeOnce {
499
565
my class BlockInfo {
500
566
has $ ! qast ; # The QAST::Block
501
567
has $ ! outer ; # Outer block's BlockInfo
@@ -685,6 +751,78 @@ class QAST::TruffleCompiler {
685
751
}
686
752
}
687
753
754
+ method deserialization_code ($ cu ) {
755
+ # Serialize it.
756
+
757
+ my $ sc_tuple := self . serialize_sc($ cu . sc);
758
+ my $ serialized := $ sc_tuple [0 ];
759
+ my $ sh := $ sc_tuple [1 ];
760
+
761
+ # Now it's serialized, pop this SC off the compiling SC stack.
762
+ nqp ::popcompsc();
763
+
764
+ # String heap QAST.
765
+ my $ sh_ast := QAST ::Op. new ( : op(' list_s' ) );
766
+ my $ sh_elems := nqp :: elems ($ sh );
767
+ my $ i := 0 ;
768
+ while $ i < $ sh_elems {
769
+ $ sh_ast . push (nqp ::isnull_s(nqp ::atpos_s($ sh , $ i ))
770
+ ?? QAST ::Op. new ( : op(' null_s' ) )
771
+ !! QAST ::SVal. new ( : value(nqp ::atpos_s($ sh , $ i )) ));
772
+ $ i := $ i + 1 ;
773
+ }
774
+ $ sh_ast := QAST ::Block. new ( : blocktype(' immediate' ), $ sh_ast );
775
+
776
+ my $ repo_conflict_resolver ;
777
+
778
+ # Handle repossession conflict resolution code, if any.
779
+ if $ cu . repo_conflict_resolver {
780
+ $ repo_conflict_resolver := nqp :: clone ($ cu . repo_conflict_resolver);
781
+ $ repo_conflict_resolver . push (QAST ::Var. new ( : name(' conflicts' ), : scope(' local' ) ));
782
+ }
783
+ else {
784
+ $ repo_conflict_resolver := QAST ::Op. new (
785
+ : op(' die_s' ),
786
+ QAST ::SVal. new ( : value(' Repossession conflicts occurred during deserialization' ) )
787
+ );
788
+ }
789
+
790
+ # Overall deserialization QAST.
791
+ QAST ::Stmts. new (
792
+ QAST ::Op. new (
793
+ : op(' bind' ),
794
+ QAST ::Var. new ( : name(' cur_sc' ), : scope(' local' ), : decl(' var' ) ),
795
+ QAST ::Op. new ( : op(' createsc' ), QAST ::SVal. new ( : value(nqp ::scgethandle($ cu . sc)) ) )
796
+ ),
797
+ QAST ::Op. new (
798
+ : op(' scsetdesc' ),
799
+ QAST ::Var. new ( : name(' cur_sc' ), : scope(' local' ) ),
800
+ QAST ::SVal. new ( : value(nqp ::scgetdesc($ cu . sc)) )
801
+ ),
802
+ QAST ::Op. new (
803
+ : op(' bind' ),
804
+ QAST ::Var. new ( : name(' conflicts' ), : scope(' local' ), : decl(' var' ) ),
805
+ QAST ::Op. new ( : op(' list' ) )
806
+ ),
807
+ QAST ::Op. new (
808
+ : op(' deserialize' ),
809
+ nqp ::isnull($ serialized ) ?? QAST ::Op. new ( : op(' null_s' ) ) !! QAST ::SVal. new ( : value($ serialized ) ),
810
+ QAST ::Var. new ( : name(' cur_sc' ), : scope(' local' ) ),
811
+ $ sh_ast ,
812
+ QAST ::Op. new ( : op(' null' ) ),
813
+ QAST ::Var. new ( : name(' conflicts' ), : scope(' local' ) )
814
+ ),
815
+ QAST ::Op. new (
816
+ : op(' if' ),
817
+ QAST ::Op. new (
818
+ : op(' elems' ),
819
+ QAST ::Var. new ( : name(' conflicts' ), : scope(' local' ) )
820
+ ),
821
+ $ repo_conflict_resolver
822
+ )
823
+ );
824
+ }
825
+
688
826
multi method as_truffle (QAST ::CompUnit $ node , : $ want ) {
689
827
my $ * HLL := ' ' ;
690
828
if $ node . hll {
@@ -693,7 +831,20 @@ class QAST::TruffleCompiler {
693
831
694
832
my $ * BLOCK := BlockInfo. new (NQPMu, NQPMu);
695
833
696
- TAST. new ($ OBJ , [' comp-unit' , $ node . hll, [' stmts' , self . as_truffle($ node [0 ][1 ], : want($ VOID )). tree , self . as_truffle($ node [0 ][3 ], : want($ OBJ )). tree ]]);
834
+ my $ pre_deserialize := [' stmts' ];
835
+
836
+ my $ deserialization_code := $ node . compilation_mode
837
+ ?? self . as_truffle(self . deserialization_code($ node ), : want($ VOID )). tree
838
+ !! [' stmts' ];
839
+
840
+
841
+ if $ node . pre_deserialize {
842
+ for $ node . pre_deserialize -> $ pre {
843
+ nqp :: push ($ pre_deserialize , self . as_truffle($ pre , : want($ VOID )). tree );
844
+ }
845
+ }
846
+
847
+ TAST. new ($ OBJ , [' comp-unit' , $ node . hll, [' stmts' , $ pre_deserialize , $ deserialization_code , self . as_truffle($ node [0 ][1 ], : want($ VOID )). tree , self . as_truffle($ node [0 ][3 ], : want($ OBJ )). tree ]]);
697
848
}
698
849
699
850
multi method as_truffle (QAST ::VM $ node , : $ want ) {
@@ -879,9 +1030,16 @@ class QAST::TruffleCompiler {
879
1030
self . NYI(' QAST node: ' ~ $ node . HOW . name ($ node ));
880
1031
}
881
1032
882
- # HACK before we deserialize objects
1033
+ multi method as_truffle (QAST ::BVal $ node , : $ want ) {
1034
+ TAST. new ($ OBJ , [' bval' , $ node . value . cuid]);
1035
+ }
1036
+
883
1037
multi method as_truffle (QAST ::WVal $ node , : $ want ) {
884
- TAST. new ($ OBJ , [' null' ]);
1038
+ my $ value := $ node . value ;
1039
+ my $ sc := nqp ::getobjsc($ value );
1040
+ my str $ handle := nqp ::scgethandle($ sc );
1041
+ my int $ idx := nqp ::scgetobjidx($ sc , $ value );
1042
+ TAST. new ($ OBJ , [' wval' , $ handle , $ idx ]);
885
1043
}
886
1044
887
1045
method NYI ($ msg ) {
@@ -961,7 +1119,8 @@ class TruffleBackend {
961
1119
}
962
1120
963
1121
method is_precomp_stage ($ stage ) {
964
- 0 ;
1122
+ # Currently, everything is pre-comp since we're a cross-compiler.
1123
+ 1 ;
965
1124
}
966
1125
967
1126
method is_textual_stage ($ stage ) {
0 commit comments