48 var ma =
new JsrMethodAnalyzer(mw, classFile, m, classLoader, flags);
49 inliner =
new JsrInliner(codeCopy, flags, m, ma);
50 }
while (inliner.InlineJsrs());
56 readonly ClassFile.Method m;
57 readonly JsrMethodAnalyzer ma;
68 this.codeCopy = codeCopy;
69 codeLength = codeCopy.Length;
77 if (codeLength == codeCopy.Length)
79 Array.Resize(
ref codeCopy, codeLength * 2);
80 Array.Resize(
ref flags, codeLength * 2);
83 codeCopy[codeLength++] = instr;
93 var subs =
new List<SubroutineCall>();
96 for (
int i = 0; i < len; i++)
102 int subroutineId = m.Instructions[i].TargetIndex;
104 var sub =
new SubroutineCall(
this, subroutineId, i + 1);
105 hasJsrs |= sub.InlineSubroutine();
111 foreach (var sub
in subs)
112 sub.DoExceptions(m.ExceptionTable, exceptions);
114 m.ExceptionTable = exceptions.ToArray();
116 instr.SetTermNop(0xFFFF);
118 Array.Resize(
ref codeCopy, codeLength);
120 m.Instructions = codeCopy;
124 sealed class SubroutineCall
128 readonly
int subroutineIndex;
129 readonly
int returnIndex;
130 readonly
int[] branchMap;
131 readonly
int baseIndex;
140 internal SubroutineCall(
JsrInliner inliner,
int subroutineIndex,
int returnIndex)
142 this.inliner = inliner;
143 this.subroutineIndex = subroutineIndex;
144 this.returnIndex = returnIndex;
145 baseIndex = inliner.codeLength;
146 branchMap =
new int[inliner.m.Instructions.Length];
147 for (
int i = 0; i < branchMap.Length; i++)
156 void EmitGoto(
int targetIndex)
164 internal bool InlineSubroutine()
173 instr.SetPC(inliner.m.Instructions[subroutineIndex].PC);
175 EmitGoto(subroutineIndex);
178 var fallThru =
false;
179 for (
int instructionIndex = 0; instructionIndex < inliner.m.Instructions.Length; instructionIndex++)
181 if ((inliner.flags[instructionIndex] &
InstructionFlags.Reachable) != 0 && inliner.ma.IsSubroutineActive(instructionIndex, subroutineIndex))
184 branchMap[instructionIndex] = inliner.codeLength;
186 switch (inliner.m.Instructions[instructionIndex].NormalizedOpCode)
198 Emit(inliner.m.Instructions[instructionIndex]);
205 int subid = inliner.ma.GetLocalTypeWrapper(instructionIndex, inliner.m.Instructions[instructionIndex].TargetIndex).SubroutineIndex;
206 if (subid == subroutineIndex)
207 EmitGoto(returnIndex);
209 Emit(inliner.m.Instructions[instructionIndex]);
214 Emit(inliner.m.Instructions[instructionIndex]);
220 EmitGoto(instructionIndex);
224 endIndex = inliner.codeLength;
231 for (
int instructionIndex = baseIndex; instructionIndex < endIndex; instructionIndex++)
233 switch (inliner.codeCopy[instructionIndex].NormalizedOpCode)
238 var targets =
new int[inliner.codeCopy[instructionIndex].SwitchEntryCount];
239 for (
int i = 0; i < targets.Length; i++)
240 targets[i] = branchMap[inliner.codeCopy[instructionIndex].GetSwitchTargetIndex(i)];
242 inliner.codeCopy[instructionIndex].SetSwitchTargets(targets);
243 inliner.codeCopy[instructionIndex].DefaultTarget = branchMap[inliner.codeCopy[instructionIndex].DefaultTarget];
264 inliner.codeCopy[instructionIndex].TargetIndex = branchMap[inliner.codeCopy[instructionIndex].TargetIndex];
270 int MapExceptionStartEnd(
int index)
272 while (branchMap[index] < baseIndex)
275 if (index == branchMap.Length)
279 return branchMap[index];
284 foreach (var entry
in table)
286 int start = MapExceptionStartEnd(entry.startIndex);
287 int end = MapExceptionStartEnd(entry.endIndex);
291 newExceptions.Add(newEntry);
304 sealed class ReturnAddressType : SimpleType
307 internal readonly
int subroutineIndex;
309 internal ReturnAddressType(
int subroutineIndex)
311 this.subroutineIndex = subroutineIndex;
316 internal static readonly SimpleType Invalid =
null;
317 internal static readonly SimpleType Primitive =
new SimpleType();
318 internal static readonly SimpleType WidePrimitive =
new SimpleType();
319 internal static readonly SimpleType Object =
new SimpleType();
320 internal static readonly SimpleType[] EmptyArray = [];
330 internal bool IsPrimitive =>
this == SimpleType.Primitive ||
this == SimpleType.WidePrimitive;
332 internal bool IsWidePrimitive =>
this == SimpleType.WidePrimitive;
334 internal static SimpleType MakeRet(
int subroutineIndex)
336 return new ReturnAddressType(subroutineIndex);
339 internal static bool IsRet(SimpleType w)
341 return w is ReturnAddressType;
344 internal int SubroutineIndex => ((ReturnAddressType)
this).subroutineIndex;
348 sealed class JsrMethodAnalyzer
353 readonly List<int>[] _callsites;
354 readonly List<int>[] _returnsites;
370 if (method.VerifyError !=
null)
373 _classFile = classFile;
375 _callsites =
new List<int>[method.Instructions.Length];
376 _returnsites =
new List<int>[method.Instructions.Length];
379 var returnAddressTypes =
new Dictionary<int, SimpleType>();
384 for (
int i = 0; i < method.ExceptionTable.Length; i++)
386 int start = method.ExceptionTable[i].startIndex;
387 int end = method.ExceptionTable[i].endIndex;
388 int handler = method.ExceptionTable[i].handlerIndex;
389 if (start >= end || start == -1 || end == -1 || handler <= 0)
390 throw new IndexOutOfRangeException();
393 catch (IndexOutOfRangeException)
395 throw new ClassFormatError(
string.Format(
"Illegal exception table (class: {0}, method: {1}, signature: {2}", classFile.Name, method.Name, method.Signature));
401 int firstNonArgLocalIndex = 0;
402 if (method.IsStatic ==
false)
404 thisType = SimpleType.Object;
405 _state[0].SetLocalType(firstNonArgLocalIndex++, thisType, -1);
412 var argTypeWrappers = mw.GetParameters();
413 for (
int i = 0; i < argTypeWrappers.Length; i++)
415 var tw = argTypeWrappers[i];
418 if (tw.IsWidePrimitive)
420 type = SimpleType.WidePrimitive;
422 else if (tw.IsPrimitive)
424 type = SimpleType.Primitive;
428 type = SimpleType.Object;
431 _state[0].SetLocalType(firstNonArgLocalIndex++, type, -1);
432 if (type.IsWidePrimitive)
433 firstNonArgLocalIndex++;
436 var argumentsByLocalIndex =
new SimpleType[firstNonArgLocalIndex];
437 for (
int i = 0; i < argumentsByLocalIndex.Length; i++)
438 argumentsByLocalIndex[i] = _state[0].GetLocalTypeEx(i);
440 var s = _state[0].Copy();
442 var instructions = method.Instructions;
448 for (
int i = 0; i < instructions.Length; i++)
450 if (_state[i] !=
null && _state[i].changed)
455 _state[i].changed =
false;
458 for (
int j = 0; j < method.ExceptionTable.Length; j++)
459 if (method.ExceptionTable[j].startIndex <= i && i < method.ExceptionTable[j].endIndex)
460 MergeExceptionHandler(method.ExceptionTable[j].handlerIndex, _state[i]);
463 var instr = instructions[i];
465 switch (instr.NormalizedOpCode)
469 var type = s.GetLocalType(instr.NormalizedArg1);
470 if (type == SimpleType.Invalid || type.IsPrimitive)
471 throw new VerifyError(
"Object reference expected");
477 s.SetLocalType(instr.NormalizedArg1, s.PopObjectType(), i);
535 s.PushWidePrimitive();
538 s.PopWidePrimitive();
545 s.PushWidePrimitive();
548 s.PopWidePrimitive();
596 s.PushType(GetFieldref(instr.Arg1).Signature);
599 s.PopType(GetFieldref(instr.Arg1).Signature);
603 s.PushType(GetFieldref(instr.Arg1).Signature);
606 s.PopType(GetFieldref(instr.Arg1).Signature);
611 switch (GetConstantPoolConstantType(instr.Arg1))
614 s.PushWidePrimitive();
623 s.PushWidePrimitive();
632 throw new InvalidOperationException();
641 var cpi = GetMethodref(instr.Arg1);
642 s.MultiPopAnyType(cpi.GetArgTypes().Length);
646 var sig = cpi.Signature;
647 sig = sig.Substring(sig.IndexOf(
')') + 1);
656 s.SetLocalPrimitive(instr.NormalizedArg1, i);
681 s.PopWidePrimitive();
682 s.PushWidePrimitive();
692 s.PopWidePrimitive();
693 s.PopWidePrimitive();
694 s.PushWidePrimitive();
700 s.PopWidePrimitive();
701 s.PushWidePrimitive();
717 s.PopWidePrimitive();
718 s.PushWidePrimitive();
725 s.PopWidePrimitive();
726 s.PopWidePrimitive();
727 s.PushWidePrimitive();
735 throw new VerifyError(
"Illegal dimension argument");
737 for (
int j = 0; j < instr.Arg2; j++)
753 var t1 = s.PopType();
754 var t2 = s.PopType();
768 var t = s.PopAnyType();
769 if (t.IsWidePrimitive)
776 var t2 = s.PopType();
786 var value1 = s.PopType();
787 var value2 = s.PopType();
795 var value1 = s.PopAnyType();
796 if (value1.IsWidePrimitive)
798 var value2 = s.PopType();
805 var value2 = s.PopType();
806 var value3 = s.PopType();
817 var value1 = s.PopType();
818 var value2 = s.PopAnyType();
819 if (value2.IsWidePrimitive)
827 var value3 = s.PopType();
837 var value1 = s.PopAnyType();
838 if (value1.IsWidePrimitive)
840 var value2 = s.PopAnyType();
841 if (value2.IsWidePrimitive)
851 var value3 = s.PopType();
860 var value2 = s.PopType();
861 var value3 = s.PopAnyType();
862 if (value3.IsWidePrimitive)
874 var value4 = s.PopType();
890 var type = s.PopAnyType();
891 if (!type.IsWidePrimitive)
909 s.PopWidePrimitive();
915 s.PopWidePrimitive();
922 s.SetLocalPrimitive(instr.NormalizedArg1, i);
925 s.PushWidePrimitive();
928 s.PopWidePrimitive();
929 s.SetLocalWidePrimitive(instr.NormalizedArg1, i);
932 s.PushWidePrimitive();
935 s.PopWidePrimitive();
936 s.SetLocalWidePrimitive(instr.NormalizedArg1, i);
940 s.PushWidePrimitive();
949 s.PushWidePrimitive();
952 s.PopWidePrimitive();
953 s.PopWidePrimitive();
964 s.PopWidePrimitive();
965 s.PopWidePrimitive();
999 s.PushWidePrimitive();
1007 s.PushWidePrimitive();
1010 s.PopWidePrimitive();
1014 s.PopWidePrimitive();
1018 s.PopWidePrimitive();
1019 s.PushWidePrimitive();
1027 s.PushWidePrimitive();
1031 s.PushWidePrimitive();
1034 s.PopWidePrimitive();
1038 s.PopWidePrimitive();
1042 s.PopWidePrimitive();
1043 s.PushWidePrimitive();
1052 var subroutineIndex = s.GetLocalRet(instr.Arg1);
1053 s.CheckSubroutineActive(subroutineIndex);
1057 if (i + 1 == instructions.Length)
1058 throw new VerifyError(
"Falling off the end of the code");
1063 throw new VerifyError(
"Illegal type in constant pool");
1065 throw new NotImplementedException(instr.NormalizedOpCode.ToString());
1068 if (s.GetStackHeight() > method.MaxStack)
1071 for (
int j = 0; j < method.ExceptionTable.Length; j++)
1072 if (method.ExceptionTable[j].endIndex == i + 1)
1073 MergeExceptionHandler(method.ExceptionTable[j].handlerIndex, s);
1078 switch (instr.NormalizedOpCode)
1082 for (
int j = 0; j < instr.SwitchEntryCount; j++)
1084 _state[instr.GetSwitchTargetIndex(j)] += s;
1086 _state[instr.DefaultTarget] += s;
1105 _state[instr.TargetIndex] += s;
1108 _state[instr.TargetIndex] += s;
1112 int index = instr.TargetIndex;
1113 s.SetSubroutineId(index);
1115 if (returnAddressTypes.TryGetValue(index, out var retAddressType) ==
false)
1117 retAddressType = SimpleType.MakeRet(index);
1118 returnAddressTypes[index] = retAddressType;
1121 s.PushType(retAddressType);
1124 var returns = GetReturnSites(i);
1125 if (returns !=
null)
1126 foreach (
int returnIndex
in returns)
1127 _state[i + 1] =
InstructionState.MergeSubroutineReturn(_state[i + 1], s, _state[returnIndex], _state[returnIndex].GetLocalsModified(index));
1129 AddCallSite(index, i);
1137 var subroutineIndex = s.GetLocalRet(instr.Arg1);
1138 var cs = GetCallSites(subroutineIndex);
1139 var locals_modified = s.GetLocalsModified(subroutineIndex);
1140 for (
int j = 0; j < cs.Length; j++)
1142 AddReturnSite(cs[j], i);
1143 _state[cs[j] + 1] =
InstructionState.MergeSubroutineReturn(_state[cs[j] + 1], _state[cs[j]], s, locals_modified);
1161 catch (IndexOutOfRangeException)
1167 throw new VerifyError(
"Illegal target of jump or branch");
1172 var opcode = instructions[i].NormalizedOpCode.ToString();
1173 if (opcode.StartsWith(
"__"))
1174 opcode = opcode.Substring(2);
1176 throw new VerifyError($
"{x.Message} (class: {classFile.Name}, method: {method.Name}, signature: {method.Signature}, offset: {instructions[i].PC}, instruction: {opcode})", x);
1189 var didJsrOrRet =
false;
1190 for (
int i = 0; i < instructions.Length; i++)
1198 for (
int j = 0; j < method.ExceptionTable.Length; j++)
1199 if (method.ExceptionTable[j].startIndex <= i && i < method.ExceptionTable[j].endIndex)
1200 flags[method.ExceptionTable[j].handlerIndex] |= InstructionFlags.Reachable |
InstructionFlags.BranchTarget;
1203 switch (instructions[i].NormalizedOpCode)
1208 var hasbackbranch =
false;
1209 for (
int j = 0; j < instructions[i].SwitchEntryCount; j++)
1211 hasbackbranch |= instructions[i].GetSwitchTargetIndex(j) < i;
1212 flags[instructions[i].GetSwitchTargetIndex(j)] |= InstructionFlags.Reachable |
InstructionFlags.BranchTarget;
1215 hasbackbranch |= instructions[i].DefaultTarget < i;
1216 flags[instructions[i].DefaultTarget] |= InstructionFlags.Reachable |
InstructionFlags.BranchTarget;
1220 flags[instructions[i].TargetIndex] |= InstructionFlags.Reachable |
InstructionFlags.BranchTarget;
1238 flags[instructions[i].TargetIndex] |= InstructionFlags.Reachable |
InstructionFlags.BranchTarget;
1242 flags[instructions[i].TargetIndex] |= InstructionFlags.Reachable |
InstructionFlags.BranchTarget;
1272 for (
int i = 0; i < instructions.Length; i++)
1276 var subroutineIndex = _state[i].GetLocalRet(instructions[i].Arg1);
1277 var cs = GetCallSites(subroutineIndex);
1278 for (
int j = 0; j < cs.Length; j++)
1280 flags[cs[j] + 1] |= InstructionFlags.Reachable |
InstructionFlags.BranchTarget;
1296 var ex = curr.CopyLocalsAndSubroutines();
1298 _state[handlerIndex] += ex;
1301 ClassFile.ConstantPoolItemMI GetMethodref(
int index)
1305 var item = _classFile.GetMethodref(
new MethodrefConstantHandle(checked((ushort)index)));
1309 catch (OverflowException)
1313 catch (InvalidCastException)
1317 catch (IndexOutOfRangeException)
1322 throw new VerifyError(
"Illegal constant pool index");
1325 ClassFile.ConstantPoolItemFieldref GetFieldref(
int index)
1329 var item = _classFile.GetFieldref(
new FieldrefConstantHandle(checked((ushort)index)));
1333 catch (OverflowException)
1337 catch (InvalidCastException)
1341 catch (IndexOutOfRangeException)
1346 throw new VerifyError(
"Illegal constant pool index");
1349 ClassFile.ConstantType GetConstantPoolConstantType(
int index)
1353 return _classFile.GetConstantPoolConstantType(
new ConstantHandle(ConstantKind.Unknown, checked((ushort)index)));
1355 catch (OverflowException)
1359 catch (InvalidCastException)
1363 catch (IndexOutOfRangeException)
1367 catch (InvalidOperationException)
1371 catch (NullReferenceException)
1376 throw new VerifyError(
"Illegal constant pool index");
1379 void AddReturnSite(
int callSiteIndex,
int returnSiteIndex)
1381 _returnsites[callSiteIndex] ??=
new List<int>();
1383 var l = _returnsites[callSiteIndex];
1384 if (l.IndexOf(returnSiteIndex) == -1)
1386 _state[callSiteIndex].changed =
true;
1387 l.Add(returnSiteIndex);
1391 List<int> GetReturnSites(
int callSiteIndex)
1393 return _returnsites[callSiteIndex];
1396 void AddCallSite(
int subroutineIndex,
int callSiteIndex)
1398 _callsites[subroutineIndex] ??=
new List<int>();
1400 var l = _callsites[subroutineIndex];
1401 if (l.IndexOf(callSiteIndex) == -1)
1403 l.Add(callSiteIndex);
1404 _state[subroutineIndex].AddCallSite();
1408 int[] GetCallSites(
int subroutineIndex)
1410 return _callsites[subroutineIndex].ToArray();
1413 internal SimpleType GetLocalTypeWrapper(
int index,
int local)
1415 return _state[index].GetLocalTypeEx(local);
1418 internal bool IsSubroutineActive(
int instructionIndex,
int subroutineIndex)
1420 return _state[instructionIndex].IsSubroutineActive(subroutineIndex);
1423 sealed class Subroutine
1426 readonly
int subroutineIndex;
1427 readonly
bool[] localsModified;
1434 Subroutine(
int subroutineIndex,
bool[] localsModified)
1436 this.subroutineIndex = subroutineIndex;
1437 this.localsModified = localsModified;
1445 internal Subroutine(
int subroutineIndex,
int maxLocals)
1447 this.subroutineIndex = subroutineIndex;
1448 localsModified =
new bool[maxLocals];
1451 internal int SubroutineIndex => subroutineIndex;
1453 internal bool[] LocalsModified => localsModified;
1455 internal void SetLocalModified(
int local)
1457 localsModified[local] =
true;
1460 internal Subroutine Copy()
1462 return new Subroutine(subroutineIndex, (
bool[])localsModified.Clone());
1470 enum ShareFlags :
byte
1476 All = Stack | Locals | Subroutines
1482 SimpleType[] locals;
1483 List<Subroutine> subroutines;
1485 internal bool changed =
true;
1497 private InstructionState(SimpleType[] stack,
int stackSize,
int stackEnd, SimpleType[] locals, List<Subroutine> subroutines,
int callsites)
1499 this.flags = ShareFlags.All;
1501 this.stackSize = stackSize;
1502 this.stackEnd = stackEnd;
1503 this.locals = locals;
1504 this.subroutines = subroutines;
1505 this.callsites = callsites;
1515 this.flags = ShareFlags.None;
1516 this.stack =
new SimpleType[maxStack];
1517 this.stackEnd = maxStack;
1518 this.locals =
new SimpleType[maxLocals];
1523 return new InstructionState(stack, stackSize, stackEnd, locals, subroutines, callsites);
1528 target.flags = ShareFlags.All;
1529 target.stack = stack;
1530 target.stackSize = stackSize;
1531 target.stackEnd = stackEnd;
1532 target.locals = locals;
1533 target.subroutines = subroutines;
1534 target.callsites = callsites;
1535 target.changed =
true;
1540 var copy =
new InstructionState(
new SimpleType[stack.Length], 0, stack.Length, locals, subroutines, callsites);
1541 copy.flags &= ~ShareFlags.Stack;
1545 private static List<Subroutine> CopySubroutines(List<Subroutine> l)
1550 var n =
new List<Subroutine>(l.Count);
1551 foreach (var s
in l)
1559 if (subroutines ==
null || s2.subroutines ==
null)
1561 if (subroutines !=
null)
1569 SubroutinesCopyOnWrite();
1571 var ss1 = subroutines;
1572 subroutines =
new List<Subroutine>();
1573 foreach (var ss2
in s2.subroutines)
1575 foreach (var ss
in ss1)
1577 if (ss.SubroutineIndex == ss2.SubroutineIndex)
1579 subroutines.Add(ss);
1580 for (
int i = 0; i < ss.LocalsModified.Length; i++)
1582 if (ss2.LocalsModified[i] && !ss.LocalsModified[i])
1584 ss.LocalsModified[i] =
true;
1592 if (ss1.Count != subroutines.Count)
1596 if (s2.callsites > callsites)
1599 callsites = s2.callsites;
1606 var next = ret.Copy();
1609 for (
int i = 0; i < locals_modified.Length; i++)
1610 if (!locals_modified[i])
1611 next.locals[i] = jsr.locals[i];
1613 next.flags |= ShareFlags.Subroutines;
1614 next.subroutines = jsr.subroutines;
1615 next.callsites = jsr.callsites;
1616 return jsrSuccessor + next;
1624 if (s1.stackSize != s2.stackSize || s1.stackEnd != s2.stackEnd)
1625 throw new VerifyError($
"Inconsistent stack height: {s1.stackSize + s1.stack.Length - s1.stackEnd} != {s2.stackSize + s2.stack.Length - s2.stackEnd}");
1628 s.changed = s1.changed;
1629 for (
int i = 0; i < s.stackSize; i++)
1631 var type = s.stack[i];
1632 var type2 = s2.stack[i];
1637 else if (!type.IsPrimitive)
1640 if (baseType == SimpleType.Invalid)
1642 if (SimpleType.IsRet(type) && SimpleType.IsRet(type2))
1649 throw new VerifyError(
string.Format(
"cannot merge {0} and {1}", type, type2));
1652 if (type != baseType)
1654 s.StackCopyOnWrite();
1655 s.stack[i] = baseType;
1661 throw new VerifyError(
string.Format(
"cannot merge {0} and {1}", type, type2));
1665 for (
int i = 0; i < s.locals.Length; i++)
1667 var type = s.locals[i];
1668 var type2 = s2.locals[i];
1670 if (type != baseType)
1672 s.LocalsCopyOnWrite();
1673 s.locals[i] = baseType;
1678 s.MergeSubroutineHelper(s2);
1682 internal void AddCallSite()
1688 internal void SetSubroutineId(
int subroutineIndex)
1690 SubroutinesCopyOnWrite();
1692 if (subroutines ==
null)
1694 subroutines =
new List<Subroutine>();
1698 foreach (var s
in subroutines)
1700 if (s.SubroutineIndex == subroutineIndex)
1703 throw new VerifyError(
"subroutines cannot recurse");
1708 subroutines.Add(
new Subroutine(subroutineIndex, locals.Length));
1711 internal bool[] GetLocalsModified(
int subroutineIndex)
1713 if (subroutines !=
null)
1714 foreach (var s
in subroutines)
1715 if (s.SubroutineIndex == subroutineIndex)
1716 return s.LocalsModified;
1718 throw new VerifyError(
"return from wrong subroutine");
1721 internal bool IsSubroutineActive(
int subroutineIndex)
1723 if (subroutines !=
null)
1724 foreach (var s
in subroutines)
1725 if (s.SubroutineIndex == subroutineIndex)
1731 internal void CheckSubroutineActive(
int subroutineIndex)
1733 if (!IsSubroutineActive(subroutineIndex))
1737 internal static SimpleType FindCommonBaseType(SimpleType type1, SimpleType type2)
1742 if (type1 == SimpleType.Object)
1745 if (type2 == SimpleType.Object)
1748 if (type1 == SimpleType.Invalid || type2 == SimpleType.Invalid)
1749 return SimpleType.Invalid;
1751 if (type1.IsPrimitive || type2.IsPrimitive)
1752 return SimpleType.Invalid;
1754 if (SimpleType.IsRet(type1) || SimpleType.IsRet(type2))
1755 return SimpleType.Invalid;
1757 return SimpleType.Object;
1760 void SetLocal1(
int index, SimpleType type)
1764 LocalsCopyOnWrite();
1765 SubroutinesCopyOnWrite();
1767 if (index > 0 && locals[index - 1] != SimpleType.Invalid && locals[index - 1].IsWidePrimitive)
1769 locals[index - 1] = SimpleType.Invalid;
1770 if (subroutines !=
null)
1771 foreach (var s
in subroutines)
1772 s.SetLocalModified(index - 1);
1775 locals[index] = type;
1776 if (subroutines !=
null)
1777 foreach (var s
in subroutines)
1778 s.SetLocalModified(index);
1780 catch (IndexOutOfRangeException)
1782 throw new VerifyError(
"Illegal local variable number");
1786 void SetLocal2(
int index, SimpleType type)
1790 LocalsCopyOnWrite();
1791 SubroutinesCopyOnWrite();
1793 if (index > 0 && locals[index - 1] != SimpleType.Invalid && locals[index - 1].IsWidePrimitive)
1795 locals[index - 1] = SimpleType.Invalid;
1796 if (subroutines !=
null)
1797 foreach (var s
in subroutines)
1798 s.SetLocalModified(index - 1);
1801 locals[index] = type;
1802 locals[index + 1] = SimpleType.Invalid;
1804 if (subroutines !=
null)
1806 foreach (var s
in subroutines)
1808 s.SetLocalModified(index);
1809 s.SetLocalModified(index + 1);
1813 catch (IndexOutOfRangeException)
1815 throw new VerifyError(
"Illegal local variable number");
1819 internal void SetLocalPrimitive(
int index,
int instructionIndex)
1821 SetLocal1(index, SimpleType.Primitive);
1824 internal void SetLocalWidePrimitive(
int index,
int instructionIndex)
1826 SetLocal2(index, SimpleType.WidePrimitive);
1829 internal SimpleType GetLocalType(
int index)
1833 return locals[index];
1835 catch (IndexOutOfRangeException)
1837 throw new VerifyError(
"Illegal local variable number");
1844 internal SimpleType GetLocalTypeEx(
int index)
1846 return locals[index];
1849 internal int GetLocalRet(
int index)
1851 var type = GetLocalType(index);
1852 if (SimpleType.IsRet(type))
1853 return type.SubroutineIndex;
1855 throw new VerifyError(
"incorrect local type, not ret");
1858 internal void SetLocalType(
int index, SimpleType type,
int instructionIndex)
1860 if (type.IsWidePrimitive)
1861 SetLocalWidePrimitive(index, instructionIndex);
1863 SetLocal1(index, type);
1866 internal void PushType(
string signature)
1868 switch (signature[0])
1872 PushWidePrimitive();
1884 internal void PushWidePrimitive()
1886 PushType(SimpleType.WidePrimitive);
1889 internal void PushPrimitive()
1891 PushType(SimpleType.Primitive);
1894 internal void PushObject()
1896 PushType(SimpleType.Object);
1900 internal SimpleType PopObjectType()
1902 var type = PopType();
1903 if (type.IsPrimitive)
1904 throw new VerifyError(
"Expected object reference on stack");
1909 internal void MultiPopAnyType(
int count)
1911 while (count-- != 0)
1915 internal SimpleType PopAnyType()
1918 throw new VerifyError(
"Unable to pop operand off an empty stack");
1920 var type = stack[--stackSize];
1921 if (type.IsWidePrimitive)
1928 internal SimpleType PopType()
1930 var type = PopAnyType();
1931 if (type.IsWidePrimitive)
1932 throw new VerifyError(
"Attempt to split long or double on the stack");
1937 internal void PopPrimitive()
1939 if (!PopType().IsPrimitive)
1940 throw new VerifyError(
"Primitive type expected on stack");
1943 internal void PopWidePrimitive()
1945 var type = PopAnyType();
1946 if (type != SimpleType.WidePrimitive)
1947 throw new VerifyError(
"Wide primitive type expected on stack");
1950 internal void PopType(
string signature)
1952 switch (signature[0])
1968 internal int GetStackHeight()
1973 internal void PushType(SimpleType type)
1975 if (type.IsWidePrimitive)
1978 if (stackSize >= stackEnd)
1982 stack[stackSize++] = type;
1985 private void StackCopyOnWrite()
1987 if ((flags & ShareFlags.Stack) != 0)
1989 flags &= ~ShareFlags.Stack;
1990 stack = (SimpleType[])stack.Clone();
1994 private void LocalsCopyOnWrite()
1996 if ((flags & ShareFlags.Locals) != 0)
1998 flags &= ~ShareFlags.Locals;
1999 locals = (SimpleType[])locals.Clone();
2003 private void SubroutinesCopyOnWrite()
2005 if ((flags & ShareFlags.Subroutines) != 0)
2007 flags &= ~ShareFlags.Subroutines;
2008 subroutines = CopySubroutines(subroutines);
2012 internal void DumpLocals()
2014 Console.Write(
"// ");
2016 for (
int i = 0; i < locals.Length; i++)
2019 Console.Write(locals[i]);
2022 Console.WriteLine();
2025 internal void DumpStack()
2027 Console.Write(
"// ");
2029 for (
int i = 0; i < stackSize; i++)
2032 Console.Write(stack[i]);
2035 Console.WriteLine();
2038 internal void DumpSubroutines()
2040 Console.Write(
"// subs: ");
2042 if (subroutines !=
null)
2044 for (
int i = 0; i < subroutines.Count; i++)
2047 Console.Write(((Subroutine)subroutines[i]).SubroutineIndex);
2051 Console.WriteLine();