001: /***
002: * Optimizer.java
003: *
004: * Description: Peep-hole optimizer for the assembler
005: */package org.openlaszlo.sc;
006:
007: import java.io.*;
008: import java.nio.*;
009: import java.util.*;
010: import org.openlaszlo.sc.Instructions.*;
011: import org.openlaszlo.sc.Emitter;
012: import org.openlaszlo.sc.StackModel;
013:
014: public class Optimizer implements Emitter {
015: Emitter receiver;
016: List instrBlock;
017: StackModel stackModel;
018:
019: public Optimizer(Emitter receiver) {
020: this .receiver = receiver;
021: // peephole block
022: this .instrBlock = new ArrayList();
023: // point to last instruction in block, if it is a push
024: // models the data on the stack
025: this .stackModel = new StackModel();
026: }
027:
028: public void flush() {
029: if (this .instrBlock.size() != 0) {
030: for (Iterator i = instrBlock.iterator(); i.hasNext();) {
031: this .receiver.emit((Instruction) i.next());
032: }
033: this .instrBlock.clear();
034: if (this .stackModel != null) {
035: this .stackModel.clear();
036: } else {
037: this .stackModel = new StackModel();
038: }
039: }
040: }
041:
042: public byte[] assemble(List instrs) {
043: for (Iterator i = instrs.iterator(); i.hasNext();) {
044: this .emit((Instruction) i.next());
045: }
046: this .flush();
047: return this .receiver.assemble(Collections.EMPTY_LIST);
048: }
049:
050: public void emit(Instruction instr) {
051: // Peephole optimizations.
052: // System.out.println("" + this.instrBlock);
053: // System.out.println("" + this.stackModel);
054:
055: // The push optimizations create an instruction block across
056: // which pushes may be moved and depend on the model of the
057: // stack which records the instruction that created the data at
058: // the top of the stack. This model is created when a push
059: // instruction is encountered and maintained until no further
060: // optimizations can be made. In the interim, instructions are
061: // passed straight through, without modelling, for efficiency.
062: StackModel model = this .stackModel;
063: List instrBlock = this .instrBlock;
064:
065: if (instr instanceof PUSHInstruction) {
066: PUSHInstruction push = (PUSHInstruction) instr;
067: PUSHInstruction last = model.lastPush();
068: // System.out.println("last = " + last);
069: if (last != null) {
070: // PUSH a; PUSH b -> PUSH a, b
071: // a push of a register cannot be moved across other
072: // instructions
073: if ((Instruction) last != (Instruction) instrBlock
074: .get(instrBlock.size() - 1)
075: && push.isVolatile()) {
076: // System.out.println("last: " + last + " instrBlock.get(-1): " + instrBlock.get(instrBlock.size() - 1));
077: ;
078: } else if (last.merge(push, model)) {
079: return;
080: }
081: }
082: // Accumulate the instruction and update the model
083: // Copy push, since you will smash it
084: push = new PUSHInstruction(push.args);
085: instrBlock.add(push);
086: this .stackModel = push.updateStackModel(model);
087: } else if (instr instanceof ConcreteInstruction
088: && ((ConcreteInstruction) instr).op == Actions.DUP) {
089: // PUSH a; DUP -> PUSH a,a
090: PUSHInstruction last = model.lastPush();
091: if (last != null) {
092: // System.out.println("" + this.instrBlock);
093: // System.out.println("" + this.stackModel);
094: if (last.dup(model)) {
095: return;
096: }
097: }
098: // if accumulating, accumulate, else emit straight
099: if (instrBlock.size() != 0) {
100: // Accumulate the instruction and update the model
101: instrBlock.add(instr);
102: this .stackModel = instr.updateStackModel(model);
103: } else {
104: this .receiver.emit(instr);
105: }
106: // TBD: INC, DEC
107: } else {
108: // if accumulating, accumulate, else emit straight
109: if (instrBlock.size() != 0) {
110: // Accumulate the instruction and update the model
111: instrBlock.add(instr);
112: this .stackModel = instr.updateStackModel(model);
113: } else {
114: this .receiver.emit(instr);
115: }
116: }
117: // If the stackModel becomes unknown, flush the block
118: if (this.stackModel == null) {
119: this.flush();
120: }
121: }
122: }
|