gt:             if (off == 0)
context: // x86Assembler.java, created Mon Feb  5 23:23:19 2001 by joewhaley
  // Copyright (C) 2001-3 John Whaley <jwhaley@alum.mit.edu>
  // Licensed under the terms of the GNU LGPL; see COPYING for details.
  package Assembler.x86;
  
  import java.util.HashMap;
  import java.util.Iterator;
  import java.util.Map;
  
  import Allocator.DefaultCodeAllocator;
  import Allocator.CodeAllocator.x86CodeBuffer;
  import Main.jq;
  import Memory.CodeAddress;
  import Util.Assert;
  import Util.Strings;
  import Util.Collections.LightRelation;
  import Util.Collections.Relation;
  
  // Referenced classes of package Assembler.x86:
  //            x86Constants, x86CodeBuffer, x86
  
  /**
   * x86Assembler
   *
   * @author John Whaley <jwhaley@alum.mit.edu>
   * @version $Id: x86Assembler.java,v 1.16 2003/05/12 10:04:52 joewhaley Exp $
   */
  public class x86Assembler implements x86Constants {
  
      static class PatchInfo {
  
          int patchLocation, patchSize;
          
          PatchInfo(int patchLocation, int patchSize) {
              this.patchLocation = patchLocation;
              this.patchSize = patchSize;
          }
          
          void patchTo(x86CodeBuffer mc, int target) {
              if (patchSize == 4) {
                  int v = mc.get4_endian(patchLocation - 4);
                  Assert._assert(v == 0x44444444 || v == 0x55555555 || v == 0x66666666 || v == 0x77777777, "Location: "+Strings.hex(patchLocation-4)+" value: "+Strings.hex8(v));
                  mc.put4_endian(patchLocation - 4, target - patchLocation);
              } else if (patchSize == 1) {
                  byte v = mc.get1(patchLocation - 1);
                  Assert._assert(v == 0);
                  Assert._assert(target - patchLocation <= 127);
                  Assert._assert(target - patchLocation >= -128);
                  mc.put1(patchLocation - 1, (byte)(target - patchLocation));
              } else
                  Assert.TODO();
          }
          
          public String toString() {
              return "loc:"+Strings.hex(patchLocation)+" size:"+patchSize;
          }
  
      }
  
      static class AbsPatchInfo extends PatchInfo {
  
          AbsPatchInfo(int patchLocation, int patchSize) {
              super(patchLocation, patchSize);
          }
          
          void patchTo(x86CodeBuffer mc, int target) {
              if (patchSize == 4) {
                  int v = mc.get4_endian(patchLocation - 4);
                  Assert._assert(v == 0x44444444 || v == 0x55555555 || v == 0x66666666 || v == 0x77777777, "Location: "+Strings.hex(patchLocation-4)+" value: "+Strings.hex8(v));
                  mc.put4_endian(patchLocation - 4, mc.getStartAddress().offset(target).to32BitValue());
              } else
                  Assert.TODO();
          }
          
          public String toString() {
              return "loc:"+Strings.hex(patchLocation)+" size:"+patchSize+" (abs)";
          }
  
      }
      
      public x86CodeBuffer getCodeBuffer() {
          if (!branches_to_patch.isEmpty())
              System.out.println("Error: unresolved forward branches!");
          return mc;
      }
      public int getCurrentOffset() { return mc.getCurrentOffset(); }
      public CodeAddress getCurrentAddress() { return mc.getCurrentAddress(); }
      public CodeAddress getStartAddress() { return mc.getStartAddress(); }
      public void patch1(int offset, byte value) { mc.put1(offset, value); }
      public void patch4_endian(int offset, int value) { mc.put4_endian(offset, value); }
  
      public x86Assembler(int num_targets, int est_size, int offset, int alignment) {
          mc = DefaultCodeAllocator.getCodeBuffer(est_size, offset, alignment);
          if (TRACE) System.out.println("Assembler start address: "+mc.getCurrentAddress().stringRep());
          branchtargetmap = new HashMap();
          branches_to_patch = new LightRelation();
      }
  
      public boolean containsTarget(Object target) {
          return branchtargetmap.containsKey(target);
      }
      // backward branches
      public void recordBranchTarget(Object target) {
          Assert._assert(ip == mc.getCurrentOffset());
          branchtargetmap.put(target, new Integer(ip));
      }
      public int getBranchTarget(Object target) {
          Integer i = (Integer)branchtargetmap.get(target);
          if (i == null) {
              Assert.UNREACHABLE("Invalid branch target: "+target+" offset "+getCurrentOffset());
          }
          return i.intValue();
      }
      public Map getBranchTargetMap() {
          return branchtargetmap;
      }
  
      // forward branches
      public void recordForwardBranch(int patchsize, Object target) {
          if (TRACE) System.out.println("recording forward branch from "+Strings.hex(ip)+" (size "+patchsize+") to "+target);
          branches_to_patch.add(target, new PatchInfo(ip, patchsize));
      }
      public void recordAbsoluteReference(int patchsize, Object target) {
          if (TRACE) System.out.println("recording absolute reference from "+Strings.hex(ip)+" (size "+patchsize+") to "+target);
          branches_to_patch.add(target, new AbsPatchInfo(ip, patchsize));
      }
      public void resolveForwardBranches(Object target) {
          PatchInfo p;
          Iterator it = branches_to_patch.getValues(target).iterator();
          while (it.hasNext()) {
              p = (PatchInfo)it.next();
              if (TRACE) System.out.println("patching branch to "+target+" ("+p+") to point to "+Strings.hex(ip));
              p.patchTo(mc, ip);
          }
          branches_to_patch.removeKey(target);
      }
  
      // dynamic patch section
      public void startDynamicPatch(int size) {
          if (jq.SMP) {
              int end = ip+size;
              int mask = CACHE_LINE_SIZE-1;
              while ((ip & mask) != (end & mask))
                  emit1(x86.NOP);
          }
          dynPatchStart = ip;
          dynPatchSize = size;
      }
      public void endDynamicPatch() {
          Assert._assert(ip <= dynPatchStart + dynPatchSize);
          while (ip < dynPatchStart + dynPatchSize) 
              emit1(x86.NOP);
          dynPatchSize = 0;
      }
  
      // prefix
      public void emitprefix(byte prefix) {
          mc.add1(prefix);
          ++ip;
      }
  
      // special case instructions
      public void emitPUSH_i(int imm) {
          if (fits(imm, 8))
              ip += x86.PUSH_i8.emit1_Imm8(mc, imm);
          else
              ip += x86.PUSH_i32.emit1_Imm32(mc, imm);
      }
      public void emit2_SHIFT_Mem_Imm8(x86 x, int off, int base, byte imm) {
          if (base == ESP) {
              if (off == 0) {
                  if (imm == 1)
                      ip += x.emit2_Once_SIB_EA(mc, ESP, ESP, SCALE_1);
                  else
                      ip += x.emit2_SIB_EA_Imm8(mc, ESP, ESP, SCALE_1, imm);
              } else if (fits_signed(off, 8)) {
                  if (imm == 1)
                      ip += x.emit2_Once_SIB_DISP8(mc, ESP, ESP, SCALE_1, (byte)off);
                  else
                      ip += x.emit2_SIB_DISP8_Imm8(mc, ESP, ESP, SCALE_1, (byte)off, imm);
              } else {
                  if (imm == 1)
                      ip += x.emit2_Once_SIB_DISP32(mc, ESP, ESP, SCALE_1, off);
                  else
                      ip += x.emit2_SIB_DISP32_Imm8(mc, ESP, ESP, SCALE_1, off, imm);
              }
          } else if (off == 0 && base != EBP) {
              if (imm == 1)
                  ip += x.emit2_Once_EA(mc, base);
              else
                  ip += x.emit2_EA_Imm8(mc, base, imm);
          } else if (fits_signed(off, 8)) {
              if (imm == 1)
                  ip += x.emit2_Once_DISP8(mc, (byte)off, base);
              else
                  ip += x.emit2_DISP8_Imm8(mc, (byte)off, base, imm);
          } else {
              if (imm == 1)
                  ip += x.emit2_Once_DISP32(mc, off, base);
              else
                  ip += x.emit2_DISP32_Imm8(mc, off, base, imm);
          }
      }
  
      public void emit2_SHIFT_Reg_Imm8(x86 x, int r1, byte imm) {
          if (imm == 1)
              ip += x.emit2_Once_Reg(mc, r1);
          else
              ip += x.emit2_Reg_Imm8(mc, r1, imm);
      }
  
      // swap the order, because it is confusing.
      public void emitSHLD_r_r_rc(int r1, int r2) {
          ip += x86.SHLD_r_r_rc.emit3_Reg_Reg(mc, r2, r1);
      }
  
      // swap the order, because it is confusing.
      public void emitSHRD_r_r_rc(int r1, int r2) {
          ip += x86.SHRD_r_r_rc.emit3_Reg_Reg(mc, r2, r1);
      }
  
      // short
      public void emitShort_Reg(x86 x, int r1) {
          ip += x.emitShort_Reg(mc, r1);
      }
      public void emitShort_Reg_Imm(x86 x, int r1, int imm) {
          ip += x.emitShort_Reg_Imm32(mc, r1, imm);
      }
  
      // length 1
      public void emit1(x86 x) {
          ip += x.emit1(mc);
      }
      public void emit1_Imm8(x86 x, byte imm) {
          ip += x.emit1_Imm8(mc, imm);
      }
      public void emit1_Imm16(x86 x, char imm) {
          ip += x.emit1_Imm16(mc, imm);
      }
      public void emit1_Imm32(x86 x, int imm) {
          ip += x.emit1_Imm32(mc, imm);
      }
  
      // length 2
      public void emit2(x86 x) {
          ip += x.emit2(mc);
      }
      public void emit2_FPReg(x86 x, int r) {
          ip += x.emit2_FPReg(mc, r);
      }
      public void emit2_Mem(x86 x, int imm) {
          ip += x.emit2_Abs32(mc, imm);
      }
      public void emit2_Mem(x86 x, int off, int base) {
          if (base == ESP) {
  