From 24c3cb5a663fedd0e2b50462e7332a0877ec32f5 Mon Sep 17 00:00:00 2001 From: Jerome Haltom Date: Sat, 17 Aug 2024 12:57:42 -0500 Subject: [PATCH 1/5] Use CodeDecoder to parse instructions. --- IKVM.deps.targets | 2 +- src/IKVM.Runtime/ClassFile.Method.Code.cs | 340 ++++---- .../ClassFile.Method.Instruction.cs | 723 ++++++++++++++---- src/IKVM.Util/IKVM.Util.csproj | 2 +- 4 files changed, 755 insertions(+), 312 deletions(-) diff --git a/IKVM.deps.targets b/IKVM.deps.targets index c343585479..d79c4a938b 100644 --- a/IKVM.deps.targets +++ b/IKVM.deps.targets @@ -1,7 +1,7 @@ - + diff --git a/src/IKVM.Runtime/ClassFile.Method.Code.cs b/src/IKVM.Runtime/ClassFile.Method.Code.cs index 1ef6606c44..546dcfdad2 100644 --- a/src/IKVM.Runtime/ClassFile.Method.Code.cs +++ b/src/IKVM.Runtime/ClassFile.Method.Code.cs @@ -50,193 +50,223 @@ struct Code internal LineNumberTableEntry[] lineNumberTable; internal LocalVariableTableEntry[] localVariableTable; + /// + /// Populates the structure from the given . + /// + /// + /// + /// + /// + /// + /// internal void Read(ClassFile classFile, string[] utf8_cp, Method method, CodeAttribute attribute, ClassFileParseOptions options) { max_stack = attribute.MaxStack; max_locals = attribute.MaxLocals; - var code_length = (uint)attribute.Code.Length; - if (code_length == 0 || code_length > 65535) - throw new ClassFormatError("Invalid method Code length {1} in class file {0}", classFile.Name, code_length); + if (attribute.Code.Length == 0 || attribute.Code.Length > 65535) + throw new ClassFormatError("Invalid method Code length {1} in class file {0}", classFile.Name, attribute.Code.Length); - var instructions = new Instruction[code_length + 1]; - int basePosition = 0; - int instructionIndex = 0; + // we don't know how many instructions we will read until we read them, so first parse them into a temporary array + var _instructions = ArrayPool.Shared.Rent((int)attribute.Code.Length + 1); try { - var buf = new byte[attribute.Code.Length]; - attribute.Code.CopyTo(buf); - var rdr = new BigEndianBinaryReader(buf); - while (rdr.IsAtEnd == false) - { - instructions[instructionIndex].Read((ushort)(rdr.Position - basePosition), rdr, classFile); - hasJsr |= instructions[instructionIndex].NormalizedOpCode == NormalizedByteCode.__jsr; - instructionIndex++; - } - - // we add an additional nop instruction to make it easier for consumers of the code array - instructions[instructionIndex++].SetTermNop((ushort)(rdr.Position - basePosition)); - } - catch (ClassFormatError x) - { - // any class format errors in the code block are actually verify errors - verifyError = x.Message; - } + int instructionCount = 0; - this.instructions = new Instruction[instructionIndex]; - Array.Copy(instructions, 0, this.instructions, 0, instructionIndex); + try + { + var decoder = new CodeDecoder(attribute.Code); - // build the pcIndexMap - var pcIndexMap = new int[this.instructions[instructionIndex - 1].PC + 1]; - for (int i = 0; i < pcIndexMap.Length; i++) - pcIndexMap[i] = -1; - for (int i = 0; i < instructionIndex - 1; i++) - pcIndexMap[this.instructions[i].PC] = i; + // read instructions and parse them into local structure + foreach (var instruction in decoder) + { + _instructions[instructionCount].Read(instruction, classFile); + hasJsr |= _instructions[instructionCount].NormalizedOpCode == NormalizedByteCode.__jsr; + instructionCount++; + } - // convert branch offsets to indexes - for (int i = 0; i < instructionIndex - 1; i++) - { - switch (this.instructions[i].NormalizedOpCode) + // we add an additional nop instruction to make it easier for consumers of the code array + _instructions[instructionCount++].SetTermNop((ushort)decoder.Position.GetInteger()); + } + catch (ClassFormatError e) { - case NormalizedByteCode.__ifeq: - case NormalizedByteCode.__ifne: - case NormalizedByteCode.__iflt: - case NormalizedByteCode.__ifge: - case NormalizedByteCode.__ifgt: - case NormalizedByteCode.__ifle: - case NormalizedByteCode.__if_icmpeq: - case NormalizedByteCode.__if_icmpne: - case NormalizedByteCode.__if_icmplt: - case NormalizedByteCode.__if_icmpge: - case NormalizedByteCode.__if_icmpgt: - case NormalizedByteCode.__if_icmple: - case NormalizedByteCode.__if_acmpeq: - case NormalizedByteCode.__if_acmpne: - case NormalizedByteCode.__ifnull: - case NormalizedByteCode.__ifnonnull: - case NormalizedByteCode.__goto: - case NormalizedByteCode.__jsr: - this.instructions[i].SetTargetIndex(pcIndexMap[this.instructions[i].Arg1 + this.instructions[i].PC]); - break; - case NormalizedByteCode.__tableswitch: - case NormalizedByteCode.__lookupswitch: - this.instructions[i].MapSwitchTargets(pcIndexMap); - break; + // any class format errors in the code block are actually verify errors + verifyError = e.Message; } - } - - // read exception table - exception_table = new ExceptionTableEntry[attribute.ExceptionTable.Count]; - for (int i = 0; i < attribute.ExceptionTable.Count; i++) - { - var handler = attribute.ExceptionTable[i]; - var start_pc = handler.StartOffset; - var end_pc = handler.EndOffset; - var handler_pc = handler.HandlerOffset; - var catch_type = handler.CatchType; - - if (start_pc >= end_pc || end_pc > code_length || handler_pc >= code_length || (catch_type.IsNotNil && !classFile.SafeIsConstantPoolClass(catch_type))) - throw new ClassFormatError("Illegal exception table: {0}.{1}{2}", classFile.Name, method.Name, method.Signature); - - classFile.MarkLinkRequiredConstantPoolItem(catch_type); - - // if start_pc, end_pc or handler_pc is invalid (i.e. doesn't point to the start of an instruction), - // the index will be -1 and this will be handled by the verifier - var startIndex = pcIndexMap[start_pc]; - var endIndex = 0; - if (end_pc == code_length) + catch (ByteCodeException e) { - // it is legal for end_pc to point to just after the last instruction, - // but since there isn't an entry in our pcIndexMap for that, we have - // a special case for this - endIndex = instructionIndex - 1; + // any errors in the code block are actually verify errors + verifyError = e.Message; } - else + + // copy from temporary array into properly sized array + instructions = new Instruction[instructionCount]; + Array.Copy(_instructions, 0, instructions, 0, instructionCount); + + // build the pcIndexMap + var pcIndexMap = new int[instructions[instructionCount - 1].PC + 1]; + for (int i = 0; i < pcIndexMap.Length; i++) + pcIndexMap[i] = -1; + for (int i = 0; i < instructionCount - 1; i++) + pcIndexMap[instructions[i].PC] = i; + + // convert branch offsets to indexes + for (int i = 0; i < instructionCount - 1; i++) { - endIndex = pcIndexMap[end_pc]; + switch (instructions[i].NormalizedOpCode) + { + case NormalizedByteCode.__ifeq: + case NormalizedByteCode.__ifne: + case NormalizedByteCode.__iflt: + case NormalizedByteCode.__ifge: + case NormalizedByteCode.__ifgt: + case NormalizedByteCode.__ifle: + case NormalizedByteCode.__if_icmpeq: + case NormalizedByteCode.__if_icmpne: + case NormalizedByteCode.__if_icmplt: + case NormalizedByteCode.__if_icmpge: + case NormalizedByteCode.__if_icmpgt: + case NormalizedByteCode.__if_icmple: + case NormalizedByteCode.__if_acmpeq: + case NormalizedByteCode.__if_acmpne: + case NormalizedByteCode.__ifnull: + case NormalizedByteCode.__ifnonnull: + case NormalizedByteCode.__goto: + case NormalizedByteCode.__jsr: + this.instructions[i].SetTargetIndex(pcIndexMap[this.instructions[i].Arg1 + this.instructions[i].PC]); + break; + case NormalizedByteCode.__tableswitch: + case NormalizedByteCode.__lookupswitch: + this.instructions[i].MapSwitchTargets(pcIndexMap); + break; + } } - var handlerIndex = pcIndexMap[handler_pc]; - exception_table[i] = new ExceptionTableEntry(startIndex, endIndex, handlerIndex, catch_type, i); - } + // read exception table + exception_table = new ExceptionTableEntry[attribute.ExceptionTable.Count]; + for (int i = 0; i < attribute.ExceptionTable.Count; i++) + { + var handler = attribute.ExceptionTable[i]; + var start_pc = handler.StartOffset; + var end_pc = handler.EndOffset; + var handler_pc = handler.HandlerOffset; + var catch_type = handler.CatchType; - foreach (var _attribute in attribute.Attributes) - { - switch (classFile.GetConstantPoolUtf8String(utf8_cp, _attribute.Name)) + if (start_pc >= end_pc || end_pc > attribute.Code.Length || handler_pc >= attribute.Code.Length || (catch_type.IsNotNil && !classFile.SafeIsConstantPoolClass(catch_type))) + throw new ClassFormatError("Illegal exception table: {0}.{1}{2}", classFile.Name, method.Name, method.Signature); + + classFile.MarkLinkRequiredConstantPoolItem(catch_type); + + // if start_pc, end_pc or handler_pc is invalid (i.e. doesn't point to the start of an instruction), + // the index will be -1 and this will be handled by the verifier + var startIndex = pcIndexMap[start_pc]; + var endIndex = 0; + if (end_pc == attribute.Code.Length) + { + // it is legal for end_pc to point to just after the last instruction, + // but since there isn't an entry in our pcIndexMap for that, we have + // a special case for this + endIndex = instructionCount - 1; + } + else + { + endIndex = pcIndexMap[end_pc]; + } + + var handlerIndex = pcIndexMap[handler_pc]; + exception_table[i] = new ExceptionTableEntry(startIndex, endIndex, handlerIndex, catch_type, i); + } + + foreach (var _attribute in attribute.Attributes) { - case AttributeName.LineNumberTable: - var lnt = (IKVM.ByteCode.Decoding.LineNumberTableAttribute)_attribute; - if ((options & ClassFileParseOptions.LineNumberTable) != 0) - { - lineNumberTable = new LineNumberTableEntry[lnt.LineNumbers.Count]; - for (int j = 0; j < lnt.LineNumbers.Count; j++) + switch (classFile.GetConstantPoolUtf8String(utf8_cp, _attribute.Name)) + { + case AttributeName.LineNumberTable: + var lnt = (IKVM.ByteCode.Decoding.LineNumberTableAttribute)_attribute; + if ((options & ClassFileParseOptions.LineNumberTable) != 0) { - var item = lnt.LineNumbers[j]; - lineNumberTable[j].start_pc = item.StartPc; - lineNumberTable[j].line_number = item.LineNumber; - if (lineNumberTable[j].start_pc >= code_length) - throw new ClassFormatError("{0} (LineNumberTable has invalid pc)", classFile.Name); + lineNumberTable = new LineNumberTableEntry[lnt.LineNumbers.Count]; + for (int j = 0; j < lnt.LineNumbers.Count; j++) + { + var item = lnt.LineNumbers[j]; + lineNumberTable[j].start_pc = item.StartPc; + lineNumberTable[j].line_number = item.LineNumber; + if (lineNumberTable[j].start_pc >= attribute.Code.Length) + throw new ClassFormatError("{0} (LineNumberTable has invalid pc)", classFile.Name); + } } - } - break; - case AttributeName.LocalVariableTable: - var lvt = (IKVM.ByteCode.Decoding.LocalVariableTableAttribute)_attribute; - if ((options & ClassFileParseOptions.LocalVariableTable) != 0) - { - localVariableTable = new LocalVariableTableEntry[lvt.LocalVariables.Count]; - for (int j = 0; j < lvt.LocalVariables.Count; j++) + break; + case AttributeName.LocalVariableTable: + var lvt = (IKVM.ByteCode.Decoding.LocalVariableTableAttribute)_attribute; + if ((options & ClassFileParseOptions.LocalVariableTable) != 0) { - var item = lvt.LocalVariables[j]; - localVariableTable[j].start_pc = item.StartPc; - localVariableTable[j].length = item.Length; - localVariableTable[j].name = classFile.GetConstantPoolUtf8String(utf8_cp, item.Name); - localVariableTable[j].descriptor = classFile.GetConstantPoolUtf8String(utf8_cp, item.Descriptor).Replace('/', '.'); - localVariableTable[j].index = item.Slot; + localVariableTable = new LocalVariableTableEntry[lvt.LocalVariables.Count]; + for (int j = 0; j < lvt.LocalVariables.Count; j++) + { + var item = lvt.LocalVariables[j]; + localVariableTable[j].start_pc = item.StartPc; + localVariableTable[j].length = item.Length; + localVariableTable[j].name = classFile.GetConstantPoolUtf8String(utf8_cp, item.Name); + localVariableTable[j].descriptor = classFile.GetConstantPoolUtf8String(utf8_cp, item.Descriptor).Replace('/', '.'); + localVariableTable[j].index = item.Slot; + } } - } - break; - default: - break; + break; + default: + break; + } } - } - // build the argmap - var sig = method.Signature; - var args = new List(); - int pos = 0; - if (!method.IsStatic) - args.Add(pos++); + // build the argmap + var sig = method.Signature; + var args = new List(); + int pos = 0; + if (!method.IsStatic) + args.Add(pos++); - for (int i = 1; sig[i] != ')'; i++) - { - args.Add(pos++); - switch (sig[i]) + for (int i = 1; sig[i] != ')'; i++) { - case 'L': - i = sig.IndexOf(';', i); - break; - case 'D': - case 'J': - args.Add(-1); - break; - case '[': - { - while (sig[i] == '[') - { - i++; - } - if (sig[i] == 'L') + args.Add(pos++); + switch (sig[i]) + { + case 'L': + i = sig.IndexOf(';', i); + break; + case 'D': + case 'J': + args.Add(-1); + break; + case '[': { - i = sig.IndexOf(';', i); + while (sig[i] == '[') + { + i++; + } + if (sig[i] == 'L') + { + i = sig.IndexOf(';', i); + } + break; } - break; - } + } } - } - argmap = args.ToArray(); + argmap = args.ToArray(); - if (args.Count > max_locals) - throw new ClassFormatError("{0} (Arguments can't fit into locals)", classFile.Name); + if (args.Count > max_locals) + throw new ClassFormatError("{0} (Arguments can't fit into locals)", classFile.Name); + } + catch (InvalidCodeException e) + { + throw new ClassFormatError(e.Message); + } + catch (ByteCodeException e) + { + throw new ClassFormatError(e.Message); + } + finally + { + ArrayPool.Shared.Return(_instructions); + } } internal bool IsEmpty => instructions == null; diff --git a/src/IKVM.Runtime/ClassFile.Method.Instruction.cs b/src/IKVM.Runtime/ClassFile.Method.Instruction.cs index 50ab0955d0..d3eb53f8b7 100644 --- a/src/IKVM.Runtime/ClassFile.Method.Instruction.cs +++ b/src/IKVM.Runtime/ClassFile.Method.Instruction.cs @@ -115,198 +115,609 @@ internal void MapSwitchTargets(int[] pcIndexMap) } } - internal void Read(ushort pc, BigEndianBinaryReader br, ClassFile classFile) + internal void Read(IKVM.ByteCode.Decoding.Instruction instruction, ClassFile classFile) { - this.pc = pc; - var bc = (ByteCode)br.ReadByte(); - switch (ByteCodeMetaData.GetMode(bc)) + this.pc = (ushort)instruction.Offset; + + switch (instruction.OpCode) { - case ByteCodeMode.Simple: + case IKVM.ByteCode.OpCode.Nop: + break; + case IKVM.ByteCode.OpCode.AconstNull: + break; + case IKVM.ByteCode.OpCode.IconstM1: + break; + case IKVM.ByteCode.OpCode.Iconst0: + break; + case IKVM.ByteCode.OpCode.Iconst1: + break; + case IKVM.ByteCode.OpCode.Iconst2: + break; + case IKVM.ByteCode.OpCode.Iconst3: + break; + case IKVM.ByteCode.OpCode.Iconst4: + break; + case IKVM.ByteCode.OpCode.Iconst5: + break; + case IKVM.ByteCode.OpCode.Lconst0: + break; + case IKVM.ByteCode.OpCode.Lconst1: + break; + case IKVM.ByteCode.OpCode.Fconst0: + break; + case IKVM.ByteCode.OpCode.Fconst1: + break; + case IKVM.ByteCode.OpCode.Fconst2: + break; + case IKVM.ByteCode.OpCode.Dconst0: + break; + case IKVM.ByteCode.OpCode.Dconst1: + break; + case IKVM.ByteCode.OpCode.Bipush: + var _bipush = instruction.AsBipush(); + arg1 = _bipush.Value; + break; + case IKVM.ByteCode.OpCode.Sipush: + var _sipush = instruction.AsSipush(); + arg1 = _sipush.Value; + break; + case IKVM.ByteCode.OpCode.Ldc: + var _ldc = instruction.AsLdc(); + arg1 = _ldc.Constant.Slot; + classFile.MarkLinkRequiredConstantPoolItem(arg1); + break; + case IKVM.ByteCode.OpCode.LdcW: + var _ldcw = instruction.AsLdcW(); + arg1 = _ldcw.Constant.Slot; + classFile.MarkLinkRequiredConstantPoolItem(arg1); + break; + case IKVM.ByteCode.OpCode.Ldc2W: + var _ldc2w = instruction.AsLdc2W(); + arg1 = _ldc2w.Constant.Slot; + classFile.MarkLinkRequiredConstantPoolItem(arg1); + break; + case IKVM.ByteCode.OpCode.Iload: + var _iload = instruction.AsIload(); + arg1 = _iload.Local; + break; + case IKVM.ByteCode.OpCode.Lload: + var _lload = instruction.AsLload(); + arg1 = _lload.Local; + break; + case IKVM.ByteCode.OpCode.Fload: + var _fload = instruction.AsFload(); + arg1 = _fload.Local; + break; + case IKVM.ByteCode.OpCode.Dload: + var _dload = instruction.AsDload(); + arg1 = _dload.Local; + break; + case IKVM.ByteCode.OpCode.Aload: + var _aload = instruction.AsAload(); + arg1 = _aload.Local; + break; + case IKVM.ByteCode.OpCode.Iload0: + break; + case IKVM.ByteCode.OpCode.Iload1: + break; + case IKVM.ByteCode.OpCode.Iload2: + break; + case IKVM.ByteCode.OpCode.Iload3: + break; + case IKVM.ByteCode.OpCode.Lload0: + break; + case IKVM.ByteCode.OpCode.Lload1: + break; + case IKVM.ByteCode.OpCode.Lload2: + break; + case IKVM.ByteCode.OpCode.Lload3: + break; + case IKVM.ByteCode.OpCode.Fload0: + break; + case IKVM.ByteCode.OpCode.Fload1: + break; + case IKVM.ByteCode.OpCode.Fload2: + break; + case IKVM.ByteCode.OpCode.Fload3: + break; + case IKVM.ByteCode.OpCode.Dload0: + break; + case IKVM.ByteCode.OpCode.Dload1: + break; + case IKVM.ByteCode.OpCode.Dload2: + break; + case IKVM.ByteCode.OpCode.Dload3: + break; + case IKVM.ByteCode.OpCode.Aload0: + break; + case IKVM.ByteCode.OpCode.Aload1: + break; + case IKVM.ByteCode.OpCode.Aload2: + break; + case IKVM.ByteCode.OpCode.Aload3: + break; + case IKVM.ByteCode.OpCode.Iaload: + break; + case IKVM.ByteCode.OpCode.Laload: + break; + case IKVM.ByteCode.OpCode.Faload: + break; + case IKVM.ByteCode.OpCode.Daload: + break; + case IKVM.ByteCode.OpCode.Aaload: + break; + case IKVM.ByteCode.OpCode.Baload: + break; + case IKVM.ByteCode.OpCode.Caload: + break; + case IKVM.ByteCode.OpCode.Saload: + break; + case IKVM.ByteCode.OpCode.Istore: + var _istore = instruction.AsIstore(); + arg1 = _istore.Local; + break; + case IKVM.ByteCode.OpCode.Lstore: + var _lstore = instruction.AsLstore(); + arg1 = _lstore.Local; + break; + case IKVM.ByteCode.OpCode.Fstore: + var _fstore = instruction.AsFstore(); + arg1 = _fstore.Local; + break; + case IKVM.ByteCode.OpCode.Dstore: + var _dstore = instruction.AsDstore(); + arg1 = _dstore.Local; + break; + case IKVM.ByteCode.OpCode.Astore: + var _astore = instruction.AsAstore(); + arg1 = _astore.Local; + break; + case IKVM.ByteCode.OpCode.Istore0: + break; + case IKVM.ByteCode.OpCode.Istore1: + break; + case IKVM.ByteCode.OpCode.Istore2: + break; + case IKVM.ByteCode.OpCode.Istore3: + break; + case IKVM.ByteCode.OpCode.Lstore0: + break; + case IKVM.ByteCode.OpCode.Lstore1: + break; + case IKVM.ByteCode.OpCode.Lstore2: + break; + case IKVM.ByteCode.OpCode.Lstore3: + break; + case IKVM.ByteCode.OpCode.Fstore0: + break; + case IKVM.ByteCode.OpCode.Fstore1: + break; + case IKVM.ByteCode.OpCode.Fstore2: + break; + case IKVM.ByteCode.OpCode.Fstore3: + break; + case IKVM.ByteCode.OpCode.Dstore0: + break; + case IKVM.ByteCode.OpCode.Dstore1: + break; + case IKVM.ByteCode.OpCode.Dstore2: + break; + case IKVM.ByteCode.OpCode.Dstore3: + break; + case IKVM.ByteCode.OpCode.Astore0: + break; + case IKVM.ByteCode.OpCode.Astore1: + break; + case IKVM.ByteCode.OpCode.Astore2: + break; + case IKVM.ByteCode.OpCode.Astore3: + break; + case IKVM.ByteCode.OpCode.Iastore: + break; + case IKVM.ByteCode.OpCode.Lastore: + break; + case IKVM.ByteCode.OpCode.Fastore: + break; + case IKVM.ByteCode.OpCode.Dastore: + break; + case IKVM.ByteCode.OpCode.Aastore: + break; + case IKVM.ByteCode.OpCode.Bastore: + break; + case IKVM.ByteCode.OpCode.Castore: + break; + case IKVM.ByteCode.OpCode.Sastore: + break; + case IKVM.ByteCode.OpCode.Pop: + break; + case IKVM.ByteCode.OpCode.Pop2: + break; + case IKVM.ByteCode.OpCode.Dup: + break; + case IKVM.ByteCode.OpCode.DupX1: + break; + case IKVM.ByteCode.OpCode.DupX2: + break; + case IKVM.ByteCode.OpCode.Dup2: + break; + case IKVM.ByteCode.OpCode.Dup2X1: + break; + case IKVM.ByteCode.OpCode.Dup2X2: + break; + case IKVM.ByteCode.OpCode.Swap: + break; + case IKVM.ByteCode.OpCode.Iadd: + break; + case IKVM.ByteCode.OpCode.Ladd: + break; + case IKVM.ByteCode.OpCode.Fadd: + break; + case IKVM.ByteCode.OpCode.Dadd: + break; + case IKVM.ByteCode.OpCode.Isub: + break; + case IKVM.ByteCode.OpCode.Lsub: + break; + case IKVM.ByteCode.OpCode.Fsub: + break; + case IKVM.ByteCode.OpCode.Dsub: + break; + case IKVM.ByteCode.OpCode.Imul: + break; + case IKVM.ByteCode.OpCode.Lmul: + break; + case IKVM.ByteCode.OpCode.Fmul: + break; + case IKVM.ByteCode.OpCode.Dmul: + break; + case IKVM.ByteCode.OpCode.Idiv: + break; + case IKVM.ByteCode.OpCode.Ldiv: + break; + case IKVM.ByteCode.OpCode.Fdiv: + break; + case IKVM.ByteCode.OpCode.Ddiv: + break; + case IKVM.ByteCode.OpCode.Irem: + break; + case IKVM.ByteCode.OpCode.Lrem: + break; + case IKVM.ByteCode.OpCode.Frem: + break; + case IKVM.ByteCode.OpCode.Drem: + break; + case IKVM.ByteCode.OpCode.Ineg: + break; + case IKVM.ByteCode.OpCode.Lneg: + break; + case IKVM.ByteCode.OpCode.Fneg: + break; + case IKVM.ByteCode.OpCode.Dneg: + break; + case IKVM.ByteCode.OpCode.Ishl: + break; + case IKVM.ByteCode.OpCode.Lshl: + break; + case IKVM.ByteCode.OpCode.Ishr: + break; + case IKVM.ByteCode.OpCode.Lshr: + break; + case IKVM.ByteCode.OpCode.Iushr: + break; + case IKVM.ByteCode.OpCode.Lushr: + break; + case IKVM.ByteCode.OpCode.Iand: + break; + case IKVM.ByteCode.OpCode.Land: + break; + case IKVM.ByteCode.OpCode.Ior: + break; + case IKVM.ByteCode.OpCode.Lor: break; - case ByteCodeMode.Constant_1: - arg1 = br.ReadByte(); + case IKVM.ByteCode.OpCode.Ixor: + break; + case IKVM.ByteCode.OpCode.Lxor: + break; + case IKVM.ByteCode.OpCode.Iinc: + var _iinc = instruction.AsIinc(); + arg1 = _iinc.Local; + arg2 = _iinc.Value; + break; + case IKVM.ByteCode.OpCode.I2l: + break; + case IKVM.ByteCode.OpCode.I2f: + break; + case IKVM.ByteCode.OpCode.I2d: + break; + case IKVM.ByteCode.OpCode.L2i: + break; + case IKVM.ByteCode.OpCode.L2f: + break; + case IKVM.ByteCode.OpCode.L2d: + break; + case IKVM.ByteCode.OpCode.F2i: + break; + case IKVM.ByteCode.OpCode.F2l: + break; + case IKVM.ByteCode.OpCode.F2d: + break; + case IKVM.ByteCode.OpCode.D2i: + break; + case IKVM.ByteCode.OpCode.D2l: + break; + case IKVM.ByteCode.OpCode.D2f: + break; + case IKVM.ByteCode.OpCode.I2b: + break; + case IKVM.ByteCode.OpCode.I2c: + break; + case IKVM.ByteCode.OpCode.I2s: + break; + case IKVM.ByteCode.OpCode.Lcmp: + break; + case IKVM.ByteCode.OpCode.Fcmpl: + break; + case IKVM.ByteCode.OpCode.Fcmpg: + break; + case IKVM.ByteCode.OpCode.Dcmpl: + break; + case IKVM.ByteCode.OpCode.Dcmpg: + break; + case IKVM.ByteCode.OpCode.Ifeq: + var _ifeq = instruction.AsIfeq(); + arg1 = _ifeq.Target; + break; + case IKVM.ByteCode.OpCode.Ifne: + var _ifne = instruction.AsIfne(); + arg1 = _ifne.Target; + break; + case IKVM.ByteCode.OpCode.Iflt: + var _iflt = instruction.AsIflt(); + arg1 = _iflt.Target; + break; + case IKVM.ByteCode.OpCode.Ifge: + var _ifge = instruction.AsIfge(); + arg1 = _ifge.Target; + break; + case IKVM.ByteCode.OpCode.Ifgt: + var _ifgt = instruction.AsIfgt(); + arg1 = _ifgt.Target; + break; + case IKVM.ByteCode.OpCode.Ifle: + var _ifle = instruction.AsIfle(); + arg1 = _ifle.Target; + break; + case IKVM.ByteCode.OpCode.IfIcmpeq: + var _ificmpeq = instruction.AsIfIcmpeq(); + arg1 = _ificmpeq.Target; + break; + case IKVM.ByteCode.OpCode.IfIcmpne: + var _ificmpne = instruction.AsIfIcmpne(); + arg1 = _ificmpne.Target; + break; + case IKVM.ByteCode.OpCode.IfIcmplt: + var _ificmplt = instruction.AsIfIcmplt(); + arg1 = _ificmplt.Target; + break; + case IKVM.ByteCode.OpCode.IfIcmpge: + var _ificmpge = instruction.AsIfIcmpge(); + arg1 = _ificmpge.Target; + break; + case IKVM.ByteCode.OpCode.IfIcmpgt: + var _ificmpgt = instruction.AsIfIcmpgt(); + arg1 = _ificmpgt.Target; + break; + case IKVM.ByteCode.OpCode.IfIcmple: + var _ificmple = instruction.AsIfIcmple(); + arg1 = _ificmple.Target; + break; + case IKVM.ByteCode.OpCode.IfAcmpeq: + var _ifacmpeq = instruction.AsIfAcmpeq(); + arg1 = _ifacmpeq.Target; + break; + case IKVM.ByteCode.OpCode.IfAcmpne: + var _ifacmpne = instruction.AsIfAcmpne(); + arg1 = _ifacmpne.Target; + break; + case IKVM.ByteCode.OpCode.Goto: + var _goto = instruction.AsGoto(); + arg1 = _goto.Target; + break; + case IKVM.ByteCode.OpCode.Jsr: + var _jsr = instruction.AsJsr(); + arg1 = _jsr.Target; + break; + case IKVM.ByteCode.OpCode.Ret: + var _ret = instruction.AsRet(); + arg1 = _ret.Local; + break; + case IKVM.ByteCode.OpCode.Ireturn: + break; + case IKVM.ByteCode.OpCode.Lreturn: + break; + case IKVM.ByteCode.OpCode.Freturn: + break; + case IKVM.ByteCode.OpCode.Dreturn: + break; + case IKVM.ByteCode.OpCode.Areturn: + break; + case IKVM.ByteCode.OpCode.Return: + break; + case IKVM.ByteCode.OpCode.GetStatic: + var _getstatic = instruction.AsGetStatic(); + arg1 = _getstatic.Field.Slot; classFile.MarkLinkRequiredConstantPoolItem(arg1); break; - case ByteCodeMode.Local_1: - arg1 = br.ReadByte(); + case IKVM.ByteCode.OpCode.PutStatic: + var _putstatic = instruction.AsPutStatic(); + arg1 = _putstatic.Field.Slot; + classFile.MarkLinkRequiredConstantPoolItem(arg1); break; - case ByteCodeMode.Constant_2: - arg1 = br.ReadUInt16(); + case IKVM.ByteCode.OpCode.GetField: + var _getfield = instruction.AsGetField(); + arg1 = _getfield.Field.Slot; classFile.MarkLinkRequiredConstantPoolItem(arg1); break; - case ByteCodeMode.Branch_2: - arg1 = br.ReadInt16(); + case IKVM.ByteCode.OpCode.PutField: + var _putfield = instruction.AsPutField(); + arg1 = _putfield.Field.Slot; + classFile.MarkLinkRequiredConstantPoolItem(arg1); break; - case ByteCodeMode.Branch_4: - arg1 = br.ReadInt32(); + case IKVM.ByteCode.OpCode.InvokeVirtual: + var _invokevirtual = instruction.AsInvokeVirtual(); + arg1 = _invokevirtual.Method.Slot; + classFile.MarkLinkRequiredConstantPoolItem(arg1); break; - case ByteCodeMode.Constant_2_1_1: - arg1 = br.ReadUInt16(); + case IKVM.ByteCode.OpCode.InvokeSpecial: + var _invokespecial = instruction.AsInvokeSpecial(); + arg1 = _invokespecial.Method.Slot; classFile.MarkLinkRequiredConstantPoolItem(arg1); - arg2 = br.ReadByte(); - if (br.ReadByte() != 0) - { + break; + case IKVM.ByteCode.OpCode.InvokeStatic: + var _invokestatic = instruction.AsInvokeStatic(); + arg1 = _invokestatic.Method.Slot; + classFile.MarkLinkRequiredConstantPoolItem(arg1); + break; + case IKVM.ByteCode.OpCode.InvokeInterface: + var _invokeinterface = instruction.AsInvokeInterface(); + if (_invokeinterface.Zero != 0) throw new ClassFormatError("invokeinterface filler must be zero"); - } + + arg1 = _invokeinterface.Method.Slot; + arg2 = _invokeinterface.Count; + classFile.MarkLinkRequiredConstantPoolItem(arg1); + break; + case IKVM.ByteCode.OpCode.InvokeDynamic: + var _invokedynamic = instruction.AsInvokeDynamic(); + if (_invokedynamic.Zero != 0) + throw new ClassFormatError("invokedynamic filler must be zero"); + if (_invokedynamic.Zero2 != 0) + throw new ClassFormatError("invokedynamic filler must be zero"); + + arg1 = _invokedynamic.Method.Slot; + classFile.MarkLinkRequiredConstantPoolItem(arg1); break; - case ByteCodeMode.Immediate_1: - arg1 = br.ReadSByte(); + case IKVM.ByteCode.OpCode.New: + var _new = instruction.AsNew(); + arg1 = _new.Constant.Slot; + classFile.MarkLinkRequiredConstantPoolItem(arg1); + break; + case IKVM.ByteCode.OpCode.Newarray: + var _newarray = instruction.AsNewarray(); + arg1 = _newarray.Value; + break; + case IKVM.ByteCode.OpCode.Anewarray: + var _anewarray = instruction.AsAnewarray(); + arg1 = _anewarray.Constant.Slot; + classFile.MarkLinkRequiredConstantPoolItem(arg1); break; - case ByteCodeMode.Immediate_2: - arg1 = br.ReadInt16(); + case IKVM.ByteCode.OpCode.Arraylength: break; - case ByteCodeMode.Local_1_Immediate_1: - arg1 = br.ReadByte(); - arg2 = br.ReadSByte(); + case IKVM.ByteCode.OpCode.Athrow: break; - case ByteCodeMode.Constant_2_Immediate_1: - arg1 = br.ReadUInt16(); + case IKVM.ByteCode.OpCode.Checkcast: + var _checkcast = instruction.AsCheckcast(); + arg1 = _checkcast.Type.Slot; classFile.MarkLinkRequiredConstantPoolItem(arg1); - arg2 = br.ReadSByte(); break; - case ByteCodeMode.Tableswitch: - { - // skip the padding - uint p = pc + 1u; - uint align = ((p + 3) & 0x7ffffffc) - p; - br.Skip(align); - int default_offset = br.ReadInt32(); - this.arg1 = default_offset; - int low = br.ReadInt32(); - int high = br.ReadInt32(); - if (low > high || high > 16384L + low) - { - throw new ClassFormatError("Incorrect tableswitch"); - } - SwitchEntry[] entries = new SwitchEntry[high - low + 1]; - for (int i = low; i < high; i++) - { - entries[i - low].value = i; - entries[i - low].target = br.ReadInt32(); - } - // do the last entry outside the loop, to avoid overflowing "i", if high == int.MaxValue - entries[high - low].value = high; - entries[high - low].target = br.ReadInt32(); - this.switch_entries = entries; - break; - } - case ByteCodeMode.Lookupswitch: + case IKVM.ByteCode.OpCode.InstanceOf: + var _instanceof = instruction.AsInstanceOf(); + arg1 = _instanceof.Type.Slot; + classFile.MarkLinkRequiredConstantPoolItem(arg1); + break; + case IKVM.ByteCode.OpCode.MonitorEnter: + break; + case IKVM.ByteCode.OpCode.MonitorExit: + break; + case IKVM.ByteCode.OpCode.Multianewarray: + var _multianewarray = instruction.AsMultianewarray(); + arg1 = _multianewarray.Type.Slot; + classFile.MarkLinkRequiredConstantPoolItem(arg1); + arg2 = _multianewarray.Dimensions; + break; + case IKVM.ByteCode.OpCode.IfNull: + var _ifnull = instruction.AsIfNull(); + arg1 = _ifnull.Target; + break; + case IKVM.ByteCode.OpCode.IfNonNull: + var _ifnonnull = instruction.AsIfNonNull(); + arg1 = _ifnonnull.Target; + break; + case IKVM.ByteCode.OpCode.GotoW: + var _gotow = instruction.AsGotoW(); + arg1 = _gotow.Target; + break; + case IKVM.ByteCode.OpCode.JsrW: + var _jsrw = instruction.AsJsrW(); + arg1 = _jsrw.Target; + break; + case IKVM.ByteCode.OpCode.LookupSwitch: + var _lookupswitch = instruction.AsLookupSwitch(); + if (_lookupswitch.Matches.Count < 0 || _lookupswitch.Matches.Count > 16384) + throw new ClassFormatError("Incorrect lookupswitch"); + + arg1 = _lookupswitch.DefaultTarget; + + var lookupswitchentries = new SwitchEntry[_lookupswitch.Matches.Count]; + for (int i = 0; i < _lookupswitch.Matches.Count; i++) { - // skip the padding - uint p = pc + 1u; - uint align = ((p + 3) & 0x7ffffffc) - p; - br.Skip(align); - int default_offset = br.ReadInt32(); - this.arg1 = default_offset; - int count = br.ReadInt32(); - if (count < 0 || count > 16384) - { - throw new ClassFormatError("Incorrect lookupswitch"); - } - SwitchEntry[] entries = new SwitchEntry[count]; - for (int i = 0; i < count; i++) - { - entries[i].value = br.ReadInt32(); - entries[i].target = br.ReadInt32(); - } - this.switch_entries = entries; - break; + lookupswitchentries[i].value = _lookupswitch.Matches[i].Key; + lookupswitchentries[i].target = _lookupswitch.Matches[i].Target; } - case ByteCodeMode.WidePrefix: - bc = (ByteCode)br.ReadByte(); - // NOTE the PC of a wide instruction is actually the PC of the - // wide prefix, not the following instruction (vmspec 4.9.2) - switch (ByteCodeMetaData.GetWideMode(bc)) + + switch_entries = lookupswitchentries; + break; + case IKVM.ByteCode.OpCode.TableSwitch: + var _tableswitch = instruction.AsTableSwitch(); + if (_tableswitch.Low > _tableswitch.High || _tableswitch.High > 16384L + _tableswitch.Low) + throw new ClassFormatError("Incorrect tableswitch"); + + arg1 = _tableswitch.DefaultTarget; + + var tableswitchentries = new SwitchEntry[_tableswitch.High - _tableswitch.Low + 1]; + for (int i = _tableswitch.Low; i < _tableswitch.High; i++) { - case ByteCodeModeWide.Local_2: - arg1 = br.ReadUInt16(); - break; - case ByteCodeModeWide.Local_2_Immediate_2: - arg1 = br.ReadUInt16(); - arg2 = br.ReadInt16(); - break; - default: - throw new ClassFormatError("Invalid wide prefix on opcode: {0}", bc); + tableswitchentries[i].value = i; + tableswitchentries[i].target = _tableswitch.Matches[i]; } + + // do the last entry outside the loop, to avoid overflowing "i", if high == int.MaxValue + tableswitchentries[_tableswitch.High - _tableswitch.Low].value = _tableswitch.High; + tableswitchentries[_tableswitch.High - _tableswitch.Low].target = _tableswitch.Matches[_tableswitch.High]; + + switch_entries = tableswitchentries; break; default: - throw new ClassFormatError("Invalid opcode: {0}", bc); + throw new ClassFormatError("Invalid opcode: {0}", instruction.OpCode); } - this.normopcode = ByteCodeMetaData.GetNormalizedByteCode(bc); - arg1 = ByteCodeMetaData.GetArg(bc, arg1); - } - internal int PC - { - get - { - return pc; - } + this.normopcode = ByteCodeMetaData.GetNormalizedByteCode((ByteCode)(int)instruction.OpCode); + arg1 = ByteCodeMetaData.GetArg((ByteCode)(int)instruction.OpCode, arg1); } - internal NormalizedByteCode NormalizedOpCode - { - get - { - return normopcode; - } - } + internal int PC => pc; - internal int Arg1 - { - get - { - return arg1; - } - } + internal NormalizedByteCode NormalizedOpCode => normopcode; + + internal int Arg1 => arg1; internal int TargetIndex { - get - { - return arg1; - } - set - { - arg1 = value; - } + get => arg1; + set => arg1 = value; } - internal int Arg2 - { - get - { - return arg2; - } - } + internal int Arg2 => arg2; - internal int NormalizedArg1 - { - get - { - return arg1; - } - } + internal int NormalizedArg1 => arg1; internal int DefaultTarget { - get - { - return arg1; - } - set - { - arg1 = value; - } + get => arg1; + set => arg1 = value; } - internal int SwitchEntryCount - { - get - { - return switch_entries.Length; - } - } + internal int SwitchEntryCount => switch_entries.Length; internal int GetSwitchValue(int i) { @@ -320,15 +731,17 @@ internal int GetSwitchTargetIndex(int i) internal void SetSwitchTargets(int[] targets) { - SwitchEntry[] newEntries = (SwitchEntry[])switch_entries.Clone(); + var newEntries = (SwitchEntry[])switch_entries.Clone(); for (int i = 0; i < newEntries.Length; i++) - { newEntries[i].target = targets[i]; - } + switch_entries = newEntries; } + } + } + } } diff --git a/src/IKVM.Util/IKVM.Util.csproj b/src/IKVM.Util/IKVM.Util.csproj index 88ed239ec0..cea3b7dcfc 100644 --- a/src/IKVM.Util/IKVM.Util.csproj +++ b/src/IKVM.Util/IKVM.Util.csproj @@ -8,7 +8,7 @@ - + From b3e82ec5fe85ffd986d36d8024fba74714255739 Mon Sep 17 00:00:00 2001 From: Jerome Haltom Date: Sat, 17 Aug 2024 18:36:07 -0500 Subject: [PATCH 2/5] Latest IKVM.ByteCode. Fixes switch decode. Integrate CodeDecoder into IKVM. No longer uses it's own parser. --- IKVM.deps.targets | 2 +- src/IKVM.Runtime/ClassFile.Method.Code.cs | 6 +- .../ClassFile.Method.Instruction.cs | 1156 +++++++++-------- src/IKVM.Util/IKVM.Util.csproj | 2 +- 4 files changed, 590 insertions(+), 576 deletions(-) diff --git a/IKVM.deps.targets b/IKVM.deps.targets index d79c4a938b..5b7a3754e7 100644 --- a/IKVM.deps.targets +++ b/IKVM.deps.targets @@ -1,7 +1,7 @@ - + diff --git a/src/IKVM.Runtime/ClassFile.Method.Code.cs b/src/IKVM.Runtime/ClassFile.Method.Code.cs index 546dcfdad2..d45d8b0b74 100644 --- a/src/IKVM.Runtime/ClassFile.Method.Code.cs +++ b/src/IKVM.Runtime/ClassFile.Method.Code.cs @@ -88,14 +88,16 @@ internal void Read(ClassFile classFile, string[] utf8_cp, Method method, CodeAtt // we add an additional nop instruction to make it easier for consumers of the code array _instructions[instructionCount++].SetTermNop((ushort)decoder.Position.GetInteger()); } + catch (ArgumentOutOfRangeException e) + { + verifyError = e.Message; + } catch (ClassFormatError e) { - // any class format errors in the code block are actually verify errors verifyError = e.Message; } catch (ByteCodeException e) { - // any errors in the code block are actually verify errors verifyError = e.Message; } diff --git a/src/IKVM.Runtime/ClassFile.Method.Instruction.cs b/src/IKVM.Runtime/ClassFile.Method.Instruction.cs index d3eb53f8b7..f4f7d0cf82 100644 --- a/src/IKVM.Runtime/ClassFile.Method.Instruction.cs +++ b/src/IKVM.Runtime/ClassFile.Method.Instruction.cs @@ -22,15 +22,20 @@ Jeroen Frijters */ +using System; + namespace IKVM.Runtime { sealed partial class ClassFile { + internal sealed partial class Method { + internal struct Instruction { + private ushort pc; private NormalizedByteCode normopcode; private int arg1; @@ -119,580 +124,587 @@ internal void Read(IKVM.ByteCode.Decoding.Instruction instruction, ClassFile cla { this.pc = (ushort)instruction.Offset; - switch (instruction.OpCode) + try { - case IKVM.ByteCode.OpCode.Nop: - break; - case IKVM.ByteCode.OpCode.AconstNull: - break; - case IKVM.ByteCode.OpCode.IconstM1: - break; - case IKVM.ByteCode.OpCode.Iconst0: - break; - case IKVM.ByteCode.OpCode.Iconst1: - break; - case IKVM.ByteCode.OpCode.Iconst2: - break; - case IKVM.ByteCode.OpCode.Iconst3: - break; - case IKVM.ByteCode.OpCode.Iconst4: - break; - case IKVM.ByteCode.OpCode.Iconst5: - break; - case IKVM.ByteCode.OpCode.Lconst0: - break; - case IKVM.ByteCode.OpCode.Lconst1: - break; - case IKVM.ByteCode.OpCode.Fconst0: - break; - case IKVM.ByteCode.OpCode.Fconst1: - break; - case IKVM.ByteCode.OpCode.Fconst2: - break; - case IKVM.ByteCode.OpCode.Dconst0: - break; - case IKVM.ByteCode.OpCode.Dconst1: - break; - case IKVM.ByteCode.OpCode.Bipush: - var _bipush = instruction.AsBipush(); - arg1 = _bipush.Value; - break; - case IKVM.ByteCode.OpCode.Sipush: - var _sipush = instruction.AsSipush(); - arg1 = _sipush.Value; - break; - case IKVM.ByteCode.OpCode.Ldc: - var _ldc = instruction.AsLdc(); - arg1 = _ldc.Constant.Slot; - classFile.MarkLinkRequiredConstantPoolItem(arg1); - break; - case IKVM.ByteCode.OpCode.LdcW: - var _ldcw = instruction.AsLdcW(); - arg1 = _ldcw.Constant.Slot; - classFile.MarkLinkRequiredConstantPoolItem(arg1); - break; - case IKVM.ByteCode.OpCode.Ldc2W: - var _ldc2w = instruction.AsLdc2W(); - arg1 = _ldc2w.Constant.Slot; - classFile.MarkLinkRequiredConstantPoolItem(arg1); - break; - case IKVM.ByteCode.OpCode.Iload: - var _iload = instruction.AsIload(); - arg1 = _iload.Local; - break; - case IKVM.ByteCode.OpCode.Lload: - var _lload = instruction.AsLload(); - arg1 = _lload.Local; - break; - case IKVM.ByteCode.OpCode.Fload: - var _fload = instruction.AsFload(); - arg1 = _fload.Local; - break; - case IKVM.ByteCode.OpCode.Dload: - var _dload = instruction.AsDload(); - arg1 = _dload.Local; - break; - case IKVM.ByteCode.OpCode.Aload: - var _aload = instruction.AsAload(); - arg1 = _aload.Local; - break; - case IKVM.ByteCode.OpCode.Iload0: - break; - case IKVM.ByteCode.OpCode.Iload1: - break; - case IKVM.ByteCode.OpCode.Iload2: - break; - case IKVM.ByteCode.OpCode.Iload3: - break; - case IKVM.ByteCode.OpCode.Lload0: - break; - case IKVM.ByteCode.OpCode.Lload1: - break; - case IKVM.ByteCode.OpCode.Lload2: - break; - case IKVM.ByteCode.OpCode.Lload3: - break; - case IKVM.ByteCode.OpCode.Fload0: - break; - case IKVM.ByteCode.OpCode.Fload1: - break; - case IKVM.ByteCode.OpCode.Fload2: - break; - case IKVM.ByteCode.OpCode.Fload3: - break; - case IKVM.ByteCode.OpCode.Dload0: - break; - case IKVM.ByteCode.OpCode.Dload1: - break; - case IKVM.ByteCode.OpCode.Dload2: - break; - case IKVM.ByteCode.OpCode.Dload3: - break; - case IKVM.ByteCode.OpCode.Aload0: - break; - case IKVM.ByteCode.OpCode.Aload1: - break; - case IKVM.ByteCode.OpCode.Aload2: - break; - case IKVM.ByteCode.OpCode.Aload3: - break; - case IKVM.ByteCode.OpCode.Iaload: - break; - case IKVM.ByteCode.OpCode.Laload: - break; - case IKVM.ByteCode.OpCode.Faload: - break; - case IKVM.ByteCode.OpCode.Daload: - break; - case IKVM.ByteCode.OpCode.Aaload: - break; - case IKVM.ByteCode.OpCode.Baload: - break; - case IKVM.ByteCode.OpCode.Caload: - break; - case IKVM.ByteCode.OpCode.Saload: - break; - case IKVM.ByteCode.OpCode.Istore: - var _istore = instruction.AsIstore(); - arg1 = _istore.Local; - break; - case IKVM.ByteCode.OpCode.Lstore: - var _lstore = instruction.AsLstore(); - arg1 = _lstore.Local; - break; - case IKVM.ByteCode.OpCode.Fstore: - var _fstore = instruction.AsFstore(); - arg1 = _fstore.Local; - break; - case IKVM.ByteCode.OpCode.Dstore: - var _dstore = instruction.AsDstore(); - arg1 = _dstore.Local; - break; - case IKVM.ByteCode.OpCode.Astore: - var _astore = instruction.AsAstore(); - arg1 = _astore.Local; - break; - case IKVM.ByteCode.OpCode.Istore0: - break; - case IKVM.ByteCode.OpCode.Istore1: - break; - case IKVM.ByteCode.OpCode.Istore2: - break; - case IKVM.ByteCode.OpCode.Istore3: - break; - case IKVM.ByteCode.OpCode.Lstore0: - break; - case IKVM.ByteCode.OpCode.Lstore1: - break; - case IKVM.ByteCode.OpCode.Lstore2: - break; - case IKVM.ByteCode.OpCode.Lstore3: - break; - case IKVM.ByteCode.OpCode.Fstore0: - break; - case IKVM.ByteCode.OpCode.Fstore1: - break; - case IKVM.ByteCode.OpCode.Fstore2: - break; - case IKVM.ByteCode.OpCode.Fstore3: - break; - case IKVM.ByteCode.OpCode.Dstore0: - break; - case IKVM.ByteCode.OpCode.Dstore1: - break; - case IKVM.ByteCode.OpCode.Dstore2: - break; - case IKVM.ByteCode.OpCode.Dstore3: - break; - case IKVM.ByteCode.OpCode.Astore0: - break; - case IKVM.ByteCode.OpCode.Astore1: - break; - case IKVM.ByteCode.OpCode.Astore2: - break; - case IKVM.ByteCode.OpCode.Astore3: - break; - case IKVM.ByteCode.OpCode.Iastore: - break; - case IKVM.ByteCode.OpCode.Lastore: - break; - case IKVM.ByteCode.OpCode.Fastore: - break; - case IKVM.ByteCode.OpCode.Dastore: - break; - case IKVM.ByteCode.OpCode.Aastore: - break; - case IKVM.ByteCode.OpCode.Bastore: - break; - case IKVM.ByteCode.OpCode.Castore: - break; - case IKVM.ByteCode.OpCode.Sastore: - break; - case IKVM.ByteCode.OpCode.Pop: - break; - case IKVM.ByteCode.OpCode.Pop2: - break; - case IKVM.ByteCode.OpCode.Dup: - break; - case IKVM.ByteCode.OpCode.DupX1: - break; - case IKVM.ByteCode.OpCode.DupX2: - break; - case IKVM.ByteCode.OpCode.Dup2: - break; - case IKVM.ByteCode.OpCode.Dup2X1: - break; - case IKVM.ByteCode.OpCode.Dup2X2: - break; - case IKVM.ByteCode.OpCode.Swap: - break; - case IKVM.ByteCode.OpCode.Iadd: - break; - case IKVM.ByteCode.OpCode.Ladd: - break; - case IKVM.ByteCode.OpCode.Fadd: - break; - case IKVM.ByteCode.OpCode.Dadd: - break; - case IKVM.ByteCode.OpCode.Isub: - break; - case IKVM.ByteCode.OpCode.Lsub: - break; - case IKVM.ByteCode.OpCode.Fsub: - break; - case IKVM.ByteCode.OpCode.Dsub: - break; - case IKVM.ByteCode.OpCode.Imul: - break; - case IKVM.ByteCode.OpCode.Lmul: - break; - case IKVM.ByteCode.OpCode.Fmul: - break; - case IKVM.ByteCode.OpCode.Dmul: - break; - case IKVM.ByteCode.OpCode.Idiv: - break; - case IKVM.ByteCode.OpCode.Ldiv: - break; - case IKVM.ByteCode.OpCode.Fdiv: - break; - case IKVM.ByteCode.OpCode.Ddiv: - break; - case IKVM.ByteCode.OpCode.Irem: - break; - case IKVM.ByteCode.OpCode.Lrem: - break; - case IKVM.ByteCode.OpCode.Frem: - break; - case IKVM.ByteCode.OpCode.Drem: - break; - case IKVM.ByteCode.OpCode.Ineg: - break; - case IKVM.ByteCode.OpCode.Lneg: - break; - case IKVM.ByteCode.OpCode.Fneg: - break; - case IKVM.ByteCode.OpCode.Dneg: - break; - case IKVM.ByteCode.OpCode.Ishl: - break; - case IKVM.ByteCode.OpCode.Lshl: - break; - case IKVM.ByteCode.OpCode.Ishr: - break; - case IKVM.ByteCode.OpCode.Lshr: - break; - case IKVM.ByteCode.OpCode.Iushr: - break; - case IKVM.ByteCode.OpCode.Lushr: - break; - case IKVM.ByteCode.OpCode.Iand: - break; - case IKVM.ByteCode.OpCode.Land: - break; - case IKVM.ByteCode.OpCode.Ior: - break; - case IKVM.ByteCode.OpCode.Lor: - break; - case IKVM.ByteCode.OpCode.Ixor: - break; - case IKVM.ByteCode.OpCode.Lxor: - break; - case IKVM.ByteCode.OpCode.Iinc: - var _iinc = instruction.AsIinc(); - arg1 = _iinc.Local; - arg2 = _iinc.Value; - break; - case IKVM.ByteCode.OpCode.I2l: - break; - case IKVM.ByteCode.OpCode.I2f: - break; - case IKVM.ByteCode.OpCode.I2d: - break; - case IKVM.ByteCode.OpCode.L2i: - break; - case IKVM.ByteCode.OpCode.L2f: - break; - case IKVM.ByteCode.OpCode.L2d: - break; - case IKVM.ByteCode.OpCode.F2i: - break; - case IKVM.ByteCode.OpCode.F2l: - break; - case IKVM.ByteCode.OpCode.F2d: - break; - case IKVM.ByteCode.OpCode.D2i: - break; - case IKVM.ByteCode.OpCode.D2l: - break; - case IKVM.ByteCode.OpCode.D2f: - break; - case IKVM.ByteCode.OpCode.I2b: - break; - case IKVM.ByteCode.OpCode.I2c: - break; - case IKVM.ByteCode.OpCode.I2s: - break; - case IKVM.ByteCode.OpCode.Lcmp: - break; - case IKVM.ByteCode.OpCode.Fcmpl: - break; - case IKVM.ByteCode.OpCode.Fcmpg: - break; - case IKVM.ByteCode.OpCode.Dcmpl: - break; - case IKVM.ByteCode.OpCode.Dcmpg: - break; - case IKVM.ByteCode.OpCode.Ifeq: - var _ifeq = instruction.AsIfeq(); - arg1 = _ifeq.Target; - break; - case IKVM.ByteCode.OpCode.Ifne: - var _ifne = instruction.AsIfne(); - arg1 = _ifne.Target; - break; - case IKVM.ByteCode.OpCode.Iflt: - var _iflt = instruction.AsIflt(); - arg1 = _iflt.Target; - break; - case IKVM.ByteCode.OpCode.Ifge: - var _ifge = instruction.AsIfge(); - arg1 = _ifge.Target; - break; - case IKVM.ByteCode.OpCode.Ifgt: - var _ifgt = instruction.AsIfgt(); - arg1 = _ifgt.Target; - break; - case IKVM.ByteCode.OpCode.Ifle: - var _ifle = instruction.AsIfle(); - arg1 = _ifle.Target; - break; - case IKVM.ByteCode.OpCode.IfIcmpeq: - var _ificmpeq = instruction.AsIfIcmpeq(); - arg1 = _ificmpeq.Target; - break; - case IKVM.ByteCode.OpCode.IfIcmpne: - var _ificmpne = instruction.AsIfIcmpne(); - arg1 = _ificmpne.Target; - break; - case IKVM.ByteCode.OpCode.IfIcmplt: - var _ificmplt = instruction.AsIfIcmplt(); - arg1 = _ificmplt.Target; - break; - case IKVM.ByteCode.OpCode.IfIcmpge: - var _ificmpge = instruction.AsIfIcmpge(); - arg1 = _ificmpge.Target; - break; - case IKVM.ByteCode.OpCode.IfIcmpgt: - var _ificmpgt = instruction.AsIfIcmpgt(); - arg1 = _ificmpgt.Target; - break; - case IKVM.ByteCode.OpCode.IfIcmple: - var _ificmple = instruction.AsIfIcmple(); - arg1 = _ificmple.Target; - break; - case IKVM.ByteCode.OpCode.IfAcmpeq: - var _ifacmpeq = instruction.AsIfAcmpeq(); - arg1 = _ifacmpeq.Target; - break; - case IKVM.ByteCode.OpCode.IfAcmpne: - var _ifacmpne = instruction.AsIfAcmpne(); - arg1 = _ifacmpne.Target; - break; - case IKVM.ByteCode.OpCode.Goto: - var _goto = instruction.AsGoto(); - arg1 = _goto.Target; - break; - case IKVM.ByteCode.OpCode.Jsr: - var _jsr = instruction.AsJsr(); - arg1 = _jsr.Target; - break; - case IKVM.ByteCode.OpCode.Ret: - var _ret = instruction.AsRet(); - arg1 = _ret.Local; - break; - case IKVM.ByteCode.OpCode.Ireturn: - break; - case IKVM.ByteCode.OpCode.Lreturn: - break; - case IKVM.ByteCode.OpCode.Freturn: - break; - case IKVM.ByteCode.OpCode.Dreturn: - break; - case IKVM.ByteCode.OpCode.Areturn: - break; - case IKVM.ByteCode.OpCode.Return: - break; - case IKVM.ByteCode.OpCode.GetStatic: - var _getstatic = instruction.AsGetStatic(); - arg1 = _getstatic.Field.Slot; - classFile.MarkLinkRequiredConstantPoolItem(arg1); - break; - case IKVM.ByteCode.OpCode.PutStatic: - var _putstatic = instruction.AsPutStatic(); - arg1 = _putstatic.Field.Slot; - classFile.MarkLinkRequiredConstantPoolItem(arg1); - break; - case IKVM.ByteCode.OpCode.GetField: - var _getfield = instruction.AsGetField(); - arg1 = _getfield.Field.Slot; - classFile.MarkLinkRequiredConstantPoolItem(arg1); - break; - case IKVM.ByteCode.OpCode.PutField: - var _putfield = instruction.AsPutField(); - arg1 = _putfield.Field.Slot; - classFile.MarkLinkRequiredConstantPoolItem(arg1); - break; - case IKVM.ByteCode.OpCode.InvokeVirtual: - var _invokevirtual = instruction.AsInvokeVirtual(); - arg1 = _invokevirtual.Method.Slot; - classFile.MarkLinkRequiredConstantPoolItem(arg1); - break; - case IKVM.ByteCode.OpCode.InvokeSpecial: - var _invokespecial = instruction.AsInvokeSpecial(); - arg1 = _invokespecial.Method.Slot; - classFile.MarkLinkRequiredConstantPoolItem(arg1); - break; - case IKVM.ByteCode.OpCode.InvokeStatic: - var _invokestatic = instruction.AsInvokeStatic(); - arg1 = _invokestatic.Method.Slot; - classFile.MarkLinkRequiredConstantPoolItem(arg1); - break; - case IKVM.ByteCode.OpCode.InvokeInterface: - var _invokeinterface = instruction.AsInvokeInterface(); - if (_invokeinterface.Zero != 0) - throw new ClassFormatError("invokeinterface filler must be zero"); - - arg1 = _invokeinterface.Method.Slot; - arg2 = _invokeinterface.Count; - classFile.MarkLinkRequiredConstantPoolItem(arg1); - break; - case IKVM.ByteCode.OpCode.InvokeDynamic: - var _invokedynamic = instruction.AsInvokeDynamic(); - if (_invokedynamic.Zero != 0) - throw new ClassFormatError("invokedynamic filler must be zero"); - if (_invokedynamic.Zero2 != 0) - throw new ClassFormatError("invokedynamic filler must be zero"); - - arg1 = _invokedynamic.Method.Slot; - classFile.MarkLinkRequiredConstantPoolItem(arg1); - break; - case IKVM.ByteCode.OpCode.New: - var _new = instruction.AsNew(); - arg1 = _new.Constant.Slot; - classFile.MarkLinkRequiredConstantPoolItem(arg1); - break; - case IKVM.ByteCode.OpCode.Newarray: - var _newarray = instruction.AsNewarray(); - arg1 = _newarray.Value; - break; - case IKVM.ByteCode.OpCode.Anewarray: - var _anewarray = instruction.AsAnewarray(); - arg1 = _anewarray.Constant.Slot; - classFile.MarkLinkRequiredConstantPoolItem(arg1); - break; - case IKVM.ByteCode.OpCode.Arraylength: - break; - case IKVM.ByteCode.OpCode.Athrow: - break; - case IKVM.ByteCode.OpCode.Checkcast: - var _checkcast = instruction.AsCheckcast(); - arg1 = _checkcast.Type.Slot; - classFile.MarkLinkRequiredConstantPoolItem(arg1); - break; - case IKVM.ByteCode.OpCode.InstanceOf: - var _instanceof = instruction.AsInstanceOf(); - arg1 = _instanceof.Type.Slot; - classFile.MarkLinkRequiredConstantPoolItem(arg1); - break; - case IKVM.ByteCode.OpCode.MonitorEnter: - break; - case IKVM.ByteCode.OpCode.MonitorExit: - break; - case IKVM.ByteCode.OpCode.Multianewarray: - var _multianewarray = instruction.AsMultianewarray(); - arg1 = _multianewarray.Type.Slot; - classFile.MarkLinkRequiredConstantPoolItem(arg1); - arg2 = _multianewarray.Dimensions; - break; - case IKVM.ByteCode.OpCode.IfNull: - var _ifnull = instruction.AsIfNull(); - arg1 = _ifnull.Target; - break; - case IKVM.ByteCode.OpCode.IfNonNull: - var _ifnonnull = instruction.AsIfNonNull(); - arg1 = _ifnonnull.Target; - break; - case IKVM.ByteCode.OpCode.GotoW: - var _gotow = instruction.AsGotoW(); - arg1 = _gotow.Target; - break; - case IKVM.ByteCode.OpCode.JsrW: - var _jsrw = instruction.AsJsrW(); - arg1 = _jsrw.Target; - break; - case IKVM.ByteCode.OpCode.LookupSwitch: - var _lookupswitch = instruction.AsLookupSwitch(); - if (_lookupswitch.Matches.Count < 0 || _lookupswitch.Matches.Count > 16384) - throw new ClassFormatError("Incorrect lookupswitch"); - - arg1 = _lookupswitch.DefaultTarget; - - var lookupswitchentries = new SwitchEntry[_lookupswitch.Matches.Count]; - for (int i = 0; i < _lookupswitch.Matches.Count; i++) - { - lookupswitchentries[i].value = _lookupswitch.Matches[i].Key; - lookupswitchentries[i].target = _lookupswitch.Matches[i].Target; - } - - switch_entries = lookupswitchentries; - break; - case IKVM.ByteCode.OpCode.TableSwitch: - var _tableswitch = instruction.AsTableSwitch(); - if (_tableswitch.Low > _tableswitch.High || _tableswitch.High > 16384L + _tableswitch.Low) - throw new ClassFormatError("Incorrect tableswitch"); - - arg1 = _tableswitch.DefaultTarget; - - var tableswitchentries = new SwitchEntry[_tableswitch.High - _tableswitch.Low + 1]; - for (int i = _tableswitch.Low; i < _tableswitch.High; i++) - { - tableswitchentries[i].value = i; - tableswitchentries[i].target = _tableswitch.Matches[i]; - } - - // do the last entry outside the loop, to avoid overflowing "i", if high == int.MaxValue - tableswitchentries[_tableswitch.High - _tableswitch.Low].value = _tableswitch.High; - tableswitchentries[_tableswitch.High - _tableswitch.Low].target = _tableswitch.Matches[_tableswitch.High]; - - switch_entries = tableswitchentries; - break; - default: - throw new ClassFormatError("Invalid opcode: {0}", instruction.OpCode); + switch (instruction.OpCode) + { + case IKVM.ByteCode.OpCode.Nop: + break; + case IKVM.ByteCode.OpCode.AconstNull: + break; + case IKVM.ByteCode.OpCode.IconstM1: + break; + case IKVM.ByteCode.OpCode.Iconst0: + break; + case IKVM.ByteCode.OpCode.Iconst1: + break; + case IKVM.ByteCode.OpCode.Iconst2: + break; + case IKVM.ByteCode.OpCode.Iconst3: + break; + case IKVM.ByteCode.OpCode.Iconst4: + break; + case IKVM.ByteCode.OpCode.Iconst5: + break; + case IKVM.ByteCode.OpCode.Lconst0: + break; + case IKVM.ByteCode.OpCode.Lconst1: + break; + case IKVM.ByteCode.OpCode.Fconst0: + break; + case IKVM.ByteCode.OpCode.Fconst1: + break; + case IKVM.ByteCode.OpCode.Fconst2: + break; + case IKVM.ByteCode.OpCode.Dconst0: + break; + case IKVM.ByteCode.OpCode.Dconst1: + break; + case IKVM.ByteCode.OpCode.Bipush: + var _bipush = instruction.AsBipush(); + arg1 = _bipush.Value; + break; + case IKVM.ByteCode.OpCode.Sipush: + var _sipush = instruction.AsSipush(); + arg1 = _sipush.Value; + break; + case IKVM.ByteCode.OpCode.Ldc: + var _ldc = instruction.AsLdc(); + arg1 = _ldc.Constant.Slot; + classFile.MarkLinkRequiredConstantPoolItem(arg1); + break; + case IKVM.ByteCode.OpCode.LdcW: + var _ldcw = instruction.AsLdcW(); + arg1 = _ldcw.Constant.Slot; + classFile.MarkLinkRequiredConstantPoolItem(arg1); + break; + case IKVM.ByteCode.OpCode.Ldc2W: + var _ldc2w = instruction.AsLdc2W(); + arg1 = _ldc2w.Constant.Slot; + classFile.MarkLinkRequiredConstantPoolItem(arg1); + break; + case IKVM.ByteCode.OpCode.Iload: + var _iload = instruction.AsIload(); + arg1 = _iload.Local; + break; + case IKVM.ByteCode.OpCode.Lload: + var _lload = instruction.AsLload(); + arg1 = _lload.Local; + break; + case IKVM.ByteCode.OpCode.Fload: + var _fload = instruction.AsFload(); + arg1 = _fload.Local; + break; + case IKVM.ByteCode.OpCode.Dload: + var _dload = instruction.AsDload(); + arg1 = _dload.Local; + break; + case IKVM.ByteCode.OpCode.Aload: + var _aload = instruction.AsAload(); + arg1 = _aload.Local; + break; + case IKVM.ByteCode.OpCode.Iload0: + break; + case IKVM.ByteCode.OpCode.Iload1: + break; + case IKVM.ByteCode.OpCode.Iload2: + break; + case IKVM.ByteCode.OpCode.Iload3: + break; + case IKVM.ByteCode.OpCode.Lload0: + break; + case IKVM.ByteCode.OpCode.Lload1: + break; + case IKVM.ByteCode.OpCode.Lload2: + break; + case IKVM.ByteCode.OpCode.Lload3: + break; + case IKVM.ByteCode.OpCode.Fload0: + break; + case IKVM.ByteCode.OpCode.Fload1: + break; + case IKVM.ByteCode.OpCode.Fload2: + break; + case IKVM.ByteCode.OpCode.Fload3: + break; + case IKVM.ByteCode.OpCode.Dload0: + break; + case IKVM.ByteCode.OpCode.Dload1: + break; + case IKVM.ByteCode.OpCode.Dload2: + break; + case IKVM.ByteCode.OpCode.Dload3: + break; + case IKVM.ByteCode.OpCode.Aload0: + break; + case IKVM.ByteCode.OpCode.Aload1: + break; + case IKVM.ByteCode.OpCode.Aload2: + break; + case IKVM.ByteCode.OpCode.Aload3: + break; + case IKVM.ByteCode.OpCode.Iaload: + break; + case IKVM.ByteCode.OpCode.Laload: + break; + case IKVM.ByteCode.OpCode.Faload: + break; + case IKVM.ByteCode.OpCode.Daload: + break; + case IKVM.ByteCode.OpCode.Aaload: + break; + case IKVM.ByteCode.OpCode.Baload: + break; + case IKVM.ByteCode.OpCode.Caload: + break; + case IKVM.ByteCode.OpCode.Saload: + break; + case IKVM.ByteCode.OpCode.Istore: + var _istore = instruction.AsIstore(); + arg1 = _istore.Local; + break; + case IKVM.ByteCode.OpCode.Lstore: + var _lstore = instruction.AsLstore(); + arg1 = _lstore.Local; + break; + case IKVM.ByteCode.OpCode.Fstore: + var _fstore = instruction.AsFstore(); + arg1 = _fstore.Local; + break; + case IKVM.ByteCode.OpCode.Dstore: + var _dstore = instruction.AsDstore(); + arg1 = _dstore.Local; + break; + case IKVM.ByteCode.OpCode.Astore: + var _astore = instruction.AsAstore(); + arg1 = _astore.Local; + break; + case IKVM.ByteCode.OpCode.Istore0: + break; + case IKVM.ByteCode.OpCode.Istore1: + break; + case IKVM.ByteCode.OpCode.Istore2: + break; + case IKVM.ByteCode.OpCode.Istore3: + break; + case IKVM.ByteCode.OpCode.Lstore0: + break; + case IKVM.ByteCode.OpCode.Lstore1: + break; + case IKVM.ByteCode.OpCode.Lstore2: + break; + case IKVM.ByteCode.OpCode.Lstore3: + break; + case IKVM.ByteCode.OpCode.Fstore0: + break; + case IKVM.ByteCode.OpCode.Fstore1: + break; + case IKVM.ByteCode.OpCode.Fstore2: + break; + case IKVM.ByteCode.OpCode.Fstore3: + break; + case IKVM.ByteCode.OpCode.Dstore0: + break; + case IKVM.ByteCode.OpCode.Dstore1: + break; + case IKVM.ByteCode.OpCode.Dstore2: + break; + case IKVM.ByteCode.OpCode.Dstore3: + break; + case IKVM.ByteCode.OpCode.Astore0: + break; + case IKVM.ByteCode.OpCode.Astore1: + break; + case IKVM.ByteCode.OpCode.Astore2: + break; + case IKVM.ByteCode.OpCode.Astore3: + break; + case IKVM.ByteCode.OpCode.Iastore: + break; + case IKVM.ByteCode.OpCode.Lastore: + break; + case IKVM.ByteCode.OpCode.Fastore: + break; + case IKVM.ByteCode.OpCode.Dastore: + break; + case IKVM.ByteCode.OpCode.Aastore: + break; + case IKVM.ByteCode.OpCode.Bastore: + break; + case IKVM.ByteCode.OpCode.Castore: + break; + case IKVM.ByteCode.OpCode.Sastore: + break; + case IKVM.ByteCode.OpCode.Pop: + break; + case IKVM.ByteCode.OpCode.Pop2: + break; + case IKVM.ByteCode.OpCode.Dup: + break; + case IKVM.ByteCode.OpCode.DupX1: + break; + case IKVM.ByteCode.OpCode.DupX2: + break; + case IKVM.ByteCode.OpCode.Dup2: + break; + case IKVM.ByteCode.OpCode.Dup2X1: + break; + case IKVM.ByteCode.OpCode.Dup2X2: + break; + case IKVM.ByteCode.OpCode.Swap: + break; + case IKVM.ByteCode.OpCode.Iadd: + break; + case IKVM.ByteCode.OpCode.Ladd: + break; + case IKVM.ByteCode.OpCode.Fadd: + break; + case IKVM.ByteCode.OpCode.Dadd: + break; + case IKVM.ByteCode.OpCode.Isub: + break; + case IKVM.ByteCode.OpCode.Lsub: + break; + case IKVM.ByteCode.OpCode.Fsub: + break; + case IKVM.ByteCode.OpCode.Dsub: + break; + case IKVM.ByteCode.OpCode.Imul: + break; + case IKVM.ByteCode.OpCode.Lmul: + break; + case IKVM.ByteCode.OpCode.Fmul: + break; + case IKVM.ByteCode.OpCode.Dmul: + break; + case IKVM.ByteCode.OpCode.Idiv: + break; + case IKVM.ByteCode.OpCode.Ldiv: + break; + case IKVM.ByteCode.OpCode.Fdiv: + break; + case IKVM.ByteCode.OpCode.Ddiv: + break; + case IKVM.ByteCode.OpCode.Irem: + break; + case IKVM.ByteCode.OpCode.Lrem: + break; + case IKVM.ByteCode.OpCode.Frem: + break; + case IKVM.ByteCode.OpCode.Drem: + break; + case IKVM.ByteCode.OpCode.Ineg: + break; + case IKVM.ByteCode.OpCode.Lneg: + break; + case IKVM.ByteCode.OpCode.Fneg: + break; + case IKVM.ByteCode.OpCode.Dneg: + break; + case IKVM.ByteCode.OpCode.Ishl: + break; + case IKVM.ByteCode.OpCode.Lshl: + break; + case IKVM.ByteCode.OpCode.Ishr: + break; + case IKVM.ByteCode.OpCode.Lshr: + break; + case IKVM.ByteCode.OpCode.Iushr: + break; + case IKVM.ByteCode.OpCode.Lushr: + break; + case IKVM.ByteCode.OpCode.Iand: + break; + case IKVM.ByteCode.OpCode.Land: + break; + case IKVM.ByteCode.OpCode.Ior: + break; + case IKVM.ByteCode.OpCode.Lor: + break; + case IKVM.ByteCode.OpCode.Ixor: + break; + case IKVM.ByteCode.OpCode.Lxor: + break; + case IKVM.ByteCode.OpCode.Iinc: + var _iinc = instruction.AsIinc(); + arg1 = _iinc.Local; + arg2 = _iinc.Value; + break; + case IKVM.ByteCode.OpCode.I2l: + break; + case IKVM.ByteCode.OpCode.I2f: + break; + case IKVM.ByteCode.OpCode.I2d: + break; + case IKVM.ByteCode.OpCode.L2i: + break; + case IKVM.ByteCode.OpCode.L2f: + break; + case IKVM.ByteCode.OpCode.L2d: + break; + case IKVM.ByteCode.OpCode.F2i: + break; + case IKVM.ByteCode.OpCode.F2l: + break; + case IKVM.ByteCode.OpCode.F2d: + break; + case IKVM.ByteCode.OpCode.D2i: + break; + case IKVM.ByteCode.OpCode.D2l: + break; + case IKVM.ByteCode.OpCode.D2f: + break; + case IKVM.ByteCode.OpCode.I2b: + break; + case IKVM.ByteCode.OpCode.I2c: + break; + case IKVM.ByteCode.OpCode.I2s: + break; + case IKVM.ByteCode.OpCode.Lcmp: + break; + case IKVM.ByteCode.OpCode.Fcmpl: + break; + case IKVM.ByteCode.OpCode.Fcmpg: + break; + case IKVM.ByteCode.OpCode.Dcmpl: + break; + case IKVM.ByteCode.OpCode.Dcmpg: + break; + case IKVM.ByteCode.OpCode.Ifeq: + var _ifeq = instruction.AsIfeq(); + arg1 = _ifeq.Target; + break; + case IKVM.ByteCode.OpCode.Ifne: + var _ifne = instruction.AsIfne(); + arg1 = _ifne.Target; + break; + case IKVM.ByteCode.OpCode.Iflt: + var _iflt = instruction.AsIflt(); + arg1 = _iflt.Target; + break; + case IKVM.ByteCode.OpCode.Ifge: + var _ifge = instruction.AsIfge(); + arg1 = _ifge.Target; + break; + case IKVM.ByteCode.OpCode.Ifgt: + var _ifgt = instruction.AsIfgt(); + arg1 = _ifgt.Target; + break; + case IKVM.ByteCode.OpCode.Ifle: + var _ifle = instruction.AsIfle(); + arg1 = _ifle.Target; + break; + case IKVM.ByteCode.OpCode.IfIcmpeq: + var _ificmpeq = instruction.AsIfIcmpeq(); + arg1 = _ificmpeq.Target; + break; + case IKVM.ByteCode.OpCode.IfIcmpne: + var _ificmpne = instruction.AsIfIcmpne(); + arg1 = _ificmpne.Target; + break; + case IKVM.ByteCode.OpCode.IfIcmplt: + var _ificmplt = instruction.AsIfIcmplt(); + arg1 = _ificmplt.Target; + break; + case IKVM.ByteCode.OpCode.IfIcmpge: + var _ificmpge = instruction.AsIfIcmpge(); + arg1 = _ificmpge.Target; + break; + case IKVM.ByteCode.OpCode.IfIcmpgt: + var _ificmpgt = instruction.AsIfIcmpgt(); + arg1 = _ificmpgt.Target; + break; + case IKVM.ByteCode.OpCode.IfIcmple: + var _ificmple = instruction.AsIfIcmple(); + arg1 = _ificmple.Target; + break; + case IKVM.ByteCode.OpCode.IfAcmpeq: + var _ifacmpeq = instruction.AsIfAcmpeq(); + arg1 = _ifacmpeq.Target; + break; + case IKVM.ByteCode.OpCode.IfAcmpne: + var _ifacmpne = instruction.AsIfAcmpne(); + arg1 = _ifacmpne.Target; + break; + case IKVM.ByteCode.OpCode.Goto: + var _goto = instruction.AsGoto(); + arg1 = _goto.Target; + break; + case IKVM.ByteCode.OpCode.Jsr: + var _jsr = instruction.AsJsr(); + arg1 = _jsr.Target; + break; + case IKVM.ByteCode.OpCode.Ret: + var _ret = instruction.AsRet(); + arg1 = _ret.Local; + break; + case IKVM.ByteCode.OpCode.Ireturn: + break; + case IKVM.ByteCode.OpCode.Lreturn: + break; + case IKVM.ByteCode.OpCode.Freturn: + break; + case IKVM.ByteCode.OpCode.Dreturn: + break; + case IKVM.ByteCode.OpCode.Areturn: + break; + case IKVM.ByteCode.OpCode.Return: + break; + case IKVM.ByteCode.OpCode.GetStatic: + var _getstatic = instruction.AsGetStatic(); + arg1 = _getstatic.Field.Slot; + classFile.MarkLinkRequiredConstantPoolItem(arg1); + break; + case IKVM.ByteCode.OpCode.PutStatic: + var _putstatic = instruction.AsPutStatic(); + arg1 = _putstatic.Field.Slot; + classFile.MarkLinkRequiredConstantPoolItem(arg1); + break; + case IKVM.ByteCode.OpCode.GetField: + var _getfield = instruction.AsGetField(); + arg1 = _getfield.Field.Slot; + classFile.MarkLinkRequiredConstantPoolItem(arg1); + break; + case IKVM.ByteCode.OpCode.PutField: + var _putfield = instruction.AsPutField(); + arg1 = _putfield.Field.Slot; + classFile.MarkLinkRequiredConstantPoolItem(arg1); + break; + case IKVM.ByteCode.OpCode.InvokeVirtual: + var _invokevirtual = instruction.AsInvokeVirtual(); + arg1 = _invokevirtual.Method.Slot; + classFile.MarkLinkRequiredConstantPoolItem(arg1); + break; + case IKVM.ByteCode.OpCode.InvokeSpecial: + var _invokespecial = instruction.AsInvokeSpecial(); + arg1 = _invokespecial.Method.Slot; + classFile.MarkLinkRequiredConstantPoolItem(arg1); + break; + case IKVM.ByteCode.OpCode.InvokeStatic: + var _invokestatic = instruction.AsInvokeStatic(); + arg1 = _invokestatic.Method.Slot; + classFile.MarkLinkRequiredConstantPoolItem(arg1); + break; + case IKVM.ByteCode.OpCode.InvokeInterface: + var _invokeinterface = instruction.AsInvokeInterface(); + if (_invokeinterface.Zero != 0) + throw new ClassFormatError("invokeinterface filler must be zero"); + + arg1 = _invokeinterface.Method.Slot; + arg2 = _invokeinterface.Count; + classFile.MarkLinkRequiredConstantPoolItem(arg1); + break; + case IKVM.ByteCode.OpCode.InvokeDynamic: + var _invokedynamic = instruction.AsInvokeDynamic(); + if (_invokedynamic.Zero != 0) + throw new ClassFormatError("invokedynamic filler must be zero"); + if (_invokedynamic.Zero2 != 0) + throw new ClassFormatError("invokedynamic filler must be zero"); + + arg1 = _invokedynamic.Method.Slot; + classFile.MarkLinkRequiredConstantPoolItem(arg1); + break; + case IKVM.ByteCode.OpCode.New: + var _new = instruction.AsNew(); + arg1 = _new.Constant.Slot; + classFile.MarkLinkRequiredConstantPoolItem(arg1); + break; + case IKVM.ByteCode.OpCode.Newarray: + var _newarray = instruction.AsNewarray(); + arg1 = _newarray.Value; + break; + case IKVM.ByteCode.OpCode.Anewarray: + var _anewarray = instruction.AsAnewarray(); + arg1 = _anewarray.Constant.Slot; + classFile.MarkLinkRequiredConstantPoolItem(arg1); + break; + case IKVM.ByteCode.OpCode.Arraylength: + break; + case IKVM.ByteCode.OpCode.Athrow: + break; + case IKVM.ByteCode.OpCode.Checkcast: + var _checkcast = instruction.AsCheckcast(); + arg1 = _checkcast.Type.Slot; + classFile.MarkLinkRequiredConstantPoolItem(arg1); + break; + case IKVM.ByteCode.OpCode.InstanceOf: + var _instanceof = instruction.AsInstanceOf(); + arg1 = _instanceof.Type.Slot; + classFile.MarkLinkRequiredConstantPoolItem(arg1); + break; + case IKVM.ByteCode.OpCode.MonitorEnter: + break; + case IKVM.ByteCode.OpCode.MonitorExit: + break; + case IKVM.ByteCode.OpCode.Multianewarray: + var _multianewarray = instruction.AsMultianewarray(); + arg1 = _multianewarray.Type.Slot; + classFile.MarkLinkRequiredConstantPoolItem(arg1); + arg2 = _multianewarray.Dimensions; + break; + case IKVM.ByteCode.OpCode.IfNull: + var _ifnull = instruction.AsIfNull(); + arg1 = _ifnull.Target; + break; + case IKVM.ByteCode.OpCode.IfNonNull: + var _ifnonnull = instruction.AsIfNonNull(); + arg1 = _ifnonnull.Target; + break; + case IKVM.ByteCode.OpCode.GotoW: + var _gotow = instruction.AsGotoW(); + arg1 = _gotow.Target; + break; + case IKVM.ByteCode.OpCode.JsrW: + var _jsrw = instruction.AsJsrW(); + arg1 = _jsrw.Target; + break; + case IKVM.ByteCode.OpCode.LookupSwitch: + var _lookupswitch = instruction.AsLookupSwitch(); + if (_lookupswitch.Cases.Count < 0 || _lookupswitch.Cases.Count > 16384) + throw new ClassFormatError("Incorrect lookupswitch"); + + arg1 = _lookupswitch.DefaultTarget; + + var _lookupswitchindex = 0; + var lookupswitchentries = new SwitchEntry[_lookupswitch.Cases.Count]; + foreach (var _case in _lookupswitch.Cases) + { + lookupswitchentries[_lookupswitchindex].value = _case.Key; + lookupswitchentries[_lookupswitchindex].value = _case.Target; + _lookupswitchindex++; + } + + switch_entries = lookupswitchentries; + break; + case IKVM.ByteCode.OpCode.TableSwitch: + var _tableswitch = instruction.AsTableSwitch(); + if (_tableswitch.Low > _tableswitch.High || _tableswitch.High > 16384L + _tableswitch.Low) + throw new ClassFormatError("Incorrect tableswitch"); + + arg1 = _tableswitch.DefaultTarget; + + var _tableswitchindex = 0; + var tableswitchentries = new SwitchEntry[_tableswitch.Cases.Count]; + foreach (var _case in _tableswitch.Cases) + { + tableswitchentries[_tableswitchindex].value = _tableswitch.Low + _tableswitchindex; + tableswitchentries[_tableswitchindex].value = _case; + _tableswitchindex++; + } + + switch_entries = tableswitchentries; + break; + default: + throw new ClassFormatError($"Invalid opcode: {instruction.OpCode}"); + } + + this.normopcode = ByteCodeMetaData.GetNormalizedByteCode((ByteCode)(int)instruction.OpCode); + arg1 = ByteCodeMetaData.GetArg((ByteCode)(int)instruction.OpCode, arg1); + } + catch (ArgumentOutOfRangeException) + { + throw new ClassFormatError($"Invalid instruction data: {instruction.OpCode}"); } - - this.normopcode = ByteCodeMetaData.GetNormalizedByteCode((ByteCode)(int)instruction.OpCode); - arg1 = ByteCodeMetaData.GetArg((ByteCode)(int)instruction.OpCode, arg1); } internal int PC => pc; diff --git a/src/IKVM.Util/IKVM.Util.csproj b/src/IKVM.Util/IKVM.Util.csproj index cea3b7dcfc..c6c37d2e10 100644 --- a/src/IKVM.Util/IKVM.Util.csproj +++ b/src/IKVM.Util/IKVM.Util.csproj @@ -8,7 +8,7 @@ - + From edd21ced8d2ca8ea11b65073fa94cf7ec6617979 Mon Sep 17 00:00:00 2001 From: Jerome Haltom Date: Sat, 17 Aug 2024 19:07:45 -0500 Subject: [PATCH 3/5] Fix Index/Range thing. Might as well keep this. But it's unrelated to this PR. Latest ByteCode release. --- IKVM.deps.targets | 2 +- src/IKVM.Runtime/ClassFile.Method.Instruction.cs | 4 ++-- src/IKVM.Runtime/System/Index.cs | 4 +++- src/IKVM.Runtime/System/Range.cs | 6 ++++-- .../System/Runtime/CompilerServices/RuntimeHelpers.cs | 5 ----- src/IKVM.Util/IKVM.Util.csproj | 2 +- 6 files changed, 11 insertions(+), 12 deletions(-) diff --git a/IKVM.deps.targets b/IKVM.deps.targets index 5b7a3754e7..f2ef26dcb7 100644 --- a/IKVM.deps.targets +++ b/IKVM.deps.targets @@ -1,7 +1,7 @@ - + diff --git a/src/IKVM.Runtime/ClassFile.Method.Instruction.cs b/src/IKVM.Runtime/ClassFile.Method.Instruction.cs index f4f7d0cf82..c61f085dc1 100644 --- a/src/IKVM.Runtime/ClassFile.Method.Instruction.cs +++ b/src/IKVM.Runtime/ClassFile.Method.Instruction.cs @@ -670,7 +670,7 @@ internal void Read(IKVM.ByteCode.Decoding.Instruction instruction, ClassFile cla foreach (var _case in _lookupswitch.Cases) { lookupswitchentries[_lookupswitchindex].value = _case.Key; - lookupswitchentries[_lookupswitchindex].value = _case.Target; + lookupswitchentries[_lookupswitchindex].target = _case.Target; _lookupswitchindex++; } @@ -688,7 +688,7 @@ internal void Read(IKVM.ByteCode.Decoding.Instruction instruction, ClassFile cla foreach (var _case in _tableswitch.Cases) { tableswitchentries[_tableswitchindex].value = _tableswitch.Low + _tableswitchindex; - tableswitchentries[_tableswitchindex].value = _case; + tableswitchentries[_tableswitchindex].target = _case; _tableswitchindex++; } diff --git a/src/IKVM.Runtime/System/Index.cs b/src/IKVM.Runtime/System/Index.cs index 15312fffdc..566d892d32 100644 --- a/src/IKVM.Runtime/System/Index.cs +++ b/src/IKVM.Runtime/System/Index.cs @@ -2,7 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#if NETSTANDARD2_1 +#if NETSTANDARD2_1 || NET +using System.Runtime.CompilerServices; + [assembly: TypeForwardedTo(typeof(System.Index))] #else using System.Runtime.CompilerServices; diff --git a/src/IKVM.Runtime/System/Range.cs b/src/IKVM.Runtime/System/Range.cs index 45884ff5d2..7d536244c0 100644 --- a/src/IKVM.Runtime/System/Range.cs +++ b/src/IKVM.Runtime/System/Range.cs @@ -2,8 +2,10 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#if NETSTANDARD2_1 -[assembly: TypeForwardedTo(typeof(System.Range))] +#if NETSTANDARD2_1 || NET +using System.Runtime.CompilerServices; + +[assembly: TypeForwardedTo(typeof(global::System.Range))] #else using System.Runtime.CompilerServices; diff --git a/src/IKVM.Runtime/System/Runtime/CompilerServices/RuntimeHelpers.cs b/src/IKVM.Runtime/System/Runtime/CompilerServices/RuntimeHelpers.cs index 6ca51f3a78..e69de29bb2 100644 --- a/src/IKVM.Runtime/System/Runtime/CompilerServices/RuntimeHelpers.cs +++ b/src/IKVM.Runtime/System/Runtime/CompilerServices/RuntimeHelpers.cs @@ -1,5 +0,0 @@ -#if NETFRAMEWORK - - - -#endif diff --git a/src/IKVM.Util/IKVM.Util.csproj b/src/IKVM.Util/IKVM.Util.csproj index c6c37d2e10..4b20341d19 100644 --- a/src/IKVM.Util/IKVM.Util.csproj +++ b/src/IKVM.Util/IKVM.Util.csproj @@ -8,7 +8,7 @@ - + From c17401dd35b8fd68ea1cbfaf41e10ef9c9fd4a15 Mon Sep 17 00:00:00 2001 From: Jerome Haltom Date: Sat, 17 Aug 2024 21:22:36 -0500 Subject: [PATCH 4/5] Ensure we keep last nop in the right place. --- src/IKVM.Runtime/ClassFile.Method.Code.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/IKVM.Runtime/ClassFile.Method.Code.cs b/src/IKVM.Runtime/ClassFile.Method.Code.cs index d45d8b0b74..d12a3e79dd 100644 --- a/src/IKVM.Runtime/ClassFile.Method.Code.cs +++ b/src/IKVM.Runtime/ClassFile.Method.Code.cs @@ -76,17 +76,20 @@ internal void Read(ClassFile classFile, string[] utf8_cp, Method method, CodeAtt try { var decoder = new CodeDecoder(attribute.Code); + var lastIns = default(IKVM.ByteCode.Decoding.Instruction); // read instructions and parse them into local structure foreach (var instruction in decoder) { + lastIns = instruction; + _instructions[instructionCount].Read(instruction, classFile); hasJsr |= _instructions[instructionCount].NormalizedOpCode == NormalizedByteCode.__jsr; instructionCount++; } // we add an additional nop instruction to make it easier for consumers of the code array - _instructions[instructionCount++].SetTermNop((ushort)decoder.Position.GetInteger()); + _instructions[instructionCount++].SetTermNop((ushort)(lastIns.IsNotNil ? lastIns.Offset + lastIns.Data.Length : 0)); } catch (ArgumentOutOfRangeException e) { @@ -107,8 +110,7 @@ internal void Read(ClassFile classFile, string[] utf8_cp, Method method, CodeAtt // build the pcIndexMap var pcIndexMap = new int[instructions[instructionCount - 1].PC + 1]; - for (int i = 0; i < pcIndexMap.Length; i++) - pcIndexMap[i] = -1; + pcIndexMap.AsSpan().Fill(-1); for (int i = 0; i < instructionCount - 1; i++) pcIndexMap[instructions[i].PC] = i; From f9de90a1269204fca8efb79077f88fe2b229a6ba Mon Sep 17 00:00:00 2001 From: Jerome Haltom Date: Sun, 18 Aug 2024 10:10:58 -0500 Subject: [PATCH 5/5] Fix from rename --- src/IKVM.Util/Jar/JarFileExtensions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/IKVM.Util/Jar/JarFileExtensions.cs b/src/IKVM.Util/Jar/JarFileExtensions.cs index 63e03088c0..14893f23a6 100644 --- a/src/IKVM.Util/Jar/JarFileExtensions.cs +++ b/src/IKVM.Util/Jar/JarFileExtensions.cs @@ -45,7 +45,7 @@ static ModuleInfo GetModuleInfoFromClass(JarFile jar) using var s = e.Open(); using var c = ClassFile.Read(s); - if ((c.AccessFlags & AccessFlag.ACC_MODULE) != 0) + if ((c.AccessFlags & AccessFlag.Module) != 0) { var a = c.Attributes.FirstOrDefault(i => i.IsNotNil && i.Name.IsNotNil && c.Constants.Get(i.Name).Value == AttributeName.Module); if (a.IsNotNil)