--Java class editor


--[[
This will show an userinterface for editing java classes and will return a list of "patch" commands
that can be used with the runtime java class edit commands

e.g:
DefineLabel(spot)
InsertBytecode(spot, command)
ModifyBytecode(spot, command)
DeleteBytecode(spot)  (could be ModifyBytecode(spot,"nop") )


The user should not have to know about exceptions and how their positions change with each insert/delete

gui:
listview:
index|byteindex|label |exception|instruction|
-----|---------|------|---------|-----------|
0    |0        |      |         |nop        |   Insert
0    |1        |l1:   |ex1:     |branch l1  |   Delete
                                                Modify

--]]

--http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-6.html


java_bytecodes={}

--[[
paramtypes:
  s1=signed 1 byte
  s2=signed 2 byte
  s4=signed 4 byte
  u1=unsigned 1 byte
  u2=unsigned 2 byte
  u4=unsigned 4 byte


  02=null 2 bytes
  wide=special wide operand

  pad4=pad till 4 byte alignment

  [s4]=array of 4 byte signed values
  [s4s4]=array of 2 4 byte signed values
--]]

function signExtendByte(byte)
  --byte is a value between 0 and 255
  --if bit 7 is 1, it's a negative
  if bAnd(byte,0x80)~=0 then
    return byte-0x100
  else
    return byte
  end
end

function signExtendWord(word)
  if bAnd(word,0x8000)~=0 then
    return word-0x10000
  else
    return word
  end
end

function signExtendDword(dword)
  --assuming dword is in the range of 0 to 0xffffffff
  if bAnd(dword,0x80000000)~=0 then
    return dword-0x100000000
  else
    return dword
  end
end


function calculateTableSwitch(address, bytes)
  local result=nil

  if bytes[address]==0xaa then
    local padding=0

  if (address-1) % 4>0 then
    padding=4-(address-1) % 4
  end

    --local defaultbyte=byteTableToDword({bytes[8],bytes[7],bytes[6],bytes[5]})
  local low=byteTableToDword({bytes[address+1+padding+7],bytes[address+1+padding+6],bytes[address+1+padding+5],bytes[address+1+padding+4]})
  local high=byteTableToDword({bytes[address+1+padding+11],bytes[address+1+padding+10],bytes[address+1+padding+9],bytes[address+1+padding+8]})
  result=padding+4+4+4+((high-low)+1)*4 --paramsize
  end

  return result;
end

function calculateLookupSwitch(address, bytes)
  local result=nil

  if bytes[address]==0xab then
    local padding=0

  if (address-1) % 4>0 then
    padding=4-(address-1) % 4
  end

    --local defaultbyte=byteTableToDword({bytes[8],bytes[7],bytes[6],bytes[5]})
  local npairs=byteTableToDword({bytes[address+1+padding+7],bytes[address+1+padding+6],bytes[address+1+padding+5],bytes[address+1+padding+4]})
  result=padding+4+4+npairs*8 --paramsize
  end

  return result;

end

java_bytecodes[0x00]={operation="nop", description="Do nothing"}
java_bytecodes[0x01]={operation="aconst_null", description="Push null"}
java_bytecodes[0x02]={operation="iconst_m1", description="Push int -1"}
java_bytecodes[0x03]={operation="iconst_0", description="Push int 0"}
java_bytecodes[0x04]={operation="iconst_1", description="Push int 1"}
java_bytecodes[0x05]={operation="iconst_2", description="Push int 2"}
java_bytecodes[0x06]={operation="iconst_3", description="Push int 3"}
java_bytecodes[0x07]={operation="iconst_4", description="Push int 4"}
java_bytecodes[0x08]={operation="iconst_5", description="Push int 5"}
java_bytecodes[0x09]={operation="lconst_0", description="Push long 0"}
java_bytecodes[0x0a]={operation="lconst_1", description="Push long 1"}
java_bytecodes[0x0b]={operation="fconst_0", description="Push float 0.0"}
java_bytecodes[0x0c]={operation="fconst_1", description="Push float 1.0"}
java_bytecodes[0x0d]={operation="fconst_2", description="Push float 2.0"}
java_bytecodes[0x0e]={operation="dconst_0", description="Push double 0.0"}
java_bytecodes[0x0f]={operation="dconst_1", description="Push double 1.0"}
java_bytecodes[0x10]={operation="bipush", parameters={bytecount=1, {paramname="const", paramtype="s1"}}, description="Push byte"}
java_bytecodes[0x11]={operation="sipush", parameters={bytecount=2, {paramname="const", paramtype="s2"}}, description="Push short"}
java_bytecodes[0x12]={operation="ldc", parameters={bytecount=1, {paramname="index", paramtype="u1"}}, description="Push item from run-time constant pool"}
java_bytecodes[0x13]={operation="ldc_w", parameters={bytecount=2, {paramname="index", paramtype="u2"}}, description="Push item from run-time constant pool(wide)"}
java_bytecodes[0x14]={operation="ldc2_w", parameters={bytecount=2, {paramname="index", paramtype="u2"}}, description="Push long or double from run-time constant pool(wide)"}
java_bytecodes[0x15]={operation="iload", parameters={bytecount=1, {paramname="index", paramtype="u1"}}, wideparameters={bytecount=2, {paramname="index", paramtype="u2"}},description="Load int from local variable"}
java_bytecodes[0x16]={operation="lload", parameters={bytecount=1, {paramname="index", paramtype="u1"}}, wideparameters={bytecount=2, {paramname="index", paramtype="u2"}},description="Load long from local variable"}
java_bytecodes[0x17]={operation="fload", parameters={bytecount=1, {paramname="index", paramtype="u1"}}, wideparameters={bytecount=2, {paramname="index", paramtype="u2"}},description="Load float from local variable"}
java_bytecodes[0x18]={operation="dload", parameters={bytecount=1, {paramname="index", paramtype="u1"}}, wideparameters={bytecount=2, {paramname="index", paramtype="u2"}}, description="Load double from local variable"}
java_bytecodes[0x19]={operation="aload", parameters={bytecount=1, {paramname="index", paramtype="u1"}}, wideparameters={bytecount=2, {paramname="index", paramtype="u2"}}, description="Load reference from local variable"}
java_bytecodes[0x1a]={operation="iload_0", description="Load int from local variable at index 0"}
java_bytecodes[0x1b]={operation="iload_1", description="Load int from local variable at index 1"}
java_bytecodes[0x1c]={operation="iload_2", description="Load int from local variable at index 2"}
java_bytecodes[0x1d]={operation="iload_3", description="Load int from local variable at index 3"}
java_bytecodes[0x1e]={operation="lload_0", description="Load long from local variable at index 0"}
java_bytecodes[0x1f]={operation="lload_1", description="Load long from local variable at index 1"}
java_bytecodes[0x20]={operation="lload_2", description="Load long from local variable at index 2"}
java_bytecodes[0x21]={operation="lload_3", description="Load long from local variable at index 3"}
java_bytecodes[0x22]={operation="fload_0", description="Load float from local variable at index 0"}
java_bytecodes[0x23]={operation="fload_1", description="Load float from local variable at index 1"}
java_bytecodes[0x24]={operation="fload_2", description="Load float from local variable at index 2"}
java_bytecodes[0x25]={operation="fload_3", description="Load float from local variable at index 3"}
java_bytecodes[0x26]={operation="dload_0", description="Load double from local variable at index 0"}
java_bytecodes[0x27]={operation="dload_1", description="Load double from local variable at index 1"}
java_bytecodes[0x28]={operation="dload_2", description="Load double from local variable at index 2"}
java_bytecodes[0x29]={operation="dload_3", description="Load double from local variable at index 3"}
java_bytecodes[0x2a]={operation="aload_0", description="Load reference from local variable at index 0"}
java_bytecodes[0x2b]={operation="aload_1", description="Load reference from local variable at index 1"}
java_bytecodes[0x2c]={operation="aload_2", description="Load reference from local variable at index 2"}
java_bytecodes[0x2d]={operation="aload_3", description="Load reference from local variable at index 3"}
java_bytecodes[0x2e]={operation="iaload", description="Load int from array"}
java_bytecodes[0x2f]={operation="laload", description="Load long from array"}
java_bytecodes[0x30]={operation="faload", description="Load float from array"}
java_bytecodes[0x31]={operation="daload", description="Load double from array"}
java_bytecodes[0x32]={operation="aaload", description="Load reference from array"}
java_bytecodes[0x33]={operation="baload", description="Load byte or boolean from array"}
java_bytecodes[0x34]={operation="caload", description="Load char from array"}
java_bytecodes[0x35]={operation="saload", description="Load short from array"}
java_bytecodes[0x36]={operation="istore", parameters={bytecount=1, {paramname="index", paramtype="u1"}}, wideparameters={bytecount=2, {paramname="index", paramtype="u2"}}, description="Store float into local variable"}
java_bytecodes[0x37]={operation="lstore", parameters={bytecount=1, {paramname="index", paramtype="u1"}}, wideparameters={bytecount=2, {paramname="index", paramtype="u2"}}, description="Store float into local variable"}
java_bytecodes[0x38]={operation="fstore", parameters={bytecount=1, {paramname="index", paramtype="u1"}}, wideparameters={bytecount=2, {paramname="index", paramtype="u2"}}, description="Store float into local variable"}
java_bytecodes[0x39]={operation="dstore", parameters={bytecount=1, {paramname="index", paramtype="u1"}}, wideparameters={bytecount=2, {paramname="index", paramtype="u2"}}, description="Store double into local variable"}
java_bytecodes[0x3a]={operation="astore", parameters={bytecount=1, {paramname="index", paramtype="u1"}}, wideparameters={bytecount=2, {paramname="index", paramtype="u2"}}, description="Store reference into local variable"}
java_bytecodes[0x3b]={operation="istore_0", description="Store int into local variable at index 0"}
java_bytecodes[0x3c]={operation="istore_1", description="Store int into local variable at index 1"}
java_bytecodes[0x3d]={operation="istore_2", description="Store int into local variable at index 2"}
java_bytecodes[0x3e]={operation="istore_3", description="Store int into local variable at index 3"}
java_bytecodes[0x3f]={operation="lstore_0", description="Store long into local variable at index 0"}
java_bytecodes[0x40]={operation="lstore_1", description="Store long into local variable at index 1"}
java_bytecodes[0x41]={operation="lstore_2", description="Store long into local variable at index 2"}
java_bytecodes[0x42]={operation="lstore_3", description="Store long into local variable at index 3"}
java_bytecodes[0x43]={operation="fstore_0", description="Store float into local variable at index 0"}
java_bytecodes[0x44]={operation="fstore_1", description="Store float into local variable at index 1"}
java_bytecodes[0x45]={operation="fstore_2", description="Store float into local variable at index 2"}
java_bytecodes[0x46]={operation="fstore_3", description="Store float into local variable at index 3"}
java_bytecodes[0x47]={operation="dstore_0", description="Store double into local variable at index 0"}
java_bytecodes[0x48]={operation="dstore_1", description="Store double into local variable at index 1"}
java_bytecodes[0x49]={operation="dstore_2", description="Store double into local variable at index 2"}
java_bytecodes[0x4a]={operation="dstore_3", description="Store double into local variable at index 3"}
java_bytecodes[0x4b]={operation="astore_0", description="Store reference into local variable at index 0"}
java_bytecodes[0x4c]={operation="astore_1", description="Store reference into local variable at index 1"}
java_bytecodes[0x4d]={operation="astore_2", description="Store reference into local variable at index 2"}
java_bytecodes[0x4e]={operation="astore_3", description="Store reference into local variable at index 3"}
java_bytecodes[0x4f]={operation="iastore", description="Store into int array"}
java_bytecodes[0x50]={operation="lastore", description="Store into long array"}
java_bytecodes[0x51]={operation="fastore", description="Store into float array"}
java_bytecodes[0x52]={operation="dastore", description="Store into double array"}
java_bytecodes[0x53]={operation="aastore", description="Store into reference array"}
java_bytecodes[0x54]={operation="bastore", description="Store into byte or boolean array"}
java_bytecodes[0x55]={operation="castore", description="Store into char array"}
java_bytecodes[0x56]={operation="sastore", description="Store into short array"}
java_bytecodes[0x57]={operation="pop", description="Pop the top operand stack value"}
java_bytecodes[0x58]={operation="pop", description="Pop the top one or two operand stack values"}
java_bytecodes[0x59]={operation="dup", description="Duplicate the top operand stack value"}
java_bytecodes[0x5a]={operation="dup_x1", description="Duplicate the top operand stack value and insert two values down"}
java_bytecodes[0x5b]={operation="dup_x2", description="Duplicate the top operand stack value and insert three values down"}
java_bytecodes[0x5c]={operation="dup2", description="Duplicate the top one or two operand stack values"}
java_bytecodes[0x5d]={operation="dup2_x1", description="Duplicate the top one or two operand stack values and insert two or three values down"}
java_bytecodes[0x5e]={operation="dup2_x2", description="Duplicate the top one or two operand stack values and insert two, three, or four values down "}
java_bytecodes[0x5f]={operation="swap", description="Swap the two operand stack values"}
java_bytecodes[0x60]={operation="iadd", description="Add int"}
java_bytecodes[0x61]={operation="ladd", description="Add long"}
java_bytecodes[0x62]={operation="fadd", description="Add float"}
java_bytecodes[0x63]={operation="dadd", description="Add double"}
java_bytecodes[0x64]={operation="isub", description="Subtract int"}
java_bytecodes[0x65]={operation="lsub", description="Subtract long"}
java_bytecodes[0x66]={operation="fsub", description="Subtract float"}
java_bytecodes[0x67]={operation="dsub", description="Subtract double"}
java_bytecodes[0x68]={operation="imul", description="Multiply int"}
java_bytecodes[0x69]={operation="lmul", description="Multiply long"}
java_bytecodes[0x6a]={operation="fmul", description="Multiply float"}
java_bytecodes[0x6b]={operation="dmul", description="Multiply double"}
java_bytecodes[0x6c]={operation="idiv", description="Divide int"}
java_bytecodes[0x6d]={operation="ldiv", description="Divide long"}
java_bytecodes[0x6e]={operation="fdiv", description="Divide float"}
java_bytecodes[0x6f]={operation="ddiv", description="Divide double"}
java_bytecodes[0x70]={operation="irem", description="Remainder int"}
java_bytecodes[0x71]={operation="lrem", description="Remainder long"}
java_bytecodes[0x72]={operation="frem", description="Remainder float"}
java_bytecodes[0x73]={operation="drem", description="Remainder double"}
java_bytecodes[0x74]={operation="ineg", description="Negate int"}
java_bytecodes[0x75]={operation="lneg", description="Negate long"}
java_bytecodes[0x76]={operation="fneg", description="Negate float"}
java_bytecodes[0x77]={operation="dneg", description="Negate double"}
java_bytecodes[0x78]={operation="ishl", description="Shift left int"}
java_bytecodes[0x79]={operation="lshl", description="Shift left long"}
java_bytecodes[0x7a]={operation="ishr", description="Shift right int"}
java_bytecodes[0x7b]={operation="lshr", description="Aritmetic shift right long"}
java_bytecodes[0x7c]={operation="iushr", description="Logical shift right int"}
java_bytecodes[0x7d]={operation="lushr", description="Logical shift right long"}
java_bytecodes[0x7e]={operation="iand", description="Boolean AND int"}
java_bytecodes[0x7f]={operation="land", description="Boolean AND long"}
java_bytecodes[0x80]={operation="ior", description="Boolean OR int"}
java_bytecodes[0x81]={operation="lor", description="Boolean OR long"}
java_bytecodes[0x82]={operation="ixor", description="Boolean XOR int"}
java_bytecodes[0x83]={operation="lxor", description="Boolean XOR long"}
java_bytecodes[0x84]={operation="iinc", parameters={bytecount=2, {paramname="index", paramtype="u1"}, {paramname="const", paramtype="s1"}}, wideparameters={bytecount=4, {paramname="index", paramtype="u2"}, {paramname="const", paramtype="s2"}}, description="Increment local variable by constant"}
java_bytecodes[0x85]={operation="i2l", description="Convert int to long"}
java_bytecodes[0x86]={operation="i2f", description="Convert int to float"}
java_bytecodes[0x87]={operation="i2d", description="Convert int to double"}
java_bytecodes[0x88]={operation="l2i", description="Convert long to int"}
java_bytecodes[0x89]={operation="l2f", description="Convert long to float"}
java_bytecodes[0x8a]={operation="l2d", description="Convert long to double"}
java_bytecodes[0x8b]={operation="f2i", description="Convert float to int"}
java_bytecodes[0x8c]={operation="f2l", description="Convert float to long"}
java_bytecodes[0x8d]={operation="f2d", description="Convert float to double"}
java_bytecodes[0x8e]={operation="d2i", description="Convert double to int"}
java_bytecodes[0x8f]={operation="d2l", description="Convert double to long"}
java_bytecodes[0x90]={operation="d2f", description="Convert double to float"}
java_bytecodes[0x91]={operation="i2b", description="Convert int to byte"}
java_bytecodes[0x92]={operation="i2c", description="Convert int to char"}
java_bytecodes[0x93]={operation="i2s", description="Convert int to short"}
java_bytecodes[0x94]={operation="lcmp", description="Compare long"}
java_bytecodes[0x95]={operation="fcmpl", description="Compare float"}
java_bytecodes[0x96]={operation="fcmpg", description="Compare float"}
java_bytecodes[0x97]={operation="dcmpl", description="Compare double"}
java_bytecodes[0x98]={operation="dcmpg", description="Compare double"}
java_bytecodes[0x99]={operation="ifeq", parameters={bytecount=2, {paramname="branchoffset", paramtype="s2"}}, description="Branch if int comparison with 0 is equal"}
java_bytecodes[0x9a]={operation="ifne", parameters={bytecount=2, {paramname="branchoffset", paramtype="s2"}}, description="Branch if int comparison with 0 is not equal"}
java_bytecodes[0x9b]={operation="iflt", parameters={bytecount=2, {paramname="branchoffset", paramtype="s2"}}, description="Branch if int comparison with 0 is less"}
java_bytecodes[0x9c]={operation="ifge", parameters={bytecount=2, {paramname="branchoffset", paramtype="s2"}}, description="Branch if int comparison with 0 is greater or equal"}
java_bytecodes[0x9d]={operation="ifgt", parameters={bytecount=2, {paramname="branchoffset", paramtype="s2"}}, description="Branch if int comparison with 0 is greater"}
java_bytecodes[0x9e]={operation="ifle", parameters={bytecount=2, {paramname="branchoffset", paramtype="s2"}}, description="Branch if int comparison with 0 is less or equal"}
java_bytecodes[0x9f]={operation="if_icmpeq", parameters={bytecount=2, {paramname="branchoffset", paramtype="s2"}}, description="Branch if int comparison is equal"}
java_bytecodes[0xa0]={operation="if_icmpne", parameters={bytecount=2, {paramname="branchoffset", paramtype="s2"}}, description="Branch if int comparison is not equal"}
java_bytecodes[0xa1]={operation="if_icmplt", parameters={bytecount=2, {paramname="branchoffset", paramtype="s2"}}, description="Branch if int comparison is less"}
java_bytecodes[0xa2]={operation="if_icmpge", parameters={bytecount=2, {paramname="branchoffset", paramtype="s2"}}, description="Branch if int comparison is greater or equal"}
java_bytecodes[0xa3]={operation="if_icmpgt", parameters={bytecount=2, {paramname="branchoffset", paramtype="s2"}}, description="Branch if int comparison is greater"}
java_bytecodes[0xa4]={operation="if_icmple", parameters={bytecount=2, {paramname="branchoffset", paramtype="s2"}}, description="Branch if int comparison is less or equal"}
java_bytecodes[0xa5]={operation="if_acmpeq", parameters={bytecount=2, {paramname="branchoffset", paramtype="s2"}}, description="Branch if reference comparison is true"}
java_bytecodes[0xa6]={operation="if_acmpne", parameters={bytecount=2, {paramname="branchoffset", paramtype="s2"}}, description="Branch if reference comparison is false"}
java_bytecodes[0xa7]={operation="goto", parameters={bytecount=2, {paramname="branchoffset", paramtype="s2"}}, description="Branch always"}
java_bytecodes[0xa8]={operation="jsr", parameters={bytecount=2, {paramname="branchoffset", paramtype="s2"}}, description="Jump subroutine"}
java_bytecodes[0xa9]={operation="ret", parameters={bytecount=1, {paramname="index", paramtype="u1"}}, description="Return from subroutine"}
java_bytecodes[0xaa]={operation="tableswitch", parameters={bytecount=calculateTableSwitch, {paramname="padding", paramtype="pad4"}, {paramname="default", paramtype="s4"},{paramname="low", paramtype="s4"},{paramname="high", paramtype="s4"},{paramname="array",paramtype="[s4]"}}, description="Access jump table by key match and jump"}
java_bytecodes[0xab]={operation="lookupswitch", parameters={bytecount=calculateLookupSwitch, {paramname="padding", paramtype="pad4"}, {paramname="default", paramtype="s4"},{paramname="npairs", paramtype="s4"},{paramname="array",paramtype="[s4s4]"}}, description="Access jump table by key match and jump"}
java_bytecodes[0xac]={operation="ireturn", description="Return int from method"}
java_bytecodes[0xad]={operation="lreturn", description="Return long from method"}
java_bytecodes[0xae]={operation="freturn", description="Return float from method"}
java_bytecodes[0xaf]={operation="dreturn", description="Return double from method"}
java_bytecodes[0xb0]={operation="areturn", description="Return reference from method"}
java_bytecodes[0xb1]={operation="return", description="Return void from method"}
java_bytecodes[0xb2]={operation="getstatic", parameters={bytecount=2, {paramname="index", paramtype="u2"}}, description="Get static field from class"}
java_bytecodes[0xb3]={operation="putstatic", parameters={bytecount=2, {paramname="index", paramtype="u2"}}, description="Set static field in class"}
java_bytecodes[0xb4]={operation="getfield", parameters={bytecount=2, {paramname="index", paramtype="u2"}}, description="Fetch field from object"}
java_bytecodes[0xb5]={operation="putfield", parameters={bytecount=2, {paramname="index", paramtype="u2"}}, description="Set field in object"}
java_bytecodes[0xb6]={operation="invokevirtual", parameters={bytecount=2, {paramname="index", paramtype="u2"}}, description="Invoke instance method; dispatch based on class"}
java_bytecodes[0xb7]={operation="invokespecial", parameters={bytecount=2, {paramname="index", paramtype="u2"}}, description="Invoke instance method; special handling for superclass, private, and instance initialization method invocations"}
java_bytecodes[0xb8]={operation="invokestatic", parameters={bytecount=2, {paramname="index", paramtype="u2"}}, description="Invoke static method"}
java_bytecodes[0xb9]={operation="invokeinterface", parameters={bytecount=4, {paramname="index", paramtype="u2"}, {paramname="count", paramtype="u1"}, {paramname="null", paramtype="01"}}, description="Invoke interface method"}
java_bytecodes[0xba]={operation="invokedynamic", parameters={bytecount=4, {paramname="index", paramtype="u2"}, {paramname="null", paramtype="02"}}, description="Invoke dynamic method"}
java_bytecodes[0xbb]={operation="new", parameters={bytecount=2, {paramname="index", paramtype="u2"}}, description="Create new object"}
java_bytecodes[0xbc]={operation="newarray", parameters={bytecount=2, {paramname="atype", paramtype="u1"}}, description="Create new array"}
java_bytecodes[0xbd]={operation="anewarray", parameters={bytecount=2, {paramname="index", paramtype="u2"}}, description="Create new array of reference"}
java_bytecodes[0xbe]={operation="arraylength", description="Get length of array"}
java_bytecodes[0xbf]={operation="athrow", description="Throw exception or error"}
java_bytecodes[0xc0]={operation="checkcast", parameters={bytecount=2, {paramname="index", paramtype="u2"}}, description="Check wheter object is of given type"}
java_bytecodes[0xc1]={operation="instanceof", parameters={bytecount=2, {paramname="index", paramtype="u2"}}, description="Determine if object is of given type"}
java_bytecodes[0xc2]={operation="monitorenter", description="Enter monitor for object"}
java_bytecodes[0xc3]={operation="monitorexit", description="Exit monitor for object"}
java_bytecodes[0xc4]={operation="wide", parameters={bytecount=nil, {paramname="instruction", paramtype="wide"}}, description="Extend local variable index by additional bytes"}
java_bytecodes[0xc5]={operation="multianewarray", parameters={bytecount=3, {paramname="index", paramtype="u2"}, {paramname="dimensions", paramtype="u1"}}, description="Create new multidimensional array"}
java_bytecodes[0xc6]={operation="ifnull", parameters={bytecount=2, {paramname="branchoffset", paramtype="s2"}}, description="Branch if reference is null"}
java_bytecodes[0xc7]={operation="ifnonnull", parameters={bytecount=2, {paramname="branchoffset", paramtype="s2"}}, description="Branch if reference is not null"}
java_bytecodes[0xc8]={operation="goto_w", parameters={bytecount=4, {paramname="branchoffset", paramtype="s4"}}, description="Branch always(wide)"}
java_bytecodes[0xc9]={operation="jsr_w", parameters={bytecount=4, {paramname="branchoffset", paramtype="s4"}}, description="Jump subroutine(wide)"}

java_operations={}


function java_buildoptobytecodetable()
  --parse through java_bytecodes and fill in java_operations
  for x,y in pairs(java_bytecodes) do
    java_operations[y.operation]=java_bytecodes[x]
    java_operations[y.operation].byte=x
  end
end

function bytecodeDisassembler(bytes)
  --note: Bytes start at index 1.  Some instructions like values on an alignment of 4 byte, so keep in mind that that is (address-1) % 4
  local i,j

  result={}
  result.labels={}
  local byteindex=1
  local index=1
  while byteindex<=#bytes do
    local startindex=byteindex
    local wide=false

    if bytes[byteindex]==0xc4 then --wide
      wide=true
      byteindex=byteindex+1
    end

    local data=java_bytecodes[bytes[byteindex]]

    result[index]={}
    result[index].data=data
    result[index].operation=data.operation
    result[index].parameter=''
    result[index].byteindex=startindex-1

    local parameters=data.parameters
    if wide then
      parameters=data.wideparameters
    end

    if parameters~=nil then
      for i=1,#parameters do
        if parameters[i].paramtype=='s1' then
          result[index].parameter=result[index].parameter..signExtendByte(bytes[byteindex+1])..' '
        elseif parameters[i].paramtype=='s2' then
          result[index].parameter=result[index].parameter..signExtendWord(byteTableToWord({bytes[byteindex+2], bytes[byteindex+1]}))..' '
        elseif parameters[i].paramtype=='s4' then
            result[index].parameter=result[index].parameter..signExtendWord(byteTableToDword({bytes[byteindex+4], bytes[byteindex+3], bytes[byteindex+2], bytes[byteindex+1]}))..' '
          elseif parameters[i].paramtype=='u1' then
          result[index].parameter=result[index].parameter..bytes[byteindex+1]..' '
        elseif parameters[i].paramtype=='u2' then
          result[index].parameter=result[index].parameter..byteTableToWord({bytes[byteindex+2], bytes[byteindex+1]})..' '
        elseif parameters[i].paramtype=='u4' then
          result[index].parameter=result[index].parameter..byteTableToDword({bytes[byteindex+4], bytes[byteindex+3], bytes[byteindex+2], bytes[byteindex+1]})..' '
        end

        if (i==1) and (parameters[i].paramname=="branchoffset") then
          local destination=tonumber(result[index].byteindex+result[index].parameter)
          local label=nil

          for j=1, #result.labels do
            --check if it's already defined
            if result.labels[j].destination==destination then
              label=result.labels[j]
              break
            end

          end

          if label==nil then
            --new label, define it
            label={}
            label.destination=destination
            label.labelname='lbl'..(#result.labels+1)
            label.origins={}
            table.insert(result.labels, label)
          end


          result[index].parameter='lbl'..#result.labels


          table.insert(label.origins, startindex)




        end

      end
    end

    if parameters==nil then
      result[index].bytesize=1
    else
      if type(parameters.bytecount)=='function' then
        result[index].bytesize=1+parameters.bytecount(byteindex, bytes)
      else
        result[index].bytesize=1+parameters.bytecount
      end
    end

    --copy the bytes
    result[index].bytes={}
    for j=startindex, startindex+result[index].bytesize-1 do
      result[index].bytes[1+(j-startindex)]=bytes[j]
    end

    byteindex=byteindex+result[index].bytesize

    index=index+1
  end

  return result
end

function singleLineBytecodeAssembler(address, instruction, labels, updatelabels)
  local result=nil
  local operation
  local parameterstring
  local userparameters={}
  local wide=false
  local i,j,s
  s=0
  i=0

  for s in string.gmatch(instruction, "%S+") do
    if i==0 then
      if s~='wide' then
        operation=s
        i=i+1
      else
        wide=true
      end
    else
      userparameters[i]=s
      i=i+1
    end
  end

  parameterstring=''
  for i=1, #userparameters do
    parameterstring=parameterstring..userparameters[i]..' '
  end


  local data=java_operations[operation]

  if data~=nil then
    if type(data.bytecount)=='function' then
      error(data.operation..' is currently not implemented')
    end

    result={}
    result.bytes={}
    result.data=data
    result.operation=data.operation
    result.byteindex=address
    result.parameters=userparams
    result.parameter=parameterstring



    local parameters
    if wide then
      parameters=data.wideparameters
      if parameters==nil then
        error('wide can not be used with '..data.operation)
      end
      table.insert(result, 0xc4)
    else
      parameters=data.parameters
    end

    table.insert(result.bytes, data.byte)

    if parameters~=nil then
      if #userparameters~=#parameters then
        error('Invalid amount of parameters provided for '..data.operation)
      end


      for i=1, #parameters do
        local bytes={}

        if (i==1) and (parameters[i].paramname=="branchoffset") then --this instruction has a label reference
          --convert the parameter to the current label
          local label=nil

          if labels~=nil then
            for j=1, #labels do
              if labels[j].labelname==result.parameters[i] then
                label=labels[j]

                result.parameters[i]=labels[j].destination-address
              end
            end
          end

          if tonumber(result.parameters[i])==nil then
            error("The label "..userparameters[i].."is not yet defined")
          end

          if (updatelabels~=nil) and (updatelabels==true) then
            if label==nil then --add it
              label={}
              label.destination=result.parameters[i]
              label.labelname='lbl'..(#labels+1)
              label.origins={}
              table.insert(labels, label)
            end

            table.insert(label.origins, address)
          end




        end



        if parameters[i].paramtype=='s1' then
          bytes={tonumber(userparameters[i]) % 256}

        elseif parameters[i].paramtype=='s2' then
          bytes=wordToByteTable(tonumber(userparameters[i]) % 65536)
        elseif parameters[i].paramtype=='s4' then
          bytes=dwordToByteTable(tonumber(userparameters[i]) % 65536)
        elseif parameters[i].paramtype=='u1' then
          bytes={tonumber(userparameters[i]) % 256}
        elseif parameters[i].paramtype=='u2' then
          bytes=wordToByteTable(tonumber(userparameters[i]) % 65536)
        elseif parameters[i].paramtype=='u4' then
          bytes=dwordToByteTable(tonumber(userparameters[i]) % 65536)
        else
          error('This instruction is currently not implemented')
        end

        for j=1, #bytes do
          table.insert(result.bytes, bytes[j])
        end
      end

    end

    result.bytesize=#result.bytes
  else
    error('unknown instruction:'..operation);
  end

  return result
end



function javaclass_applyAssembleCommand(class, method, byteindex, instruction, insert)
  local codeattribute=javaclass_method_findCodeAttribute(method)

  local labels=codeattribute.code.labels
  local exceptions=codeattribute.exception_table


  --get the size of the instruction to be assembled (plus side: unlike intel with it's horrible and easily reachable 128 byte limit for small branches, java gives 32768 bytes, so less chance of an insertion causing problems)
  local newcode
  local codeattribute_codeIndex=nil


  newcode=singleLineBytecodeAssembler(byteindex, instruction, labels,false) --get the size, but don't mess with the labels

  local i,j

  local startindex=byteindex
  local offset=0

  --update the labels and exception table based on the size

  startindex=byteindex

  if insert then
    offset=newcode.bytesize
  else
    local oldcode=nil

    for i=1, #codeattribute.code do
      if codeattribute.code[i].byteindex==byteindex then
        oldcode=codeattribute.code[i]
        break
      end
    end

    if oldcode==nil then
      error('You can only replace instructions on an instruction boundary')
    end

    offset=newcode.bytesize-oldcode.bytesize
  end


  javaclass_updateOffsets(class, method, startindex, offset)

  --labels and other byteindex are updated. Now you can insert/modify the instruction

  newcode=singleLineBytecodeAssembler(byteindex, instruction, labels,true)

  local currentbyteindex=0
  for i=1, #codeattribute.code do
    if insert then
      --the byteindex has already been updated

      if currentbyteindex==byteindex then
        table.insert(codeattribute.code, i, newcode)
        break
      end
    else
      if currentbyteindex==byteindex then
        codeattribute.code[i]=newcode
        break
      end
    end

    currentbyteindex=currentbyteindex+codeattribute.code[i].bytesize
  end


end

function javaclass_updateOffsets(class, method, startindex, offset)

  print("si="..startindex.." offset="..offset)
  local i,j

  local codeattribute=javaclass_method_findCodeAttribute(method)
  local code=codeattribute.code


  local labels=codeattribute.code.labels
  local exceptions=codeattribute.exception_table

  for i=1, #labels do
    if labels[i].destination>=startindex then --the destination has been updated
      labels[i].destination=labels[i].destination+offset
    end

    for j=1, #labels[i].origins do
      local originaladdress=labels[i].origins[j]

      if originaladdress>=startindex then --this got shifted as well
        labels[i].origins[j]=originaladdress+offset
      end


      --adjust this branch instruction (note though, if originaddress was bigger than destination address, there should be no branchoffset change)
      --find the instruction in the code
      local k

      for k=1, #codeattribute.code do
        if codeattribute.code[k].byteindex==originaladdress then --check the original address (the byteindex hasn't been updated)
          local size=codeattribute.code[k].dataparameters[1].paramtype:sub(2,2) --branches only have type s2 or s4
          local newbranchoffset=labels[i].destination-labels[i].origins[j]
          local newbytes


          if size=='2' then --remember, it's big endian
            newbytes=wordToByteTable(newbranchoffset)
            codeattribute.code[k].bytes[2]=newbytes[2]
            codeattribute.code[k].bytes[3]=newbytes[1]
          elseif size=='4' then
            newbytes=dwordToByteTable(newbranchoffset)
            codeattribute.code[k].bytes[2]=newbytes[4]
            codeattribute.code[k].bytes[3]=newbytes[3]
            codeattribute.code[k].bytes[4]=newbytes[2]
            codeattribute.code[k].bytes[5]=newbytes[1]
          end
        end



      end
    end
  end

  --update tableswitch and lookupswitch commands
  for i=1,#code do
    if code[i].data.byte==0xaa then
      --tableswitch
      local defaultbyteindex=code[i].byteindex+1
      local defaultindex=2

      --find alignment padding
      local rest=defaultbyteindex%4
      if rest>0 then
        defaultindex=defaultindex+(4-rest)
        defaultbyteindex=defaultbyteindex+(4-rest)
      end

      local lowindex=defaultindex+4
      local highindex=lowindex+4
      local offsetindex=highindex+4

      local low=byteTableToDword({code[i].bytes[lowindex+3], code[i].bytes[lowindex+2], code[i].bytes[lowindex+1], code[i].bytes[lowindex]}) --big endian
      local high=byteTableToDword({code[i].bytes[highindex+3], code[i].bytes[highindex+2], code[i].bytes[highindex+1], code[i].bytes[highindex]})

      local count=high-low+1

      for j=1,count do
        local currentoffsetindex=offsetindex+(i-1)*4
        local currentoffset=byteTableToDword({code[i].bytes[currentoffsetindex+3], code[i].bytes[currentoffsetindex+2], code[i].bytes[currentoffsetindex+1], code[i].bytes[currentoffsetindex]})

        if currentoffset>=startindex then
          --update the address it points to
          currentoffset=currentoffset+offset

          local newbytes=dwordToByteTable(currentoffset)

          code.bytes[currentoffsetindex]=newbytes[4]
          code.bytes[currentoffsetindex+1]=newbytes[3]
          code.bytes[currentoffsetindex+2]=newbytes[2]
          code.bytes[currentoffsetindex+3]=newbytes[1]
        end
      end



    elseif code[i].data.byte==0xab then
      --lookupswitch
      local defaultbyteindex=code[i].byteindex+1
      local defaultindex=2

      --find alignment padding
      local rest=defaultbyteindex%4
      if rest>0 then
        defaultindex=defaultindex+(4-rest)
        defaultbyteindex=defaultbyteindex+(4-rest)
      end

      local countindex=defaultindex+4
      local count=byteTableToDword({code[i].bytes[countindex+3], code[i].bytes[countindex+2], code[i].bytes[countindex+1], code[i].bytes[countindex]})


      for j=1,count do
        local currentoffsetindex=countindex+(j-1)*8+4
        local currentoffset=byteTableToDword({code[i].bytes[currentoffsetindex+3], code[i].bytes[currentoffsetindex+2], code[i].bytes[currentoffsetindex+1], code[i].bytes[currentoffsetindex]})

        if currentoffset>=startindex then
          --update the address it points to
          currentoffset=currentoffset+offset

          local newbytes=dwordToByteTable(currentoffset)

          code.bytes[currentoffsetindex]=newbytes[4]
          code.bytes[currentoffsetindex+1]=newbytes[3]
          code.bytes[currentoffsetindex+2]=newbytes[2]
          code.bytes[currentoffsetindex+3]=newbytes[1]
        end

      end


    end
  end


  --update the exception table

  for i=1, #exceptions do
    if exceptions[i].start_pc>=startindex then
      exceptions[i].start_pc=exceptions[i].start_pc+offset
    end

    if exceptions[i].start_pc>=startindex then
      exceptions[i].end_pc=exceptions[i].end_pc+offset
    end

    if exceptions[i].start_pc>=startindex then
      exceptions[i].handler_pc=exceptions[i].handler_pc+offset
    end
  end



  --finally update the byteindexes
  for i=1, #codeattribute.code do
    if codeattribute.code[i].byteindex>=startindex then
      codeattribute.code[i].byteindex=codeattribute.code[i].byteindex+offset
    end
  end
end




function javaclasseditor_editMethod_fillInstructionsListview(lv, method)
  local i
  local codeattribute=javaclass_method_findCodeAttribute(method)
  local code=codeattribute.code
  local labels=code.labels
  local exceptions=codeattribute.exception_table
  local haslabels=false
  local hasexceptions=false

  lv.Items.clear()

  for i=1, #code do
    local j
    local item=lv.Items.add()
    local bytestring=''

    item.Caption=i-1


    for j=1, code[i].bytesize do
      bytestring=bytestring..string.format("%.2x ", code[i].bytes[j])
    end

    item.SubItems.Add(code[i].byteindex .. ':'..bytestring) --display as 0 start


    local labelname=''
    if #labels>0 then
      haslabels=true
      for j=1, #labels do
        if code[i].byteindex==labels[j].destination then
          labelname='lbl'..j
          break
        end
      end

    end


    local exceptionstr=''
    if #exceptions>0 then
      hasexceptions=true
      for j=1, #exceptions do
        if code[i].byteindex==exceptions[j].start_pc then
          exceptionstr=exceptionstr..'start'..j..' '
        end

        if code[i].byteindex==exceptions[j].end_pc then
          exceptionstr=exceptionstr..'end'..j..' '
        end

        if code[i].byteindex==exceptions[j].handler_pc then
          exceptionstr=exceptionstr..'handler'..j..' '
        end
      end
    end
    item.SubItems.Add(labelname)
    item.SubItems.Add(exceptionstr)
    item.SubItems.Add(code[i].operation..' '..code[i].parameter)
  end
end

function javaclasseditor_editMethod_insertLine(sender)
  local classMethod=getRef(sender.Tag)
  local codeattribute=javaclass_method_findCodeAttribute(classMethod.method)
  local code=codeattribute.code



  local lv=classMethod.method.editor.lvInstructions
  local linenr
  if lv.Selected==nil then
    linenr=0
  else
    linenr=lv.Selected.Index
  end

  local byteindex=code[linenr+1].byteindex


  local line=inputQuery('Insert line', 'Input the java assembly code you wish to insert at line '..linenr..'(byteindex '..byteindex..')','')
  if line~=nil then
    --showMessage('Assembling '..line)
    --assemble
    javaclass_applyAssembleCommand(classMethod.class, classMethod.method, byteindex, line, true)

    --show update
    javaclasseditor_editMethod_fillInstructionsListview(classMethod.method.editor.lvInstructions, classMethod.method)
  end
end

function javaclasseditor_editMethod_editLine(sender)
  local classMethod=getRef(sender.Tag)
  local codeattribute=javaclass_method_findCodeAttribute(classMethod.method)
  local code=codeattribute.code



  local lv=classMethod.method.editor.lvInstructions
  local linenr
  if lv.Selected==nil then
    return
  else
    linenr=lv.Selected.Index
  end

  local byteindex=code[linenr+1].byteindex
  local originalcode=code[linenr+1].operation..' '..code[linenr+1].parameter


  local line=inputQuery('Edit line', 'Input the java assembly code you wish to insert at line '..linenr..'(byteindex '..byteindex..')',originalcode)
  if line~=nil then
    javaclass_applyAssembleCommand(classMethod.class, classMethod.method, byteindex, line, false)

    --show update
    javaclasseditor_editMethod_fillInstructionsListview(classMethod.method.editor.lvInstructions, classMethod.method)
  end
end

function javaclasseditor_editMethod_defineLabel(sender)
  local classMethod=getRef(sender.Tag)
  local codeattribute=javaclass_method_findCodeAttribute(classMethod.method)
  local code=codeattribute.code
  local labels=code.labels

  local lv=classMethod.method.editor.lvInstructions
  local linenr
  if lv.Selected==nil then
    return
  else
    linenr=lv.Selected.Index
  end

  local byteindex=code[linenr+1].byteindex
  local labelname=inputQuery('Define new label', 'Give a labelname for line '..linenr..'(byteindex '..byteindex..')','')

  if (labelname~=nil) and (labelname~='') then
    local i
    --check if it already exists
    for i=1,#labels do
      if labels[i].labelname==labelname then
        error('There is already a label with this name')
      end
    end

    --still here, so the it wasn't in the list
    local newlabel={}
    newlabel.labelname=labelname
    newlabel.destination=byteindex
    newlabel.origins={}
    table.insert(labels, newlabel)
  end
end

function javaclasseditor_editMethod_applyUpdates(method)
  --converts the bytes of the interpreted code into the .info field of the code attribute (used by the writer)
  local i
  local codeattribute=javaclass_method_findCodeAttribute(method)
  local code=codeattribute.code

  codeattribute.max_stack=tonumber(method.editor.edtMaxStack.Text)
  codeattribute.max_locals=tonumber(method.editor.edtMaxLocals.Text)

ca=codeattribute



  local s={}  --write stream
  s.data=''
  s.index=0 --not really needed by writes but helps with debugging

  java_write_u2(s, codeattribute.max_stack)
  java_write_u2(s, codeattribute.max_locals)


  local bytesize=0
  for i=1,#code do
    bytesize=bytesize+#code[i].bytes
  end

  java_write_u4(s, bytesize) --code_length

  for i=1,#code do
    local j
    for j=1,#code[i].bytes do
      s.data=s.data..string.char(code[i].bytes[j])
    end
  end

  s.index=s.index+#code

  --exception table  (genius to allow code size to be specified by 4 bytes but not exception addresses)
  java_write_u2(s, codeattribute.exception_table_length);
  for i=1, codeattribute.exception_table_length do
    java_write_u2(s, codeattribute.exception_table[i].start_pc)
  java_write_u2(s, codeattribute.exception_table[i].end_pc)
  java_write_u2(s, codeattribute.exception_table[i].handler_pc)
  java_write_u2(s, codeattribute.exception_table[i].catch_type)
  end

  java_write_u2(s, codeattribute.attributes_count)
  java_writeAttributes(s, codeattribute.attributes, codeattribute.attributes_count)

  print(string.format("old bsize=%d new bsize=%d", codeattribute.code_length, bytesize))

  print(string.format("old size=%d new size=%d", #codeattribute.info, #s.data))


  codeattribute.info=s.data
  codeattribute.attribute_length=#codeattribute.info
end


function btnApplyChangesClick(sender)
  --apply the changes
  local classMethod=getRef(sender.Tag)
  local method=classMethod.method

  javaclasseditor_editMethod_applyUpdates(method)


  if method.editor.callbackfunction~=nil then
    method.editor.callbackfunction(classMethod.class, method.editor.callbackparam)
  end
end


function javaclasseditor_editMethod(class, method, callbackfunction, callbackparam)
  --create a gui for this method
  --note that throughout this file we call the parsed class "class".  It's not the jclass object

  if method.editor==nil then
    local ca=javaclass_method_findCodeAttribute(method)
    local classMethodRef=createRef({class=class, method=method})

    --build a gui
    method.editor={}
    method.editor.form=createForm()
    method.editor.form.onClose=nil --do not destroy on close
    method.editor.form.tag=classMethodRef --this way gui launched functions can find the base form and fetch this data if it needs it
    method.editor.form.borderstyle=bsSizeable

    method.editor.form.width=640
    method.editor.form.height=480

    method.editor.form.caption="Method: "..class.constant_pool[class.constant_pool[class.this_class].name_index].utf8.."."..class.constant_pool[method.name_index].utf8
    method.editor.form.Position=poScreenCenter


    method.editor.lblMaxStack=createLabel(method.editor.form)
    method.editor.lblMaxLocals=createLabel(method.editor.form)

    method.editor.lblMaxStack.caption="Max Stack"
    method.editor.lblMaxLocals.caption="Max Locals"

    method.editor.edtMaxStack=createEdit(method.editor.form)
    method.editor.edtMaxLocals=createEdit(method.editor.form)

    method.editor.edtMaxStack.Text=ca.max_stack
    method.editor.edtMaxLocals.Text=ca.max_locals


    method.editor.lblMaxStack.AnchorSideLeft.Control=method.editor.form
    method.editor.lblMaxStack.AnchorSideLeft.Side=asrLeft
    method.editor.lblMaxStack.AnchorSideTop.Control=method.editor.form
    method.editor.lblMaxStack.AnchorSideTop.Side=asrTop
    method.editor.lblMaxStack.Anchors="[akTop, akLeft]"

    method.editor.edtMaxStack.AnchorSideLeft.Control=method.editor.form
    method.editor.edtMaxStack.AnchorSideLeft.Side=asrLeft
    method.editor.edtMaxStack.AnchorSideTop.Control=method.editor.lblMaxStack
    method.editor.edtMaxStack.AnchorSideTop.Side=asrBottom
    method.editor.edtMaxStack.Anchors="[akTop, akLeft]"

    method.editor.lblMaxLocals.AnchorSideLeft.Control=method.editor.edtMaxStack
    method.editor.lblMaxLocals.AnchorSideLeft.Side=asrRight
    method.editor.lblMaxLocals.AnchorSideTop.Control=method.editor.form
    method.editor.lblMaxLocals.AnchorSideTop.Side=asrTop
    method.editor.lblMaxLocals.BorderSpacing.Left=6

    method.editor.lblMaxLocals.Anchors="[akTop, akLeft]"

    method.editor.edtMaxLocals.AnchorSideLeft.Control=method.editor.lblMaxLocals
    method.editor.edtMaxLocals.AnchorSideLeft.Side=asrLeft
    method.editor.edtMaxLocals.AnchorSideTop.Control=method.editor.edtMaxStack
    method.editor.edtMaxLocals.AnchorSideTop.Side=asrTop
    method.editor.edtMaxLocals.Anchors="[akTop, akLeft]"


    method.editor.btnApplyChanges=createButton(method.editor.form)
    method.editor.btnApplyChanges.AutoSize=true
    method.editor.btnApplyChanges.Caption="Save changes"
    method.editor.btnApplyChanges.OnClick=btnApplyChangesClick
    method.editor.btnApplyChanges.Tag=classMethodRef

    method.editor.btnApplyChanges.AnchorSideLeft.Control=method.editor.edtMaxLocals
    method.editor.btnApplyChanges.AnchorSideLeft.Side=asrRight
    method.editor.btnApplyChanges.AnchorSideTop.Control=method.editor.edtMaxLocals
    method.editor.btnApplyChanges.AnchorSideTop.Side=asrTop
    method.editor.lblMaxLocals.BorderSpacing.Left=12
    method.editor.btnApplyChanges.Anchors="[akTop, akLeft]"



    method.editor.lvInstructions=createListView(method.editor.form)
    method.editor.lvInstructions.Name="lvInstructions"

    local columns=method.editor.lvInstructions.Columns
    local lcIndex=columns.add()
    local lcByteIndex=columns.add()
    local lcLabel=columns.add()
    local lcException=columns.add()
    local lcInstruction=columns.add()


    lcIndex.Caption="Index"
    lcByteIndex.Caption="ByteIndex"
    lcLabel.Caption="Label"
    lcException.Caption="Exception"
    lcInstruction.Caption="Instruction"

    lcByteIndex.width=100

    lcInstruction.AutoSize=true


    method.editor.lvInstructions.AutoWidthLastColumn=true
    method.editor.lvInstructions.RowSelect=true
    method.editor.lvInstructions.HideSelection=false
    method.editor.lvInstructions.ReadOnly=true

    method.editor.lvInstructions.AnchorSideLeft.Control=method.editor.form
    method.editor.lvInstructions.AnchorSideLeft.Side=asrLeft
    method.editor.lvInstructions.AnchorSideTop.Control=method.editor.edtMaxStack
    method.editor.lvInstructions.AnchorSideTop.Side=asrBottom
    method.editor.lvInstructions.BorderSpacing.Top=6

    method.editor.lvInstructions.AnchorSideRight.Control=method.editor.form
    method.editor.lvInstructions.AnchorSideRight.Side=asrRight
    method.editor.lvInstructions.AnchorSideBottom.Control=method.editor.form
    method.editor.lvInstructions.AnchorSideBottom.Side=asrBottom

    method.editor.lvInstructions.Anchors="[akTop, akLeft, akRight, akBottom]"

    --create a popupmenu for adding/editing lines, and adding new labels
    method.editor.pmEdit=createPopupMenu(method.editor.form)
    method.editor.pmEdit.Tag=classMethodRef

    local miInsertLine=createMenuItem(method.editor.pmEdit)
    miInsertLine.caption="Insert line"
    miInsertLine.onClick=javaclasseditor_editMethod_insertLine
    miInsertLine.Shortcut="Ctrl+I"
    miInsertLine.Tag=classMethodRef

    local miEditLine=createMenuItem(method.editor.pmEdit)
    miEditLine.caption="Edit line"
    miEditLine.onClick=javaclasseditor_editMethod_editLine
    miEditLine.Shortcut="Ctrl+E"
    miEditLine.Tag=classMethodRef

    local miDefineLine=createMenuItem(method.editor.pmEdit)
    miDefineLine.caption="Define label"
    miDefineLine.onClick=javaclasseditor_editMethod_defineLabel
    miDefineLine.Shortcut="Ctrl+L"
    miDefineLine.Tag=classMethodRef


    method.editor.lvInstructions.OnDblClick=javaclasseditor_editMethod_editLine
    method.editor.lvInstructions.Tag=classMethodRef


    method.editor.pmEdit.Items.add(miInsertLine)
    method.editor.pmEdit.Items.add(miEditLine)
    method.editor.pmEdit.Items.add(miDefineLine)

    method.editor.lvInstructions.PopupMenu=method.editor.pmEdit

    method.editor.callbackfunction=callbackfunction
    method.editor.callbackparam=callbackparam
  end

  javaclasseditor_editMethod_fillInstructionsListview(method.editor.lvInstructions, method)

  method.editor.form.show()

end




java_buildoptobytecodetable()
