1 (* ============================================================ *)
2 (* JavaMaker is the concrete class for emitting java *)
4 (* Diane Corney - September,2000. *)
5 (* ============================================================ *)
31 (* ------------------------------------ *)
35 RECORD (JavaBase
.ClassEmitter
)
36 (* --------------------------- *
38 * --------------------------- *)
41 work
: POINTER TO ARRAY OF JavaEmitter
;
44 (* ------------------------------------ *)
48 RECORD (JavaBase
.ClassEmitter
)
49 (* --------------------------- *
51 * --------------------------- *)
55 (* ------------------------------------ *)
57 TYPE JavaModEmitter
* =
60 (* --------------------------- *
62 * outF : JavaBase.JavaFile; *
63 * --------------------------- *)
66 (* ------------------------------------ *)
68 TYPE JavaRecEmitter
* =
71 (* --------------------------- *
73 * outF : Ju.JavaFile; *
74 * --------------------------- *)
78 (* ------------------------------------ *)
80 TYPE JavaProcTypeEmitter
* =
83 (* --------------------------- *
85 * outF : Ju.JavaFile; *
86 * --------------------------- *)
90 (* ------------------------------------ *)
94 RECORD (ClassMaker
.Assembler
)
98 (* ------------------------------------ *)
101 asmList
: L
.CharOpenSeq
;
102 currentLoopLabel
: Ju
.Label
;
104 (* ============================================================ *)
106 PROCEDURE Append(list
: JavaWorkList
;
108 VAR temp
: POINTER TO ARRAY OF JavaEmitter
;
111 IF list
.tide
> list
.high
THEN (* must expand *)
113 list
.high
:= list
.high
* 2 + 1;
114 NEW(list
.work
, (list
.high
+1));
115 FOR i
:= 0 TO list
.tide
-1 DO list
.work
[i
] := temp
[i
] END;
117 list
.work
[list
.tide
] := emit
; INC(list
.tide
);
120 (* ============================================================ *)
122 PROCEDURE newJavaEmitter
*(mod
: Id
.BlkId
) : JavaWorkList
;
123 VAR emitter
: JavaWorkList
;
124 modEmit
: JavaModEmitter
;
125 modName
: L
.CharOpen
;
127 modName
:= Sy
.getName
.ChPtr(mod
);
129 * Allocate a new worklist object.
133 NEW(emitter
.work
, 4);
136 JavaBase
.worklist
:= emitter
;
138 * Allocate a JavaModEmitter to be first item
139 * on the worklist. All later items will be of
140 * JavaRecEmitter type.
145 * Now append the mod-emitter to the worklist.
147 Append(emitter
, modEmit
);
151 (* ============================================================ *)
153 PROCEDURE newJavaAsm
*() : JavaAssembler
;
154 VAR asm
: JavaAssembler
;
157 L
.ResetCharOpenSeq(asmList
);
161 (* ============================================================ *)
163 PROCEDURE (list
: JavaWorkList
)AddNewRecEmitter
*(inTp
: Ty
.Record
);
164 VAR emit
: JavaRecEmitter
;
167 emit
.mod
:= list
.mod
;
169 * Set the current record type for this class.
173 * Now append the new RecEmitter to the worklist.
176 END AddNewRecEmitter
;
178 (* ============================================================ *)
180 PROCEDURE (list
: JavaWorkList
)AddNewProcTypeEmitter
*(inTp
: Ty
.Procedure
);
181 VAR emit
: JavaProcTypeEmitter
;
184 emit
.mod
:= list
.mod
;
186 * Set the current record type for this class.
190 * Now append the new RecEmitter to the worklist.
193 END AddNewProcTypeEmitter
;
195 (* ============================================================ *)
196 (* Mainline emitter, consumes worklist emitting assembler *)
197 (* files until the worklist is empty. *)
198 (* ============================================================ *)
200 PROCEDURE (this
: JavaWorkList
)Emit
*();
204 * First construct the base class-name string in the BlkId.
207 Ju
.MkBlkName(this
.mod
);
210 WHILE ix
< this
.tide
DO
211 this
.work
[ix
].Emit();
216 (* ============================================================ *)
217 (* Creates basic imports for java.lang, and inserts a few type *)
218 (* descriptors for Object, Exception, and String. *)
219 (* ============================================================ *)
221 PROCEDURE (this
: JavaWorkList
)Init
*();
231 * Create import descriptor for java.lang
233 Bi
.MkDummyImport("java_lang", "java.lang", blk
);
236 * Create various classes.
238 Bi
.MkDummyClass("Object", blk
, Ty
.isAbs
, obj
);
239 Cst
.ntvObj
:= obj
.type
;
240 Bi
.MkDummyClass("String", blk
, Ty
.noAtt
, str
);
241 Cst
.ntvStr
:= str
.type
;
242 Bi
.MkDummyClass("Exception", blk
, Ty
.extns
, exc
);
243 Cst
.ntvExc
:= exc
.type
;
244 Bi
.MkDummyClass("Class", blk
, Ty
.noAtt
, cls
);
245 Cst
.ntvTyp
:= cls
.type
;
247 * Create import descriptor for CP.RTS
249 Bi
.MkDummyImport("RTS", "", blk
);
250 Bi
.MkDummyAlias("NativeType", blk
, cls
.type
, Cst
.clsId
);
251 Bi
.MkDummyAlias("NativeObject", blk
, obj
.type
, Cst
.objId
);
252 Bi
.MkDummyAlias("NativeString", blk
, str
.type
, Cst
.strId
);
253 Bi
.MkDummyAlias("NativeException", blk
, exc
.type
, Cst
.excId
);
255 Bi
.MkDummyVar("dblPosInfinity",blk
,Bi
.realTp
,Cst
.dblInf
);
256 Bi
.MkDummyVar("dblNegInfinity",blk
,Bi
.realTp
,Cst
.dblNInf
);
257 Bi
.MkDummyVar("fltPosInfinity",blk
,Bi
.sReaTp
,Cst
.fltInf
);
258 Bi
.MkDummyVar("fltNegInfinity",blk
,Bi
.sReaTp
,Cst
.fltNInf
);
259 INCL(blk
.xAttr
, Sy
.need
);
261 * Uplevel addressing stuff.
263 Bi
.MkDummyImport("$CPJrts$", "CP.CPJrts", blk
);
264 Bi
.MkDummyClass("XHR", blk
, Ty
.isAbs
, xhr
);
265 Cst
.rtsXHR
:= xhr
.type
;
266 Cst
.xhrId
.recTyp
:= Cst
.rtsXHR
;
267 Cst
.xhrId
.type
:= Cst
.rtsXHR
;
270 (* ============================================================ *)
272 PROCEDURE (this
: JavaWorkList
)ObjectFeatures
*();
273 VAR prcSig
: Ty
.Procedure
;
277 prcSig
.retType
:= Cst
.strId
.type
;
278 Id
.InitParSeq(prcSig
.formals
, 2);
279 Bi
.MkDummyMethodAndInsert("toString", prcSig
, Cst
.ntvObj
, Cst
.sysLib
, Sy
.pubMode
, Sy
.var
, Id
.extns
);
282 prcSig
.retType
:= Bi
.intTp
;
283 Id
.InitParSeq(prcSig
.formals
, 2);
284 Bi
.MkDummyMethodAndInsert("hashCode", prcSig
, Cst
.ntvObj
, Cst
.sysLib
, Sy
.pubMode
, Sy
.var
, Id
.extns
);
287 prcSig
.retType
:= Cst
.ntvObj
;
288 Id
.InitParSeq(prcSig
.formals
, 2);
289 Bi
.MkDummyMethodAndInsert("clone", prcSig
, Cst
.ntvObj
, Cst
.sysLib
, Sy
.protect
, Sy
.var
, Id
.extns
);
293 prcSig
.retType
:= Bi
.boolTp
;
294 Id
.InitParSeq(prcSig
.formals
, 2);
295 thePar
.parMod
:= Sy
.val
;
296 thePar
.type
:= Cst
.ntvObj
;
298 Id
.AppendParam(prcSig
.formals
, thePar
);
299 Bi
.MkDummyMethodAndInsert("equals", prcSig
, Cst
.ntvObj
, Cst
.sysLib
, Sy
.pubMode
, Sy
.var
, Id
.extns
);
302 (* ============================================================ *)
303 PROCEDURE (this
: JavaAssembler
)Assemble
*();
306 IF asmList
.tide
> 0 THEN
307 Cst
.Message("Jasmin Assmbler no longer supported");
308 Cst
.Message("The following jasmin text files were created:");
309 FOR ix
:= 0 TO asmList
.tide
-1 DO
310 Console
.Write(ASCII
.HT
);
311 Console
.WriteString(asmList
.a
[ix
]^
);
317 (* ============================================================ *)
319 PROCEDURE (t
: JavaEmitter
)EmitBody(f
: Ju
.JavaFile
),NEW,ABSTRACT
;
320 PROCEDURE^
(e
: JavaEmitter
)EmitProc(proc
: Id
.Procs
),NEW;
321 PROCEDURE^
(e
: JavaEmitter
)EmitStat(stat
: Sy
.Stmt
; OUT ok
: BOOLEAN),NEW;
322 PROCEDURE^
(e
: JavaEmitter
)PushCall(callX
: Xp
.CallX
),NEW;
323 PROCEDURE^
(e
: JavaEmitter
)PushValue(exp
: Sy
.Expr
; typ
: Sy
.Type
),NEW;
324 PROCEDURE^
(e
: JavaEmitter
)FallFalse(exp
: Sy
.Expr
; tLb
: Ju
.Label
),NEW;
325 PROCEDURE^
(e
: JavaEmitter
)ValueCopy(act
: Sy
.Expr
; fmT
: Sy
.Type
),NEW;
326 PROCEDURE^
(e
: JavaEmitter
)PushArg(act
: Sy
.Expr
;
328 VAR seq
: Sy
.ExprSeq
),NEW;
330 (* ============================================================ *)
332 PROCEDURE (t
: JavaRecEmitter
)CopyProc(),NEW;
333 VAR out
: Ju
.JavaFile
;
341 * Emit the copy procedure "__copy__()
344 out
.CopyProcHead(t
.recT
);
345 junk
:= out
.newLocal(); (* create space for two locals *)
346 junk
:= out
.newLocal();
348 * Recurse to super class, if necessary.
350 IF (t
.recT
.baseTp
# NIL) &
351 (t
.recT
.baseTp
IS Ty
.Record
) &
352 ~t
.recT
.baseTp
.isNativeObj() THEN
353 out
.Code(Jvm
.opc_aload_0
);
354 out
.Code(Jvm
.opc_aload_1
);
355 out
.ValRecCopy(t
.recT
.baseTp(Ty
.Record
));
358 * Emit field-by-field copy.
360 FOR indx
:= 0 TO t
.recT
.fields
.tide
-1 DO
361 idnt
:= t
.recT
.fields
.a
[indx
];
363 out
.Code(Jvm
.opc_aload_0
);
364 IF (fTyp
.kind
= Ty
.recTp
) OR
365 (fTyp
.kind
= Ty
.arrTp
) THEN
366 out
.PutGetF(Jvm
.opc_getfield
, t
.recT
, idnt(Id
.FldId
));
368 out
.Code(Jvm
.opc_aload_1
);
369 out
.PutGetF(Jvm
.opc_getfield
, t
.recT
, idnt(Id
.FldId
));
370 WITH fTyp
: Ty
.Array
DO
371 out
.ValArrCopy(fTyp
);
372 | fTyp
: Ty
.Record
DO
373 out
.ValRecCopy(fTyp
);
375 out
.PutGetF(Jvm
.opc_putfield
, t
.recT
, idnt(Id
.FldId
));
381 (* ============================================================ *)
383 PROCEDURE (this
: JavaProcTypeEmitter
)EmitBody(out
: Ju
.JavaFile
);
384 (** Create the assembler for a class file for this proc-type wrapper. *)
385 VAR pType
: Ty
.Procedure
; (* The procedure type that is being emitted *)
386 proxy
: Ty
.Record
; (* The record that stands for the proc-type *)
387 invoke
: Id
.MthId
; (* The abstract invoke method for this *)
390 proxy
:= pType
.hostClass
;
391 proxy
.idnt
:= pType
.idnt
;
392 proxy
.recAtt
:= Ty
.isAbs
;
393 out
.StartRecClass(proxy
);
395 (* Emit the no-arg constructor *)
396 out
.RecMakeInit(proxy
, NIL);
397 out
.CallSuperCtor(proxy
, NIL);
400 (* Emit the abstract Invoke method *)
401 invoke
:= Ju
.getProcVarInvoke(pType
);
402 Ju
.MkProcName(invoke
);
403 Ju
.RenumberLocals(invoke
);
405 out
.StartProc(invoke
);
409 (* ============================================================ *)
411 PROCEDURE (this
: JavaRecEmitter
)EmitBody(out
: Ju
.JavaFile
);
412 (** Create the assembler for a class file for this record. *)
419 sCtTy
: Ty
.Procedure
;
432 out
.StartRecClass(record
);
434 * Emit all the fields ...
436 out
.InitFields(record
.fields
.tide
);
437 FOR index
:= 0 TO record
.fields
.tide
-1 DO
438 out
.EmitField(record
.fields
.a
[index
](Id
.FldId
));
440 out
.InitMethods(record
.methods
.tide
+2);
442 * Emit the no-arg constructor
444 IF ~
(Sy
.noNew
IN record
.xAttr
) &
445 ~
(Sy
.xCtor
IN record
.xAttr
) THEN
446 out
.RecMakeInit(record
, NIL);
447 out
.CallSuperCtor(record
, NIL);
451 * Emit constructors with args
453 FOR index
:= 0 TO record
.statics
.tide
-1 DO
455 ctorD
:= record
.statics
.a
[index
](Id
.PrcId
);
456 out
.RecMakeInit(record
, ctorD
);
458 * Copy args for super constructors with args.
461 sCtor
:= ctorD
.basCll
.sprCtor(Id
.PrcId
);
463 sCtTy
:= sCtor
.type(Ty
.Procedure
);
464 IF sCtTy
.xName
= NIL THEN Ju
.MkCallAttr(sCtor
, sCtTy
) END;
465 FOR parIx
:= 0 TO ctorD
.basCll
.actuals
.tide
-1 DO
466 form
:= sCtTy
.formals
.a
[parIx
];
467 expr
:= ctorD
.basCll
.actuals
.a
[parIx
];
468 this
.PushArg(expr
, form
, ctorD
.basCll
.actuals
);
473 * Now call the super constructor
475 out
.CallSuperCtor(record
, sCtTy
);
476 IF (ctorD
# NIL) & (ctorD
.body
# NIL) THEN
477 IF ctorD
.rescue
# NIL THEN out
.Try
END;
478 this
.EmitStat(ctorD
.body
, live
);
479 IF ctorD
.rescue
# NIL THEN
481 this
.EmitStat(ctorD
.rescue
, live
);
486 IF ~
(Sy
.noCpy
IN record
.xAttr
) THEN this
.CopyProc() END;
488 * Emit all the (non-forward) methods ...
490 FOR index
:= 0 TO record
.methods
.tide
-1 DO
491 ident
:= record
.methods
.a
[index
];
492 method
:= ident(Id
.MthId
);
493 IF method
.kind
= Id
.conMth
THEN
494 IF method
.scopeNm
= NIL THEN
495 Ju
.MkProcName(method
);
496 Ju
.RenumberLocals(method
);
498 this
.EmitProc(method
)
503 (* ============================================================ *)
505 PROCEDURE (this
: JavaModEmitter
)EmitBody(out
: Ju
.JavaFile
);
506 (** Create the assembler for a class file for this module. *)
514 out
.StartModClass(this
.mod
);
515 FOR index
:= 0 TO this
.mod
.procs
.tide
-1 DO
517 * Create the mangled name for all non-forward procedures
519 proc
:= this
.mod
.procs
.a
[index
];
520 IF (proc
.kind
= Id
.conPrc
) OR
521 (proc
.kind
= Id
.conMth
) THEN
523 Ju
.RenumberLocals(proc
);
527 * Do all the fields (ie. static vars)
529 out
.InitFields(this
.mod
.locals
.tide
);
530 FOR index
:= 0 TO this
.mod
.locals
.tide
-1 DO
531 varId
:= this
.mod
.locals
.a
[index
](Id
.VarId
);
532 out
.EmitField(varId
);
535 FOR index := 0 TO this.mod.procs.tide-1 DO
537 * Create the mangled name for all non-forward procedures
539 proc
:= this
.mod
.procs
.a
[index
];
540 IF (proc
.kind
= Id
.conPrc
) OR
541 (proc
.kind
= Id
.conMth
) THEN
543 Ju
.RenumberLocals(proc
);
548 * Do all the procs, including <init> and <clinit>
550 out
.InitMethods(this
.mod
.procs
.tide
+3);
553 out
.InitVars(this
.mod
);
554 IF this
.mod
.main
THEN
556 * Emit <clinit>, and module body as main()
560 this
.EmitStat(this
.mod
.modBody
, returned
);
562 this
.EmitStat(this
.mod
.modClose
, returned
);
567 * Emit single <clinit> incorporating module body
569 this
.EmitStat(this
.mod
.modBody
, returned
);
573 * Emit all of the static procedures
575 FOR index
:= 0 TO this
.mod
.procs
.tide
-1 DO
576 proc
:= this
.mod
.procs
.a
[index
];
577 IF (proc
.kind
= Id
.conPrc
) &
578 (proc
.dfScp
.kind
= Id
.modId
) THEN this
.EmitProc(proc
) END;
581 * And now, just in case exported types have been missed ...
582 * For example, if they are unreferenced in this module.
584 FOR index
:= 0 TO this
.mod
.expRecs
.tide
-1 DO
585 type
:= this
.mod
.expRecs
.a
[index
];
586 IF type
.xName
= NIL THEN
587 WITH type
: Ty
.Record
DO
589 | type
: Ty
.Procedure
DO
590 Ju
.MkProcTypeName(type
);
596 (* ============================================================ *)
598 PROCEDURE (this
: JavaEmitter
)Emit
*();
599 (** Create the assembler for a class file for this module. *)
600 VAR fileName
: FileNames
.NameString
;
601 cf
: ClassUtil
.ClassFile
;
602 jf
: JsmnUtil
.JsmnFile
;
605 * Create the classFile structure, and open the output file.
606 * The default for the JVM target is to write a class file
607 * directly. The -jasmin option writes a jasmin output file
608 * but does not call the (now unavailable) assembler.
610 IF Cst
.doCode
& ~Cst
.doJsmn
THEN
611 WITH this
: JavaModEmitter
DO
612 L
.ToStr(this
.mod
.xName
, fileName
);
613 | this
: JavaRecEmitter
DO
614 L
.ToStr(this
.recT
.xName
, fileName
);
615 | this
: JavaProcTypeEmitter
DO
616 L
.ToStr(this
.prcT
.xName
, fileName
);
618 fileName
:= fileName
+ ".class";
619 cf
:= ClassUtil
.newClassFile(fileName
);
622 WITH this
: JavaModEmitter
DO
623 Sy
.getName
.Of(this
.mod
, fileName
);
624 | this
: JavaRecEmitter
DO
625 FileNames
.StripUpToLast("/", this
.recT
.xName
, fileName
);
626 | this
: JavaProcTypeEmitter
DO
627 FileNames
.StripUpToLast("/", this
.prcT
.xName
, fileName
);
629 fileName
:= fileName
+ ".j";
630 jf
:= JsmnUtil
.newJsmnFile(fileName
);
633 * Add this file to the list to assemble
635 L
.AppendCharOpen(asmList
, L
.strToCharOpen(fileName
));
637 IF this
.outF
= NIL THEN
638 CPascalS
.SemError
.Report(177, 0, 0);
639 Error
.WriteString("Cannot create out-file <" + fileName
+ ">");
643 IF Cst
.verbose
THEN Cst
.Message("Created "+ fileName
) END;
644 this
.outF
.Header(Cst
.srcNam
);
645 this
.EmitBody(this
.outF
);
650 (* ============================================================ *)
651 (* Shared code-emission methods *)
652 (* ============================================================ *)
654 PROCEDURE (e
: JavaEmitter
)EmitProc(proc
: Id
.Procs
),NEW;
655 VAR out
: Ju
.JavaFile
;
660 procName
: FileNames
.NameString
;
663 * Recursively emit nested procedures first.
665 FOR indx
:= 0 TO proc
.nestPs
.tide
-1 DO
666 nest
:= proc
.nestPs
.a
[indx
];
667 IF nest
.kind
= Id
.conPrc
THEN e
.EmitProc(nest
) END;
673 * Output the body if not ABSTRACT
675 IF ~out
.isAbstract() THEN
677 * Initialize any locals which need this.
680 IF proc
.rescue
# NIL THEN out
.Try
END;
682 * Finally! Emit the method body.
684 e
.EmitStat(proc
.body
, live
);
686 * For proper procedure which reach the fall-
687 * through ending, copy OUT params and return.
689 IF live
& proc
.type
.isProperProcType() THEN
690 out
.FixOutPars(proc
, retn
);
693 IF proc
.rescue
# NIL THEN
695 e
.EmitStat(proc
.rescue
, live
);
696 IF live
& proc
.type
.isProperProcType() THEN
697 out
.FixOutPars(proc
, retn
);
705 (* ============================================================ *)
706 (* Expression Handling Methods *)
707 (* ============================================================ *)
709 PROCEDURE longValue(lit
: Sy
.Expr
) : LONGINT;
711 RETURN lit(Xp
.LeafX
).value
.long();
714 PROCEDURE intValue(lit
: Sy
.Expr
) : INTEGER;
716 RETURN lit(Xp
.LeafX
).value
.int();
719 PROCEDURE isStrExp(exp
: Sy
.Expr
) : BOOLEAN;
721 RETURN (exp
.type
= Bi
.strTp
) &
722 (exp
.kind
# Xp
.mkStr
) OR
723 exp
.type
.isNativeStr();
726 (* ============================================================ *)
728 PROCEDURE (e
: JavaEmitter
)UbyteClear(),NEW;
729 VAR out
: Ju
.JavaFile
;
733 out
.Code(Jvm
.opc_iand
);
736 (* ============================================================ *)
738 PROCEDURE (e
: JavaEmitter
)newLeaf(rd
: INTEGER; tp
: Sy
.Type
) : Xp
.IdLeaf
,NEW;
744 id
.dfScp
:= e
.outF
.getScope();
745 RETURN Xp
.mkIdLeaf(id
);
748 (* ============================================================ *)
750 PROCEDURE RevTest(tst
: INTEGER) : INTEGER;
753 | Xp
.equal
: RETURN Xp
.notEq
;
754 | Xp
.notEq
: RETURN Xp
.equal
;
755 | Xp
.greT
: RETURN Xp
.lessEq
;
756 | Xp
.lessT
: RETURN Xp
.greEq
;
757 | Xp
.greEq
: RETURN Xp
.lessT
;
758 | Xp
.lessEq
: RETURN Xp
.greT
;
762 (* ============================================================ *)
764 PROCEDURE (e
: JavaEmitter
)DoCmp(cmpE
: INTEGER;
767 (** Compare two TOS elems and jump to tLab if true. *)
768 (* ------------------------------------------------- *)
769 VAR out
: Ju
.JavaFile
;
772 (* ------------------------------------------------- *)
773 PROCEDURE test(t
: INTEGER) : INTEGER;
776 | Xp
.greT
: RETURN Jvm
.opc_ifgt
;
777 | Xp
.greEq
: RETURN Jvm
.opc_ifge
;
778 | Xp
.notEq
: RETURN Jvm
.opc_ifne
;
779 | Xp
.lessEq
: RETURN Jvm
.opc_ifle
;
780 | Xp
.lessT
: RETURN Jvm
.opc_iflt
;
781 | Xp
.equal
: RETURN Jvm
.opc_ifeq
;
784 (* ------------------------------------------------- *)
787 code
:= test(cmpE
); (* default code *)
788 WITH type
: Ty
.Base
DO
791 | Ty
.strN
, Ty
.sStrN
: out
.CallRTS(Ju
.StrCmp
,2,1);
792 | Ty
.realN
: out
.Code(Jvm
.opc_dcmpl
);
793 | Ty
.sReaN
: out
.Code(Jvm
.opc_fcmpl
);
794 | Ty
.lIntN
: out
.Code(Jvm
.opc_lcmp
);
795 | Ty
.anyRec
, Ty
.anyPtr
:
797 | Xp
.notEq
: code
:= Jvm
.opc_if_acmpne
;
798 | Xp
.equal
: code
:= Jvm
.opc_if_acmpeq
;
800 ELSE (* Ty.boolN,Ty.sChrN,Ty.charN,Ty.byteN,Ty.sIntN,Ty.intN,Ty.setN *)
802 | Xp
.greT
: code
:= Jvm
.opc_if_icmpgt
; (* override default code *)
803 | Xp
.greEq
: code
:= Jvm
.opc_if_icmpge
;
804 | Xp
.notEq
: code
:= Jvm
.opc_if_icmpne
;
805 | Xp
.lessEq
: code
:= Jvm
.opc_if_icmple
;
806 | Xp
.lessT
: code
:= Jvm
.opc_if_icmplt
;
807 | Xp
.equal
: code
:= Jvm
.opc_if_icmpeq
;
810 ELSE (* This must be a reference or string comparison *)
811 IF type
.isCharArrayType() THEN out
.CallRTS(Ju
.StrCmp
,2,1);
812 ELSIF cmpE
= Xp
.equal
THEN code
:= Jvm
.opc_if_acmpeq
;
813 ELSIF cmpE
= Xp
.notEq
THEN code
:= Jvm
.opc_if_acmpne
;
816 out
.CodeLb(code
, tLab
);
819 (* ================= old code =========================== *
820 * IF type IS Ty.Base THEN
821 * tNum := type(Ty.Base).tpOrd;
822 * IF (tNum = Ty.strN) OR (tNum = Ty.sStrN) THEN
823 * out.CallRTS(Ju.StrCmp,2,1);
824 * ELSIF tNum = Ty.realN THEN
825 * out.Code(Jvm.opc_dcmpl);
826 * ELSIF tNum = Ty.sReaN THEN
827 * out.Code(Jvm.opc_fcmpl);
828 * ELSIF tNum = Ty.lIntN THEN
829 * out.Code(Jvm.opc_lcmp);
830 * ELSE (* Common, integer cases use separate instructions *)
832 * | Xp
.greT
: code
:= Jvm
.opc_if_icmpgt
; (* override default *)
833 * | Xp
.greEq
: code
:= Jvm
.opc_if_icmpge
;
834 * | Xp
.notEq
: code
:= Jvm
.opc_if_icmpne
;
835 * | Xp
.lessEq
: code
:= Jvm
.opc_if_icmple
;
836 * | Xp
.lessT
: code
:= Jvm
.opc_if_icmplt
;
837 * | Xp
.equal
: code
:= Jvm
.opc_if_icmpeq
;
840 * ELSE (* This must be a reference or string comparison *)
841 * IF type
.isCharArrayType() THEN
842 * out
.CallRTS(Ju
.StrCmp
,2,1);
843 * ELSIF cmpE
= Xp
.equal
THEN
844 * code
:= Jvm
.opc_if_acmpeq
;
845 * ELSIF cmpE
= Xp
.notEq
THEN
846 * code
:= Jvm
.opc_if_acmpne
;
849 * out
.CodeLb(code
, tLab
);
851 * ================= old code
=========================== *)
853 (* ---------------------------------------------------- *)
855 PROCEDURE (e
: JavaEmitter
)SetCmp(lOp
,rOp
: Sy
.Expr
;
857 theTest
: INTEGER),NEW;
858 VAR out
: Ju
.JavaFile
;
863 e
.PushValue(lOp
, Bi
.setTp
);
865 (* ---------------------------------- *)
867 e
.PushValue(rOp
, Bi
.setTp
);
868 out
.CodeLb(Jvm
.opc_if_icmpeq
, theLabl
);
869 (* ---------------------------------- *)
871 e
.PushValue(rOp
, Bi
.setTp
);
872 out
.CodeLb(Jvm
.opc_if_icmpne
, theLabl
);
873 (* ---------------------------------- *)
874 | Xp
.greEq
, Xp
.lessEq
:
876 * The semantics are implemented by the identities
878 * (L <= R) == (L AND R = L)
879 * (L >= R) == (L OR R = L)
881 out
.Code(Jvm
.opc_dup
);
882 e
.PushValue(rOp
, Bi
.setTp
);
883 IF theTest
= Xp
.greEq
THEN
884 out
.Code(Jvm
.opc_ior
);
886 out
.Code(Jvm
.opc_iand
);
888 out
.CodeLb(Jvm
.opc_if_icmpeq
, theLabl
);
889 (* ---------------------------------- *)
890 | Xp
.greT
, Xp
.lessT
:
892 * The semantics are implemented by the identities
894 * (L < R) == (L AND R = L) AND NOT (L = R)
895 * (L > R) == (L OR R = L) AND NOT (L = R)
899 xit
:= out
.newLabel();
900 out
.Code(Jvm
.opc_dup
); (* ... L,L *)
901 out
.Code(Jvm
.opc_dup
); (* ... L,L,L *)
902 out
.StoreLocal(l
, Bi
.setTp
); (* ... L,L, *)
903 e
.PushValue(rOp
, Bi
.setTp
); (* ... L,L,R *)
904 out
.Code(Jvm
.opc_dup
); (* ... L,L,R,R *)
905 out
.StoreLocal(r
, Bi
.setTp
); (* ... L,L,R *)
906 IF theTest
= Xp
.greT
THEN
907 out
.Code(Jvm
.opc_ior
); (* ... L,LvR *)
909 out
.Code(Jvm
.opc_iand
); (* ... L,L^R *)
911 out
.CodeLb(Jvm
.opc_if_icmpne
, xit
);
912 out
.LoadLocal(l
, Bi
.setTp
); (* ... L@R,l *)
913 out
.LoadLocal(r
, Bi
.setTp
); (* ... L@R,l,r *)
914 out
.CodeLb(Jvm
.opc_if_icmpne
, theLabl
);
921 (* ---------------------------------------------------- *)
923 PROCEDURE (e
: JavaEmitter
)BinCmp(exp
: Sy
.Expr
;
925 rev
: BOOLEAN; (* reverse sense *)
927 VAR binOp
: Xp
.BinaryX
;
930 binOp
:= exp(Xp
.BinaryX
);
931 lType
:= binOp
.lKid
.type
;
932 IF rev
THEN tst
:= RevTest(tst
) END;
933 IF lType
= Bi
.setTp
THEN (* only partially ordered *)
934 e
.SetCmp(binOp
.lKid
, binOp
.rKid
, lab
, tst
);
935 ELSE (* a totally ordered type *)
936 e
.PushValue(binOp
.lKid
, lType
);
937 IF isStrExp(binOp
.lKid
) THEN
938 e
.outF
.CallRTS(Ju
.StrToChrOpen
,1,1);
940 e
.PushValue(binOp
.rKid
, binOp
.rKid
.type
);
941 IF isStrExp(binOp
.rKid
) THEN
942 e
.outF
.CallRTS(Ju
.StrToChrOpen
,1,1);
944 e
.DoCmp(tst
, lab
, lType
);
948 (* ---------------------------------------------------- *)
950 PROCEDURE (e
: JavaEmitter
)FallTrue(exp
: Sy
.Expr
; fLb
: Ju
.Label
),NEW;
951 (** Evaluate exp, fall through if true, jump to fLab otherwise *)
952 VAR binOp
: Xp
.BinaryX
;
958 | Xp
.tBool
: (* just do nothing *)
960 out
.CodeLb(Jvm
.opc_goto
, fLb
);
962 e
.FallFalse(exp(Xp
.UnaryX
).kid
, fLb
);
963 | Xp
.greT
, Xp
.greEq
, Xp
.notEq
, Xp
.lessEq
, Xp
.lessT
, Xp
.equal
:
964 e
.BinCmp(exp
, exp
.kind
, TRUE
, fLb
);
966 binOp
:= exp(Xp
.BinaryX
);
967 label
:= out
.newLabel();
968 e
.FallFalse(binOp
.lKid
, label
);
969 e
.FallTrue(binOp
.rKid
, fLb
);
972 binOp
:= exp(Xp
.BinaryX
);
973 e
.FallTrue(binOp
.lKid
, fLb
);
974 e
.FallTrue(binOp
.rKid
, fLb
);
976 binOp
:= exp(Xp
.BinaryX
);
977 e
.PushValue(binOp
.lKid
, binOp
.lKid
.type
);
978 out
.CodeT(Jvm
.opc_instanceof
, binOp
.rKid(Xp
.IdLeaf
).ident
.type
);
979 out
.CodeLb(Jvm
.opc_ifeq
, fLb
);
981 binOp
:= exp(Xp
.BinaryX
);
982 out
.Code(Jvm
.opc_iconst_1
);
983 e
.PushValue(binOp
.lKid
, binOp
.lKid
.type
);
984 out
.Code(Jvm
.opc_ishl
);
985 out
.Code(Jvm
.opc_dup
);
986 e
.PushValue(binOp
.rKid
, binOp
.rKid
.type
);
987 out
.Code(Jvm
.opc_iand
);
988 out
.CodeLb(Jvm
.opc_if_icmpne
, fLb
);
989 ELSE (* Xp.fnCll, Xp.qualId, Xp.index, Xp.selct *)
990 e
.PushValue(exp
, exp
.type
); (* boolean variable *)
991 out
.CodeLb(Jvm
.opc_ifeq
, fLb
);
995 (* ---------------------------------------------------- *)
997 PROCEDURE (e
: JavaEmitter
)FallFalse(exp
: Sy
.Expr
; tLb
: Ju
.Label
),NEW;
998 (** Evaluate exp, fall through if false, jump to tLb otherwise *)
999 VAR binOp
: Xp
.BinaryX
;
1005 | Xp
.fBool
: (* just do nothing *)
1007 out
.CodeLb(Jvm
.opc_goto
, tLb
);
1009 e
.FallTrue(exp(Xp
.UnaryX
).kid
, tLb
);
1010 | Xp
.greT
, Xp
.greEq
, Xp
.notEq
, Xp
.lessEq
, Xp
.lessT
, Xp
.equal
:
1011 e
.BinCmp(exp
, exp
.kind
, FALSE
, tLb
);
1013 binOp
:= exp(Xp
.BinaryX
);
1014 e
.FallFalse(binOp
.lKid
, tLb
);
1015 e
.FallFalse(binOp
.rKid
, tLb
);
1017 label
:= out
.newLabel();
1018 binOp
:= exp(Xp
.BinaryX
);
1019 e
.FallTrue(binOp
.lKid
, label
);
1020 e
.FallFalse(binOp
.rKid
, tLb
);
1023 binOp
:= exp(Xp
.BinaryX
);
1024 e
.PushValue(binOp
.lKid
, binOp
.lKid
.type
);
1025 out
.CodeT(Jvm
.opc_instanceof
, binOp
.rKid(Xp
.IdLeaf
).ident
.type
);
1026 out
.CodeLb(Jvm
.opc_ifne
, tLb
);
1028 binOp
:= exp(Xp
.BinaryX
);
1029 out
.Code(Jvm
.opc_iconst_1
);
1030 e
.PushValue(binOp
.lKid
, binOp
.lKid
.type
);
1031 out
.Code(Jvm
.opc_ishl
);
1032 out
.Code(Jvm
.opc_dup
);
1033 e
.PushValue(binOp
.rKid
, binOp
.rKid
.type
);
1034 out
.Code(Jvm
.opc_iand
);
1035 out
.CodeLb(Jvm
.opc_if_icmpeq
, tLb
);
1036 ELSE (* Xp.fnCll, Xp.qualId, Xp.index, Xp.selct *)
1037 e
.PushValue(exp
, exp
.type
); (* boolean variable *)
1038 out
.CodeLb(Jvm
.opc_ifne
, tLb
);
1042 (* ============================================================ *)
1044 PROCEDURE (e
: JavaEmitter
)PushUnary(exp
: Xp
.UnaryX
; dst
: Sy
.Type
),NEW;
1049 (* ------------------------------------- *)
1050 PROCEDURE MkBox(emt
: JavaEmitter
; exp
: Xp
.UnaryX
);
1056 src
:= exp
.kid
.type
;
1057 dst
:= exp
.type(Ty
.Pointer
).boundTp
;
1058 IF isStrExp(exp
.kid
) THEN
1059 emt
.PushValue(exp
.kid
, src
);
1060 out
.CallRTS(Ju
.StrToChrOpen
,1,1);
1062 emt
.ValueCopy(exp
.kid
, dst
);
1065 (* ------------------------------------- *)
1067 IF exp
.kind
= Xp
.mkBox
THEN MkBox(e
,exp
); RETURN END; (* PRE-EMPTIVE RET *)
1068 e
.PushValue(exp
.kid
, exp
.kid
.type
);
1071 | Xp
.mkStr
, Xp
.deref
: (* skip *)
1073 out
.CodeT(Jvm
.opc_checkcast
, exp
.type
.boundRecTp()(Ty
.Record
));
1075 IF ~
isStrExp(exp
.kid
) THEN
1076 out
.CallRTS(Ju
.ChrsToStr
,1,1);
1078 | Xp
.strChk
: (* Some range checks required *)
1079 out
.Code(Jvm
.opc_dup
);
1080 out
.CallRTS(Ju
.StrCheck
,1,0);
1082 out
.Code(Jvm
.opc_iconst_m1
);
1083 out
.Code(Jvm
.opc_ixor
);
1085 dNum
:= dst(Ty
.Base
).tpOrd
;
1086 IF dNum
= Ty
.realN
THEN
1087 code
:= Jvm
.opc_dneg
;
1088 ELSIF dNum
= Ty
.sReaN
THEN
1089 code
:= Jvm
.opc_fneg
;
1090 ELSIF dNum
= Ty
.lIntN
THEN
1091 code
:= Jvm
.opc_lneg
;
1092 ELSE (* all INTEGER cases *)
1093 code
:= Jvm
.opc_ineg
;
1097 dNum
:= dst(Ty
.Base
).tpOrd
;
1098 IF dNum
= Ty
.realN
THEN
1099 out
.Code(Jvm
.opc_dup2
);
1100 out
.Code(Jvm
.opc_dconst_0
);
1101 out
.Code(Jvm
.opc_dcmpg
);
1102 code
:= Jvm
.opc_dneg
;
1103 ELSIF dNum
= Ty
.sReaN
THEN
1104 out
.Code(Jvm
.opc_dup
);
1105 out
.Code(Jvm
.opc_fconst_0
);
1106 out
.Code(Jvm
.opc_fcmpg
);
1107 code
:= Jvm
.opc_fneg
;
1108 ELSIF dNum
= Ty
.lIntN
THEN
1109 out
.Code(Jvm
.opc_dup2
);
1110 out
.Code(Jvm
.opc_lconst_0
);
1111 out
.Code(Jvm
.opc_lcmp
);
1112 code
:= Jvm
.opc_lneg
;
1113 ELSE (* all INTEGER cases *)
1114 out
.Code(Jvm
.opc_dup
);
1115 code
:= Jvm
.opc_ineg
;
1117 labl
:= out
.newLabel();
1118 out
.CodeLb(Jvm
.opc_ifge
, labl
); (* NOT ifle, Aug2001 *)
1122 dNum
:= dst(Ty
.Base
).tpOrd
;
1123 IF dNum
= Ty
.sReaN
THEN out
.Code(Jvm
.opc_f2d
) END;
1125 // We _could_ check if the value is >= 0.0, and
1126 // skip the call in that case, falling through
1127 // into the round-to-zero mode opc_d2l.
1129 out
.CallRTS(Ju
.DFloor
,1,1);
1130 out
.Code(Jvm
.opc_d2l
);
1132 out
.CallRTS(Ju
.ToUpper
,1,1);
1134 out
.Code(Jvm
.opc_iconst_1
);
1135 out
.Code(Jvm
.opc_ixor
);
1137 out
.CallRTS(Ju
.StrLen
,1,1);
1139 IF exp
.kid
.type
.isLongType() THEN out
.Code(Jvm
.opc_l2i
) END;
1140 out
.Code(Jvm
.opc_iconst_1
);
1141 out
.Code(Jvm
.opc_iand
);
1147 (* ============================================================ *)
1149 PROCEDURE (e
: JavaEmitter
)PushVecElemHandle(lOp
,rOp
: Sy
.Expr
),NEW;
1150 VAR vTp
: Ty
.Vector
;
1157 vTp
:= lOp
.type(Ty
.Vector
);
1159 tde
:= out
.newLocal();
1160 xLb
:= out
.newLabel();
1162 e
.PushValue(lOp
, eTp
); (* vRef ... *)
1163 out
.Code(Jvm
.opc_dup
); (* vRef, vRef ... *)
1164 out
.GetVecLen(); (* tide, vRef ... *)
1165 out
.StoreLocal(tde
, Bi
.intTp
); (* vRef ... *)
1167 e
.outF
.GetVecArr(eTp
); (* arr ... *)
1168 e
.PushValue(rOp
, Bi
.intTp
); (* idx, arr ... *)
1169 out
.Code(Jvm
.opc_dup
); (* idx, idx, arr ... *)
1170 out
.LoadLocal(tde
, Bi
.intTp
); (* tide, idx, idx, arr ... *)
1172 out
.CodeLb(Jvm
.opc_if_icmplt
, xLb
);
1173 out
.Trap("Vector index out of bounds");
1175 out
.DefLab(xLb
); (* idx, arr ... *)
1176 out
.ReleaseLocal(tde
);
1177 END PushVecElemHandle
;
1179 (* ============================================================ *)
1181 (* Assert: lOp is already pushed. *)
1182 PROCEDURE ShiftInt(kind
: INTEGER; e
: JavaEmitter
; lOp
: Sy
.Expr
; rOp
: Sy
.Expr
);
1185 shrLab
, fixLab
, s31Lab
, exitLb
: Ju
.Label
;
1188 IF rOp
.kind
= Xp
.numLt
THEN
1189 indx
:= intValue(rOp
);
1190 IF indx
= 0 THEN (* skip *)
1191 ELSIF indx
< -31 THEN (* right shift out *)
1192 IF kind
= Xp
.ashInt
THEN
1194 out
.Code(Jvm
.opc_ishr
);
1196 out
.Code(Jvm
.opc_pop
);
1199 ELSIF indx
< 0 THEN (* right shift *)
1201 IF kind
= Xp
.ashInt
THEN (* arith shift *)
1202 out
.Code(Jvm
.opc_ishr
);
1203 ELSE (* logical shift *)
1204 out
.Code(Jvm
.opc_iushr
);
1206 ELSIF indx
> 31 THEN (* result is zero *)
1207 out
.Code(Jvm
.opc_pop
);
1209 ELSE (* a left shift *)
1211 out
.Code(Jvm
.opc_ishl
);
1213 ELSE (* variable sized shift *)
1214 shrLab
:= out
.newLabel();
1215 fixLab
:= out
.newLabel();
1216 s31Lab
:= out
.newLabel();
1217 exitLb
:= out
.newLabel();
1219 * This is a variable shift. Do it the hard way.
1220 * First, check the sign of the right hand op.
1222 e
.PushValue(rOp
, Bi
.intTp
); (* TOS: rOp, lOp, ... *)
1223 out
.Code(Jvm
.opc_dup
); (* TOS: rOp, rOp, lOp, ... *)
1224 out
.CodeLb(Jvm
.opc_iflt
, shrLab
); (* TOS: rOp, lOp, ... *)
1226 * Positive selector ==> shift left;
1227 * But first: a range check ...
1229 out
.Code(Jvm
.opc_dup
); (* TOS: rOp, rOp, lOp, ... *)
1230 out
.PushInt(31); (* TOS: 31, rOp, rOp, lOp, ... *)
1231 out
.CodeLb(Jvm
.opc_if_icmpgt
, fixLab
); (* TOS: rOp, lOp, ... *)
1232 out
.Code(Jvm
.opc_ishl
); (* TOS: rslt, ... *)
1233 out
.CodeLb(Jvm
.opc_goto
, exitLb
);
1235 * Out of range shift, set result to zero.
1237 out
.DefLab(fixLab
); (* TOS: rOp, lOp, ... *)
1238 out
.Code(Jvm
.opc_pop2
); (* TOS: ... *)
1239 out
.PushInt(0); (* TOS: 0, ... *)
1240 out
.CodeLb(Jvm
.opc_goto
, exitLb
);
1242 * Out of range, rslt = rOp >> 31.
1244 out
.DefLab(s31Lab
); (* TOS: rOp, lOp, ... *)
1245 out
.Code(Jvm
.opc_pop
); (* TOS: lOp, ... *)
1246 out
.PushInt(31); (* TOS: 31, lOp, ... *)
1247 out
.Code(Jvm
.opc_ishr
);
1248 out
.CodeLb(Jvm
.opc_goto
, exitLb
);
1250 * Negative selector ==> shift right;
1252 out
.DefLab(shrLab
); (* TOS: rOp, lOp, ... *)
1253 out
.Code(Jvm
.opc_ineg
); (* TOS: -rOp, lOp, ... *)
1254 out
.Code(Jvm
.opc_dup
); (* TOS: -rOp, -rOp, lOp, ... *)
1255 out
.PushInt(31); (* TOS: 31, -rOp, -rOp, lOp, ...*)
1256 IF kind
= Xp
.lshInt
THEN (* LSH *)
1257 out
.CodeLb(Jvm
.opc_if_icmpgt
, fixLab
); (* TOS: -rOp, lOp, ... *)
1258 out
.Code(Jvm
.opc_iushr
); (* TOS: rslt, ... *)
1259 ELSE (* ASH *) (* TOS: 31, rOp, rOp, lOp, ... *)
1260 out
.CodeLb(Jvm
.opc_if_icmpgt
, s31Lab
); (* TOS: rOp, lOp, ... *)
1261 out
.Code(Jvm
.opc_ishr
); (* TOS: rslt, ... *)
1267 (* ============================================================ *)
1269 (* Assert: lOp is already pushed. *)
1270 PROCEDURE ShiftLong(kind
: INTEGER; e
: JavaEmitter
; lOp
: Sy
.Expr
; rOp
: Sy
.Expr
);
1273 shrLab
, fixLab
, s63Lab
, exitLb
: Ju
.Label
;
1276 IF rOp
.kind
= Xp
.numLt
THEN
1277 indx
:= intValue(rOp
);
1278 IF indx
= 0 THEN (* skip *)
1279 ELSIF indx
< -63 THEN (* right shift out *)
1280 IF kind
= Xp
.ashInt
THEN
1282 out
.Code(Jvm
.opc_lshr
);
1284 out
.Code(Jvm
.opc_pop2
);
1287 ELSIF indx
< 0 THEN (* right shift *)
1289 IF kind
= Xp
.ashInt
THEN (* arith shift *)
1290 out
.Code(Jvm
.opc_lshr
);
1291 ELSE (* logical shift *)
1292 out
.Code(Jvm
.opc_lushr
);
1294 ELSIF indx
> 63 THEN (* result is zero *)
1295 out
.Code(Jvm
.opc_pop2
);
1297 ELSE (* a left shift *)
1299 out
.Code(Jvm
.opc_lshl
);
1301 ELSE (* variable sized shift *)
1302 shrLab
:= out
.newLabel();
1303 fixLab
:= out
.newLabel();
1304 s63Lab
:= out
.newLabel();
1305 exitLb
:= out
.newLabel();
1307 * This is a variable shift. Do it the hard way.
1308 * First, check the sign of the right hand op.
1310 e
.PushValue(rOp
, Bi
.intTp
); (* TOS: rOp, lOp, ... *)
1311 out
.Code(Jvm
.opc_dup
); (* TOS: rOp, rOp, lOp, ... *)
1312 out
.CodeLb(Jvm
.opc_iflt
, shrLab
); (* TOS: rOp, lOp, ... *)
1314 * Positive selector ==> shift left;
1315 * But first: a range check ...
1317 out
.Code(Jvm
.opc_dup
); (* TOS: rOp, rOp, lOp, ... *)
1318 out
.PushInt(63); (* TOS: 63, rOp, rOp, lOp, ... *)
1319 out
.CodeLb(Jvm
.opc_if_icmpgt
, fixLab
); (* TOS: rOp, lOp, ... *)
1320 out
.Code(Jvm
.opc_lshl
); (* TOS: rslt, ... *)
1321 out
.CodeLb(Jvm
.opc_goto
, exitLb
);
1323 * Out of range shift, set result to zero.
1325 out
.DefLab(fixLab
); (* TOS: rOp, lOp, ... *)
1326 out
.Code(Jvm
.opc_pop
); (* TOS: lOp, ... *)
1327 out
.Code(Jvm
.opc_pop2
); (* TOS: ... *)
1328 out
.PushLong(0); (* TOS: 0, ... *)
1329 out
.CodeLb(Jvm
.opc_goto
, exitLb
);
1331 * Out of range, rslt = rOp >> 63.
1333 out
.DefLab(s63Lab
); (* TOS: rOp, lOp, ... *)
1334 out
.Code(Jvm
.opc_pop
); (* TOS: lOp, ... *)
1335 out
.PushInt(63); (* TOS: 63, lOp, ... *)
1336 out
.Code(Jvm
.opc_lshr
);
1337 out
.CodeLb(Jvm
.opc_goto
, exitLb
);
1339 * Negative selector ==> shift right;
1341 out
.DefLab(shrLab
); (* TOS: rOp, lOp, ... *)
1342 out
.Code(Jvm
.opc_ineg
); (* TOS: -rOp, lOp, ... *)
1343 out
.Code(Jvm
.opc_dup
); (* TOS: -rOp, -rOp, lOp, ... *)
1344 out
.PushInt(63); (* TOS: 63, -rOp, -rOp, lOp, ...*)
1345 IF kind
= Xp
.lshInt
THEN (* LSH *)
1346 out
.CodeLb(Jvm
.opc_if_icmpgt
, fixLab
); (* TOS: -rOp, lOp, ... *)
1347 out
.Code(Jvm
.opc_lushr
); (* TOS: rslt, ... *)
1348 ELSE (* ASH *) (* TOS: 31, rOp, rOp, lOp, ... *)
1349 out
.CodeLb(Jvm
.opc_if_icmpgt
, s63Lab
); (* TOS: rOp, lOp, ... *)
1350 out
.Code(Jvm
.opc_lshr
); (* TOS: rslt, ... *)
1356 (* ============================================================ *)
1357 (* Assert: lOp is already pushed. *)
1358 PROCEDURE RotateInt(e
: JavaEmitter
; lOp
: Sy
.Expr
; rOp
: Sy
.Expr
);
1360 temp
, ixSv
: INTEGER; (* local vars *)
1361 indx
: INTEGER; (* literal index *)
1366 IF lOp
.type
= Bi
.sIntTp
THEN
1368 out
.ConvertDn(Bi
.intTp
, Bi
.charTp
);
1369 ELSIF (lOp
.type
= Bi
.byteTp
) OR (lOp
.type
= Bi
.uBytTp
) THEN
1371 out
.ConvertDn(Bi
.intTp
, Bi
.uBytTp
);
1375 temp
:= out
.newLocal();
1376 IF rOp
.kind
= Xp
.numLt
THEN
1377 indx
:= intValue(rOp
) MOD rtSz
;
1378 IF indx
= 0 THEN (* skip *)
1380 * Rotation is achieved by means of the identity
1381 * Forall 0 <= n < rtSz:
1382 * ROT(a, n) = LSH(a,n) bitwiseOR LSH(a,n-rtSz);
1384 out
.Code(Jvm
.opc_dup
);
1385 out
.StoreLocal(temp
, Bi
.intTp
);
1387 out
.Code(Jvm
.opc_ishl
);
1388 out
.LoadLocal(temp
, Bi
.intTp
);
1389 out
.PushInt(rtSz
- indx
);
1390 out
.Code(Jvm
.opc_iushr
);
1391 out
.Code(Jvm
.opc_ior
);
1392 out
.ConvertDn(Bi
.intTp
, lOp
.type
);
1395 ixSv
:= out
.newLocal();
1396 out
.Code(Jvm
.opc_dup
); (* TOS: lOp, lOp, ... *)
1397 out
.StoreLocal(temp
, Bi
.intTp
); (* TOS: lOp, ... *)
1398 e
.PushValue(rOp
, rOp
.type
); (* TOS: rOp, lOp, ... *)
1399 out
.PushInt(rtSz
-1); (* TOS: 31, rOp, lOp, ... *)
1400 out
.Code(Jvm
.opc_iand
); (* TOS: rOp', lOp, ... *)
1401 out
.Code(Jvm
.opc_dup
); (* TOS: rOp', rOp', lOp, ... *)
1402 out
.StoreLocal(ixSv
, Bi
.intTp
); (* TOS: rOp', lOp, ... *)
1403 out
.Code(Jvm
.opc_ishl
); (* TOS: lRz, ... *)
1404 out
.LoadLocal(temp
, Bi
.intTp
); (* TOS: lOp, lRz, ... *)
1405 out
.PushInt(rtSz
); (* TOS: 32, lOp, lRz, ... *)
1406 out
.LoadLocal(ixSv
, Bi
.intTp
); (* TOS: rOp',32, lOp, lRz, ... *)
1407 out
.Code(Jvm
.opc_isub
); (* TOS: rOp'', lOp, lRz, ... *)
1408 out
.Code(Jvm
.opc_iushr
); (* TOS: rRz, lRz, ... *)
1409 out
.Code(Jvm
.opc_ior
); (* TOS: ROT(lOp, rOp), ... *)
1410 out
.ReleaseLocal(ixSv
);
1411 out
.ConvertDn(Bi
.intTp
, lOp
.type
);
1413 out
.ReleaseLocal(temp
);
1416 (* ============================================================ *)
1418 (* Assert: lOp is already pushed. *)
1419 PROCEDURE RotateLong(e
: JavaEmitter
; lOp
: Sy
.Expr
; rOp
: Sy
.Expr
);
1421 tmp1
,tmp2
, ixSv
: INTEGER; (* local vars *)
1422 indx
: INTEGER; (* literal index *)
1426 tmp1
:= out
.newLocal(); (* Pair of locals *)
1427 tmp2
:= out
.newLocal();
1428 IF rOp
.kind
= Xp
.numLt
THEN
1429 indx
:= intValue(rOp
) MOD 64;
1430 IF indx
= 0 THEN (* skip *)
1432 * Rotation is achieved by means of the identity
1433 * Forall 0 <= n < rtSz:
1434 * ROT(a, n) = LSH(a,n) bitwiseOR LSH(a,n-rtSz);
1436 out
.Code(Jvm
.opc_dup2
);
1437 out
.StoreLocal(tmp1
, Bi
.lIntTp
);
1439 out
.Code(Jvm
.opc_lshl
);
1440 out
.LoadLocal(tmp1
, Bi
.lIntTp
);
1441 out
.PushInt(64 - indx
);
1442 out
.Code(Jvm
.opc_lushr
);
1443 out
.Code(Jvm
.opc_lor
);
1446 ixSv
:= out
.newLocal();
1447 out
.Code(Jvm
.opc_dup2
); (* TOS: lOp, lOp, ... *)
1448 out
.StoreLocal(tmp1
, Bi
.lIntTp
); (* TOS: lOp, ... *)
1449 e
.PushValue(rOp
, rOp
.type
); (* TOS: rOp, lOp, ... *)
1450 out
.PushInt(63); (* TOS: 31, rOp, lOp, ... *)
1451 out
.Code(Jvm
.opc_iand
); (* TOS: rOp', lOp, ... *)
1452 out
.Code(Jvm
.opc_dup
); (* TOS: rOp', rOp', lOp, ... *)
1453 out
.StoreLocal(ixSv
, Bi
.intTp
); (* TOS: rOp', lOp, ... *)
1454 out
.Code(Jvm
.opc_lshl
); (* TOS: lRz, ... *)
1455 out
.LoadLocal(tmp1
, Bi
.lIntTp
); (* TOS: lOp, lRz, ... *)
1456 out
.PushInt(64); (* TOS: 32, lOp, lRz, ... *)
1457 out
.LoadLocal(ixSv
, Bi
.intTp
); (* TOS: rOp',32, lOp, lRz, ... *)
1458 out
.Code(Jvm
.opc_isub
); (* TOS: rOp'', lOp, lRz, ... *)
1459 out
.Code(Jvm
.opc_lushr
); (* TOS: rRz, lRz, ... *)
1460 out
.Code(Jvm
.opc_lor
); (* TOS: ROT(lOp, rOp), ... *)
1461 out
.ReleaseLocal(ixSv
);
1463 out
.ReleaseLocal(tmp2
);
1464 out
.ReleaseLocal(tmp1
);
1467 (* ============================================================ *)
1469 PROCEDURE (e
: JavaEmitter
)PushBinary(exp
: Xp
.BinaryX
; dst
: Sy
.Type
),NEW;
1470 VAR out
: Ju
.JavaFile
;
1482 (* -------------------------------- *)
1483 PROCEDURE plusCode(tNnm
: INTEGER) : INTEGER;
1486 | Ty
.realN
: RETURN Jvm
.opc_dadd
;
1487 | Ty
.sReaN
: RETURN Jvm
.opc_fadd
;
1488 | Ty
.lIntN
: RETURN Jvm
.opc_ladd
;
1489 ELSE RETURN Jvm
.opc_iadd
;
1492 (* -------------------------------- *)
1493 PROCEDURE minusCode(tNnm
: INTEGER) : INTEGER;
1496 | Ty
.realN
: RETURN Jvm
.opc_dsub
;
1497 | Ty
.sReaN
: RETURN Jvm
.opc_fsub
;
1498 | Ty
.lIntN
: RETURN Jvm
.opc_lsub
;
1499 ELSE RETURN Jvm
.opc_isub
;
1502 (* -------------------------------- *)
1503 PROCEDURE multCode(tNnm
: INTEGER) : INTEGER;
1506 | Ty
.realN
: RETURN Jvm
.opc_dmul
;
1507 | Ty
.sReaN
: RETURN Jvm
.opc_fmul
;
1508 | Ty
.lIntN
: RETURN Jvm
.opc_lmul
;
1509 ELSE RETURN Jvm
.opc_imul
;
1512 (* -------------------------------- *)
1513 BEGIN (* PushBinary *)
1518 (* -------------------------------- *)
1520 IF exp
.lKid
.type
IS Ty
.Vector
THEN
1521 e
.PushVecElemHandle(lOp
, rOp
);
1522 out
.GetVecElement(dst
); (* load the element *)
1524 IF rOp
.type
= NIL THEN rOp
.type
:= Bi
.intTp
END;
1525 e
.PushValue(lOp
, lOp
.type
); (* push arr. desig. *)
1526 e
.PushValue(rOp
, rOp
.type
); (* push index value *)
1527 out
.GetElement(lOp
.type(Ty
.Array
).elemTp
); (* load the element *)
1528 IF dst
= Bi
.uBytTp
THEN e
.UbyteClear() END;
1530 (* -------------------------------- *)
1531 | Xp
.range
: (* set i..j range ... *)
1532 (* We want to create an integer with bits-- *)
1533 (* [0...01...10...0] *)
1534 (* MSB==31 j i 0==LSB *)
1535 (* One method is A *)
1536 (* 1) [0..010........0] 1 << (j+1) *)
1537 (* 2) [1..110........0] negate(1) *)
1538 (* 3) [0.......010...0] 1 << i *)
1539 (* 4) [1.......110...0] negate(3) *)
1540 (* 5) [0...01...10...0] (2)xor(4) *)
1541 (* Another method is B *)
1542 (* 1) [1.............1] -1 *)
1543 (* 2) [0...01........1] (1) >>> (31-j) *)
1544 (* 3) [0........01...1] (2) >> i *)
1545 (* 4) [0...01...10...0] (3) << i *)
1546 (* --------------------------------------------- *
1550 * out
.Code(Jvm
.opc_iconst_1
); *
1551 * out
.Code(Jvm
.opc_iconst_1
); *
1552 * e
.PushValue(rOp
, Bi
.intTp
); *
1553 * (* Do unsigned less than 32 test here *) *
1554 * out
.Code(Jvm
.opc_iadd
); *
1555 * out
.Code(Jvm
.opc_ishl
); *
1556 * out
.Code(Jvm
.opc_ineg
); *
1557 * out
.Code(Jvm
.opc_iconst_1
); *
1558 * e
.PushValue(lOp
, Bi
.intTp
); *
1559 * (* Do unsigned less than 32 test here *) *
1560 * out
.Code(Jvm
.opc_ishl
); *
1561 * out
.Code(Jvm
.opc_ineg
); *
1562 * out
.Code(Jvm
.opc_ixor
); *
1563 * -------------------------------------------- *)
1567 IF rOp
.kind
= Xp
.numLt
THEN
1568 (* out.PushInt(-1 >>> (31 - intValue(rOp))); *)
1569 out
.PushInt(ORD({0 .. intValue(rOp
)}));
1571 out
.Code(Jvm
.opc_iconst_m1
);
1573 e
.PushValue(rOp
, Bi
.intTp
);
1574 (* Do unsigned less than 32 test here ...*)
1575 out
.Code(Jvm
.opc_isub
);
1576 out
.Code(Jvm
.opc_iushr
);
1578 IF lOp
.kind
= Xp
.numLt
THEN
1579 (* out.PushInt(-1 << intValue(lOp)); *)
1580 out
.PushInt(ORD({intValue(lOp
) .. 31}));
1581 out
.Code(Jvm
.opc_iand
);
1583 e
.PushValue(lOp
, Bi
.intTp
);
1584 (* Do unsigned less than 32 test here ...*)
1585 out
.Code(Jvm
.opc_dup_x1
);
1586 out
.Code(Jvm
.opc_ishr
);
1587 out
.Code(Jvm
.opc_swap
);
1588 out
.Code(Jvm
.opc_ishl
);
1590 (* -------------------------------- *)
1592 e
.PushValue(lOp
, lOp
.type
);
1593 IF lOp
.type
IS Ty
.Vector
THEN
1596 FOR indx
:= 0 TO intValue(rOp
) - 1 DO
1597 out
.Code(Jvm
.opc_iconst_0
);
1598 out
.Code(Jvm
.opc_aaload
);
1600 out
.Code(Jvm
.opc_arraylength
);
1602 (* -------------------------------- *)
1603 | Xp
.maxOf
, Xp
.minOf
:
1604 long
:= dst
.isLongType();
1605 tpLb
:= out
.newLabel();
1606 exLb
:= out
.newLabel();
1608 * Push left operand, duplicate
1609 * stack is (top) lOp lOp ...
1611 e
.PushValue(lOp
, dst
);
1613 out
.Code(Jvm
.opc_dup2
);
1615 out
.Code(Jvm
.opc_dup
);
1618 * Push right operand
1619 * stack is (top) rOp lOp lOp ...
1621 e
.PushValue(rOp
, dst
);
1623 * Duplicate and stow
1624 * stack is (top) rOp lOp rOp lOp ...
1627 out
.Code(Jvm
.opc_dup2_x2
);
1629 out
.Code(Jvm
.opc_dup_x1
);
1632 * Compare two top items and jump
1633 * stack is (top) rOp lOp ...
1635 IF exp
.kind
= Xp
.maxOf
THEN
1636 e
.DoCmp(Xp
.lessT
, tpLb
, dst
);
1638 e
.DoCmp(Xp
.greT
, tpLb
, dst
);
1640 indx
:= out
.getDepth();
1643 * stack is (top) lOp ...
1646 out
.Code(Jvm
.opc_pop2
);
1648 out
.Code(Jvm
.opc_pop
);
1650 out
.CodeLb(Jvm
.opc_goto
, exLb
);
1654 * Swap top two items and discard top
1655 * stack is (top) rOp ...
1658 out
.Code(Jvm
.opc_dup2_x2
);
1659 out
.Code(Jvm
.opc_pop2
);
1660 out
.Code(Jvm
.opc_pop2
);
1662 out
.Code(Jvm
.opc_swap
);
1663 out
.Code(Jvm
.opc_pop
);
1666 (* -------------------------------- *)
1668 e
.PushValue(lOp
, dst
);
1669 e
.PushValue(rOp
, dst
);
1671 * A literal bitAnd might be a long
1672 * operation, from a folded MOD.
1674 IF dst
.isLongType() THEN
1675 out
.Code(Jvm
.opc_land
);
1677 out
.Code(Jvm
.opc_iand
);
1679 (* -------------------------------- *)
1681 e
.PushValue(lOp
, dst
);
1682 e
.PushValue(rOp
, dst
);
1683 out
.Code(Jvm
.opc_ior
);
1684 (* -------------------------------- *)
1686 e
.PushValue(lOp
, dst
);
1687 e
.PushValue(rOp
, dst
);
1688 out
.Code(Jvm
.opc_ixor
);
1689 (* -------------------------------- *)
1691 dNum
:= dst(Ty
.Base
).tpOrd
;
1692 e
.PushValue(lOp
, dst
);
1693 e
.PushValue(rOp
, dst
);
1694 out
.Code(plusCode(dNum
));
1695 (* -------------------------------- *)
1697 dNum
:= dst(Ty
.Base
).tpOrd
;
1698 e
.PushValue(lOp
, dst
);
1699 e
.PushValue(rOp
, dst
);
1700 out
.Code(minusCode(dNum
));
1701 (* -------------------------------- *)
1703 dNum
:= dst(Ty
.Base
).tpOrd
;
1704 e
.PushValue(lOp
, dst
);
1705 e
.PushValue(rOp
, dst
);
1706 out
.Code(multCode(dNum
));
1707 (* -------------------------------- *)
1709 e
.PushValue(lOp
, dst
);
1710 e
.PushValue(rOp
, dst
);
1711 out
.Code(Jvm
.opc_ddiv
);
1712 (* -------------------------------- *)
1714 dNum
:= dst(Ty
.Base
).tpOrd
;
1715 e
.PushValue(lOp
, dst
);
1716 e
.PushValue(rOp
, dst
);
1717 IF dNum
= Ty
.lIntN
THEN
1718 out
.CallRTS(Ju
.ModL
,4,2);
1720 out
.CallRTS(Ju
.ModI
,2,1);
1722 (* -------------------------------- *)
1725 * dNum := dst(Ty.Base).tpOrd;
1726 * e.PushValue(lOp, dst);
1727 * e.PushValue(rOp, dst);
1728 * IF dNum = Ty.lIntN THEN
1729 * out.CallRTS(Ju.DivL,4,2);
1731 * out.CallRTS(Ju.DivI,2,1);
1734 * Alternative, inline code ...
1736 e
.PushValue(lOp
, dst
);
1737 long
:= dst(Ty
.Base
).tpOrd
= Ty
.lIntN
;
1738 IF (rOp
.kind
= Xp
.numLt
) & (longValue(rOp
) > 0) THEN
1739 tpLb
:= out
.newLabel();
1741 rLit
:= longValue(rOp
);
1742 out
.Code(Jvm
.opc_dup2
);
1744 out
.Code(Jvm
.opc_lcmp
);
1745 out
.CodeLb(Jvm
.opc_ifge
, tpLb
);
1746 out
.PushLong(rLit
-1);
1747 out
.Code(Jvm
.opc_lsub
);
1750 out
.Code(Jvm
.opc_ldiv
);
1752 indx
:= intValue(rOp
);
1753 out
.Code(Jvm
.opc_dup
);
1754 out
.CodeLb(Jvm
.opc_ifge
, tpLb
);
1755 out
.PushInt(indx
-1);
1756 out
.Code(Jvm
.opc_isub
);
1759 out
.Code(Jvm
.opc_idiv
);
1762 e
.PushValue(rOp
, dst
);
1764 out
.CallRTS(Ju
.DivL
,4,2);
1766 out
.CallRTS(Ju
.DivI
,2,1);
1769 (* -------------------------------- *)
1771 dNum
:= dst(Ty
.Base
).tpOrd
;
1772 e
.PushValue(lOp
, dst
);
1773 e
.PushValue(rOp
, dst
);
1774 IF dNum
= Ty
.lIntN
THEN
1775 out
.Code(Jvm
.opc_lrem
);
1777 out
.Code(Jvm
.opc_irem
);
1779 (* -------------------------------- *)
1781 dNum
:= dst(Ty
.Base
).tpOrd
;
1782 e
.PushValue(lOp
, dst
);
1783 e
.PushValue(rOp
, dst
);
1784 IF dNum
= Ty
.lIntN
THEN
1785 out
.Code(Jvm
.opc_ldiv
);
1787 out
.Code(Jvm
.opc_idiv
);
1789 (* -------------------------------- *)
1790 | Xp
.blOr
, Xp
.blAnd
, Xp
.greT
, Xp
.greEq
,
1791 Xp
.notEq
, Xp
.lessEq
, Xp
.lessT
, Xp
.equal
, Xp
.inOp
:
1792 tpLb
:= out
.newLabel();
1793 exLb
:= out
.newLabel();
1795 * Jumping code is mandated for blOr and blAnd...
1797 * For the Relational Ops this next seems crude, but
1798 * appears to be the only way that the JVM allows
1799 * construction of boolean values.
1801 e
.FallTrue(exp
, tpLb
);
1802 out
.Code(Jvm
.opc_iconst_1
);
1803 out
.CodeLb(Jvm
.opc_goto
, exLb
);
1805 out
.Code(Jvm
.opc_iconst_0
);
1807 (* -------------------------------- *)
1809 e
.PushValue(lOp
, lOp
.type
);
1810 out
.CodeT(Jvm
.opc_instanceof
, rOp(Xp
.IdLeaf
).ident
.type
);
1811 (* -------------------------------- *)
1813 e
.PushValue(lOp
, lOp
.type
);
1814 IF lOp
.type
= Bi
.lIntTp
THEN
1815 RotateLong(e
, lOp
, rOp
);
1817 RotateInt(e
, lOp
, rOp
);
1819 (* -------------------------------- *)
1820 | Xp
.ashInt
, Xp
.lshInt
:
1821 long
:= dst
.isLongType();
1822 e
.PushValue(lOp
, lOp
.type
);
1824 ShiftLong(exp
.kind
, e
, lOp
, rOp
);
1826 ShiftInt(exp
.kind
, e
, lOp
, rOp
);
1828 (* -------------------------------- *)
1830 e
.PushValue(lOp
, lOp
.type
);
1831 e
.PushValue(rOp
, rOp
.type
);
1832 IF (lOp
.type
= Bi
.strTp
) &
1833 (lOp
.kind
# Xp
.mkStr
) OR
1834 lOp
.type
.isNativeStr() THEN
1835 IF (rOp
.type
= Bi
.strTp
) &
1836 (rOp
.kind
# Xp
.mkStr
) OR
1837 rOp
.type
.isNativeStr() THEN
1838 out
.CallRTS(Ju
.StrCatSS
,2,1);
1840 out
.CallRTS(Ju
.StrCatSA
, 2, 1);
1843 IF (rOp
.type
= Bi
.strTp
) &
1844 (rOp
.kind
# Xp
.mkStr
) OR
1845 rOp
.type
.isNativeStr() THEN
1846 out
.CallRTS(Ju
.StrCatAS
, 2, 1);
1848 out
.CallRTS(Ju
.StrCatAA
, 2, 1);
1851 (* -------------------------------- *)
1855 (* ============================================================ *)
1857 PROCEDURE (e
: JavaEmitter
)PushValue(exp
: Sy
.Expr
; typ
: Sy
.Type
),NEW;
1858 VAR out
: Ju
.JavaFile
;
1862 emt
: BOOLEAN; (* ==> more than one set element expr *)
1865 WITH exp
: Xp
.IdLeaf
DO
1866 IF exp
.isProcLit() THEN
1867 out
.MakeAndPushProcLitValue(exp
, typ(Ty
.Procedure
));
1868 ELSIF exp
.kind
= Xp
.typOf
THEN
1869 out
.LoadType(exp
.ident
);
1871 out
.GetVar(exp
.ident
);
1872 IF typ
= Bi
.uBytTp
THEN e
.UbyteClear() END;
1874 | exp
: Xp
.SetExp
DO
1877 * Write out the constant part, if there is one.
1879 IF exp
.value
# NIL THEN
1880 out
.PushInt(exp
.value
.int()); (* const part *)
1884 * Write out the element expressions.
1885 * taking the union with any part emitted already.
1887 FOR ix
:= 0 TO exp
.varSeq
.tide
-1 DO
1888 elm
:= exp
.varSeq
.a
[ix
];
1889 IF elm
.kind
= Xp
.range
THEN
1890 e
.PushValue(elm
, Bi
.intTp
);
1893 e
.PushValue(exp
.varSeq
.a
[ix
], Bi
.intTp
);
1894 out
.Code(Jvm
.opc_ishl
);
1896 IF ~emt
THEN out
.Code(Jvm
.opc_ior
) END;
1900 * If neither of the above emitted anything, emit zero!
1902 IF emt
THEN out
.Code(Jvm
.opc_iconst_0
) END;
1905 | Xp
.tBool
: out
.Code(Jvm
.opc_iconst_1
);
1906 | Xp
.fBool
: out
.Code(Jvm
.opc_iconst_0
);
1907 | Xp
.nilLt
: out
.Code(Jvm
.opc_aconst_null
);
1908 | Xp
.charLt
: out
.PushInt(ORD(exp
.value
.char()));
1909 | Xp
.setLt
: out
.PushInt(exp
.value
.int());
1911 IF typ
= Bi
.lIntTp
THEN
1912 out
.PushLong(exp
.value
.long());
1914 out
.PushInt(exp
.value
.int());
1917 IF typ
= Bi
.realTp
THEN
1918 out
.PushReal(exp
.value
.real());
1920 out
.PushSReal(exp
.value
.real());
1923 IF (typ
= Bi
.charTp
) OR (typ
= Bi
.sChrTp
) THEN
1924 out
.PushInt(ORD(exp
.value
.chr0()));
1926 out
.PushStr(exp
.value
.chOpen());
1929 IF typ
= Bi
.realTp
THEN
1930 out
.GetVar(Cst
.dblInf
);
1932 out
.GetVar(Cst
.fltInf
);
1935 IF typ
= Bi
.realTp
THEN
1936 out
.GetVar(Cst
.dblNInf
);
1938 out
.GetVar(Cst
.fltNInf
);
1943 | exp
: Xp
.IdentX
DO
1944 e
.PushValue(exp
.kid
, exp
.kid
.type
);
1945 IF exp
.kind
= Xp
.selct
THEN
1946 rec
:= exp
.kid
.type(Ty
.Record
);
1947 out
.PutGetF(Jvm
.opc_getfield
, rec
, exp
.ident(Id
.FldId
));
1948 IF typ
= Bi
.uBytTp
THEN e
.UbyteClear() END;
1949 ELSIF exp
.kind
= Xp
.cvrtUp
THEN
1950 out
.ConvertUp(exp
.kid
.type
, typ
);
1951 ELSIF exp
.kind
= Xp
.cvrtDn
THEN
1952 out
.ConvertDn(exp
.kid
.type
, typ
);
1954 | exp
: Xp
.UnaryX
DO
1955 e
.PushUnary(exp
, typ
);
1956 | exp
: Xp
.BinaryX
DO
1957 e
.PushBinary(exp
, typ
);
1961 (* ---------------------------------------------------- *)
1963 PROCEDURE SwapHandle(out
: Ju
.JavaFile
; exp
: Sy
.Expr
; long
: BOOLEAN);
1964 (* Precondition: exp must be a variable designator *)
1965 (* A value is below a handle of 0,1,2 words. Swap val to top *)
1971 IF (type
IS Ty
.Record
) OR
1972 ((type
IS Ty
.Array
) & (type
.kind
# Ty
.vecTp
)) THEN
1975 WITH exp
: Xp
.IdLeaf
DO
1977 WITH idnt
: Id
.LocId
DO
1978 IF Id
.uplevA
IN idnt
.locAtt
THEN hSiz
:= 1 ELSE hSiz
:= 0 END;
1982 | exp
: Xp
.BinaryX
DO
1986 END; (* -------------------- *)
1987 END; (* -------------------- *)
1988 (* Before ==> After *)
1989 IF hSiz
= 1 THEN (* -------------------- *)
1990 IF ~long
THEN (* [hndl] ==> [valu] *)
1991 out
.Code(Jvm
.opc_swap
); (* [valu] [hndl] *)
1992 (* -------------------- *)
1993 ELSE (* [hndl] ==> [val2] *)
1994 out
.Code(Jvm
.opc_dup_x2
); (* [val2] [val1] *)
1995 out
.Code(Jvm
.opc_pop
); (* [val1] [hndl] *)
1996 END; (* -------------------- *)
1997 ELSIF hSiz
= 2 THEN (* -------------------- *)
1998 IF ~long
THEN (* [indx] ==> [valu] *)
1999 out
.Code(Jvm
.opc_dup2_x1
); (* [hndl] [indx] *)
2000 out
.Code(Jvm
.opc_pop2
); (* [valu] [hndl] *)
2001 (* -------------------- *)
2002 ELSE (* [indx] ==> [val2] *)
2003 out
.Code(Jvm
.opc_dup2_x2
); (* [hdnl] [val1] *)
2004 out
.Code(Jvm
.opc_pop2
); (* [val2] [indx] *)
2005 END; (* [val1] [hndl] *)
2006 (* ELSE nothing to do *) (* -------------------- *)
2010 (* -------------------------------------------- *)
2012 PROCEDURE (e
: JavaEmitter
)PushHandle(exp
: Sy
.Expr
; typ
: Sy
.Type
),NEW;
2013 (* Precondition: exp must be a variable designator *)
2016 ASSERT(exp
.isVarDesig());
2017 IF (typ
IS Ty
.Record
) OR ((typ
IS Ty
.Array
) & (typ
.kind
# Ty
.vecTp
)) THEN
2018 e
.PushValue(exp
, typ
);
2020 WITH exp
: Xp
.IdentX
DO
2021 e
.PushValue(exp
.kid
, exp
.kid
.type
);
2022 | exp
: Xp
.BinaryX
DO
2023 IF exp
.lKid
.type
IS Ty
.Vector
THEN
2024 e
.PushVecElemHandle(exp
.lKid
, exp
.rKid
);
2026 * e.PushValue(exp.lKid, exp.lKid.type);
2027 * e.outF.GetVecArr(exp.lKid.type(Ty.Vector).elemTp);
2028 * e.PushValue(exp.rKid, Bi.intTp);
2031 e
.PushValue(exp
.lKid
, exp
.lKid
.type
);
2032 e
.PushValue(exp
.rKid
, Bi
.intTp
);
2034 | exp
: Xp
.IdLeaf
DO
2036 WITH idnt
: Id
.LocId
DO (* check if implemented inside XHR *)
2037 IF Id
.uplevA
IN idnt
.locAtt
THEN e
.outF
.XhrHandle(idnt
) END;
2044 (* ---------------------------------------------------- *)
2046 PROCEDURE (e
: JavaEmitter
)ScalarAssign(exp
: Sy
.Expr
),NEW;
2047 VAR out
: Ju
.JavaFile
;
2051 WITH exp
: Xp
.IdLeaf
DO
2052 (* stack has ... value, (top) *)
2053 out
.PutVar(exp
.ident
);
2054 | exp
: Xp
.IdentX
DO
2055 (* stack has ... obj-ref, value, (top) *)
2056 rec
:= exp
.kid
.type(Ty
.Record
);
2057 out
.PutGetF(Jvm
.opc_putfield
, rec
, exp
.ident(Id
.FldId
));
2058 | exp
: Xp
.BinaryX
DO
2059 (* stack has ... arr-ref, index, value, (top) *)
2060 IF exp
.lKid
.type
IS Ty
.Vector
THEN
2061 out
.PutVecElement(exp
.type
);
2063 out
.PutElement(exp
.type
);
2066 Console
.WriteString("BAD SCALAR ASSIGN"); Console
.WriteLn
;
2072 (* ---------------------------------------------------- *)
2074 PROCEDURE (e
: JavaEmitter
)ValueCopy(act
: Sy
.Expr
; fmT
: Sy
.Type
),NEW;
2075 VAR out
: Ju
.JavaFile
;
2078 * Copy this actual, where fmT is either an array or record.
2081 WITH fmT
: Ty
.Record
DO
2082 out
.MkNewRecord(fmT
); (* (top) dst... *)
2083 out
.Code(Jvm
.opc_dup
); (* (top) dst,dst... *)
2084 e
.PushValue(act
, fmT
); (* (top) src,dst,dst... *)
2085 out
.ValRecCopy(fmT
); (* (top) dst... *)
2088 * Array case: ordinary value copy
2090 IF fmT
.length
= 0 THEN (* open array case *)
2091 e
.PushValue(act
, fmT
); (* (top) src... *)
2092 out
.Code(Jvm
.opc_dup
); (* (top) src,src... *)
2093 IF act
.kind
= Xp
.mkStr
THEN
2094 out
.CallRTS(Ju
.StrLP1
,1,1); (* (top) len,src... *)
2095 out
.Alloc1d(Bi
.charTp
); (* (top) dst,src... *)
2097 out
.MkArrayCopy(fmT
); (* (top) dst,src... *)
2099 out
.Code(Jvm
.opc_dup_x1
); (* dst,src,dst... *)
2100 out
.Code(Jvm
.opc_swap
); (* (top) src,dst,dst... *)
2101 ELSE (* fixed array case *)
2102 out
.MkNewFixedArray(fmT
.elemTp
, fmT
.length
);
2103 out
.Code(Jvm
.opc_dup
); (* (top) dst,dst... *)
2104 e
.PushValue(act
, fmT
); (* (top) src,dst,dst... *)
2106 IF act
.kind
= Xp
.mkStr
THEN
2107 out
.CallRTS(Ju
.StrVal
, 2, 0); (* (top) dst... *)
2109 out
.ValArrCopy(fmT
); (* (top) dst... *)
2112 e
.PushValue(act
, fmT
);
2116 (* ---------------------------------------------------- *)
2118 PROCEDURE (e
: JavaEmitter
)StringCopy(act
: Sy
.Expr
; fmT
: Ty
.Array
),NEW;
2119 VAR out
: Ju
.JavaFile
;
2122 IF act
.kind
= Xp
.mkStr
THEN
2123 e
.ValueCopy(act
, fmT
);
2124 ELSIF fmT
.length
= 0 THEN (* str passed to open array *)
2125 e
.PushValue(act
, fmT
);
2126 out
.CallRTS(Ju
.StrToChrOpen
,1,1);
2127 ELSE (* str passed to fixed array *)
2128 out
.MkNewFixedArray(Bi
.charTp
, fmT
.length
);
2129 out
.Code(Jvm
.opc_dup
);
2130 e
.PushValue(act
, fmT
);
2131 out
.CallRTS(Ju
.StrToChrs
,2,0);
2135 (* ============================================================ *)
2137 PROCEDURE (e
: JavaEmitter
)Invoke(exp
: Sy
.Expr
; typ
: Ty
.Procedure
),NEW;
2142 IF exp
.isProcVar() THEN
2143 mthI
:= Ju
.getProcVarInvoke(exp
.type(Ty
.Procedure
));
2144 code
:= Jvm
.opc_invokevirtual
;
2145 e
.outF
.CallIT(code
, mthI
, typ
);
2147 WITH exp
: Xp
.IdLeaf
DO (* qualid *)
2148 prcI
:= exp
.ident(Id
.PrcId
);
2149 IF prcI
.kind
= Id
.ctorP
THEN
2150 code
:= Jvm
.opc_invokespecial
;
2152 code
:= Jvm
.opc_invokestatic
;
2154 e
.outF
.CallIT(code
, prcI
, typ
);
2155 | exp
: Xp
.IdentX
DO (* selct *)
2156 mthI
:= exp
.ident(Id
.MthId
);
2157 IF exp
.kind
= Xp
.sprMrk
THEN
2158 code
:= Jvm
.opc_invokespecial
;
2159 ELSIF mthI
.bndType
.isInterfaceType() THEN
2160 code
:= Jvm
.opc_invokeinterface
;
2162 code
:= Jvm
.opc_invokevirtual
;
2164 e
.outF
.CallIT(code
, mthI
, typ
);
2165 IF Id
.covar
IN mthI
.mthAtt
THEN
2166 e
.outF
.CodeT(Jvm
.opc_checkcast
, typ
.retType
);
2172 (* ---------------------------------------------------- *)
2174 PROCEDURE (e
: JavaEmitter
)PushAndGetReturn(act
: Sy
.Expr
;
2176 OUT ret
: Sy
.Expr
),NEW;
2177 (* ----------------------------------------- *)
2178 VAR out
: Ju
.JavaFile
;
2183 (* ----------------------------------------- *)
2184 PROCEDURE simple(x
: Sy
.Expr
) : BOOLEAN;
2186 IF x
.kind
= Xp
.deref
THEN x
:= x(Xp
.UnaryX
).kid
END;
2187 RETURN x
IS Xp
.LeafX
; (* IdLeaf or LeafX *)
2189 (* ----------------------------------------- *)
2192 * Assert: the expression is a (possibly complex)
2193 * variable designator. Is some part of the handle
2194 * worth saving? Note saving is mandatory for calls.
2198 WITH act
: Xp
.IdLeaf
DO
2200 * This is a simple variable. Result will be
2201 * stored directly using the same expression.
2203 e
.PushValue(act
, typ
);
2204 | act
: Xp
.IdentX
DO
2205 ASSERT(act
.kind
= Xp
.selct
);
2207 * This is a field select. If the handle is
2208 * sufficiently complicated it will be saved.
2211 e
.PushValue(recXp
, recXp
.type
);
2212 IF ~
simple(recXp
) THEN
2213 local
:= out
.newLocal();
2214 out
.Code(Jvm
.opc_dup
);
2215 out
.StoreLocal(local
, NIL);
2217 * The restore expression is a mutated
2218 * version of the original expression.
2220 act
.kid
:= e
.newLeaf(local
, recXp
.type
);
2221 act
.kid
.type
:= recXp
.type
;
2223 out
.PutGetF(Jvm
.opc_getfield
,
2224 recXp
.type(Ty
.Record
), act
.ident(Id
.FldId
));
2225 | act
: Xp
.BinaryX
DO
2226 ASSERT(act
.kind
= Xp
.index
);
2228 * This is an index select. If the handle, or
2229 * index (or both) are complicated they are saved.
2233 e
.PushValue(array
, array
.type
);
2234 IF simple(array
) THEN (* don't save handle *)
2235 e
.PushValue(index
, Bi
.intTp
);
2236 IF ~
simple(index
) THEN (* must save index *)
2237 local
:= out
.newLocal();
2238 out
.Code(Jvm
.opc_dup
);
2239 out
.StoreLocal(local
, Bi
.intTp
); (* #### *)
2240 act
.rKid
:= e
.newLeaf(local
, Bi
.intTp
);
2241 act
.rKid
.type
:= Bi
.intTp
;
2243 ELSE (* must save handle *)
2244 local
:= out
.newLocal();
2245 out
.Code(Jvm
.opc_dup
);
2246 out
.StoreLocal(local
, NIL);
2247 act
.lKid
:= e
.newLeaf(local
, array
.type
);
2248 act
.lKid
.type
:= array
.type
;
2249 e
.PushValue(index
, Bi
.intTp
);
2250 IF ~
simple(index
) THEN (* save index as well *)
2251 local
:= out
.newLocal();
2252 out
.Code(Jvm
.opc_dup
);
2253 out
.StoreLocal(local
, Bi
.intTp
); (* #### *)
2254 act
.rKid
:= e
.newLeaf(local
, Bi
.intTp
);
2255 act
.rKid
.type
:= Bi
.intTp
;
2258 out
.GetElement(typ
);
2260 act
.Diagnose(0); THROW("Bad PushAndGetReturn");
2262 END PushAndGetReturn
;
2264 (* ---------------------------------------------------- *)
2266 PROCEDURE (e
: JavaEmitter
)PushArg(act
: Sy
.Expr
;
2268 VAR seq
: Sy
.ExprSeq
),NEW;
2269 (* ------------------------- *)
2270 VAR idExp
: Xp
.IdentX
;
2273 (* ----------------------------------------- *)
2274 PROCEDURE boxNumber(exp
: Sy
.Expr
) : INTEGER;
2276 RETURN exp(Xp
.IdLeaf
).ident(Id
.ParId
).boxOrd
;
2278 (* ----------------------------------------- *)
2279 PROCEDURE boxedPar(exp
: Sy
.Expr
) : BOOLEAN;
2282 WITH exp
: Xp
.IdLeaf
DO
2284 WITH idnt
: Id
.ParId
DO
2285 RETURN (idnt
.boxOrd
# Ju
.retMarker
) & Ju
.needsBox(idnt
);
2293 (* ----------------------------------------- *)
2296 IF Ju
.needsBox(frm
) THEN (* value is returned *)
2299 IF frm
.parMod
= Sy
.out
THEN (* no value push *)
2302 e
.PushAndGetReturn(act
, frm
.type
, idExp
.kid
);
2304 IF frm
.boxOrd
# Ju
.retMarker
THEN
2305 (* ==> out value but not in return slot *)
2306 frm
.rtsTmp
:= out
.newLocal();
2307 IF boxedPar(act
) THEN
2308 out
.LoadLocal(boxNumber(act
), NIL);
2310 out
.MkNewFixedArray(frm
.type
, 1);
2312 out
.Code(Jvm
.opc_dup
);
2313 out
.StoreLocal(frm
.rtsTmp
, NIL);
2315 Sy
.AppendExpr(seq
, idExp
);
2316 ELSIF (frm
.type
IS Ty
.Array
) &
2317 ((act
.type
= Bi
.strTp
) OR act
.type
.isNativeStr()) THEN
2318 e
.StringCopy(act
, frm
.type(Ty
.Array
)); (* special string case *)
2319 ELSIF (frm
.parMod
= Sy
.val
) &
2320 ((frm
.type
IS Ty
.Record
) OR
2322 ((frm
.type
IS Ty
.Array
) & (frm
.type
.kind
# Ty
.vecTp
))) THEN
2324 e
.ValueCopy(act
, frm
.type
);
2326 e
.PushValue(act
, frm
.type
);
2330 (* ---------------------------------------------------- *)
2332 PROCEDURE (e
: JavaEmitter
)CopyOut(exp
: Sy
.Expr
; idD
: Sy
.Idnt
),NEW;
2333 VAR out
: Ju
.JavaFile
;
2336 (* Assert : this is an unboxed type *)
2338 par
:= idD(Id
.ParId
);
2339 e
.PushHandle(exp
, par
.type
);
2340 IF par
.boxOrd
# Ju
.retMarker
THEN
2341 out
.LoadLocal(par
.rtsTmp
, NIL);
2342 out
.Code(Jvm
.opc_iconst_0
);
2343 out
.GetElement(par
.type
);
2344 ELSE (* result is below handle *)
2345 SwapHandle(out
, exp
, par
.type
.isLongType());
2347 e
.ScalarAssign(exp
);
2350 (* ============================================================ *)
2351 (* Possible structures of procedure call expressions are: *)
2352 (* ============================================================ *)
2355 (* [CallX] [CallX] *)
2356 (* / +--- actuals --> ... / +--- actuals *)
2358 (* [IdentX] [IdLeaf] *)
2359 (* / +--- ident ---> [Procs] +--- ident ---> [Procs] *)
2363 (* ============================================================ *)
2364 (* only the right hand case can be a standard proc or function *)
2365 (* ============================================================ *)
2367 PROCEDURE (e
: JavaEmitter
)PushCall(callX
: Xp
.CallX
),NEW;
2368 VAR jFile
: Ju
.JavaFile
;
2369 mark0
: INTEGER; (* local ord limit on entry *)
2370 tide0
: INTEGER; (* parameter tide on entry *)
2371 index
: INTEGER; (* just a counter for loops *)
2372 prVar
: BOOLEAN; (* Procedure variable call *)
2373 formT
: Ty
.Procedure
; (* formal type of procedure *)
2374 formP
: Id
.ParId
; (* current formal parameter *)
2377 (* ---------------------------------------------------- *)
2378 PROCEDURE CheckCall(expr
: Sy
.Expr
; pTyp
: Ty
.Procedure
);
2379 VAR prcI
: Id
.PrcId
;
2383 WITH expr
: Xp
.IdLeaf
DO (* qualid *)
2385 WITH idnt
: Id
.PrcId
DO
2386 (* prcI := expr.ident(Id.PrcId); *)
2387 IF pTyp
.xName
= NIL THEN Ju
.MkCallAttr(idnt
, pTyp
) END;
2388 | idnt
: Id
.AbVar
DO
2389 mthI
:= Ju
.getProcVarInvoke(pTyp
);
2390 IF mthI
.type
.xName
= NIL THEN Ju
.MkCallAttr(mthI
, mthI
.type(Ty
.Procedure
)) END;
2392 | expr
: Xp
.IdentX
DO (* selct *)
2394 WITH idnt
: Id
.MthId
DO
2395 IF pTyp
.xName
= NIL THEN Ju
.MkCallAttr(idnt
, pTyp
) END;
2396 | idnt
: Id
.FldId
DO
2397 mthI
:= Ju
.getProcVarInvoke(pTyp
);
2398 IF mthI
.type
.xName
= NIL THEN Ju
.MkCallAttr(mthI
, mthI
.type(Ty
.Procedure
)) END;
2402 (* ---------------------------------------------------- *)
2403 PROCEDURE isNested(exp
: Xp
.IdLeaf
) : BOOLEAN;
2405 RETURN exp
.ident(Id
.PrcId
).lxDepth
> 0;
2407 (* ---------------------------------------------------- *)
2410 mark0
:= jFile
.markTop();
2411 tide0
:= callX
.actuals
.tide
;
2413 formT
:= prExp
.type(Ty
.Procedure
);
2415 * Before we push any arguments, we must ensure that
2416 * the formal-type name is computed, and the first
2417 * out-value is moved to the return-slot, if possible.
2419 prVar
:= prExp
.isProcVar();
2420 CheckCall(prExp
, formT
);
2422 * We must first deal with the receiver if this is a method.
2425 e
.PushValue(prExp
, prExp
.type
);
2426 formT
:= Ju
.getProcVarInvoke(formT
).type(Ty
.Procedure
);
2427 ELSIF formT
.receiver
# NIL THEN
2428 idExp
:= prExp(Xp
.IdentX
);
2429 formP
:= idExp
.ident(Id
.MthId
).rcvFrm
;
2430 e
.PushArg(idExp
.kid
, formP
, callX
.actuals
);
2432 WITH prExp
: Xp
.IdLeaf
DO
2433 IF prExp
.ident
.kind
= Id
.ctorP
THEN
2434 jFile
.CodeT(Jvm
.opc_new
, callX
.type
);
2435 jFile
.Code(Jvm
.opc_dup
);
2436 ELSIF isNested(prExp
) THEN
2437 jFile
.PushStaticLink(prExp
.ident(Id
.Procs
));
2443 * We push the arguments from left to right.
2444 * New IdentX expressions are appended to the argument
2445 * list to describe how to save any returned values.
2447 FOR index
:= 0 TO tide0
-1 DO
2448 formP
:= formT
.formals
.a
[index
];
2449 e
.PushArg(callX
.actuals
.a
[index
], formP
, callX
.actuals
);
2452 * Now emit the actual call instruction(s)
2454 e
.Invoke(prExp
, formT
);
2456 * Now we save any out arguments from the appended exprs.
2458 FOR index
:= tide0
TO callX
.actuals
.tide
-1 DO
2459 prExp
:= callX
.actuals
.a
[index
];
2460 idExp
:= prExp(Xp
.IdentX
);
2461 e
.CopyOut(idExp
.kid
, idExp
.ident
);
2463 jFile
.ReleaseAll(mark0
);
2465 * Normally an CallX expression can only be evaluated once,
2466 * so it does not matter if PushCall() is not idempotent.
2467 * However, there is a pathological case if a predicate in a
2468 * while loop has a function call with OUT formals. Since the
2469 * GPCP method of laying out while loops evaluates the test
2470 * twice, the actual list must be reset to its original length.
2472 callX
.actuals
.ResetTo(tide0
);
2475 (* ---------------------------------------------------- *)
2477 PROCEDURE IncByLit(out
: Ju
.JavaFile
; ord
: INTEGER; inc
: INTEGER);
2479 IF (ord
< 256) & (inc
>= -128) & (inc
<= 127) THEN
2480 out
.CodeInc(ord
, inc
);
2482 out
.LoadLocal(ord
, Bi
.intTp
);
2484 out
.Code(Jvm
.opc_iadd
);
2485 out
.StoreLocal(ord
, Bi
.intTp
);
2489 PROCEDURE LitIncLocal(out
: Ju
.JavaFile
; proc
, vOrd
, incr
: INTEGER);
2491 IF proc
= Bi
.decP
THEN incr
:= -incr
END;
2492 IncByLit(out
, vOrd
, incr
);
2495 (* ------------------------------------------ *)
2497 PROCEDURE (e
: JavaEmitter
)EmitStdProc(callX
: Xp
.CallX
),NEW;
2498 CONST fMsg
= "Assertion failure ";
2499 VAR out
: Ju
.JavaFile
;
2517 prId
:= callX
.kid(Xp
.IdLeaf
).ident(Id
.PrcId
);
2518 arg0
:= callX
.actuals
.a
[0]; (* Always need at least one arg *)
2519 argN
:= callX
.actuals
.tide
;
2521 pOrd
:= prId
.stdOrd
;
2523 (* --------------------------- *)
2525 okLb
:= out
.newLabel();
2526 e
.FallFalse(arg0
, okLb
);
2528 * If expression evaluates to false, fall
2529 * into the error code, else skip to okLb.
2532 numL
:= intValue(callX
.actuals
.a
[1]);
2533 out
.Trap(fMsg
+ L
.intToCharOpen(numL
)^
);
2535 numL
:= callX
.token
.lin
;
2536 out
.Trap(fMsg
+ Cst
.srcNam
+":"+ L
.intToCharOpen(numL
)^
);
2539 (* --------------------------- *)
2540 | Bi
.incP
, Bi
.decP
:
2541 argX
:= callX
.actuals
.a
[1];
2543 long
:= dstT
.isLongType();
2545 * Is this a local variable?
2546 * There is a special instruction for incrementing
2547 * word-sized local variables, provided the increment is
2548 * by a literal 8-bit amount, and local index is 8-bit.
2550 e
.PushHandle(arg0
, dstT
);
2551 WITH arg0
: Xp
.IdLeaf
DO
2554 WITH idX0
: Id
.LocId
DO
2555 IF Id
.uplevA
IN idX0
.locAtt
THEN (* uplevel addressing case *)
2556 out
.Code(Jvm
.opc_dup
); (* handle is one slot only *)
2557 out
.PutGetX(Jvm
.opc_getfield
, idX0
);
2558 ELSIF (argX
.kind
= Xp
.numLt
) & ~long
THEN (* PREMATURE EXIT *)
2559 LitIncLocal(out
, pOrd
, idX0
.varOrd
, intValue(argX
)); RETURN;
2561 out
.LoadLocal(idX0
.varOrd
, dstT
);
2564 e
.PushValue(arg0
, dstT
);
2566 | arg0
: Xp
.IdentX
DO
2567 flId
:= arg0
.ident(Id
.FldId
);
2568 out
.Code(Jvm
.opc_dup
); (* handle is one slot only *)
2569 out
.PutGetF(Jvm
.opc_getfield
, arg0
.kid
.type(Ty
.Record
), flId
);
2570 | arg0
: Xp
.BinaryX
DO
2571 out
.Code(Jvm
.opc_dup2
); (* handle is two slots here *)
2572 out
.GetElement(dstT
);
2574 e
.PushValue(argX
, dstT
);
2576 IF pOrd
= Bi
.incP
THEN c
:= Jvm
.opc_ladd
ELSE c
:= Jvm
.opc_lsub
END;
2578 IF pOrd
= Bi
.incP
THEN c
:= Jvm
.opc_iadd
ELSE c
:= Jvm
.opc_isub
END;
2581 e
.ScalarAssign(arg0
);
2582 (* --------------------------- *)
2584 (* ------------------------------------- *
2588 * getfield CP/CPJvec/VecBase/tide I // tide, vRef ...
2589 * <push arg1> // arg1, tide, vRef ...
2590 * dup_x1 // arg1, tide, arg1, vRef ...
2591 * if_icmpge okLb // arg1, vRef ...
2592 * <throw index trap>
2593 * okLb: // arg1, vRef ...
2594 * putfield CP/CPJvec/VecBase/tide I // (empty)
2595 * ------------------------------------- *)
2596 argX
:= callX
.actuals
.a
[1];
2597 okLb
:= out
.newLabel();
2598 e
.PushValue(arg0
, arg0
.type
);
2599 out
.Code(Jvm
.opc_dup
);
2601 e
.PushValue(argX
, Bi
.intTp
);
2602 out
.Code(Jvm
.opc_dup_x1
);
2604 out
.Code(Jvm
.opc_iconst_1
); (* Chop the sign bit *)
2605 out
.Code(Jvm
.opc_ishl
); (* asserting, for *)
2606 out
.Code(Jvm
.opc_iconst_1
); (* correctness, that *)
2607 out
.Code(Jvm
.opc_iushr
); (* argX >> minInt. *)
2609 out
.CodeLb(Jvm
.opc_if_icmpge
, okLb
);
2610 out
.Trap("Vector index out of bounds");
2613 (* --------------------------- *)
2615 (* -------------------------------------- *
2619 * astore R // vRef ...
2620 * getfield CP/CPJvec/VecBase/tide I // tide ...
2622 * aload R // vRef ...
2623 * getfield CP/CPJvec/VecXXX/elems [X // elems ...
2624 * arraylength // aLen ...
2625 * iload T // tide, aLen ...
2631 * getfield CP/CPJvec/VecXXX/elems [X // elems ...
2632 * iload T // tide, elems ...
2633 * <push arg1> // arg1, tide, elems ...
2635 * aload R // vRef ...
2636 * iload T // tide, vRef ...
2637 * iconst_1 // 1, tide, vRef ...
2638 * iadd // tide', vRef ...
2639 * putfield CP/CPJvec/VecBase/tide I // (empty)
2640 * -------------------------------------- *)
2641 argX
:= callX
.actuals
.a
[1];
2642 dstT
:= arg0
.type(Ty
.Vector
).elemTp
;
2643 vRef
:= out
.newLocal();
2644 tide
:= out
.newLocal();
2645 okLb
:= out
.newLabel();
2646 e
.PushValue(arg0
, arg0
.type
);
2647 out
.Code(Jvm
.opc_dup
);
2648 out
.StoreLocal(vRef
, NIL);
2650 out
.StoreLocal(tide
, Bi
.intTp
);
2651 out
.LoadLocal(vRef
, NIL);
2652 out
.GetVecArr(dstT
);
2653 out
.Code(Jvm
.opc_arraylength
);
2654 out
.LoadLocal(tide
, Bi
.intTp
);
2655 out
.CodeLb(Jvm
.opc_if_icmpgt
, okLb
);
2656 out
.LoadLocal(vRef
, NIL);
2657 out
.InvokeExpand(dstT
);
2659 out
.LoadLocal(vRef
, NIL);
2660 out
.GetVecArr(dstT
);
2661 out
.LoadLocal(tide
, Bi
.intTp
);
2662 e
.ValueCopy(argX
, dstT
);
2663 out
.PutVecElement(dstT
);
2664 out
.LoadLocal(vRef
, NIL);
2665 out
.LoadLocal(tide
, Bi
.intTp
);
2666 out
.Code(Jvm
.opc_iconst_1
);
2667 out
.Code(Jvm
.opc_iadd
);
2669 out
.ReleaseLocal(tide
);
2670 out
.ReleaseLocal(vRef
);
2671 (* --------------------------- *)
2672 | Bi
.exclP
, Bi
.inclP
:
2674 argX
:= callX
.actuals
.a
[1];
2676 e
.PushHandle(arg0
, dstT
);
2677 WITH arg0
: Xp
.IdLeaf
DO
2679 WITH idX0
: Id
.LocId
DO
2680 IF Id
.uplevA
IN idX0
.locAtt
THEN (* uplevel addressing case *)
2681 out
.Code(Jvm
.opc_dup
); (* handle is one slot only *)
2682 out
.PutGetX(Jvm
.opc_getfield
, idX0
);
2684 out
.LoadLocal(idX0
.varOrd
, dstT
);
2687 e
.PushValue(arg0
, dstT
);
2689 | arg0
: Xp
.BinaryX
DO
2690 ASSERT(arg0
.kind
= Xp
.index
);
2691 out
.Code(Jvm
.opc_dup2
);
2692 out
.GetElement(dstT
);
2693 | arg0
: Xp
.IdentX
DO
2694 ASSERT(arg0
.kind
= Xp
.selct
);
2695 out
.Code(Jvm
.opc_dup
);
2696 out
.PutGetF(Jvm
.opc_getfield
,
2697 arg0
.kid
.type(Ty
.Record
), arg0
.ident(Id
.FldId
));
2699 IF argX
.kind
= Xp
.numLt
THEN
2700 out
.PushInt(ORD({intValue(argX
)}));
2702 out
.Code(Jvm
.opc_iconst_1
);
2703 e
.PushValue(argX
, Bi
.intTp
);
2704 out
.Code(Jvm
.opc_ishl
);
2706 IF pOrd
= Bi
.inclP
THEN
2707 out
.Code(Jvm
.opc_ior
);
2709 out
.Code(Jvm
.opc_iconst_m1
);
2710 out
.Code(Jvm
.opc_ixor
);
2711 out
.Code(Jvm
.opc_iand
);
2713 e
.ScalarAssign(arg0
);
2714 (* --------------------------- *)
2716 out
.PushInt(intValue(arg0
));
2717 out
.CallRTS(Ju
.SysExit
,1,0);
2718 out
.PushJunkAndReturn();
2719 (* --------------------------- *)
2721 IF Cst
.ntvExc
.assignCompat(arg0
) THEN
2722 e
.PushValue(arg0
, Cst
.ntvExc
);
2723 out
.Code(Jvm
.opc_athrow
);
2725 out
.MkNewException();
2726 out
.Code(Jvm
.opc_dup
);
2727 e
.PushValue(arg0
, Cst
.ntvStr
);
2728 out
.InitException();
2729 out
.Code(Jvm
.opc_athrow
);
2731 (* --------------------------- *)
2734 * arg0 is a pointer to a Record or Array, or else a vector type.
2736 e
.PushHandle(arg0
, arg0
.type
);
2739 * No LEN argument implies either:
2740 * pointer to record, OR
2741 * pointer to a fixed array.
2743 dstT
:= arg0
.type(Ty
.Pointer
).boundTp
;
2744 WITH dstT
: Ty
.Record
DO
2745 out
.MkNewRecord(dstT
);
2746 | dstT
: Ty
.Array
DO
2747 out
.MkNewFixedArray(dstT
.elemTp
, dstT
.length
);
2749 ELSIF arg0
.type
.kind
= Ty
.ptrTp
THEN
2750 FOR numL
:= 1 TO argN
-1 DO
2751 argX
:= callX
.actuals
.a
[numL
];
2752 e
.PushValue(argX
, Bi
.intTp
);
2754 dstT
:= arg0
.type(Ty
.Pointer
).boundTp
;
2755 out
.MkNewOpenArray(dstT(Ty
.Array
), argN
-1);
2756 ELSE (* must be a vector type *)
2757 dstT
:= arg0
.type(Ty
.Vector
).elemTp
;
2759 out
.Code(Jvm
.opc_dup
);
2760 e
.PushValue(callX
.actuals
.a
[1], Bi
.intTp
);
2763 e
.ScalarAssign(arg0
);
2764 (* --------------------------- *)
2768 (* ============================================================ *)
2769 (* Statement Handling Methods *)
2770 (* ============================================================ *)
2772 PROCEDURE (e
: JavaEmitter
)EmitAssign(stat
: St
.Assign
),NEW;
2773 VAR lhTyp
: Sy
.Type
;
2776 * This is a value assign in CP.
2778 lhTyp
:= stat
.lhsX
.type
;
2779 e
.PushHandle(stat
.lhsX
, lhTyp
);
2780 e
.PushValue(stat
.rhsX
, lhTyp
);
2781 WITH lhTyp
: Ty
.Vector
DO
2782 e
.ScalarAssign(stat
.lhsX
);
2783 | lhTyp
: Ty
.Array
DO
2784 IF stat
.rhsX
.kind
= Xp
.mkStr
THEN
2785 e
.outF
.CallRTS(Ju
.StrVal
, 2, 0);
2786 ELSIF stat
.rhsX
.type
= Bi
.strTp
THEN
2787 e
.outF
.CallRTS(Ju
.StrToChrs
,2, 0);
2789 e
.outF
.ValArrCopy(lhTyp
);
2791 | lhTyp
: Ty
.Record
DO
2792 e
.outF
.ValRecCopy(lhTyp
);
2794 e
.ScalarAssign(stat
.lhsX
);
2798 (* ---------------------------------------------------- *)
2800 PROCEDURE (e
: JavaEmitter
)EmitCall(stat
: St
.ProcCall
),NEW;
2801 VAR expr
: Xp
.CallX
; (* the stat call expression *)
2803 expr
:= stat
.expr(Xp
.CallX
);
2804 IF (expr
.kind
= Xp
.prCall
) & expr
.kid
.isStdProc() THEN
2805 e
.EmitStdProc(expr
);
2811 (* ---------------------------------------------------- *)
2813 PROCEDURE (e
: JavaEmitter
)EmitIf(stat
: St
.Choice
; OUT ok
: BOOLEAN),NEW;
2814 VAR out
: Ju
.JavaFile
;
2815 high
: INTEGER; (* Branch count. *)
2816 exLb
: Ju
.Label
; (* Exit label *)
2817 nxtP
: Ju
.Label
; (* Next predicate *)
2819 live
: BOOLEAN; (* then is live *)
2820 else
: BOOLEAN; (* else not seen *)
2826 exLb
:= out
.newLabel();
2828 high
:= stat
.preds
.tide
- 1;
2829 FOR indx
:= 0 TO high
DO
2831 pred
:= stat
.preds
.a
[indx
];
2832 then
:= stat
.blocks
.a
[indx
];
2833 nxtP
:= out
.newLabel();
2834 IF pred
= NIL THEN else
:= TRUE
ELSE e
.FallTrue(pred
, nxtP
) END;
2835 IF then
# NIL THEN e
.EmitStat(then
, live
) END;
2838 IF indx
< high
THEN out
.CodeLb(Jvm
.opc_goto
, exLb
) END;
2843 * If not ELSE has been seen, then control flow is still live!
2845 IF ~else
THEN ok
:= TRUE
END;
2849 (* ---------------------------------------------------- *)
2851 PROCEDURE (e
: JavaEmitter
)EmitRanges
2852 (locV
: INTEGER; (* select Var *)
2853 stat
: St
.CaseSt
; (* case stat *)
2854 minR
: INTEGER; (* min rng-ix *)
2855 maxR
: INTEGER; (* max rng-ix *)
2856 minI
: INTEGER; (* min index *)
2857 maxI
: INTEGER; (* max index *)
2858 labs
: ARRAY OF Ju
.Label
),NEW;
2859 (* --------------------------------------------------------- *
2860 * This procedure emits the code for a single,
2861 * dense range of selector values in the label-list.
2862 * --------------------------------------------------------- *)
2863 VAR out
: Ju
.JavaFile
;
2864 loIx
: INTEGER; (* low selector value for dense range *)
2865 hiIx
: INTEGER; (* high selector value for dense range *)
2866 rNum
: INTEGER; (* total number of ranges in the group *)
2867 peel
: INTEGER; (* max index of range to be peeled off *)
2876 rNum
:= maxR
- minR
+ 1;
2877 rnge
:= stat
.labels
.a
[minR
];
2878 IF rNum
= 1 THEN (* single range only *)
2879 lab
:= labs
[rnge
.ord
+1];
2880 out
.EmitOneRange(locV
, rnge
.loC
, rnge
.hiC
, minI
, maxI
, dfLb
, lab
);
2883 * Two or three ranges only.
2884 * Peel off the lowest of the ranges, and recurse.
2888 out
.LoadLocal(locV
, Bi
.intTp
);
2890 * There are a number of special cases
2891 * that can benefit from special code.
2895 * A singleton. Leave minI unchanged, unless peel = minI.
2898 out
.CodeLb(Jvm
.opc_if_icmpeq
, labs
[rnge
.ord
+ 1]);
2899 IF minI
= peel
THEN minI
:= peel
+1 END;
2901 ELSIF loIx
= minI
THEN
2903 * A range starting at the minimum selector value.
2906 out
.CodeLb(Jvm
.opc_if_icmple
, labs
[rnge
.ord
+ 1]);
2911 * We must peel the default range from minI to loIx.
2914 out
.CodeLb(Jvm
.opc_if_icmplt
, dfLb
);
2915 minI
:= loIx
; (* and minR is unchanged! *)
2917 e
.EmitRanges(locV
, stat
, minR
, maxR
, minI
, maxI
, labs
);
2920 * Four or more ranges. Emit a dispatch table.
2922 loIx
:= rnge
.loC
; (* low of min-range *)
2923 hiIx
:= stat
.labels
.a
[maxR
].hiC
; (* high of max-range *)
2924 out
.LoadLocal(locV
, Bi
.intTp
);
2925 out
.CodeSwitch(loIx
, hiIx
, dfLb
);
2927 FOR indx
:= minR
TO maxR
DO
2928 rnge
:= stat
.labels
.a
[indx
];
2929 WHILE loIx
< rnge
.loC
DO
2930 out
.AddSwitchLab(labs
[0],pos
); INC(pos
); INC(loIx
);
2932 WHILE loIx
<= rnge
.hiC
DO
2933 out
.AddSwitchLab(labs
[rnge
.ord
+1],pos
); INC(pos
); INC(loIx
);
2936 out
.LstDef(labs
[0]);
2940 (* ---------------------------------------------------- *)
2942 PROCEDURE (e
: JavaEmitter
)EmitGroups
2943 (locV
: INTEGER; (* select vOrd *)
2944 stat
: St
.CaseSt
; (* case stat *)
2945 minG
: INTEGER; (* min grp-indx *)
2946 maxG
: INTEGER; (* max grp-indx *)
2947 minI
: INTEGER; (* min index *)
2948 maxI
: INTEGER; (* max index *)
2949 labs
: ARRAY OF Ju
.Label
),NEW;
2950 (* --------------------------------------------------------- *
2951 * This function emits the branching code which sits on top
2952 * of the selection code for each dense range of case values.
2953 * --------------------------------------------------------- *)
2954 VAR out
: Ju
.JavaFile
;
2960 IF maxG
= -1 THEN RETURN; (* Empty case statment *)
2961 ELSIF minG
= maxG
THEN (* only one remaining dense group *)
2962 group
:= stat
.groups
.a
[minG
];
2963 e
.EmitRanges(locV
, stat
, group
.loC
, group
.hiC
, minI
, maxI
, labs
);
2966 * We must bifurcate the group range, and recurse.
2967 * We will split the value range at the lower limit
2968 * of the low-range of the upper half-group.
2970 midPt
:= (minG
+ maxG
+ 1) DIV 2;
2971 group
:= stat
.groups
.a
[midPt
];
2972 range
:= stat
.labels
.a
[group
.loC
];
2974 * Test and branch at range.loC
2977 newLb
:= out
.newLabel();
2978 out
.LoadLocal(locV
, Bi
.intTp
);
2979 out
.PushInt(range
.loC
);
2980 out
.CodeLb(Jvm
.opc_if_icmpge
, newLb
);
2984 e
.EmitGroups(locV
, stat
, minG
, midPt
-1, minI
, range
.loC
-1, labs
);
2986 e
.EmitGroups(locV
, stat
, midPt
, maxG
, range
.loC
, maxI
, labs
);
2990 (* ---------------------------------------------------- *)
2992 PROCEDURE (e
: JavaEmitter
)EmitCase(stat
: St
.CaseSt
; OUT ok
: BOOLEAN),NEW;
2993 VAR out
: Ju
.JavaFile
;
3001 labs
: POINTER TO ARRAY OF Ju
.Label
;
3003 (* ---------------------------------------------------------- *
3004 * CaseSt* = POINTER TO RECORD (Sy.Stmt)
3005 * (* ----------------------------------------- *
3006 * * kind- : INTEGER; (* tag for unions *)
3007 * * token
* : S
.Token
; (* stmt first tok *)
3008 * * ----------------------------------------- *)
3009 * select
* : Sy
.Expr
; (* case selector *)
3010 * chrSel
* : BOOLEAN; (* ==> use chars *)
3011 * blocks
* : Sy
.StmtSeq
; (* case bodies *)
3012 * elsBlk
* : Sy
.Stmt
; (* elseCase | NIL *)
3013 * labels
* : TripleSeq
; (* label seqence *)
3014 * groups
- : TripleSeq
; (* dense groups *)
3016 * --------------------------------------------------------- *
3017 * Notes on the semantics of this structure
. "blocks" holds
*
3018 * an ordered list of case statement code blocks
. "labels" *
3019 * is a list of ranges
, intially in textual order
,with flds
*
3020 * loC
, hiC and ord corresponding to the range min
, max and
*
3021 * the selected block ordinal number
. This list is later
*
3022 * sorted on the loC value
, and adjacent values merged if
*
3023 * they select the same block
. The
"groups" list of triples
*
3024 * groups ranges into dense subranges in the selector space
*
3025 * The fields loC
, hiC
, and ord to hold the lower and upper
*
3026 * indices into the labels list
, and the number of non
- *
3027 * default values in the group
. Groups are guaranteed to
*
3028 * have
density (nonDefN
/ (max
-min
+1)) > DENSITY
*
3029 * --------------------------------------------------------- *)
3032 exLb
:= out
.newLabel();
3033 NEW(labs
,stat
.blocks
.tide
+1);
3034 out
.getLabelRange(labs
);
3035 selV
:= out
.newLocal();
3038 minI
:= 0; maxI
:= ORD(MAX(CHAR));
3040 minI
:= MIN(INTEGER);
3041 maxI
:= MAX(INTEGER);
3045 * Push the selector value, and save in local variable;
3047 e
.PushValue(stat
.select
, stat
.select
.type
);
3048 out
.StoreLocal(selV
, Bi
.intTp
);
3049 e
.EmitGroups(selV
, stat
, 0, stat
.groups
.tide
-1, minI
, maxI
, labs
);
3051 * Now we emit the code for the cases.
3052 * If any branch returns, then exLb is reachable.
3054 FOR indx
:= 0 TO stat
.blocks
.tide
-1 DO
3055 out
.DefLab(labs
[indx
+ 1]);
3056 e
.EmitStat(stat
.blocks
.a
[indx
], live
);
3059 out
.CodeLb(Jvm
.opc_goto
, exLb
);
3063 * Now we emit the code for the elespart.
3064 * If the elsepart returns then exLb is reachable.
3066 out
.DefLabC(labs
[0], "Default case");
3067 IF stat
.elsBlk
# NIL THEN
3068 e
.EmitStat(stat
.elsBlk
, live
);
3069 IF live
THEN ok
:= TRUE
END;
3073 out
.ReleaseLocal(selV
);
3074 IF ok
THEN out
.DefLabC(exLb
, "Case exit label") END;
3077 (* ---------------------------------------------------- *)
3079 PROCEDURE (e
: JavaEmitter
)
3080 EmitWhile(stat
: St
.TestLoop
; OUT ok
: BOOLEAN),NEW;
3081 VAR out
: Ju
.JavaFile
;
3086 lpLb
:= out
.newLabel();
3087 exLb
:= out
.newLabel();
3088 e
.FallTrue(stat
.test
, exLb
); (* goto exLb if eval false *)
3089 out
.DefLabC(lpLb
, "Loop header");
3090 e
.EmitStat(stat
.body
, ok
);
3091 IF ok
THEN e
.FallFalse(stat
.test
, lpLb
) END;
3092 out
.DefLabC(exLb
, "Loop exit");
3095 (* ---------------------------------------------------- *)
3097 PROCEDURE (e
: JavaEmitter
)
3098 EmitRepeat(stat
: St
.TestLoop
; OUT ok
: BOOLEAN),NEW;
3099 VAR out
: Ju
.JavaFile
;
3103 lpLb
:= out
.newLabel();
3104 out
.DefLabC(lpLb
, "Loop header");
3105 e
.EmitStat(stat
.body
, ok
);
3106 IF ok
THEN e
.FallTrue(stat
.test
, lpLb
) END; (* exit on eval true *)
3109 (* ---------------------------------------------------- *)
3111 PROCEDURE (e
: JavaEmitter
)EmitFor(stat
: St
.ForLoop
; OUT ok
: BOOLEAN),NEW;
3112 (* ----------------------------------------------------------- *
3113 * This code has been split into the four cases:
3114 * - long control variable, counting up;
3115 * - long control variable, counting down;
3116 * - int control variable, counting up;
3117 * - int control variable, counting down;
3118 * Of course, it is possible to fold all of this, and have
3119 * tests everywhere, but the following is cleaner, and easier
3120 * to enhance in the future.
3122 * Note carefully the use of ForLoop::isSimple(). It is
3123 * essential to use exactly the same function here as is
3124 * used by ForLoop::flowAttr() for initialization analysis.
3125 * If this were not the case, the verifier could barf.
3126 * ----------------------------------------------------------- *)
3127 PROCEDURE SetVar(cv
: Id
.AbVar
; ln
: BOOLEAN; ou
: Ju
.JavaFile
);
3129 WITH cv
: Id
.LocId
DO (* check if implemented inside XHR *)
3130 IF Id
.uplevA
IN cv
.locAtt
THEN
3133 ou
.Code(Jvm
.opc_swap
);
3135 ou
.Code(Jvm
.opc_dup_x2
);
3136 ou
.Code(Jvm
.opc_pop
);
3143 (* ----------------------------------------------------------- *)
3144 PROCEDURE LongForUp(e
: JavaEmitter
; stat
: St
.ForLoop
; OUT ok
: BOOLEAN);
3145 VAR out
: Ju
.JavaFile
;
3155 lpLb
:= out
.newLabel();
3156 exLb
:= out
.newLabel();
3157 cVar
:= stat
.cVar(Id
.AbVar
);
3158 step
:= longValue(stat
.byXp
);
3159 smpl
:= stat
.isSimple();
3161 out
.PushLong(longValue(stat
.loXp
));
3162 SetVar(cVar
, TRUE
, out
);
3163 top1
:= -1; (* keep the verifier happy! *)
3164 top2
:= -1; (* keep the verifier happy! *)
3166 top1
:= out
.newLocal(); (* actually a pair of locals *)
3167 top2
:= out
.newLocal();
3168 e
.PushValue(stat
.hiXp
, Bi
.lIntTp
);
3169 out
.Code(Jvm
.opc_dup2
);
3170 out
.StoreLocal(top1
, Bi
.lIntTp
);
3171 e
.PushValue(stat
.loXp
, Bi
.lIntTp
);
3172 out
.Code(Jvm
.opc_dup2
);
3173 SetVar(cVar
, TRUE
, out
);
3175 * The top test is NEVER inside the loop.
3177 e
.DoCmp(Xp
.lessT
, exLb
, Bi
.lIntTp
);
3179 out
.DefLabC(lpLb
, "Loop header");
3181 * Emit the code body.
3182 * Stack contents are (top) hi, ...
3183 * and exactly the same on the backedge.
3185 e
.EmitStat(stat
.body
, ok
);
3187 * If the body returns ... do an exit test.
3191 out
.PushLong(longValue(stat
.hiXp
));
3193 out
.LoadLocal(top1
, Bi
.lIntTp
);
3195 out
.GetVar(cVar
); (* (top) cv,hi *)
3197 out
.Code(Jvm
.opc_ladd
); (* (top) cv',hi *)
3198 out
.Code(Jvm
.opc_dup2
); (* (top) cv',cv',hi *)
3199 SetVar(cVar
, TRUE
, out
);
3200 e
.DoCmp(Xp
.greEq
, lpLb
, Bi
.lIntTp
);
3205 out
.DefLabC(exLb
, "Loop trailer");
3208 (* ----------------------------------------- *)
3210 PROCEDURE LongForDn(e
: JavaEmitter
; stat
: St
.ForLoop
; OUT ok
: BOOLEAN);
3211 VAR out
: Ju
.JavaFile
;
3221 lpLb
:= out
.newLabel();
3222 exLb
:= out
.newLabel();
3223 cVar
:= stat
.cVar(Id
.AbVar
);
3224 step
:= longValue(stat
.byXp
);
3225 smpl
:= stat
.isSimple();
3227 out
.PushLong(longValue(stat
.loXp
));
3228 SetVar(cVar
, TRUE
, out
);
3229 top1
:= -1; (* keep the verifier happy! *)
3230 top2
:= -1; (* keep the verifier happy! *)
3232 top1
:= out
.newLocal(); (* actually a pair of locals *)
3233 top2
:= out
.newLocal();
3234 e
.PushValue(stat
.hiXp
, Bi
.lIntTp
);
3235 out
.Code(Jvm
.opc_dup2
);
3236 out
.StoreLocal(top1
, Bi
.lIntTp
);
3237 e
.PushValue(stat
.loXp
, Bi
.lIntTp
);
3238 out
.Code(Jvm
.opc_dup2
);
3239 SetVar(cVar
, TRUE
, out
);
3241 * The top test is NEVER inside the loop.
3243 e
.DoCmp(Xp
.greT
, exLb
, Bi
.lIntTp
);
3245 out
.DefLabC(lpLb
, "Loop header");
3247 * Emit the code body.
3248 * Stack contents are (top) hi, ...
3249 * and exactly the same on the backedge.
3251 e
.EmitStat(stat
.body
, ok
);
3253 * If the body returns ... do an exit test.
3257 out
.PushLong(longValue(stat
.hiXp
));
3259 out
.LoadLocal(top1
, Bi
.lIntTp
);
3261 out
.GetVar(cVar
); (* (top) cv,hi *)
3263 out
.Code(Jvm
.opc_ladd
); (* (top) cv',hi *)
3264 out
.Code(Jvm
.opc_dup2
); (* (top) cv',cv',hi *)
3265 SetVar(cVar
, TRUE
, out
);
3266 e
.DoCmp(Xp
.lessEq
, lpLb
, Bi
.lIntTp
);
3271 out
.DefLabC(exLb
, "Loop trailer");
3274 (* ----------------------------------------- *)
3276 PROCEDURE IntForUp(e
: JavaEmitter
; stat
: St
.ForLoop
; OUT ok
: BOOLEAN);
3277 VAR out
: Ju
.JavaFile
;
3286 * This is the common case, so we work a bit harder.
3289 lpLb
:= out
.newLabel();
3290 exLb
:= out
.newLabel();
3291 cVar
:= stat
.cVar(Id
.AbVar
);
3292 step
:= intValue(stat
.byXp
);
3293 smpl
:= stat
.isSimple();
3295 out
.PushInt(intValue(stat
.loXp
));
3296 SetVar(cVar
, FALSE
, out
);
3297 topV
:= -1; (* keep the verifier happy! *)
3299 topV
:= out
.newLocal();
3300 e
.PushValue(stat
.hiXp
, Bi
.intTp
);
3301 out
.Code(Jvm
.opc_dup
);
3302 out
.StoreLocal(topV
, Bi
.intTp
);
3303 e
.PushValue(stat
.loXp
, Bi
.intTp
);
3304 out
.Code(Jvm
.opc_dup
);
3305 SetVar(cVar
, FALSE
, out
);
3307 * The top test is NEVER inside the loop.
3309 e
.DoCmp(Xp
.lessT
, exLb
, Bi
.intTp
);
3311 out
.DefLabC(lpLb
, "Loop header");
3313 * Emit the code body.
3315 e
.EmitStat(stat
.body
, ok
);
3317 * If the body returns ... do an exit test.
3321 out
.PushInt(intValue(stat
.hiXp
));
3323 out
.LoadLocal(topV
, Bi
.intTp
);
3325 out
.GetVar(cVar
); (* (top) cv,hi *)
3327 out
.Code(Jvm
.opc_iadd
); (* (top) cv',hi *)
3328 out
.Code(Jvm
.opc_dup
); (* (top) cv',cv',hi *)
3329 SetVar(cVar
, FALSE
, out
);
3330 e
.DoCmp(Xp
.greEq
, lpLb
, Bi
.intTp
);
3335 out
.DefLabC(exLb
, "Loop trailer");
3338 (* ----------------------------------------- *)
3340 PROCEDURE IntForDn(e
: JavaEmitter
; stat
: St
.ForLoop
; OUT ok
: BOOLEAN);
3341 VAR out
: Ju
.JavaFile
;
3350 lpLb
:= out
.newLabel();
3351 exLb
:= out
.newLabel();
3352 cVar
:= stat
.cVar(Id
.AbVar
);
3353 step
:= intValue(stat
.byXp
);
3354 topV
:= out
.newLocal();
3355 smpl
:= stat
.isSimple();
3357 out
.PushInt(intValue(stat
.loXp
));
3358 SetVar(cVar
, FALSE
, out
);
3359 topV
:= -1; (* keep the verifier happy! *)
3361 e
.PushValue(stat
.hiXp
, Bi
.intTp
);
3362 out
.Code(Jvm
.opc_dup
);
3363 out
.StoreLocal(topV
, Bi
.intTp
);
3364 e
.PushValue(stat
.loXp
, Bi
.intTp
);
3365 out
.Code(Jvm
.opc_dup
);
3366 SetVar(cVar
, FALSE
, out
);
3368 * The top test is NEVER inside the loop.
3370 e
.DoCmp(Xp
.greT
, exLb
, Bi
.intTp
);
3372 out
.DefLabC(lpLb
, "Loop header");
3374 * Emit the code body.
3376 e
.EmitStat(stat
.body
, ok
);
3378 * If the body returns ... do an exit test.
3382 out
.PushInt(intValue(stat
.hiXp
));
3384 out
.LoadLocal(topV
, Bi
.intTp
);
3386 out
.GetVar(cVar
); (* (top) cv,hi *)
3388 out
.Code(Jvm
.opc_iadd
); (* (top) cv',hi *)
3389 out
.Code(Jvm
.opc_dup
); (* (top) cv',cv',hi *)
3390 SetVar(cVar
, FALSE
, out
);
3391 e
.DoCmp(Xp
.lessEq
, lpLb
, Bi
.intTp
);
3396 out
.DefLabC(exLb
, "Loop trailer");
3399 (* ----------------------------------------- *)
3400 BEGIN (* body of EmitFor *)
3401 IF stat
.cVar
.type
.isLongType() THEN
3402 IF longValue(stat
.byXp
) > 0 THEN LongForUp(e
, stat
, ok
);
3403 ELSE LongForDn(e
, stat
, ok
);
3406 IF longValue(stat
.byXp
) > 0 THEN IntForUp(e
, stat
, ok
);
3407 ELSE IntForDn(e
, stat
, ok
);
3412 (* ---------------------------------------------------- *)
3414 PROCEDURE (e
: JavaEmitter
)
3415 EmitLoop(stat
: St
.TestLoop
; OUT ok
: BOOLEAN),NEW;
3416 VAR out
: Ju
.JavaFile
;
3421 lpLb
:= out
.newLabel();
3422 tmpLb
:= currentLoopLabel
;
3423 currentLoopLabel
:= out
.newLabel();
3424 out
.DefLabC(lpLb
, "Loop header");
3425 e
.EmitStat(stat
.body
, ok
);
3426 IF ok
THEN out
.CodeLb(Jvm
.opc_goto
, lpLb
) END;
3427 out
.DefLabC(currentLoopLabel
, "Loop exit");
3428 currentLoopLabel
:= tmpLb
;
3431 (* ---------------------------------------------------- *)
3433 PROCEDURE (e
: JavaEmitter
)EmitWith(stat
: St
.Choice
; OUT ok
: BOOLEAN),NEW;
3434 VAR out
: Ju
.JavaFile
;
3435 high
: INTEGER; (* Branch count. *)
3436 exLb
: Ju
.Label
; (* Exit label *)
3437 nxtP
: Ju
.Label
; (* Next predicate *)
3443 (* --------------------------- *)
3444 PROCEDURE WithTest(je
: JavaEmitter
;
3449 VAR bX
: Xp
.BinaryX
;
3452 bX
:= pr(Xp
.BinaryX
);
3453 ty
:= bX
.rKid(Xp
.IdLeaf
).ident
.type
;
3454 je
.PushValue(bX
.lKid
, bX
.lKid
.type
);
3455 os
.CodeT(Jvm
.opc_instanceof
, ty
);
3456 os
.CodeLb(Jvm
.opc_ifeq
, nx
);
3458 * We must also generate a checkcast, because the verifier
3459 * seems to understand the typeflow consequences of the
3460 * checkcast bytecode, but not instanceof.
3462 je
.PushValue(bX
.lKid
, bX
.lKid
.type
);
3463 os
.CodeT(Jvm
.opc_checkcast
, ty
);
3464 os
.StoreLocal(tm
, ty
);
3466 (* --------------------------- *)
3472 exLb
:= out
.newLabel();
3473 high
:= stat
.preds
.tide
- 1;
3474 FOR indx
:= 0 TO high
DO
3476 pred
:= stat
.preds
.a
[indx
];
3477 then
:= stat
.blocks
.a
[indx
];
3478 tVar
:= stat
.temps
.a
[indx
](Id
.LocId
);
3479 nxtP
:= out
.newLabel();
3481 tVar
.varOrd
:= out
.newLocal();
3482 WithTest(e
, out
, pred
, nxtP
, tVar
.varOrd
);
3484 IF then
# NIL THEN e
.EmitStat(then
, live
) END;
3488 * If this is not the else case, skip over the
3489 * later cases, or jump over the WITH ELSE trap.
3491 IF pred
# NIL THEN out
.CodeLb(Jvm
.opc_goto
, exLb
) END;
3493 IF tVar
# NIL THEN out
.ReleaseLocal(tVar
.varOrd
) END;
3496 IF pred
# NIL THEN out
.WithTrap(pred(Xp
.BinaryX
).lKid(Xp
.IdLeaf
).ident
) END;
3500 (* ---------------------------------------------------- *)
3502 PROCEDURE (e
: JavaEmitter
)EmitExit(stat
: St
.ExitSt
),NEW;
3504 e
.outF
.CodeLb(Jvm
.opc_goto
, currentLoopLabel
);
3507 (* ---------------------------------------------------- *)
3509 PROCEDURE (e
: JavaEmitter
)EmitReturn(stat
: St
.Return
),NEW;
3510 VAR out
: Ju
.JavaFile
;
3515 pId
:= out
.getScope()(Id
.Procs
);
3517 * Because the return slot may be used for the first
3518 * OUT or VAR parameter, the real return type might
3519 * be different to that shown in the formal type.
3520 * FixOutPars() returns this real return type.
3522 IF (stat
.retX
# NIL) &
3523 (pId
.kind
# Id
.ctorP
) THEN e
.PushValue(stat
.retX
, stat
.retX
.type
) END;
3524 out
.FixOutPars(pId
, ret
);
3528 (* ---------------------------------------------------- *)
3530 PROCEDURE (e
: JavaEmitter
)EmitBlock(stat
: St
.Block
; OUT ok
: BOOLEAN),NEW;
3531 VAR index
, limit
: INTEGER;
3535 limit
:= stat
.sequ
.tide
;
3536 WHILE ok
& (index
< limit
) DO
3537 e
.EmitStat(stat
.sequ
.a
[index
], ok
);
3542 (* ---------------------------------------------------- *)
3543 (* ---------------------------------------------------- *)
3545 PROCEDURE (e
: JavaEmitter
)EmitStat(stat
: Sy
.Stmt
; OUT ok
: BOOLEAN),NEW;
3546 VAR depth
: INTEGER;
3548 IF (stat
= NIL) OR (stat
.kind
= St
.emptyS
) THEN ok
:= TRUE
; RETURN END;
3549 IF stat
.kind
# St
.blockS
THEN
3550 e
.outF
.Line(stat
.token
.lin
);
3552 depth
:= e
.outF
.getDepth();
3554 | St
.assignS
: e
.EmitAssign(stat(St
.Assign
)); ok
:= TRUE
;
3555 | St
.procCall
: e
.EmitCall(stat(St
.ProcCall
)); ok
:= TRUE
;
3556 | St
.ifStat
: e
.EmitIf(stat(St
.Choice
), ok
);
3557 | St
.caseS
: e
.EmitCase(stat(St
.CaseSt
), ok
);
3558 | St
.whileS
: e
.EmitWhile(stat(St
.TestLoop
), ok
);
3559 | St
.repeatS
: e
.EmitRepeat(stat(St
.TestLoop
), ok
);
3560 | St
.forStat
: e
.EmitFor(stat(St
.ForLoop
), ok
);
3561 | St
.loopS
: e
.EmitLoop(stat(St
.TestLoop
), ok
);
3562 | St
.withS
: e
.EmitWith(stat(St
.Choice
), ok
);
3563 | St
.exitS
: e
.EmitExit(stat(St
.ExitSt
)); ok
:= TRUE
;
3564 | St
.returnS
: e
.EmitReturn(stat(St
.Return
)); ok
:= FALSE
;
3565 | St
.blockS
: e
.EmitBlock(stat(St
.Block
), ok
);
3567 e
.outF
.setDepth(depth
);
3571 (* ============================================================ *)
3572 (* ============================================================ *)
3574 (* ============================================================ *)
3575 (* ============================================================ *)