26using System.Collections.Generic;
29using IKVM.ByteCode.Decoding;
34 sealed partial class ClassFile
37 internal sealed partial class Method
44 internal string verifyError;
45 internal ushort max_stack;
46 internal ushort max_locals;
49 internal int[] argmap;
50 internal LineNumberTableEntry[] lineNumberTable;
62 internal void Read(ClassFile classFile,
string[] utf8_cp, Method method, CodeAttribute attribute,
ClassFileParseOptions options)
64 max_stack = attribute.MaxStack;
65 max_locals = attribute.MaxLocals;
66 if (attribute.Code.Length == 0 || attribute.Code.Length > 65535)
67 throw new ClassFormatError(
"Invalid method Code length {1} in class file {0}", classFile.Name, attribute.Code.Length);
70 var _instructions = ArrayPool<Instruction>.Shared.Rent((
int)attribute.Code.Length + 1);
74 int instructionCount = 0;
78 var decoder =
new CodeDecoder(attribute.Code);
79 var lastIns =
default(
IKVM.ByteCode.Decoding.Instruction);
82 foreach (var instruction
in decoder)
84 lastIns = instruction;
86 _instructions[instructionCount].Read(instruction, classFile);
87 hasJsr |= _instructions[instructionCount].NormalizedOpCode ==
NormalizedByteCode.__jsr;
92 _instructions[instructionCount++].SetTermNop((ushort)(lastIns.IsNotNil ? lastIns.Offset + lastIns.Data.Length : 0));
94 catch (ArgumentOutOfRangeException e)
96 verifyError = e.Message;
100 verifyError = e.Message;
102 catch (ByteCodeException e)
104 verifyError = e.Message;
109 Array.Copy(_instructions, 0, instructions, 0, instructionCount);
112 var pcIndexMap =
new int[instructions[instructionCount - 1].PC + 1];
113 pcIndexMap.AsSpan().Fill(-1);
114 for (
int i = 0; i < instructionCount - 1; i++)
115 pcIndexMap[instructions[i].PC] = i;
118 for (
int i = 0; i < instructionCount - 1; i++)
120 switch (instructions[i].NormalizedOpCode)
140 this.instructions[i].SetTargetIndex(pcIndexMap[this.instructions[i].Arg1 + this.instructions[i].PC]);
144 this.instructions[i].MapSwitchTargets(pcIndexMap);
151 for (
int i = 0; i < attribute.ExceptionTable.Count; i++)
153 var handler = attribute.ExceptionTable[i];
154 var start_pc = handler.StartOffset;
155 var end_pc = handler.EndOffset;
156 var handler_pc = handler.HandlerOffset;
157 var catch_type = handler.CatchType;
159 if (start_pc >= end_pc || end_pc > attribute.Code.Length || handler_pc >= attribute.Code.Length || (catch_type.IsNotNil && !classFile.SafeIsConstantPoolClass(catch_type)))
160 throw new ClassFormatError(
"Illegal exception table: {0}.{1}{2}", classFile.Name, method.Name, method.Signature);
162 classFile.MarkLinkRequiredConstantPoolItem(catch_type);
166 var startIndex = pcIndexMap[start_pc];
168 if (end_pc == attribute.Code.Length)
173 endIndex = instructionCount - 1;
177 endIndex = pcIndexMap[end_pc];
180 var handlerIndex = pcIndexMap[handler_pc];
181 exception_table[i] =
new ExceptionTableEntry(startIndex, endIndex, handlerIndex, catch_type, i);
184 foreach (var _attribute
in attribute.Attributes)
186 switch (classFile.GetConstantPoolUtf8String(utf8_cp, _attribute.Name))
188 case AttributeName.LineNumberTable:
189 var lnt = (
IKVM.ByteCode.Decoding.LineNumberTableAttribute)_attribute;
192 lineNumberTable =
new LineNumberTableEntry[lnt.LineNumbers.Count];
193 for (
int j = 0; j < lnt.LineNumbers.Count; j++)
195 var item = lnt.LineNumbers[j];
196 lineNumberTable[j].start_pc = item.StartPc;
197 lineNumberTable[j].line_number = item.LineNumber;
198 if (lineNumberTable[j].start_pc >= attribute.Code.Length)
199 throw new ClassFormatError(
"{0} (LineNumberTable has invalid pc)", classFile.Name);
203 case AttributeName.LocalVariableTable:
204 var lvt = (
IKVM.ByteCode.Decoding.LocalVariableTableAttribute)_attribute;
208 for (
int j = 0; j < lvt.LocalVariables.Count; j++)
210 var item = lvt.LocalVariables[j];
211 localVariableTable[j].start_pc = item.StartPc;
212 localVariableTable[j].length = item.Length;
213 localVariableTable[j].name = classFile.GetConstantPoolUtf8String(utf8_cp, item.Name);
214 localVariableTable[j].descriptor = classFile.GetConstantPoolUtf8String(utf8_cp, item.Descriptor).Replace(
'/',
'.');
215 localVariableTable[j].index = item.Slot;
225 var sig = method.Signature;
226 var args =
new List<int>();
228 if (!method.IsStatic)
231 for (
int i = 1; sig[i] !=
')'; i++)
237 i = sig.IndexOf(
';', i);
245 while (sig[i] ==
'[')
251 i = sig.IndexOf(
';', i);
257 argmap = args.ToArray();
259 if (args.Count > max_locals)
260 throw new ClassFormatError(
"{0} (Arguments can't fit into locals)", classFile.Name);
262 catch (InvalidCodeException e)
266 catch (ByteCodeException e)
272 ArrayPool<Instruction>.Shared.Return(_instructions);
276 internal bool IsEmpty => instructions ==
null;
IKVM.Runtime.ClassFile.Method.Instruction Instruction
IKVM.Runtime.ClassFile.Method.LocalVariableTableEntry LocalVariableTableEntry
IKVM.Runtime.ClassFile.Method.ExceptionTableEntry ExceptionTableEntry