1 7 8 12 13 package org.openlaszlo.sc; 14 import java.io.*; 15 import java.nio.*; 16 import java.util.*; 17 import org.openlaszlo.sc.Instructions.*; 18 import org.openlaszlo.sc.Emitter; 19 20 38 public class Assembler implements Emitter { 39 Hashtable labels; 40 ByteBuffer bytes; 41 private static byte[] backingStore; 42 Hashtable constants; 43 44 public static class Label { 45 Object name; 46 ByteBuffer bytes; 47 int location; 48 List references; 49 50 public Label(Object name) { 51 this.name = name; 52 this.location = -1; 53 this.references = new ArrayList(); 54 } 55 56 public boolean isResolved() { 57 return this.location != -1; 58 } 59 60 public void setLocation(ByteBuffer bytes) { 61 assert (! this.isResolved()) : "Label.setLocation() called on resolved label"; 62 this.location = bytes.position(); 63 for (Iterator i = this.references.iterator(); i.hasNext(); ) { 65 int patchloc = ((Integer )i.next()).intValue(); 66 int offset = location - patchloc - 2; 67 if (offset != (short)offset) { 68 } 70 bytes.putShort(patchloc, (short)offset); 71 } 72 this.references = null; 73 } 74 75 public void addReference(int patchloc) { 76 assert (! this.isResolved()) : "adding reference to resolved label"; 77 this.references.add(new Integer (patchloc)); 78 } 79 80 public String toString() { 81 return this.name.toString(); 82 } 83 } 84 85 private synchronized byte[] getBacking() { 86 byte[] b = backingStore; 87 backingStore = null; 88 return b; 89 } 90 91 private synchronized void setBacking(byte[] b) { 92 backingStore = b; 93 } 94 95 public Assembler() { 96 this.labels = new Hashtable(); byte[] bs = getBacking(); 99 if (bs != null) { 100 this.bytes = ByteBuffer.wrap(bs); 101 } else { 102 this.bytes = ByteBuffer.allocate((1<<14) + (1<<16)); 104 } 105 this.constants = new Hashtable(); } 107 108 public byte[] assemble(List instrs) { 109 for (Iterator i = instrs.iterator(); i.hasNext(); ) { 110 this.emit((Instruction)i.next()); 111 } 112 List unresolvedLabels = new ArrayList(); 113 for (Enumeration i = this.labels.elements(); i.hasMoreElements(); ) { 115 Label label = (Label)i.nextElement(); 116 if (! label.isResolved()) { 117 unresolvedLabels.add(label); 118 } 119 } 120 assert (unresolvedLabels.size() == 0) : "unresolved labels: " + unresolvedLabels; 122 byte[] result = new byte[this.bytes.position()]; 124 this.bytes.flip(); 125 this.bytes.get(result); 126 setBacking(bytes.array()); 128 return result; 129 } 130 131 public Label getLabel(Object name) { 132 if (! this.labels.containsKey(name)) { 133 this.labels.put(name, new Label(name)); 134 } 135 return (Label)this.labels.get(name); 136 } 137 138 public void emit(Instruction instr) { 139 if (! (bytes.remaining() > 1<<18)) { 143 ByteBuffer newBytes = ByteBuffer.allocate(bytes.capacity() * 2); 145 ByteBuffer oldBytes = bytes; 146 bytes.flip(); 147 newBytes.put(bytes); 148 bytes = newBytes; 149 } 151 if (instr instanceof ConcreteInstruction && ((ConcreteInstruction)instr).op == Actions.CONSTANTS) { 152 this.constants = new Hashtable(); 154 for (ListIterator i = ((ConcreteInstruction)instr).args.listIterator(); i.hasNext(); ) { 155 int index = i.nextIndex(); 156 this.constants.put(i.next(), new Integer (index)); 157 } 158 } 160 if (instr instanceof LABELInstruction) { 161 Object name = ((LABELInstruction)instr).name; 162 Label label = this.getLabel(name); 163 assert (! label.isResolved()) : "duplicate label" + label; 164 label.setLocation(bytes); 166 } else if (instr instanceof TargetInstruction) { 167 TargetInstruction target = (TargetInstruction)instr; 168 Label label = this.getLabel(target.getTarget()); 169 int loc = label.location; 170 if (loc == -1) { 171 target.writeBytes(this.bytes, this.constants); 175 int patchloc = bytes.position() - 2; 176 label.addReference(patchloc); 177 } else { 178 target.targetOffset = 0; 180 target.writeBytes(this.bytes, this.constants); 181 int offset = loc - bytes.position(); 182 if (offset != (short)offset) { 183 throw new CompilerException("Jump offset too large"); 184 } 185 bytes.putShort(bytes.position() - 2, (short)offset); 186 } 187 } else { 188 instr.writeBytes(this.bytes, this.constants); 189 } 190 } 191 } 192 | Popular Tags |