emma

Failure(failure, EXPECTED_FAILURES)) {
        throw new EMMARuntimeException("UNEXPECTED_FAILURE", new Object[] { failure.toString(), "http://sourceforge.net/projects/emma" }, failure);
      }
      throw failure;
    }
  }
  
  InstrProcessorST()
  {
    m_jobs = new Job['?'];
    m_instrResult = new InstrVisitor.InstrResult();
  }
  
  static void writeFile(byte[] data, File outFile, boolean mkdirs)
    throws IOException
  {
    RandomAccessFile raf = null;
    try
    {
      if (mkdirs)
      {
        File parent = outFile.getParentFile();
        if (parent != null) {
          parent.mkdirs();
        }
      }
      raf = new RandomAccessFile(outFile, "rw");
      raf.setLength(data.length);
      
      raf.write(data);
    }
    finally
    {
      if (raf != null) {
        raf.close();
      }
    }
  }
  
  static void writeZipEntry(byte[] data, ZipOutputStream out, ZipEntry entry, boolean isCopy)
    throws IOException
  {
    if (isCopy)
    {
      out.putNextEntry(entry);
      try
      {
        out.write(data);
      }
      finally
      {
        out.closeEntry();
      }
    }
    else
    {
      ZipEntry entryCopy = new ZipEntry(entry.getName());
      entryCopy.setTime(entry.getTime());
      entryCopy.setMethod(0);
      
      entryCopy.setSize(data.length);
      entryCopy.setCompressedSize(data.length);
      
      CRC32 crc = new CRC32();
      crc.update(data);
      entryCopy.setCrc(crc.getValue());
      
      out.putNextEntry(entryCopy);
      try
      {
        out.write(data);
      }
      finally
      {
        out.closeEntry();
      }
    }
  }
  
  private static abstract class Job
  {
    private Job() {}
    
    protected abstract void run()
      throws IOException;
    
    Job(InstrProcessorST.1 x0)
    {
      this();
    }
  }
  
  private static final class FileWriteJob
    extends InstrProcessorST.Job
  {
    final File m_outFile;
    final boolean m_mkdirs;
    byte[] m_data;
    
    protected void run()
      throws IOException
    {
      InstrProcessorST.writeFile(m_data, m_outFile, m_mkdirs);
      m_data = null;
    }
    
    FileWriteJob(File outFile, byte[] data, boolean mkdirs)
    {
      super();
      m_outFile = outFile;
      m_data = data;
      m_mkdirs = mkdirs;
    }
  }
  
  private static final class EntryWriteJob
    extends InstrProcessorST.Job
  {
    final ZipOutputStream m_out;
    byte[] m_data;
    final ZipEntry m_entry;
    final boolean m_isCopy;
    
    protected void run()
      throws IOException
    {
      InstrProcessorST.writeZipEntry(m_data, m_out, m_entry, m_isCopy);
      m_data = null;
    }
    
    EntryWriteJob(ZipOutputStream out, byte[] data, ZipEntry entry, boolean isCopy)
    {
      super();
      m_out = out;
      m_data = data;
      m_entry = entry;
      m_isCopy = isCopy;
    }
  }
  
  private void addJob(Job job)
    throws FileNotFoundException, IOException
  {
    if (m_jobPos == 128) {
      drainJobQueue();
    }
    m_jobs[(m_jobPos++)] = job;
  }
  
  private void drainJobQueue()
    throws IOException
  {
    for (int j = 0; j < m_jobPos; j++)
    {
      Job job = m_jobs[j];
      if (job != null)
      {
        m_jobs[j] = null;
        job.run();
      }
    }
    m_jobPos = 0;
  }
  
  private void readFile(File file)
    throws IOException
  {
    int length = (int)file.length();
    
    ensureReadCapacity(length);
    
    InputStream in = null;
    try
    {
      in = new FileInputStream(file);
      
      int totalread = 0;
      int read;
      while ((totalread < length) && ((read = in.read(m_readbuf, totalread, length - totalread)) >= 0)) {
        totalread += read;
      }
      m_readpos = totalread;
    }
    finally
    {
      if (in != null) {
        try
        {
          in.close();
        }
        catch (Exception ignore) {}
      }
    }
  }
  
  private void readZipEntry(ZipInputStream in, ZipEntry entry)
    throws IOException
  {
    int length = (int)entry.getSize();
    if (length >= 0)
    {
      ensureReadCapacity(length);
      
      int totalread = 0;
      int read;
      while ((totalread < length) && ((read = in.read(m_readbuf, totalread, length - totalread)) >= 0)) {
        totalread += read;
      }
      m_readpos = totalread;
    }
    else
    {
      ensureReadCapacity(32768);
      
      m_baos.reset();
      int read;
      while ((read = in.read(m_readbuf)) >= 0) {
        m_baos.write(m_readbuf, 0, read);
      }
      m_readbuf = m_baos.copyByteArray();
      m_readpos = m_readbuf.length;
    }
  }
  
  private void ensureReadCapacity(int capacity)
  {
    if (m_readbuf.length < capacity)
    {
      int readbuflen = m_readbuf.length;
      m_readbuf = null;
      m_readbuf = new byte[Math.max(readbuflen << 1, capacity)];
    }
  }
  
  private static final Class[] EXPECTED_FAILURES = { EMMARuntimeException.class, IllegalArgumentException.class, IllegalStateException.class };
}

/* Location:
 * Qualified Name:     com.vladium.emma.instr.InstrProcessorST
 * Java Class Version: 1.2 (46.0)
 * JD-Core Version:    0.7.1
 */
package com.vladium.emma.instr;

class InstrVisitor$1 {}

/* Location:
 * Qualified Name:     com.vladium.emma.instr.InstrVisitor.1
 * Java Class Version: 1.2 (46.0)
 * JD-Core Version:    0.7.1
 */
package com.vladium.emma.instr;

import com.vladium.util.ByteArrayOStream;

final class InstrVisitor$Block
{
  int m_first;
  int m_length;
  int m_instrCount;
  public InstrVisitor.CodeSegment m_insertion;
  public InstrVisitor.Branch m_branch;
  
  InstrVisitor$Block(InstrVisitor.1 x0)
  {
    this();
  }
  
  void emit(InstrVisitor.EmitCtx ctx, byte[] code)
  {
    ByteArrayOStream out = m_out;
    int first = m_first;
    
    m_first = out.size();
    
    int i = 0;
    for (int length = m_length; i < length; i++) {
      out.write(code[(first + i)]);
    }
    if (m_insertion != null) {
      m_insertion.emit(ctx);
    }
    if (m_branch != null) {
      m_branch.emit(ctx);
    }
  }
  
  private InstrVisitor$Block() {}
}

/* Location:
 * Qualified Name:     com.vladium.emma.instr.InstrVisitor.Block
 * Java Class Version: 1.2 (46.0)
 * JD-Core Version:    0.7.1
 */
package com.vladium.emma.instr;

import java.util.ArrayList;
import java.util.List;

final class InstrVisitor$BlockList
{
  final List m_blocks;
  InstrVisitor.CodeSegment m_header;
  
  InstrVisitor$BlockList()
  {
    m_blocks = new ArrayList();
  }
  
  InstrVisitor$BlockList(int capacity)
  {
    m_blocks = new ArrayList(capacity);
  }
}

/* Location:
 * Qualified Name:     com.vladium.emma.instr.InstrVisitor.BlockList
 * Java Class Version: 1.2 (46.0)
 * JD-Core Version:    0.7.1
 */
package com.vladium.emma.instr;

import com.vladium.jcd.cls.ClassDef;
import com.vladium.jcd.compiler.CodeGen;
import com.vladium.util.ByteArrayOStream;
import java.io.IOException;

final class InstrVisitor$BlockSegment
  extends InstrVisitor.CodeSegment
{
  private final ByteArrayOStream m_buf;
  private static final int BLOCK_INIT_CAPACITY = 16;
  
  public InstrVisitor$BlockSegment(InstrVisitor visitor, int localVarIndex, int blockID)
  {
    super(visitor);
    ByteArrayOStream buf = new ByteArrayOStream(16);
    m_buf = buf;
    
    ClassDef cls = m_cls;
    
    CodeGen.load_local_object_var(buf, localVarIndex);
    
    CodeGen.push_int_value(buf, cls, blockID);
    
    buf.write2(4, 84);
  }
  
  int length()
  {
    return m_buf.size();
  }
  
  int maxstack()
  {
    return 3;
  }
  
  void emit(InstrVisitor.EmitCtx ctx)
  {
    try
    {
      m_buf.writeTo(m_out);
    }
    catch (IOException ioe) {}
  }
}

/* Location:
 * Qualified Name:     com.vladium.emma.instr.InstrVisitor.BlockSegment
 * Java Class Version: 1.2 (46.0)
 * JD-Core Version:    0.7.1
 */
package com.vladium.emma.instr;

import com.vladium.util.ByteArrayOStream;
import java.util.List;

abstract class InstrVisitor$Branch
{
  final byte m_opcode;
  final int[] m_targets;
  int m_parentBlockID;
  
  protected InstrVisitor$Branch(int opcode, int[] targets)
  {
    m_opcode = ((byte)opcode);
    m_targets = targets;
  }
  
  int maxlength()
  {
    return 1;
  }
  
  abstract void emit(InstrVisitor.EmitCtx paramEmitCtx);
  
  protected final void emitJumpOffset2(InstrVisitor.EmitCtx ctx, int ip, int targetBlockID)
  {
    ByteArrayOStream out = m_out;
    if (targetBlockID <= m_parentBlockID)
    {
      int jumpOffset = m_blocks.m_blocks.get(targetBlockID)).m_first - ip;
      
      out.write2(jumpOffset >>> 8, jumpOffset);
    }
    else
    {
      int jumpOffsetLocation = out.size();
      
      out.write2(0, 0);
      
      m_backpatchQueue.add(new int[] { 2, jumpOffsetLocation, ip, targetBlockID });
    }
  }
  
  protected final void emitJumpOffset4(InstrVisitor.EmitCtx ctx, int ip, int targetBlockID)
  {
    ByteArrayOStream out = m_out;
    if (targetBlockID <= m_parentBlockID)
    {
      int jumpOffset = m_blocks.m_blocks.get(targetBlockID)).m_first - ip;
      
      out.write4(jumpOffset >>> 24, jumpOffset >>> 16, jumpOffset >>> 8, jumpOffset);
    }
    else
    {
      int jumpOffsetLocation = out.size();
      
      out.write4(0, 0, 0, 0);
      
      m_backpatchQueue.add(new int[] { 4, jumpOffsetLocation, ip, targetBlockID });
    }
  }
}

/* Location:
 * Qualified Name:     com.vladium.emma.instr.InstrVisitor.Branch
 * Java Class Version: 1.2 (46.0)
 * JD-Core Version:    0.7.1
 */
package com.vladium.emma.instr;

abstract class InstrVisitor$CodeSegment
{
  final InstrVisitor m_visitor;
  
  InstrVisitor$CodeSegment(InstrVisitor visitor)
  {
    m_visitor = visitor;
  }
  
  abstract int length();
  
  abstract int maxstack();
  
  abstract void emit(InstrVisitor.EmitCtx paramEmitCtx);
}

/* Location:
 * Qualified Name:     com.vladium.emma.instr.InstrVisitor.CodeSegment
 * Java Class Version: 1.2 (46.0)
 * JD-Core Version:    0.7.1
 */
package com.vladium.emma.instr;

import com.vladium.util.ByteArrayOStream;
import java.util.ArrayList;
import java.util.List;

final class InstrVisitor$EmitCtx
{
  final InstrVisitor.BlockList m_blocks;
  final ByteArrayOStream m_out;
  final List m_backpatchQueue;
  
  InstrVisitor$EmitCtx(InstrVisitor.BlockList blocks, ByteArrayOStream out)
  {
    m_blocks = blocks;
    m_out = out;
    
    m_backpatchQueue = new ArrayList();
  }
}

/* Location:
 * Qualified Name:     com.vladium.emma.instr.InstrVisitor.EmitCtx
 * Java Class Version: 1.2 (46.0)
 * JD-Core Version:    0.7.1
 */
package com.vladium.emma.instr;

import com.vladium.util.ByteArrayOStream;

final class InstrVisitor$IFJUMP2
  extends InstrVisitor.Branch
{
  InstrVisitor$IFJUMP2(int opcode, int target)
  {
    super(opcode, new int[] { target });
  }
  
  int maxlength()
  {
    return 8;
  }
  
  void emit(InstrVisitor.EmitCtx ctx)
  {
    ByteArrayOStream out = m_out;
    int targetBlockID = m_targets[0];
    int ip = out.size();
    
    out.write(m_opcode);
    emitJumpOffset2(ctx, ip, targetBlockID);
  }
}

/* Location:
 * Qualified Name:     com.vladium.emma.instr.InstrVisitor.IFJUMP2
 * Java Class Version: 1.2 (46.0)
 * JD-Core Version:    0.7.1
 */
package com.vladium.emma.instr;

import com.vladium.emma.data.ClassDescriptor;

public final class InstrVisitor$InstrResult
{
  public boolean m_instrumented;
  public ClassDescriptor m_descriptor;
}

/* Location:
 * Qualified Name:     com.vladium.emma.instr.InstrVisitor.InstrResult
 * Java Class Version: 1.2 (46.0)
 * JD-Core Version:    0.7.1
 */
package com.vladium.emma.instr;

import com.vladium.util.ByteArrayOStream;

final class InstrVisitor$JUMP2
  extends InstrVisitor.Branch
{
  InstrVisitor$JUMP2(int opcode, int target)
  {
    super(opcode, new int[] { target });
  }
  
  int maxlength()
  {
    return 5;
  }
  
  void emit(InstrVisitor.EmitCtx ctx)
  {
    ByteArrayOStream out = m_out;
    int targetBlockID = m_targets[0];
    int ip = out.size();
    
    out.write(m_opcode);
    emitJumpOffset2(ctx, ip, targetBlockID);
  }
}

/* Location:
 * Qualified Name:     com.vladium.emma.instr.InstrVisitor.JUMP2
 * Java Class Version: 1.2 (46.0)
 * JD-Core Version:    0.7.1
 */
package com.vladium.emma.instr;

import com.vladium.util.ByteArrayOStream;

final class InstrVisitor$JUMP4
  extends InstrVisitor.Branch
{
  InstrVisitor$JUMP4(int opcode, int target)
  {
    super(opcode, new int[] { target });
  }
  
  int maxlength()
  {
    return 5;
  }
  
  void emit(InstrVisitor.EmitCtx ctx)
  {
    ByteArrayOStream out = m_out;
    int targetBlockID = m_targets[0];
    int ip = out.size();
    
    out.write(m_opcode);
    emitJumpOffset4(ctx, ip, targetBlockID);
  }
}

/* Location:
 * Qualified Name:     com.vladium.emma.instr.InstrVisitor.JUMP4
 * Java Class Version: 1.2 (46.0)
 * JD-Core Version:    0.7.1
 */
package com.vladium.emma.instr;

import com.vladium.util.ByteArrayOStream;

final class InstrVisitor$LOOKUPSWITCH
  extends InstrVisitor.Branch
{
  final int[] m_keys;
  
  InstrVisitor$LOOKUPSWITCH(int[] keys, int[] targets)
  {
    super(171, targets);
    m_keys = keys;
  }
  
  int maxlength()
  {
    return 12 + (m_keys.length << 3);
  }
  
  void emit(InstrVisitor.EmitCtx ctx)
  {
    ByteArrayOStream out = m_out;
    int ip = out.size();
    
    out.write(m_opcode);
    
    int p = 0;
    for (int padCount = 3 - (ip & 0x3); p < padCount; p++) {
      out.write(0);
    }
    emitJumpOffset4(ctx, ip, m_targets[0]);
    
    int npairs = m_keys.length;
    out.write4(npairs >>> 24, npairs >>> 16, npairs >>> 8, npairs);
    for (int t = 1; t < m_targets.length; t++)
    {
      int key = m_keys[(t - 1)];
      out.write4(key >>> 24, key >>> 16, key >>> 8, key);
      
      emitJumpOffset4(ctx, ip, m_targets[t]);
    }
  }
}

/* Location:
 * Qualified Name:     com.vladium.emma.instr.InstrVisitor.LOOKUPSWITCH
 * Java Class Version: 1.2 (46.0)
 * JD-Core Version:    0.7.1
 */
package com.vladium.emma.instr;

import com.vladium.jcd.cls.attribute.LineNumber_info;
import java.util.Comparator;

final class InstrVisitor$LineNumberComparator
  implements Comparator
{
  InstrVisitor$LineNumberComparator(InstrVisitor.1 x0)
  {
    this();
  }
  
  public final int compare(Object o1, Object o2)
  {
    return m_start_pc - m_start_pc;
  }
  
  private InstrVisitor$LineNumberComparator() {}
}

/* Location:
 * Qualified Name:     com.vladium.emma.instr.InstrVisitor.LineNumberComparator
 * Java Class Version: 1.2 (46.0)
 * JD-Core Version:    0.7.1
 */
package com.vladium.emma.instr;

import com.vladium.util.ByteArrayOStream;

final class InstrVisitor$RET
  extends InstrVisitor.Branch
{
  final int m_varindex;
  
  InstrVisitor$RET(int opcode, int varindex)
  {
    super(opcode, null);
    m_varindex = varindex;
  }
  
  int length()
  {
    return m_varindex <= 255 ? 2 : 3;
  }
  
  void emit(InstrVisitor.EmitCtx ctx)
  {
    ByteArrayOStream out = m_out;
    if (m_varindex <= 255) {
      out.write2(m_opcode, m_varindex);
    } else {
      out.write4(196, m_opcode, m_varindex >>> 8, m_varindex);
    }
  }
}

/* Location:
 * Qualified Name:     com.vladium.emma.instr.InstrVisitor.RET
 * Java Class Version: 1.2 (46.0)
 * JD-Core Version:    0.7.1
 */
package com.vladium.emma.instr;

import com.vladium.util.ByteArrayOStream;

final class InstrVisitor$TABLESWITCH
  extends InstrVisitor.Branch
{
  final int m_low;
  final int m_high;
  
  InstrVisitor$TABLESWITCH(int low, int high, int[] targets)
  {
    super(170, targets);
    m_low = low;
    m_high = high;
  }
  
  int maxlength()
  {
    return 12 + (m_targets.length << 2);
  }
  
  void emit(InstrVisitor.EmitCtx ctx)
  {
    ByteArrayOStream out = m_out;
    int ip = out.size();
    
    out.write(m_opcode);
    
    int p = 0;
    for (int padCount = 3 - (ip & 0x3); p < padCount; p++) {
      out.write(0);
    }
    emitJumpOffset4(ctx, ip, m_targets[0]);
    
    int low = m_low;
    out.write4(low >>> 24, low >>> 16, low >>> 8, low);
    
    int high = m_high;
    out.write4(high >>> 24, high >>> 16, high >>> 8, high);
    for (int t = 1; t < m_targets.length; t++) {
      emitJumpOffset4(ctx, ip, m_targets[t]);
    }
  }
}

/* Location:
 * Qualified Name:     com.vladium.emma.instr.InstrVisitor.TABLESWITCH
 * Java Class Version: 1.2 (46.0)
 * JD-Core Version:    0.7.1
 */
package com.vladium.emma.instr;

import com.vladium.util.ByteArrayOStream;

final class InstrVisitor$TERMINATE
  extends InstrVisitor.Branch
{
  InstrVisitor$TERMINATE(int opcode)
  {
    super(opcode, null);
  }
  
  int length()
  {
    return 1;
  }
  
  void emit(InstrVisitor.EmitCtx ctx)
  {
    m_out.write(m_opcode);
  }
}

/* Location:
 * Qualified Name:     com.vladium.emma.instr.InstrVisitor.TERMINATE
 * Java Class Version: 1.2 (46.0)
 * JD-Core Version:    0.7.1
 */
package com.vladium.emma.instr;

import com.vladium.jcd.cls.ClassDef;
import com.vladium.jcd.compiler.CodeGen;
import com.vladium.util.ByteArrayOStream;
import java.io.IOException;

final class InstrVisitor$clinitHeader
  extends InstrVisitor.CodeSegment
{
  private final ByteArrayOStream m_buf;
  private static final int CLINIT_HEADER_INIT_CAPACITY = 32;
  
  InstrVisitor$clinitHeader(InstrVisitor visitor, int localVarIndex)
  {
    super(visitor);
    ByteArrayOStream buf = new ByteArrayOStream(32);
    m_buf = buf;
    
    ClassDef cls = m_cls;
    
    int[] blockCounts = m_classBlockCounts;
    int instrMethodCount = m_classInstrMethodCount;
    
    int coverageFieldrefIndex = m_coverageFieldrefIndex;
    int preclinitMethodrefIndex = m_preclinitMethodrefIndex;
    int classNameConstantIndex = m_classNameConstantIndex;
    
    buf.write3(184, preclinitMethodrefIndex >>> 8, preclinitMethodrefIndex);
    
    CodeGen.push_int_value(buf, cls, m_methodID);
    
    buf.write(50);
    
    CodeGen.store_local_object_var(buf, localVarIndex);
  }
  
  int length()
  {
    return m_buf.size();
  }
  
  int maxstack()
  {
    return 2;
  }
  
  void emit(InstrVisitor.EmitCtx ctx)
  {
    try
    {
      m_buf.writeTo(m_out);
    }
    catch (IOException ioe) {}
  }
}

/* Location:
 * Qualified Name:     com.vladium.emma.instr.InstrVisitor.clinitHeader
 * Java Class Version: 1.2 (46.0)
 * JD-Core Version:    0.7.1
 */
package com.vladium.emma.instr;

import com.vladium.jcd.cls.ClassDef;
import com.vladium.jcd.compiler.CodeGen;
import com.vladium.util.ByteArrayOStream;
import java.io.IOException;

final class InstrVisitor$methodHeader
  extends InstrVisitor.CodeSegment
{
  private final ByteArrayOStream m_buf;
  private static final int HEADER_INIT_CAPACITY = 16;
  
  InstrVisitor$methodHeader(InstrVisitor visitor, int localVarIndex)
  {
    super(visitor);
    ByteArrayOStream buf = new ByteArrayOStream(16);
    m_buf = buf;
    
    ClassDef cls = m_cls;
    int coverageFieldrefIndex = m_coverageFieldrefIndex;
    int preclinitMethodrefIndex = m_preclinitMethodrefIndex;
    
    buf.write4(178, coverageFieldrefIndex >>> 8, coverageFieldrefIndex, 89);
    
    buf.write3(199, 0, 7);
    
    buf.write4(87, 184, preclinitMethodrefIndex >>> 8, preclinitMethodrefIndex);
    
    CodeGen.push_int_value(buf, cls, m_methodID);
    
    buf.write(50);
    
    CodeGen.store_local_object_var(buf, localVarIndex);
  }
  
  int length()
  {
    return m_buf.size();
  }
  
  int maxstack()
  {
    return 2;
  }
  
  void emit(InstrVisitor.EmitCtx ctx)
  {
    try
    {
      m_buf.writeTo(m_out);
    }
    catch (IOException ioe) {}
  }
}

/* Location:
 * Qualified Name:     com.vladium.emma.instr.InstrVisitor.methodHeader
 * Java Class Version: 1.2 (46.0)
 * JD-Core Version:    0.7.1
 */
package com.vladium.emma.instr;

import com.vladium.emma.IAppConstants;
import com.vladium.emma.data.ClassDescriptor;
import com.vladium.emma.data.CoverageOptions;
import com.vladium.emma.data.MethodDescriptor;
import com.vladium.jcd.cls.AbstractClassDefVisitor;
import com.vladium.jcd.cls.ClassDef;
import com.vladium.jcd.cls.ElementFactory;
import com.vladium.jcd.cls.Field_info;
import com.vladium.jcd.cls.IAttributeCollection;
import com.vladium.jcd.cls.IClassDefVisitor;
import com.vladium.jcd.cls.IConstantCollection;
import com.vladium.jcd.cls.IFieldCollection;
import com.vladium.jcd.cls.IInterfaceCollection;
import com.vladium.jcd.cls.IMethodCollection;
import com.vladium.jcd.cls.Method_info;
import com.vladium.jcd.cls.attribute.AttributeElementFactory;
import com.vladium.jcd.cls.attribute.Attribute_info;
import com.vladium.jcd.cls.attribute.BridgeAttribute_info;
import com.vladium.jcd.cls.attribute.CodeAttribute_info;
import com.vladium.jcd.cls.attribute.ConstantValueAttribute_info;
import com.vladium.jcd.cls.attribute.Exception_info;
import com.vladium.jcd.cls.attribute.ExceptionsAttribute_info;
import com.vladium.jcd.cls.attribute.GenericAttribute_info;
import com.vladium.jcd.cls.attribute.IAttributeVisitor;
import com.vladium.jcd.cls.attribute.IExceptionHandlerTable;
import com.vladium.jcd.cls.attribute.InnerClassesAttribute_info;
import com.vladium.jcd.cls.attribute.LineNumberTableAttribute_info;
import com.vladium.jcd.cls.attribute.LineNumber_info;
import com.vladium.jcd.cls.attribute.SourceFileAttribute_info;
import com.vladium.jcd.cls.attribute.SyntheticAttribute_info;
import com.vladium.jcd.cls.constant.CONSTANT_Class_info;
import com.vladium.jcd.cls.constant.CONSTANT_Long_info;
import com.vladium.jcd.cls.constant.CONSTANT_Methodref_info;
import com.vladium.jcd.cls.constant.CONSTANT_String_info;
import com.vladium.jcd.cls.constant.CONSTANT_Utf8_info;
import com.vladium.jcd.compiler.CodeGen;
import com.vladium.jcd.lib.Types;
import com.vladium.jcd.opcodes.IOpcodes;
import com.vladium.logging.Logger;
import com.vladium.util.ByteArrayOStream;
import com.vladium.util.IConstants;
import com.vladium.util.IntIntMap;
import com.vladium.util.IntObjectMap;
import com.vladium.util.IntSet;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;

public final class InstrVisitor
  extends AbstractClassDefVisitor
  implements IClassDefVisitor, IAttributeVisitor, IOpcodes, IConstants
{
  private final boolean m_excludeSyntheticMethods;
  private final boolean m_excludeBridgeMethods;
  private final boolean m_doSUIDCompensation;
  private final Logger m_log;
  private boolean m_warningIssued;
  private boolean m_instrument;
  private boolean m_metadata;
  private boolean m_ignoreAlreadyInstrumented;
  ClassDef m_cls;
  private String m_classPackageName;
  private String m_className;
  private String m_classSrcFileName;
  private int[][][] m_classBlockMetadata;
  private MethodDescriptor[] m_classMethodDescriptors;
  private int m_syntheticStringIndex;
  int m_coverageFieldrefIndex;
  private int m_registerMethodrefIndex;
  int m_preclinitMethodrefIndex;
  int m_classNameConstantIndex;
  private int m_stampIndex;
  private int m_clinitID;
  private int m_clinitStatus;
  int m_classInstrMethodCount;
  int[] m_classBlockCounts;
  private long m_classSignature;
  int m_methodID;
  private String m_methodName;
  private int m_methodFirstLine;
  private int[] m_methodBlockOffsets;
  private int[] m_methodBlockSizes;
  private int[] m_methodJumpAdjOffsets;
  private int[] m_methodJumpAdjValues;
  private static final long NBEAST = 16661L;
  private static final String COVERAGE_FIELD_NAME = "$VRc";
  private static final String SUID_FIELD_NAME = "serialVersionUID";
  private static final String PRECLINIT_METHOD_NAME = "$VRi";
  private static final String JAVA_IO_SERIALIZABLE_NAME = "java/io/Serializable";
  private static final String JAVA_IO_EXTERNALIZABLE_NAME = "java/io/Externalizable";
  private static final int EMIT_CTX_MIN_INIT_CAPACITY = 64;
  private static final int PRECLINIT_INIT_CAPACITY = 128;
  private static final boolean MARK_ADDED_ELEMENTS_SYNTHETIC = true;
  private static final boolean SKIP_SYNTHETIC_CLASSES = false;
  
  public InstrVisitor(CoverageOptions options)
  {
    m_excludeSyntheticMethods = options.excludeSyntheticMethods();
    m_excludeBridgeMethods = options.excludeBridgeMethods();
    m_doSUIDCompensation = options.doSUIDCompensation();
    
    m_log = Logger.getLogger();
  }
  
  public void process(ClassDef cls, boolean ignoreAlreadyInstrumented, boolean instrument, boolean metadata, InstrResult out)
  {
    m_instrumented = false;
    m_descriptor = null;
    if ((!instrument) && (!metadata)) {
      return;
    }
    if (cls.isInterface()) {
      return;
    }
    reset();
    
    m_cls = cls;
    
    m_instrument = instrument;
    m_metadata = metadata;
    m_ignoreAlreadyInstrumented = ignoreAlreadyInstrumented;
    
    visit((ClassDef)null, null);
    if (m_metadata)
    {
      setClassName(cls.getName());
      
      m_descriptor = new ClassDescriptor(m_classPackageName, m_className, m_classSignature, m_classSrcFileName, m_classMethodDescriptors);
    }
    m_instrumented = m_instrument;
  }
  
  public Object visit(ClassDef ignore, Object ctx)
  {
    ClassDef cls = m_cls;
    String clsVMName = cls.getName();
    String clsName = Types.vmNameToJavaName(clsVMName);
    
    boolean trace1 = m_log.atTRACE1();
    if (trace1) {
      m_log.trace1("visit", "class: [" + clsVMName + "]");
    }
    if ((!m_warningIssued) && (clsName.startsWith(IAppConstants.APP_PACKAGE)))
    {
      m_warningIssued = true;
      
      m_log.warning("EMMA classes appear to be included on the instrumentation");
      m_log.warning("path: this is not a correct way to use EMMA");
    }
    int[] existing = cls.getFields("$VRc");
    if (existing.length > 0)
    {
      m_instrument = false;
      m_metadata = false;
      if (m_ignoreAlreadyInstrumented)
      {
        if (trace1) {
          m_log.trace1("visit", "skipping instrumented class");
        }
        return ctx;
      }
      throw new IllegalStateException("class [" + clsName + "] appears to be instrumented already");
    }
    IConstantCollection constants = cls.getConstants();
    
    SyntheticAttribute_info syntheticMarker = null;
    
    m_syntheticStringIndex = cls.addCONSTANT_Utf8("Synthetic", true);
    
    String fieldDescriptor = "[[Z";
    
    int fieldModifiers = 26;
    
    IAttributeCollection fieldAttributes = ElementFactory.newAttributeCollection(1);
    
    syntheticMarker = new SyntheticAttribute_info(m_syntheticStringIndex);
    fieldAttributes.add(syntheticMarker);
    
    int coverageFieldOffset = cls.addField("$VRc", "[[Z", 26, fieldAttributes);
    
    m_coverageFieldrefIndex = cls.addFieldref(coverageFieldOffset);
    
    String classJVMName = "com/vladium/emma/rt/RT";
    int class_index = cls.addClassref("com/vladium/emma/rt/RT");
    
    String methodDescriptor = "([[ZLjava/lang/String;J)V";
    int nametype_index = cls.addNameType("r", "([[ZLjava/lang/String;J)V");
    
    m_registerMethodrefIndex = constants.add(new CONSTANT_Methodref_info(class_index, nametype_index));
    
    String methodDescriptor = "()[[Z";
    int nametype_index = cls.addNameType("$VRi", "()[[Z");
    
    m_preclinitMethodrefIndex = constants.add(new CONSTANT_Methodref_info(cls.getThisClassIndex(), nametype_index));
    
    m_classNameConstantIndex = constants.add(new CONSTANT_String_info(getThisClassm_name_index));
    
    visit(cls.getMethods(), ctx);
    if (m_doSUIDCompensation)
    {
      boolean compensate = (m_clinitStatus & 0x8) != 0;
      
      int existingSUIDFieldCount = 0;
      if (compensate)
      {
        int[] existing = cls.getFields("serialVersionUID");
        existingSUIDFieldCount = existing.length;
        if (existingSUIDFieldCount > 0)
        {
          IFieldCollection fields = cls.getFields();
          for (int f = 0; f < existingSUIDFieldCount; f++)
          {
            Field_info field = fields.get(existing[f]);
            if ((field.getAccessFlags() & 0x18) == 24)
            {
              compensate = false;
              break;
            }
          }
        }
        if ((compensate) && (cls.getThisClassIndex() == 0))
        {
          boolean serializable = false;
          
          IInterfaceCollection interfaces = cls.getInterfaces();
          int i = 0;
          for (int iLimit = interfaces.size(); i < iLimit; i++)
          {
            CONSTANT_Class_info ifc = (CONSTANT_Class_info)constants.get(interfaces.get(i));
            String ifcName = ifc.getName(cls);
            if (("java/io/Serializable".equals(ifcName)) || ("java/io/Externalizable".equals(ifcName)))
            {
              serializable = true;
              break;
            }
          }
          if (!serializable) {
            compensate = false;
          }
        }
      }
      if (compensate)
      {
        if (existingSUIDFieldCount > 0)
        {
          m_log.warning("class [" + clsName + "] declares a 'serialVersionUID'");
          m_log.warning("field that is not static and final: this is likely an implementation mistake");
          m_log.warning("and can interfere with EMMA's SUID compensation");
        }
        String fieldDescriptor = "J";
        int fieldModifiers = 26;
        IAttributeCollection fieldAttributes = ElementFactory.newAttributeCollection(2);
        
        int nameIndex = cls.addCONSTANT_Utf8("ConstantValue", true);
        int valueIndex = constants.add(new CONSTANT_Long_info(cls.computeSUID(true)));
        
        ConstantValueAttribute_info initializer = new ConstantValueAttribute_info(nameIndex, valueIndex);
        fieldAttributes.add(initializer);
        if (syntheticMarker == null) {
          syntheticMarker = new SyntheticAttribute_info(m_syntheticStringIndex);
        }
        fieldAttributes.add(syntheticMarker);
        
        cls.addField("serialVersionUID", "J", 26, fieldAttributes);
      }
    }
    visit(cls.getAttributes(), ctx);
    
    return ctx;
  }
  
  public Object visit(IMethodCollection methods, Object ctx)
  {
    ClassDef cls = m_cls;
    
    boolean trace2 = m_log.atTRACE2();
    
    int originalMethodCount = methods.size();
    boolean constructMetadata = m_metadata;
    
    m_classBlockCounts = new int[originalMethodCount + 1];
    if (constructMetadata)
    {
      m_classBlockMetadata = new int[originalMethodCount + 1][][];
      
      m_classMethodDescriptors = new MethodDescriptor[originalMethodCount];
    }
    for (int m = 0; m < originalMethodCount; m++)
    {
      Method_info method = methods.get(m);
      m_methodName = method.getName(cls);
      if (trace2) {
        m_log.trace2("visit", (method.isSynthetic() ? "synthetic " : "") + "method #" + m + ": [" + m_methodName + "]");
      }
      boolean isClinit = "<clinit>".equals(m_methodName);
      
      boolean excluded = false;
      if (!isClinit) {
        if ((m_excludeSyntheticMethods) && (method.isSynthetic()))
        {
          excluded = true;
          if (trace2) {
            m_log.trace2("visit", "skipped synthetic method");
          }
        }
        else if ((m_excludeBridgeMethods) && (method.isBridge()))
        {
          excluded = true;
          if (trace2) {
            m_log.trace2("visit", "skipped bridge method");
          }
        }
      }
      if (excluded)
      {
        if (constructMetadata) {
          m_classMethodDescriptors[m] = new MethodDescriptor(m_methodName, method.getDescriptor(cls), 4, m_methodBlockSizes, (int[][])null, 0);
        }
      }
      else if ((method.getAccessFlags() & 0x500) != 0)
      {
        if (constructMetadata) {
          m_classMethodDescriptors[m] = new MethodDescriptor(m_methodName, method.getDescriptor(cls), 2, m_methodBlockSizes, (int[][])null, 0);
        }
        if (trace2) {
          m_log.trace2("visit", "skipped " + (method.isAbstract() ? "abstract" : "native") + " method");
        }
      }
      else
      {
        m_methodFirstLine = 0;
        
        m_methodID = m;
        if (isClinit)
        {
          m_clinitID = m;
          if (trace2) {
            m_log.trace2("visit", "<clinit> method delayed");
          }
        }
        else
        {
          IAttributeCollection attributes = method.getAttributes();
          int attributeCount = attributes.size();
          for (int a = 0; a < attributeCount; a++)
          {
            Attribute_info attribute = attributes.get(a);
            attribute.accept(this, ctx);
          }
          if (constructMetadata)
          {
            int[][] methodBlockMetadata = m_classBlockMetadata[m_methodID];
            int status = methodBlockMetadata == null ? 1 : 0;
            
            m_classMethodDescriptors[m] = new MethodDescriptor(m_methodName, method.getDescriptor(cls), status, m_methodBlockSizes, methodBlockMetadata, m_methodFirstLine);
          }
        }
      }
    }
    boolean instrumentClinit = false;
    Method_info clinit;
    if (m_clinitID >= 0)
    {
      Method_info clinit = methods.get(m_clinitID);
      
      m_classInstrMethodCount = originalMethodCount;
    }
    else
    {
      m_clinitStatus = 8;
      
      int attribute_name_index = cls.addCONSTANT_Utf8("Code", true);
      int name_index = cls.addCONSTANT_Utf8("<clinit>", true);
      int descriptor_index = cls.addCONSTANT_Utf8("()V", true);
      
      IAttributeCollection attributes = ElementFactory.newAttributeCollection(2);
      
      CodeAttribute_info code = new CodeAttribute_info(attribute_name_index, 0, 0, new byte[] { -79 }, AttributeElementFactory.newExceptionHandlerTable(0), ElementFactory.newAttributeCollection(0));
      
      attributes.add(code);
      
      attributes.add(new SyntheticAttribute_info(m_syntheticStringIndex));
      
      clinit = new Method_info(10, name_index, descriptor_index, attributes);
      
      m_clinitID = cls.addMethod(clinit);
      if (trace2) {
        m_log.trace2("visit", "added synthetic <clinit> method");
      }
      m_classInstrMethodCount = (originalMethodCount + 1);
    }
    m_methodFirstLine = 0;
    m_methodID = m_clinitID;
    if (trace2) {
      m_log.trace2("visit", (clinit.isSynthetic() ? "synthetic " : "") + "method #" + m_methodID + ": [<clinit>]");
    }
    IAttributeCollection attributes = clinit.getAttributes();
    int attributeCount = attributes.size();
    for (int a = 0; a < attributeCount; a++)
    {
      Attribute_info attribute = attributes.get(a);
      attribute.accept(this, ctx);
    }
    int attribute_name_index = cls.addCONSTANT_Utf8("Code", true);
    int name_index = cls.addCONSTANT_Utf8("$VRi", false);
    int descriptor_index = cls.addCONSTANT_Utf8("()[[Z", false);
    
    IAttributeCollection attributes = ElementFactory.newAttributeCollection(2);
    
    ByteArrayOStream buf = new ByteArrayOStream(128);
    
    int[] blockCounts = m_classBlockCounts;
    int instrMethodCount = m_classInstrMethodCount;
    
    CodeGen.push_int_value(buf, cls, instrMethodCount);
    
    int type_index = cls.addClassref("[[Z");
    buf.write4(197, type_index >>> 8, type_index, 1);
    
    buf.write4(89, 179, m_coverageFieldrefIndex >>> 8, m_coverageFieldrefIndex);
    for (int m = 0; m < instrMethodCount; m++)
    {
      int blockCount = blockCounts[m];
      if (blockCount > 0)
      {
        buf.write(89);
        
        CodeGen.push_int_value(buf, cls, m);
        
        CodeGen.push_int_value(buf, cls, blockCount);
        
        buf.write3(188, 4, 83);
      }
    }
    buf.write(89);
    
    CodeGen.push_constant_index(buf, m_classNameConstantIndex);
    
    buf.write3(20, m_stampIndex >>> 8, m_stampIndex);
    
    buf.write3(184, m_registerMethodrefIndex >>> 8, m_registerMethodrefIndex);
    
    buf.write(176);
    
    CodeAttribute_info code = new CodeAttribute_info(attribute_name_index, 5, 0, EMPTY_BYTE_ARRAY, AttributeElementFactory.newExceptionHandlerTable(0), ElementFactory.newAttributeCollection(0));
    
    code.setCode(buf.getByteArray(), buf.size());
    
    attributes.add(code);
    
    attributes.add(new SyntheticAttribute_info(m_syntheticStringIndex));
    
    Method_info preclinit = new Method_info(10, name_index, descriptor_index, attributes);
    cls.addMethod(preclinit);
    if (trace2) {
      m_log.trace2("visit", "added synthetic pre-<clinit> method");
    }
    if (constructMetadata)
    {
      int[][] methodBlockMetadata = m_classBlockMetadata[m_methodID];
      m_clinitStatus |= (methodBlockMetadata == null ? 1 : 0);
      if ((m_clinitStatus & 0x8) == 0) {
        m_classMethodDescriptors[m_methodID] = new MethodDescriptor("<clinit>", clinit.getDescriptor(cls), m_clinitStatus, m_methodBlockSizes, methodBlockMetadata, m_methodFirstLine);
      }
    }
    return ctx;
  }
  
  public Object visit(IAttributeCollection attributes, Object ctx)
  {
    int a = 0;
    for (int aCount = attributes.size(); a < aCount; a++) {
      attributes.get(a).accept(this, ctx);
    }
    return ctx;
  }
  
  public Object visit(CodeAttribute_info attribute, Object ctx)
  {
    boolean trace2 = m_log.atTRACE2();
    boolean trace3 = m_log.atTRACE3();
    
    byte[] code = attribute.getCode();
    int codeSize = attribute.getCodeSize();
    if (trace2) {
      m_log.trace2("visit", "code attribute for method #" + m_methodID + ": size = " + codeSize);
    }
    IntSet leaders = new IntSet();
    
    IntIntMap instructionMap = new IntIntMap();
    
    leaders.add(0);
    
    IExceptionHandlerTable exceptions = attribute.getExceptionTable();
    int exceptionCount = exceptions.size();
    for (int e = 0; e < exceptionCount; e++)
    {
      Exception_info exception = exceptions.get(e);
      leaders.add(m_handler_pc);
    }
    IntObjectMap branches = new IntObjectMap();
    
    boolean branch = false;
    boolean wide = false;
    
    int instructionCount = 0;
    instructionMap.put(0, 0);
    for (int ip = 0; ip < codeSize;)
    {
      int opcode = 0xFF & code[ip];
      int size = 0;
      if (branch)
      {
        leaders.add(ip);
        branch = false;
      }
      switch (opcode)
      {
      case 153: 
      case 154: 
      case 155: 
      case 156: 
      case 157: 
      case 158: 
      case 159: 
      case 160: 
      case 161: 
      case 162: 
      case 163: 
      case 164: 
      case 165: 
      case 166: 
      case 198: 
      case 199: 
        int scan = ip + 1;
        int ov = code[scan] << 8 | 0xFF & code[(++scan)];
        
        int target = ip + ov;
        leaders.add(target);
        
        branches.put(ip, new IFJUMP2(opcode, target));
        branch = true;
        
        break;
      case 167: 
      case 168: 
        int scan = ip + 1;
        int ov = code[scan] << 8 | 0xFF & code[(++scan)];
        
        int target = ip + ov;
        leaders.add(target);
        
        branches.put(ip, new JUMP2(opcode, target));
        branch = true;
        
        break;
      case 171: 
        int scan = ip + 4 - (ip & 0x3);
        
        int ov = code[scan] << 24 | (0xFF & code[(++scan)]) << 16 | (0xFF & code[(++scan)]) << 8 | 0xFF & code[(++scan)];
        leaders.add(ip + ov);
        
        int npairs = (0xFF & code[(++scan)]) << 24 | (0xFF & code[(++scan)]) << 16 | (0xFF & code[(++scan)]) << 8 | 0xFF & code[(++scan)];
        
        int[] keys = new int[npairs];
        int[] targets = new int[npairs + 1];
        targets[0] = (ip + ov);
        for (int p = 0; p < npairs; p++)
        {
          int iv = code[(++scan)] << 24 | (0xFF & code[(++scan)]) << 16 | (0xFF & code[(++scan)]) << 8 | 0xFF & code[(++scan)];
          keys[p] = iv;
          
          ov = code[(++scan)] << 24 | (0xFF & code[(++scan)]) << 16 | (0xFF & code[(++scan)]) << 8 | 0xFF & code[(++scan)];
          targets[(p + 1)] = (ip + ov);
          leaders.add(ip + ov);
        }
        branches.put(ip, new LOOKUPSWITCH(keys, targets));
        branch = true;
        
        size = ip - scan - 1;
        
        break;
      case 170: 
        int scan = ip + 4 - (ip & 0x3);
        
        int ov = code[scan] << 24 | (0xFF & code[(++scan)]) << 16 | (0xFF & code[(++scan)]) << 8 | 0xFF & code[(++scan)];
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22

Further reading...

For more information on Java 1.5 Tiger, you may find Java 1.5 Tiger, A developer's Notebook by D. Flanagan and B. McLaughlin from O'Reilly of interest.

New!JAR listings


Copyright 2006-2017. Infinite Loop Ltd