1   // Copyright 2012- Bill Campbell, Swami Iyer and Bahar Akbal-Delibas
2   
3   package jminusminus;
4   
5   import java.util.ArrayList;
6   
7   import static jminusminus.CLConstants.*;
8   import static jminusminus.NPhysicalRegister.*;
9   
10  /**
11   * This abstract base class provides a high-level intermediate representation (HIR) of a JVM
12   * instruction.
13   */
14  abstract class NHIRInstruction {
15      /**
16       * Maps JVM opcode to a string mnemonic for HIR instructions. For example, the opcode imul is
17       * mapped to the string "*".
18       */
19      protected static String[] hirMnemonic;
20  
21      static {
22          hirMnemonic = new String[256];
23          hirMnemonic[IADD] = "+";
24          hirMnemonic[ISUB] = "-";
25          hirMnemonic[IMUL] = "*";
26          hirMnemonic[MULTIANEWARRAY] = "multianewarray";
27          hirMnemonic[AALOAD] = "aaload";
28          hirMnemonic[IALOAD] = "iaload";
29          hirMnemonic[IASTORE] = "iastore";
30          hirMnemonic[IF_ICMPNE] = "!=";
31          hirMnemonic[IF_ICMPGT] = ">";
32          hirMnemonic[IF_ICMPLE] = "<=";
33          hirMnemonic[GETSTATIC] = "getstatic";
34          hirMnemonic[PUTSTATIC] = "putstatic";
35          hirMnemonic[INVOKESPECIAL] = "invokespecial";
36          hirMnemonic[INVOKESTATIC] = "invokestatic";
37          hirMnemonic[ARETURN] = "areturn";
38          hirMnemonic[RETURN] = "return";
39          hirMnemonic[IRETURN] = "ireturn";
40      }
41  
42      /**
43       * The block containing this instruction.
44       */
45      public NBasicBlock block;
46  
47      /**
48       * Unique identifier of this instruction.
49       */
50      public int id;
51  
52      /**
53       * Short type name for this instruction.
54       */
55      public String sType;
56  
57      /**
58       * Long type name for this instruction.
59       */
60      public String lType;
61  
62      /**
63       * The LIR instruction corresponding to this HIR instruction.
64       */
65      public NLIRInstruction lir;
66  
67      /**
68       * Constructs a NHIRInstruction object.
69       *
70       * @param block enclosing block.
71       * @param id    identifier of the instruction.
72       */
73      protected NHIRInstruction(NBasicBlock block, int id) {
74          this(block, id, "", "");
75      }
76  
77      /**
78       * Constructs a NHIRInstruction object.
79       *
80       * @param block enclosing block.
81       * @param id    identifier of the instruction.
82       * @param sType short type name of the instruction.
83       * @param lType long type name of the instruction.
84       */
85      protected NHIRInstruction(NBasicBlock block, int id, String sType, String lType) {
86          this.block = block;
87          this.id = id;
88          this.sType = sType;
89          this.lType = lType;
90      }
91  
92      /**
93       * Returns true if this instruction is the same as the other, and false otherwise.
94       *
95       * @param other the instruction to compare to.
96       * @return true if this instruction is the same as the other, and false otherwise.
97       */
98      public boolean equals(NHIRInstruction other) {
99          return this.id == other.id;
100     }
101 
102     /**
103      * Converts and returns a low-level representation (LIR) of this HIR instruction. Also adds
104      * the returned LIR instruction to the list of LIR instructions for the block containing this
105      * instruction, along with any other intermediate LIR instructions needed.
106      *
107      * @return the LIR instruction corresponding to this HIR instruction.
108      */
109     public NLIRInstruction toLir() {
110         return null;
111     }
112 
113     /**
114      * Returns the identifier of this instruction with the short type name prefix.
115      *
116      * @return the identifier of this instruction with the short type name prefix.
117      */
118     public String id() {
119         return sType + id;
120     }
121 
122     /**
123      * Returns a string representation of this instruction.
124      *
125      * @return a string representation of this instruction.
126      */
127     public String toString() {
128         return sType + id;
129     }
130 }
131 
132 /**
133  * HIR instruction corresponding to the JVM arithmetic instructions.
134  */
135 class NHIRArithmetic extends NHIRInstruction {
136     // Opcode for the arithmetic operator.
137     private int opcode;
138 
139     // Lhs HIR id.
140     private int lhs;
141 
142     // Rhs HIR id.
143     private int rhs;
144 
145     /**
146      * Constructs an NHIRArithmetic object.
147      *
148      * @param block  enclosing block.
149      * @param id     identifier of the instruction.
150      * @param opcode opcode for the arithmetic operator.
151      * @param lhs    lhs HIR id.
152      * @param rhs    rhs HIR id.
153      */
154     public NHIRArithmetic(NBasicBlock block, int id, int opcode, int lhs, int rhs) {
155         super(block, id, "I", "I");
156         this.opcode = opcode;
157         this.lhs = lhs;
158         this.rhs = rhs;
159     }
160 
161     /**
162      * {@inheritDoc}
163      */
164     public NLIRInstruction toLir() {
165         if (lir != null) {
166             return lir;
167         }
168         NLIRInstruction ins1 = block.cfg.hirMap.get(lhs).toLir();
169         NLIRInstruction ins2 = block.cfg.hirMap.get(rhs).toLir();
170         lir = new NLIRArithmetic(block, NControlFlowGraph.lirId++, opcode, ins1, ins2);
171         block.lir.add(lir);
172         return lir;
173     }
174 
175     /**
176      * {@inheritDoc}
177      */
178     public String toString() {
179         return id() + ": " + block.cfg.hirMap.get(lhs).id() + " " + hirMnemonic[opcode] + " " +
180                 block.cfg.hirMap.get(rhs).id();
181     }
182 }
183 
184 /**
185  * HIR instruction corresponding to the JVM instructions representing integer constants.
186  */
187 class NHIRIntConstant extends NHIRInstruction {
188     // The constant int value.
189     private int value;
190 
191     /**
192      * Constructs an NHIRIntConstant object.
193      *
194      * @param block enclosing block.
195      * @param id    identifier of the instruction.
196      * @param value the constant int value.
197      */
198     public NHIRIntConstant(NBasicBlock block, int id, int value) {
199         super(block, id, "I", "I");
200         this.value = value;
201     }
202 
203     /**
204      * {@inheritDoc}
205      */
206     public NLIRInstruction toLir() {
207         if (lir != null) {
208             return lir;
209         }
210         lir = new NLIRIntConstant(block, NControlFlowGraph.lirId++, value);
211         block.lir.add(lir);
212         return lir;
213     }
214 
215     /**
216      * {@inheritDoc}
217      */
218     public String toString() {
219         return id() + ": " + value;
220     }
221 }
222 
223 /**
224  * HIR instruction corresponding to the JVM instructions representing string
225  * constants.
226  */
227 
228 class NHIRStringConstant extends NHIRInstruction {
229     // The constant string value.
230     private String value;
231 
232     /**
233      * Constructs an NHIRStringConstant object.
234      *
235      * @param block enclosing block.
236      * @param id    identifier for the instruction.
237      * @param value the constant string value.
238      */
239     public NHIRStringConstant(NBasicBlock block, int id, String value) {
240         super(block, id, "L", "Ljava/lang/String;");
241         this.value = value;
242     }
243 
244     /**
245      * {@inheritDoc}
246      */
247     public NLIRInstruction toLir() {
248         if (lir != null) {
249             return lir;
250         }
251         lir = new NLIRStringConstant(block, NControlFlowGraph.lirId++, value);
252         block.lir.add(lir);
253         return lir;
254     }
255 
256     /**
257      * {@inheritDoc}
258      */
259     public String toString() {
260         return id() + ": \"" + value + "\"";
261     }
262 }
263 
264 /**
265  * HIR instruction representing an conditional jump instructions in JVM.
266  */
267 class NHIRConditionalJump extends NHIRInstruction {
268     // Lhs HIR id.
269     private int lhs;
270 
271     // Rhs HIR id.
272     private int rhs;
273 
274     // Test expression opcode.
275     private int opcode;
276 
277     // Block to jump to on true.
278     private NBasicBlock onTrueDestination;
279 
280     // Block to jump to on false.
281     private NBasicBlock onFalseDestination;
282 
283     /**
284      * Constructs an NHIRConditionalJump object.
285      *
286      * @param block              enclosing block.
287      * @param id                 identifier of the instruction.
288      * @param lhs                Lhs HIR id.
289      * @param rhs                Rhs HIR id.
290      * @param opcode             opcode in the test.
291      * @param onTrueDestination  block to jump to on true.
292      * @param onFalseDestination block to jump to on false.
293      */
294     public NHIRConditionalJump(NBasicBlock block, int id, int lhs, int rhs, int opcode,
295                                NBasicBlock onTrueDestination, NBasicBlock onFalseDestination) {
296         super(block, id, "", "");
297         this.lhs = lhs;
298         this.rhs = rhs;
299         this.opcode = opcode;
300         this.onTrueDestination = onTrueDestination;
301         this.onFalseDestination = onFalseDestination;
302     }
303 
304     /**
305      * {@inheritDoc}
306      */
307     public NLIRInstruction toLir() {
308         if (lir != null) {
309             return lir;
310         }
311         NLIRInstruction ins1 = block.cfg.hirMap.get(lhs).toLir();
312         NLIRInstruction ins2 = block.cfg.hirMap.get(rhs).toLir();
313         lir = new NLIRConditionalJump(block, NControlFlowGraph.lirId++, ins1, ins2, opcode,
314                 onTrueDestination, onFalseDestination);
315         block.lir.add(lir);
316         return lir;
317     }
318 
319     /**
320      * {@inheritDoc}
321      */
322     public String toString() {
323         return id() + ": if " + block.cfg.hirMap.get(lhs).id() + " " + hirMnemonic[opcode] + " " +
324                 block.cfg.hirMap.get(rhs).id() + " then " + onTrueDestination.id() + " else " +
325                 onFalseDestination.id();
326     }
327 }
328 
329 /**
330  * HIR instruction representing an unconditional jump instruction in JVM.
331  */
332 class NHIRGoto extends NHIRInstruction {
333     // The destination block to unconditionally jump to.
334     private NBasicBlock destination;
335 
336     /**
337      * Constructs an NHIRGoto object.
338      *
339      * @param block       enclosing block.
340      * @param id          identifier of the instruction.
341      * @param destination the block to jump to.
342      */
343     public NHIRGoto(NBasicBlock block, int id, NBasicBlock destination) {
344         super(block, id, "", "");
345         this.destination = destination;
346     }
347 
348     /**
349      * {@inheritDoc}
350      */
351     public NLIRInstruction toLir() {
352         if (lir != null) {
353             return lir;
354         }
355         lir = new NLIRGoto(block, NControlFlowGraph.lirId++, destination);
356         block.lir.add(lir);
357         return lir;
358     }
359 
360     /**
361      * {@inheritDoc}
362      */
363     public String toString() {
364         return id() + ": goto " + destination.id();
365     }
366 }
367 
368 /**
369  * HIR instruction representing method invocation instructions in JVM.
370  */
371 class NHIRInvoke extends NHIRInstruction {
372     // Opcode of the JVM instruction.
373     private int opcode;
374 
375     // Target for the method.
376     private String target;
377 
378     // Name of the method being invoked.
379     private String name;
380 
381     // List of HIR ids of arguments for the method.
382     private ArrayList<Integer> arguments;
383 
384     /**
385      * Constructs an NHIRInvoke object.
386      *
387      * @param block     enclosing block.
388      * @param id        identifier of the instruction.
389      * @param opcode    opcode of the JVM instruction.
390      * @param target    target of the method.
391      * @param name      name of the method.
392      * @param arguments list of HIR ids of arguments for the method.
393      * @param sType     return type (short name) of the method.
394      * @param lType     return type (long name) of the method.
395      */
396     public NHIRInvoke(NBasicBlock block, int id, int opcode, String target, String name,
397                       ArrayList<Integer> arguments, String sType, String lType) {
398         super(block, id, sType, lType);
399         this.opcode = opcode;
400         this.target = target;
401         this.name = name;
402         this.arguments = arguments;
403     }
404 
405     /**
406      * {@inheritDoc}
407      */
408     public NLIRInstruction toLir() {
409         if (lir != null) {
410             return lir;
411         }
412 
413         // First four arguments are stored in physical registers (a0, ..., a3) and the rest are 
414         // on the stack. Allocate space on stack for arguments fourth or above; [0, block.cfg
415         // .offset - 1].
416         if (this.arguments.size() - 4 > block.cfg.offset) {
417             block.cfg.offset = this.arguments.size() - 4;
418         }
419 
420         ArrayList<NRegister> arguments = new ArrayList<NRegister>();
421         ArrayList<NPhysicalRegister> froms = new ArrayList<NPhysicalRegister>();
422         ArrayList<NVirtualRegister> tos = new ArrayList<NVirtualRegister>();
423         for (int i = 0; i < this.arguments.size(); i++) {
424             int arg = this.arguments.get(i);
425             NLIRInstruction ins = block.cfg.hirMap.get(arg).toLir();
426             if (i < 4) {
427                 // Generate an LIR move instruction (move1) to save away the physical register a0
428                 // + i into a virtual register, and another LIR move instruction (move2) to copy 
429                 // the argument from the virtual register it's in to the physical register a0 + i.
430                 String sType = block.cfg.hirMap.get(arg).sType;
431                 String lType = block.cfg.hirMap.get(arg).lType;
432                 NPhysicalRegister from = NPhysicalRegister.regInfo[A0 + i];
433                 block.cfg.registers.set(A0 + i, from);
434                 NVirtualRegister to = new NVirtualRegister(NControlFlowGraph.regId++, sType, lType);
435                 block.cfg.registers.add(to);
436                 NLIRMove move1 = new NLIRMove(block, NControlFlowGraph.lirId++, from, to);
437                 block.lir.add(move1);
438                 NLIRMove move2 = new NLIRMove(block, NControlFlowGraph.lirId++, ins.write, from);
439                 block.lir.add(move2);
440                 arguments.add(NPhysicalRegister.regInfo[A0 + i]);
441 
442                 // Remember the froms and the tos so we can restore the values of a0 + i registers.
443                 froms.add(from);
444                 tos.add(to);
445             } else {
446                 NLIRStore store = new NLIRStore(block, NControlFlowGraph.lirId++, i - 4,
447                         OffsetFrom.SP, ins.write);
448                 block.lir.add(store);
449                 arguments.add(ins.write);
450             }
451         }
452         lir = new NLIRInvoke(block, NControlFlowGraph.lirId++, opcode, target, name, arguments,
453                 sType, lType);
454         block.lir.add(lir);
455 
456         // If the function returns a value, generate an LIR move instruction to save away the 
457         // value in the physical register v0 into a virtual register.
458         if (lir.write != null) {
459             NVirtualRegister to = new NVirtualRegister(NControlFlowGraph.regId++, sType, lType);
460             NLIRMove move = new NLIRMove(block, NControlFlowGraph.lirId++,
461                     NPhysicalRegister.regInfo[V0], to);
462             block.cfg.registers.add(to);
463             block.lir.add(move);
464             lir = move;
465         }
466 
467         // Generate LIR move instructions to restore the a0, ..., a3 instructions.
468         for (int i = 0; i < tos.size(); i++) {
469             NLIRMove move = new NLIRMove(block, NControlFlowGraph.lirId++, tos.get(i),
470                     froms.get(i));
471             block.lir.add(move);
472         }
473         return lir;
474     }
475 
476     /**
477      * {@inheritDoc}
478      */
479     public String toString() {
480         String s = id() + ": " + hirMnemonic[opcode] + " " + target + "." + name + "( ";
481         for (int arg : arguments) {
482             s += block.cfg.hirMap.get(arg).id() + " ";
483         }
484         s += ")";
485         return s;
486     }
487 }
488 
489 /**
490  * HIR instruction representing a JVM return instruction.
491  */
492 class NHIRReturn extends NHIRInstruction {
493     // JVM opcode for the return instruction.
494     private int opcode;
495 
496     // Return value HIR id.
497     private int value;
498 
499     /**
500      * Constructs an NHIRReturn object.
501      *
502      * @param block  enclosing block.
503      * @param id     identifier of the instruction.
504      * @param opcode JVM opcode for the return instruction.
505      * @param value  return value HIR id.
506      */
507     public NHIRReturn(NBasicBlock block, int id, int opcode, int value) {
508         super(block, id, value == -1 ? "" : block.cfg.hirMap.get(value).sType,
509                 value == -1 ? "" : block.cfg.hirMap.get(value).lType);
510         this.opcode = opcode;
511         this.value = value;
512     }
513 
514     /**
515      * {@inheritDoc}
516      */
517     public NLIRInstruction toLir() {
518         if (lir != null) {
519             return lir;
520         }
521         NLIRInstruction result = null;
522         if (value != -1) {
523             result = block.cfg.hirMap.get(value).toLir();
524             NLIRMove move = new NLIRMove(block, NControlFlowGraph.lirId++, result.write,
525                     NPhysicalRegister.regInfo[V0]);
526             block.lir.add(move);
527             block.cfg.registers.set(V0, NPhysicalRegister.regInfo[V0]);
528         }
529         lir = new NLIRReturn(block, NControlFlowGraph.lirId++, opcode, result == null ? null :
530                 NPhysicalRegister.regInfo[V0]);
531         block.lir.add(lir);
532         return lir;
533     }
534 
535     /**
536      * {@inheritDoc}
537      */
538     public String toString() {
539         if (value == -1) {
540             return id() + ": " + hirMnemonic[opcode];
541         }
542         return id() + ": " + hirMnemonic[opcode] + " " + block.cfg.hirMap.get(value).id();
543     }
544 }
545 
546 /**
547  * HIR instruction representing JVM (put) field instructions.
548  */
549 class NHIRPutField extends NHIRInstruction {
550     // Opcode of the JVM instruction.
551     private int opcode;
552 
553     // Target for the field.
554     private String target;
555 
556     // Name of the field being accessed.
557     private String name;
558 
559     // HIR id of the value of the field.
560     private int value;
561 
562     /**
563      * Constructs an NHIRPutField object.
564      *
565      * @param block  enclosing block.
566      * @param id     identifier of the instruction.
567      * @param opcode JVM opcode for the instruction.
568      * @param target target for the field.
569      * @param name   name of the field.
570      * @param sType  type (short name) of the field.
571      * @param lType  type (long name) of the field.
572      * @param value  HIR id of the value of the field.
573      */
574     public NHIRPutField(NBasicBlock block, int id, int opcode, String target, String name,
575                         String sType, String lType, int value) {
576         super(block, id, sType, lType);
577         this.opcode = opcode;
578         this.target = target;
579         this.name = name;
580         this.value = value;
581     }
582 
583     /**
584      * {@inheritDoc}
585      */
586     public NLIRInstruction toLir() {
587         if (lir != null) {
588             return lir;
589         }
590         NLIRInstruction result = block.cfg.hirMap.get(value).toLir();
591         lir = new NLIRPutField(block, NControlFlowGraph.lirId++, opcode, target, name, sType,
592                 lType, result);
593         block.lir.add(lir);
594         return lir;
595     }
596 
597     /**
598      * {@inheritDoc}
599      */
600     public String toString() {
601         return id() + ": " + hirMnemonic[opcode] + " " + target + "." + name + " = " +
602                 block.cfg.hirMap.get(value).id();
603     }
604 }
605 
606 /**
607  * HIR instruction representing JVM (get) field instructions.
608  */
609 class NHIRGetField extends NHIRInstruction {
610     // Opcode of the JVM instruction.
611     private int opcode;
612 
613     // Target for the field.
614     private String target;
615 
616     // Name of the field being accessed.
617     private String name;
618 
619     /**
620      * Constructs an NHIRGetField object.
621      *
622      * @param block  enclosing block.
623      * @param id     identifier of the instruction.
624      * @param opcode JVM opcode for the instruction.
625      * @param target target for the field.
626      * @param name   name of the field.
627      * @param sType  type (short name) of the field.
628      * @param lType  type (long name) of the field.
629      */
630     public NHIRGetField(NBasicBlock block, int id, int opcode, String target, String name,
631                         String sType, String lType) {
632         super(block, id, sType, lType);
633         this.opcode = opcode;
634         this.target = target;
635         this.name = name;
636     }
637 
638     /**
639      * {@inheritDoc}
640      */
641     public NLIRInstruction toLir() {
642         if (lir != null) {
643             return lir;
644         }
645         lir = new NLIRGetField(block, NControlFlowGraph.lirId++, opcode, target, name, sType,
646                 lType);
647         block.lir.add(lir);
648         return lir;
649     }
650 
651     /**
652      * {@inheritDoc}
653      */
654     public String toString() {
655         return id() + ": " + hirMnemonic[opcode] + " " + target + "." + name;
656     }
657 }
658 
659 /**
660  * HIR instruction representing JVM array creation instructions.
661  */
662 class NHIRNewArray extends NHIRInstruction {
663     // Opcode of the JVM instruction.
664     private int opcode;
665 
666     // Dimension of the array.
667     private int dim;
668 
669     /**
670      * Constructs an NHIRNewArray object.
671      *
672      * @param block  enclosing block.
673      * @param id     identifier of the instruction.
674      * @param opcode JVM opcode for the instruction.
675      * @param dim    dimension of the array.
676      * @param sType  type (short name) of the array.
677      * @param lType  type (long name) of the array.
678      */
679     public NHIRNewArray(NBasicBlock block, int id, int opcode, int dim, String sType,
680                         String lType) {
681         super(block, id, lType, sType);
682         this.opcode = opcode;
683         this.dim = dim;
684     }
685 
686     /**
687      * {@inheritDoc}
688      */
689     public NLIRInstruction toLir() {
690         if (lir != null) {
691             return lir;
692         }
693         lir = new NLIRNewArray(block, NControlFlowGraph.lirId++, opcode, dim, sType, lType);
694         block.lir.add(lir);
695         return lir;
696     }
697 
698     /**
699      * {@inheritDoc}
700      */
701     public String toString() {
702         return id() + ": " + hirMnemonic[opcode] + " " + lType + " [" + dim + "]";
703     }
704 }
705 
706 /**
707  * HIR instruction representing JVM array load instructions.
708  */
709 class NHIRALoad extends NHIRInstruction {
710     // Opcode of the JVM instruction.
711     private int opcode;
712 
713     // HIR id of the array reference.
714     private int arrayRef;
715 
716     // HIR id of the array index.
717     private int index;
718 
719     /**
720      * Constructs an NHIRALoad object.
721      *
722      * @param block    enclosing block.
723      * @param id       identifier of the instruction.
724      * @param opcode   JVM opcode for the instruction.
725      * @param arrayRef HIR id of the array reference.
726      * @param index    HIR id of the the array index.
727      * @param sType    type (short name) of the array.
728      * @param lType    type (long name) of the array.
729      */
730     public NHIRALoad(NBasicBlock block, int id, int opcode, int arrayRef, int index,
731                      String sType, String lType) {
732         super(block, id, sType, lType);
733         this.opcode = opcode;
734         this.arrayRef = arrayRef;
735         this.index = index;
736     }
737 
738     /**
739      * {@inheritDoc}
740      */
741     public NLIRInstruction toLir() {
742         if (lir != null) {
743             return lir;
744         }
745         NLIRInstruction arrayRef = block.cfg.hirMap.get(this.arrayRef).toLir();
746         NLIRInstruction index = block.cfg.hirMap.get(this.index).toLir();
747         lir = new NLIRALoad(block, NControlFlowGraph.lirId++, opcode, arrayRef, index, sType,
748                 lType);
749         block.lir.add(lir);
750         return lir;
751     }
752 
753     /**
754      * {@inheritDoc}
755      */
756     public String toString() {
757         return id() + ": " + hirMnemonic[opcode] + " " + block.cfg.hirMap.get(arrayRef).id() +
758                 "[" + block.cfg.hirMap.get(index).id() + "]";
759     }
760 }
761 
762 /**
763  * HIR instruction representing JVM array store instructions.
764  */
765 class NHIRAStore extends NHIRInstruction {
766     // Opcode of the JVM instruction.
767     private int opcode;
768 
769     // HIR id of the array reference.
770     private int arrayRef;
771 
772     // HIR id of the array index.
773     private int index;
774 
775     // HIR id of the value to store.
776     private int value;
777 
778     /**
779      * Constructs an NHIRAStore object.
780      *
781      * @param block    enclosing block.
782      * @param id       identifier of the instruction.
783      * @param opcode   JVM opcode for the instruction.
784      * @param arrayRef HIR id of the array reference.
785      * @param index    HIR id of the array index.
786      * @param value    HIR id of the value to store.
787      * @param sType    type (short name) of the array.
788      * @param lType    type (long name) of the array.
789      */
790     public NHIRAStore(NBasicBlock block, int id, int opcode, int arrayRef, int index, int value,
791                       String sType, String lType) {
792         super(block, id, sType, lType);
793         this.opcode = opcode;
794         this.arrayRef = arrayRef;
795         this.index = index;
796         this.value = value;
797     }
798 
799     /**
800      * {@inheritDoc}
801      */
802     public NLIRInstruction toLir() {
803         if (lir != null) {
804             return lir;
805         }
806         NLIRInstruction arrayRef = block.cfg.hirMap.get(this.arrayRef).toLir();
807         NLIRInstruction index = block.cfg.hirMap.get(this.index).toLir();
808         NLIRInstruction value = block.cfg.hirMap.get(this.value).toLir();
809         lir = new NLIRAStore(block, NControlFlowGraph.lirId++, opcode, arrayRef, index, value,
810                 sType, lType);
811         block.lir.add(lir);
812         return lir;
813     }
814 
815     /**
816      * {@inheritDoc}
817      */
818     public String toString() {
819         return id() + ": " + hirMnemonic[opcode] + " " + block.cfg.hirMap.get(arrayRef).id() +
820                 "[" + block.cfg.hirMap.get(index).id() + "] = " + block.cfg.hirMap.get(value).id();
821     }
822 }
823 
824 /**
825  * HIR instruction representing phi functions.
826  */
827 class NHIRPhiFunction extends NHIRInstruction {
828 
829     // List of HIR ids of arguments for the phi function.
830     private ArrayList<Integer> arguments;
831 
832     // Local variable index.
833     private int local;
834 
835     /**
836      * Constructs an NHIRPhiFunction object.
837      *
838      * @param block     enclosing block.
839      * @param id        identifier of the instruction.
840      * @param arguments list of HIR ids of arguments for the phi function.
841      * @param local     local variable index.
842      */
843     public NHIRPhiFunction(NBasicBlock block, int id, ArrayList<Integer> arguments, int local) {
844         super(block, id, "", "");
845         this.arguments = arguments;
846         this.local = local;
847     }
848 
849     /**
850      * Returns a list containing the ids of arguments for this phi function.
851      *
852      * @return a list containing the ids of arguments for this phi function.
853      */
854     public ArrayList<Integer> getArguments() {
855         return arguments;
856     }
857 
858     /**
859      * Returns the local variable index for this phi function.
860      *
861      * @return the local variable index for this phi function.
862      */
863     public int getLocal() {
864         return local;
865     }
866 
867     /**
868      * Infers type for this phi function, which is essentially the type of the arguments.
869      */
870     public void inferType() {
871         for (int arg : arguments) {
872             if (!block.cfg.hirMap.get(arguments.get(0)).sType.equals("")) {
873                 sType = block.cfg.hirMap.get(arguments.get(0)).sType;
874                 lType = block.cfg.hirMap.get(arguments.get(0)).lType;
875                 break;
876             }
877         }
878     }
879 
880     /**
881      * {@inheritDoc}
882      */
883     public NLIRInstruction toLir() {
884         if (lir != null) {
885             return lir;
886         }
887         lir = new NLIRPhiFunction(block, NControlFlowGraph.lirId++, sType, lType);
888         return lir;
889     }
890 
891     /**
892      * {@inheritDoc}
893      */
894     public String toString() {
895         String s = "[ ";
896         for (int ins : arguments) {
897             if (block.cfg.hirMap.get(ins) != null)
898                 s += block.cfg.hirMap.get(ins).sType + ins + " ";
899         }
900         s += "]";
901         return s;
902     }
903 }
904 
905 /**
906  * HIR instruction representing a formal parameter.
907  */
908 class NHIRLoadLocal extends NHIRInstruction {
909     // Local variable index.
910     private int local;
911 
912     /**
913      * Constructs an NHIRLoadLocal object.
914      *
915      * @param block enclosing block.
916      * @param id    identifier of the instruction.
917      * @param local local variable index.
918      * @param sType short type name of the instruction.
919      * @param lType long type name of the instruction.
920      */
921     public NHIRLoadLocal(NBasicBlock block, int id, int local, String sType, String lType) {
922         super(block, id, sType, lType);
923         this.local = local;
924     }
925 
926     /**
927      * {@inheritDoc}
928      */
929     public NLIRInstruction toLir() {
930         if (lir != null) {
931             return lir;
932         }
933         lir = new NLIRLoadLocal(block, NControlFlowGraph.lirId++, local, sType, lType);
934         block.lir.add(lir);
935         return lir;
936     }
937 
938     /**
939      * {@inheritDoc}
940      */
941     public String toString() {
942         return id() + ": LDLOC " + local;
943     }
944 }
945 
946 /**
947  * HIR instruction representing a local (not formal) variable.
948  */
949 class NHIRLocal extends NHIRInstruction {
950     // Local variable index.
951     private int local;
952 
953     /**
954      * Constructs an NHIRLocal object.
955      *
956      * @param block enclosing block.
957      * @param id    identifier of the instruction.
958      * @param local local variable index.
959      * @param sType short type name of the instruction.
960      * @param lType long type name of the instruction.
961      */
962     public NHIRLocal(NBasicBlock block, int id, int local, String sType, String lType) {
963         super(block, id, sType, lType);
964         this.local = local;
965     }
966 
967     /**
968      * {@inheritDoc}
969      */
970     public String toString() {
971         return id() + ": LOC " + lType;
972     }
973 }
974