Instructions.cs 103 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915
  1. /*
  2. * PERWAPI - An API for Reading and Writing PE Files
  3. *
  4. * Copyright (c) Diane Corney, Queensland University of Technology, 2004.
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the PERWAPI Copyright as included with this
  8. * distribution in the file PERWAPIcopyright.rtf.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY as is explained in the copyright notice.
  12. *
  13. * The author may be contacted at d.corney@qut.edu.au
  14. *
  15. * Version Date: 26/01/07
  16. */
  17. using System;
  18. using System.IO;
  19. using System.Collections;
  20. using System.Diagnostics;
  21. using SCG = System.Collections.Generic;
  22. namespace QUT.PERWAPI {
  23. /**************************************************************************/
  24. // Classes to represent CIL Byte Codes
  25. /**************************************************************************/
  26. /// <summary>
  27. /// The IL instructions for a method
  28. /// </summary>
  29. public class CILInstructions {
  30. private static readonly uint MaxClauses = 10;
  31. private static readonly uint ExHeaderSize = 4;
  32. private static readonly uint FatExClauseSize = 24;
  33. private static readonly uint SmlExClauseSize = 12;
  34. private static readonly sbyte maxByteVal = 127;
  35. private static readonly sbyte minByteVal = -128;
  36. private static readonly byte maxUByteVal = 255;
  37. private static readonly int smallSize = 64;
  38. internal static readonly ushort TinyFormat = 0x2;
  39. internal static readonly ushort FatFormat = 0x03;
  40. internal static readonly ushort FatFormatHeader = 0x3003;
  41. internal static readonly ushort MoreSects = 0x8;
  42. internal static readonly ushort InitLocals = 0x10;
  43. private static readonly uint FatSize = 12;
  44. private static readonly uint FatWords = FatSize / 4;
  45. internal static readonly byte FatExceptTable = 0x41;
  46. internal static readonly byte SmlExceptTable = 0x01;
  47. internal static readonly uint EHTable = 0x1;
  48. internal static readonly uint SectFatFormat = 0x40;
  49. internal static readonly uint SectMoreSects = 0x80;
  50. private ArrayList exceptions, sourceLines, defaultLines;
  51. private SourceFile defaultSourceFile;
  52. private Stack blockStack;
  53. //private bool codeChecked = false;
  54. private static readonly int INITSIZE = 5;
  55. private CILInstruction[] buffer = new CILInstruction[INITSIZE];
  56. // REPLACE with ArrayList<CILInstruction> for next version of .NET
  57. private CILInstruction[] saveBuffer;
  58. private int tide = 0, saveTide = 0;
  59. private uint offset = 0;
  60. private ushort headerFlags = 0;
  61. private short maxStack;
  62. private uint paddingNeeded = 0;
  63. private byte exceptHeader = 0;
  64. private int currI = -1;
  65. uint localSigIx = 0;
  66. int numReplace = 0;
  67. uint codeSize = 0, exceptSize = 0;
  68. bool tinyFormat, fatExceptionFormat = false, inserting = false;
  69. MethodDef thisMeth;
  70. internal Scope currentScope;
  71. /// <summary>
  72. /// Shows if return statements in this code block require a value on the stack or not.
  73. /// </summary>
  74. internal bool ReturnsVoid;
  75. /*-------------------- Constructors ---------------------------------*/
  76. internal CILInstructions(MethodDef meth) {
  77. thisMeth = meth;
  78. }
  79. /*--------------------- public general editing methods ---------------------------*/
  80. /// <summary>
  81. /// The source file containing these IL instructions
  82. /// </summary>
  83. public SourceFile DefaultSourceFile {
  84. get { return defaultSourceFile; }
  85. set { defaultSourceFile = value; }
  86. }
  87. /// <summary>
  88. /// The number of instructions currently in the buffer.
  89. /// </summary>
  90. public int NumInstructions() {
  91. if (inserting) return tide + saveTide;
  92. return tide;
  93. }
  94. /// <summary>
  95. /// Get the next instruction in the instruction buffer in sequence.
  96. /// An internal index is kept to keep track of which instruction was the last
  97. /// retrieved by this method. On the first call, the first instruction in
  98. /// the buffer is retrieved. The instruction index may be zeroed
  99. /// using ResetInstCounter(). This method cannot be called when in "insert" mode.
  100. /// </summary>
  101. /// <returns></returns>
  102. public CILInstruction GetNextInstruction() {
  103. if (inserting) throw new Exception("Cannot access next instruction during insert");
  104. if (currI + 1 < tide)
  105. return buffer[++currI];
  106. return null;
  107. }
  108. /// <summary>
  109. /// Get the previous instruction in the instruction buffer in sequence.
  110. /// An internal index is kept to keep track of which instruction was the last
  111. /// retrieved by this method. This method cannot be called when in "insert" mode.
  112. /// </summary>
  113. /// <returns></returns>
  114. public CILInstruction GetPrevInstruction() {
  115. if (inserting) throw new Exception("Cannot access previous instruction during insert");
  116. if (currI > 0)
  117. return buffer[--currI];
  118. return null;
  119. }
  120. /// <summary>
  121. /// Reset the counter for GetNextInstuction to the first instruction.
  122. /// This method cannot be called when in "insert" mode.
  123. /// </summary>
  124. public void ResetInstCounter() {
  125. if (inserting) throw new Exception("Cannot reset instruction counter during insert");
  126. currI = -1;
  127. }
  128. /// <summary>
  129. /// Reset the counter for GetNextInstuction to the first instruction.
  130. /// This method cannot be called when in "insert" mode.
  131. /// </summary>
  132. public void EndInstCounter() {
  133. if (inserting) throw new Exception("Cannot reset instruction counter during insert");
  134. currI = tide;
  135. }
  136. /// <summary>
  137. /// Get all the IL instructions.
  138. /// This method cannot be called when in "insert" mode.
  139. /// </summary>
  140. /// <returns></returns>
  141. public CILInstruction[] GetInstructions() {
  142. if (inserting) throw new Exception("Cannot get instructions during insert");
  143. return buffer;
  144. }
  145. /// <summary>
  146. /// Set the instruction to be the new array of instructions, this will replace
  147. /// any existing instructions. This method cannot be called when in "insert" mode.
  148. /// </summary>
  149. /// <param name="insts">The new instructions</param>
  150. public void SetInstructions(CILInstruction[] insts) {
  151. if (inserting) throw new Exception("Cannot replace instructions during insert.");
  152. buffer = insts;
  153. tide = buffer.Length;
  154. for (int i = 0; i < tide; i++) {
  155. if (insts[i] == null)
  156. tide = i;
  157. insts[i].index = (uint)i;
  158. }
  159. }
  160. /// <summary>
  161. /// This method should only be used to insert instructions into a buffer which
  162. /// already contains some instructions.
  163. /// Start inserting instructions into the instruction buffer ie. set the buffer
  164. /// to "insert" mode. The position of the insertion will be directly after
  165. /// the "current instruction" as used be GetNextInstruction(). The
  166. /// instructions to be inserted are any calls to the instruction specific
  167. /// methods - Inst, TypeInst, MethodInst, etc.
  168. /// This method cannot be called if already in "insert" mode.
  169. /// </summary>
  170. public void StartInsert() {
  171. if (inserting)
  172. throw new Exception("Cannot insert into an instruction buffer already in insert mode");
  173. inserting = true;
  174. saveTide = tide;
  175. saveBuffer = buffer;
  176. tide = 0;
  177. buffer = new CILInstruction[INITSIZE];
  178. }
  179. /// <summary>
  180. /// Stop inserting instructions into the buffer. Any instructions added after
  181. /// this call will go at the end of the instruction buffer.
  182. /// To be used with StartInsert().
  183. /// This method cannot be called if not in "insert" mode.
  184. /// </summary>
  185. public void EndInsert() {
  186. if (!inserting)
  187. throw new Exception("Cannot stop inserting if not in insert mode");
  188. CILInstruction[] newInsts = buffer;
  189. buffer = saveBuffer;
  190. int numNew = tide;
  191. tide = saveTide;
  192. int insPos = currI + 1;
  193. if (numReplace > 0) insPos--;
  194. InsertInstructions(insPos, newInsts, numNew);
  195. inserting = false;
  196. numReplace = 0;
  197. }
  198. /// <summary>
  199. /// Check if the buffer is ready for insertion of extra instructions.
  200. /// The buffer only needs to be in insert mode when instructions need
  201. /// to be added to existing instructions, not for addition of instructions
  202. /// to the end of the buffer.
  203. /// </summary>
  204. /// <returns></returns>
  205. public bool InInsertMode() { return inserting; }
  206. /// <summary>
  207. /// Remove the instruction at a specified position from the buffer. If you
  208. /// remove the "current" instruction (from GetNext or GetPrev) then the
  209. /// "current" instruction becomes the instruction before that in the buffer.
  210. /// </summary>
  211. /// <param name="pos">position of the instruction to be removed</param>
  212. public void RemoveInstruction(int pos) {
  213. if (pos < 0) return;
  214. for (int i = pos; i < tide - 1; i++) {
  215. buffer[i] = buffer[i + 1];
  216. buffer[i].index = (uint)i;
  217. }
  218. tide--;
  219. if (pos == currI) currI = pos - 1;
  220. }
  221. /// <summary>
  222. /// Remove the instructions from position "startRange" to (and including)
  223. /// position "endRange" from the buffer. If the range removed contains the
  224. /// "current" instruction (from GetNext or GetPrev) then the "current"
  225. /// instruction becomes the instruction before startRange in the buffer.
  226. /// </summary>
  227. public void RemoveInstructions(int startRange, int endRange) {
  228. if (startRange < 0) startRange = 0;
  229. if (endRange >= tide - 1) {// cut to startRange
  230. tide = startRange;
  231. return;
  232. }
  233. int offset = endRange - startRange + 1;
  234. for (int i = endRange + 1; i < tide; i++) {
  235. buffer[i - offset] = buffer[i];
  236. buffer[i - offset].index = (uint)(i - offset);
  237. }
  238. tide -= offset;
  239. if ((currI >= startRange) && (currI <= endRange)) currI = startRange - 1;
  240. }
  241. /// <summary>
  242. /// Replace a single IL instruction at position pos in the buffer
  243. /// with some new instruction(s). This removes the instruction and puts
  244. /// the instruction buffer into "insert" mode at the position of the removed
  245. /// instruction. EndInsert must be called to insert the new instructions.
  246. /// This method cannot be called when in "insert" mode.
  247. /// </summary>
  248. /// <param name="pos">position of the instruction to be replaced</param>
  249. public void ReplaceInstruction(int pos) {
  250. if (inserting) throw new Exception("Cannot replace instructions during insert.");
  251. currI = pos;
  252. if ((pos > 0) || (pos < tide)) {
  253. numReplace = 1;
  254. StartInsert();
  255. }
  256. }
  257. /// <summary>
  258. /// Replace a number of IL instructions beginning at position pos in the buffer
  259. /// with some new instruction(s). This removes the instructions and puts
  260. /// the instruction buffer into "insert" mode at the position of the removed
  261. /// instructions. EndInsert must be called to insert the new instructions.
  262. /// The instructions from index "from" up to and including index "to" will
  263. /// be replaced by the new instructions entered.
  264. /// This method cannot be called when in "insert" mode.
  265. /// </summary>
  266. /// <param name="from">the index to start replacing instruction from</param>
  267. /// <param name="to">the last index of the instructions to be replaced</param>
  268. public void ReplaceInstruction(int from, int to) {
  269. if (inserting) throw new Exception("Cannot replace instructions during insert.");
  270. currI = from;
  271. if ((from < 0) || (from >= tide) || (to < 0))
  272. throw new Exception("replace index is out of range");
  273. if (to >= tide) to = tide - 1;
  274. numReplace = to - from + 1;
  275. StartInsert();
  276. }
  277. /*---------------- public instruction specific methods ------------------------*/
  278. /// <summary>
  279. /// Add a simple IL instruction
  280. /// </summary>
  281. /// <param name="inst">the IL instruction</param>
  282. public void Inst(Op inst) {
  283. AddToBuffer(new Instr(inst));
  284. }
  285. /// <summary>
  286. /// Add an IL instruction with an integer parameter
  287. /// </summary>
  288. /// <param name="inst">the IL instruction</param>
  289. /// <param name="val">the integer parameter value</param>
  290. public void IntInst(IntOp inst, int val) {
  291. if ((inst == IntOp.ldc_i4_s) || (inst == IntOp.ldc_i4)) {
  292. if ((val < 9) && (val >= -1)) {
  293. AddToBuffer(new Instr((Op)((int)Op.ldc_i4_0 + val)));
  294. }
  295. else {
  296. AddToBuffer(new IntInstr(inst, val));
  297. }
  298. }
  299. else
  300. AddToBuffer(new UIntInstr(inst, (uint)val));
  301. }
  302. /// <summary>
  303. /// Add the load long instruction
  304. /// </summary>
  305. /// <param name="cVal">the long value</param>
  306. public void ldc_i8(long cVal) {
  307. AddToBuffer(new LongInstr(SpecialOp.ldc_i8, cVal));
  308. }
  309. /// <summary>
  310. /// Add the load float32 instruction
  311. /// </summary>
  312. /// <param name="cVal">the float value</param>
  313. public void ldc_r4(float cVal) {
  314. AddToBuffer(new FloatInstr(SpecialOp.ldc_r4, cVal));
  315. }
  316. /// <summary>
  317. /// Add the load float64 instruction
  318. /// </summary>
  319. /// <param name="cVal">the float value</param>
  320. public void ldc_r8(double cVal) {
  321. AddToBuffer(new DoubleInstr(SpecialOp.ldc_r8, cVal));
  322. }
  323. /// <summary>
  324. /// Add the load string instruction
  325. /// </summary>
  326. /// <param name="str">the string value</param>
  327. public void ldstr(string str) {
  328. AddToBuffer(new StringInstr(SpecialOp.ldstr, str));
  329. }
  330. /// <summary>
  331. /// Add the calli instruction
  332. /// </summary>
  333. /// <param name="sig">the signature for the calli</param>
  334. public void calli(CalliSig sig) {
  335. AddToBuffer(new SigInstr(SpecialOp.calli, sig));
  336. }
  337. /// <summary>
  338. /// Create a new CIL label. To place the label in the CIL instruction
  339. /// stream use CodeLabel.
  340. /// </summary>
  341. /// <returns>a new CIL label</returns>
  342. public CILLabel NewLabel() {
  343. return new CILLabel();
  344. }
  345. /// <summary>
  346. /// Create a new label at this position in the code buffer
  347. /// </summary>
  348. /// <returns>the label at the current position</returns>
  349. public CILLabel NewCodedLabel() {
  350. CILLabel lab = new CILLabel();
  351. lab.Buffer = this;
  352. AddToBuffer(lab);
  353. return lab;
  354. }
  355. /// <summary>
  356. /// Add a label to the CIL instructions
  357. /// </summary>
  358. /// <param name="lab">the label to be added</param>
  359. public void CodeLabel(CILLabel lab) {
  360. if (lab.Buffer == null) {
  361. lab.Buffer = this;
  362. }
  363. else if (lab.Buffer != this) {
  364. throw new DescriptorException("Cannot add a label to two different code buffers");
  365. }
  366. AddToBuffer(lab);
  367. }
  368. /// <summary>
  369. /// Add an instruction with a field parameter
  370. /// </summary>
  371. /// <param name="inst">the CIL instruction</param>
  372. /// <param name="f">the field parameter</param>
  373. public void FieldInst(FieldOp inst, Field f) {
  374. Debug.Assert(f != null);
  375. if (f is FieldDef)
  376. if (((FieldDef)f).GetScope() != thisMeth.GetScope())
  377. throw new DescriptorException();
  378. AddToBuffer(new FieldInstr(inst, f));
  379. }
  380. /// <summary>
  381. /// Add an instruction with a method parameter
  382. /// </summary>
  383. /// <param name="inst">the CIL instruction</param>
  384. /// <param name="m">the method parameter</param>
  385. public void MethInst(MethodOp inst, Method m) {
  386. Debug.Assert(m != null);
  387. if (m is MethodDef)
  388. if (((MethodDef)m).GetScope() != thisMeth.GetScope())
  389. throw new DescriptorException();
  390. AddToBuffer(new MethInstr(inst, m));
  391. }
  392. /// <summary>
  393. /// Add an instruction with a type parameter
  394. /// </summary>
  395. /// <param name="inst">the CIL instruction</param>
  396. /// <param name="aType">the type argument for the CIL instruction</param>
  397. public void TypeInst(TypeOp inst, Type aType) {
  398. Debug.Assert(aType != null);
  399. if (aType is ClassDef) {
  400. if (((ClassDef)aType).GetScope() != thisMeth.GetScope())
  401. throw new DescriptorException();
  402. }
  403. AddToBuffer(new TypeInstr(inst, aType));
  404. }
  405. /// <summary>
  406. /// Add a branch instruction
  407. /// </summary>
  408. /// <param name="inst">the branch instruction</param>
  409. /// <param name="lab">the label that is the target of the branch</param>
  410. public void Branch(BranchOp inst, CILLabel lab) {
  411. Debug.Assert(lab != null);
  412. AddToBuffer(new BranchInstr(inst, lab));
  413. }
  414. /// <summary>
  415. /// Add a switch instruction
  416. /// </summary>
  417. /// <param name="labs">the target labels for the switch</param>
  418. public void Switch(CILLabel[] labs) {
  419. AddToBuffer(new SwitchInstr(labs));
  420. }
  421. /// <summary>
  422. /// Add a byte to the CIL instructions (.emitbyte)
  423. /// </summary>
  424. /// <param name="bVal"></param>
  425. public void emitbyte(byte bVal) {
  426. AddToBuffer(new CILByte(bVal));
  427. }
  428. /// <summary>
  429. /// Add an instruction which puts an integer on TOS. This method
  430. /// selects the correct instruction based on the value of the integer.
  431. /// </summary>
  432. /// <param name="i">the integer value</param>
  433. public void PushInt(int i) {
  434. if (i == -1) {
  435. AddToBuffer(new Instr(Op.ldc_i4_m1));
  436. }
  437. else if ((i >= 0) && (i <= 8)) {
  438. Op op = (Op)(Op.ldc_i4_0 + i);
  439. AddToBuffer(new Instr(op));
  440. }
  441. else if ((i >= minByteVal) && (i <= maxByteVal)) {
  442. AddToBuffer(new IntInstr(IntOp.ldc_i4_s, i));
  443. }
  444. else {
  445. AddToBuffer(new IntInstr(IntOp.ldc_i4, i));
  446. }
  447. }
  448. /// <summary>
  449. /// Add the instruction to load a long on TOS
  450. /// </summary>
  451. /// <param name="l">the long value</param>
  452. public void PushLong(long l) {
  453. AddToBuffer(new LongInstr(SpecialOp.ldc_i8, l));
  454. }
  455. /// <summary>
  456. /// Add an instruction to push the boolean value true on TOS
  457. /// </summary>
  458. public void PushTrue() {
  459. AddToBuffer(new Instr(Op.ldc_i4_1));
  460. }
  461. /// <summary>
  462. /// Add an instruction to push the boolean value false on TOS
  463. /// </summary>
  464. public void PushFalse() {
  465. AddToBuffer(new Instr(Op.ldc_i4_0));
  466. }
  467. /// <summary>
  468. /// Add the instruction to load an argument on TOS. This method
  469. /// selects the correct instruction based on the value of argNo
  470. /// </summary>
  471. /// <param name="argNo">the number of the argument</param>
  472. public void LoadArg(int argNo) {
  473. if (argNo < 4) {
  474. Op op = (Op)Op.ldarg_0 + argNo;
  475. AddToBuffer(new Instr(op));
  476. }
  477. else if (argNo <= maxUByteVal) {
  478. AddToBuffer(new UIntInstr(IntOp.ldarg_s, (uint)argNo));
  479. }
  480. else {
  481. AddToBuffer(new UIntInstr(IntOp.ldarg, (uint)argNo));
  482. }
  483. }
  484. /// <summary>
  485. /// Add the instruction to load the address of an argument on TOS.
  486. /// This method selects the correct instruction based on the value
  487. /// of argNo.
  488. /// </summary>
  489. /// <param name="argNo">the number of the argument</param>
  490. public void LoadArgAdr(int argNo) {
  491. if (argNo <= maxUByteVal) {
  492. AddToBuffer(new UIntInstr(IntOp.ldarga_s, (uint)argNo));
  493. }
  494. else {
  495. AddToBuffer(new UIntInstr(IntOp.ldarga, (uint)argNo));
  496. }
  497. }
  498. /// <summary>
  499. /// Add the instruction to load a local on TOS. This method selects
  500. /// the correct instruction based on the value of locNo.
  501. /// </summary>
  502. /// <param name="locNo">the number of the local to load</param>
  503. public void LoadLocal(int locNo) {
  504. if (locNo < 4) {
  505. Op op = (Op)Op.ldloc_0 + locNo;
  506. AddToBuffer(new Instr(op));
  507. }
  508. else if (locNo <= maxUByteVal) {
  509. AddToBuffer(new UIntInstr(IntOp.ldloc_s, (uint)locNo));
  510. }
  511. else {
  512. AddToBuffer(new UIntInstr(IntOp.ldloc, (uint)locNo));
  513. }
  514. }
  515. /// <summary>
  516. /// Add the instruction to load the address of a local on TOS.
  517. /// This method selects the correct instruction based on the
  518. /// value of locNo.
  519. /// </summary>
  520. /// <param name="locNo">the number of the local</param>
  521. public void LoadLocalAdr(int locNo) {
  522. if (locNo <= maxUByteVal) {
  523. AddToBuffer(new UIntInstr(IntOp.ldloca_s, (uint)locNo));
  524. }
  525. else {
  526. AddToBuffer(new UIntInstr(IntOp.ldloca, (uint)locNo));
  527. }
  528. }
  529. /// <summary>
  530. /// Add the instruction to store to an argument. This method
  531. /// selects the correct instruction based on the value of argNo.
  532. /// </summary>
  533. /// <param name="argNo">the argument to be stored to</param>
  534. public void StoreArg(int argNo) {
  535. if (argNo <= maxUByteVal) {
  536. AddToBuffer(new UIntInstr(IntOp.starg_s, (uint)argNo));
  537. }
  538. else {
  539. AddToBuffer(new UIntInstr(IntOp.starg, (uint)argNo));
  540. }
  541. }
  542. /// <summary>
  543. /// Add the instruction to store to a local. This method selects
  544. /// the correct instruction based on the value of locNo.
  545. /// </summary>
  546. /// <param name="locNo">the local to be stored to</param>
  547. public void StoreLocal(int locNo) {
  548. if (locNo < 4) {
  549. Op op = (Op)Op.stloc_0 + locNo;
  550. AddToBuffer(new Instr(op));
  551. }
  552. else if (locNo <= maxUByteVal) {
  553. AddToBuffer(new UIntInstr(IntOp.stloc_s, (uint)locNo));
  554. }
  555. else {
  556. AddToBuffer(new UIntInstr(IntOp.stloc, (uint)locNo));
  557. }
  558. }
  559. public void IntLine(int num) {
  560. Line((uint)num, 1);
  561. }
  562. /// <summary>
  563. /// CLS compliant version of Line()
  564. /// </summary>
  565. /// <param name="sLin">The start line</param>
  566. /// <param name="sCol">The start column</param>
  567. /// <param name="eLin">The end line</param>
  568. /// <param name="eCol">The end column</param>
  569. public void IntLine(int sLin, int sCol, int eLin, int eCol) {
  570. Line((uint)sLin, (uint)sCol, (uint)eLin, (uint)eCol);
  571. }
  572. /// <summary>
  573. /// Create a new line instruction.
  574. /// </summary>
  575. /// <param name="num">The line for the given code segment.</param>
  576. /// <param name="startCol">The starting column for the code segment.</param>
  577. public void Line(uint num, uint startCol) {
  578. if (this.DefaultSourceFile == null) throw new Exception("Method can only be used if DefaultSourceFile has been set.");
  579. AddToBuffer(new Line(num, startCol, this.DefaultSourceFile));
  580. }
  581. /// <summary>
  582. /// Create a new line instruction.
  583. /// </summary>
  584. /// <param name="num">The line for the given code segment.</param>
  585. /// <param name="startCol">The starting column for the code segment.</param>
  586. /// <param name="endCol">The ending column for the code segment.</param>
  587. public void Line(uint num, uint startCol, uint endCol) {
  588. if (this.DefaultSourceFile == null) throw new Exception("Method can only be used if DefaultSourceFile has been set.");
  589. AddToBuffer(new Line(num, startCol, num, endCol, this.DefaultSourceFile));
  590. }
  591. /// <summary>
  592. /// Create a new line instruction.
  593. /// </summary>
  594. /// <param name="startNum">The starting line for the code segment.</param>
  595. /// <param name="startCol">The starting column for the code segment.</param>
  596. /// <param name="endNum">The ending line for the code segment.</param>
  597. /// <param name="endCol">The ending column for the code segment.</param>
  598. public void Line(uint startNum, uint startCol, uint endNum, uint endCol) {
  599. if (this.DefaultSourceFile == null) throw new Exception("Method can only be used if DefaultSourceFile has bene set.");
  600. AddToBuffer(new Line(startNum, startCol, endNum, endCol, this.DefaultSourceFile));
  601. }
  602. /// <summary>
  603. /// Create a new line instruction.
  604. /// </summary>
  605. /// <param name="startNum">The starting line for the code segment.</param>
  606. /// <param name="startCol">The starting column for the code segment.</param>
  607. /// <param name="endNum">The ending line for the code segment.</param>
  608. /// <param name="endCol">The ending column for the code segment.</param>
  609. /// <param name="sFile">The source file for the given code segment.</param>
  610. public void Line(uint startNum, uint startCol, uint endNum, uint endCol, SourceFile sFile) {
  611. AddToBuffer(new Line(startNum, startCol, endNum, endCol, sFile));
  612. }
  613. /// <summary>
  614. /// The current scope.
  615. /// </summary>
  616. public Scope CurrentScope {
  617. get { return currentScope; }
  618. }
  619. /// <summary>
  620. /// Open a new scope.
  621. /// </summary>
  622. public void OpenScope() {
  623. currentScope = new Scope(currentScope, thisMeth);
  624. AddToBuffer(new OpenScope(currentScope));
  625. //Console.WriteLine("Open scope on " + currentScope._thisMeth.Name());
  626. }
  627. /// <summary>
  628. /// Close the current scope.
  629. /// </summary>
  630. public void CloseScope() {
  631. //Console.WriteLine("Close scope on " + currentScope._thisMeth.Name());
  632. AddToBuffer(new CloseScope(currentScope));
  633. currentScope = currentScope._parent;
  634. }
  635. /// <summary>
  636. /// Bind a local to the CIL instructions.
  637. /// </summary>
  638. /// <param name="name">The name of the local variable..</param>
  639. /// <param name="index">The index of the local variable.</param>
  640. /// <returns>The LocalBinding object created with the given values.</returns>
  641. public LocalBinding BindLocal(string name, int index) {
  642. if (currentScope == null)
  643. throw new Exception("Scope must be opened before locals can be bound.");
  644. return currentScope.AddLocalBinding(name, index);
  645. }
  646. /// <summary>
  647. /// Bind a local to the CIL instructions.
  648. /// </summary>
  649. /// <param name="local">The local variable to load.</param>
  650. /// <returns>The LocalBinding object created for the given Local object.</returns>
  651. public LocalBinding BindLocal(Local local) {
  652. return BindLocal(local.Name, local.GetIndex());
  653. }
  654. /// <summary>
  655. /// Bind a constant to the CIL instructions.
  656. /// </summary>
  657. /// <param name="name">The name of the constant.</param>
  658. /// <param name="value">The value of the constant.</param>
  659. /// <param name="type">The type of the constant.</param>
  660. /// <returns>Return the ConstantBinding created with the given values.</returns>
  661. public ConstantBinding BindConstant(string name, object value, Type type) {
  662. if (currentScope == null)
  663. throw new Exception("Scope must be opened before constants can be bound.");
  664. return currentScope.AddConstantBinding(name, value, type);
  665. }
  666. /// <summary>
  667. /// Mark this position as the start of a new block
  668. /// (try, catch, filter, finally or fault)
  669. /// </summary>
  670. public void StartBlock() {
  671. if (blockStack == null) blockStack = new Stack();
  672. blockStack.Push(NewCodedLabel());
  673. }
  674. /// <summary>
  675. /// Mark this position as the end of the last started block and
  676. /// make it a try block. This try block is added to the current
  677. /// instructions (ie do not need to call AddTryBlock)
  678. /// </summary>
  679. /// <returns>The try block just ended</returns>
  680. public TryBlock EndTryBlock() {
  681. TryBlock tBlock = new TryBlock((CILLabel)blockStack.Pop(), NewCodedLabel());
  682. AddTryBlock(tBlock);
  683. return tBlock;
  684. }
  685. /// <summary>
  686. /// Mark this position as the end of the last started block and
  687. /// make it a catch block. This catch block is associated with the
  688. /// specified try block.
  689. /// </summary>
  690. /// <param name="exceptType">the exception type to be caught</param>
  691. /// <param name="tryBlock">the try block associated with this catch block</param>
  692. public void EndCatchBlock(Class exceptType, TryBlock tryBlock) {
  693. Catch catchBlock = new Catch(exceptType, (CILLabel)blockStack.Pop(), NewCodedLabel());
  694. tryBlock.AddHandler(catchBlock);
  695. }
  696. /// <summary>
  697. /// Mark this position as the end of the last started block and
  698. /// make it a filter block. This filter block is associated with the
  699. /// specified try block. The format is:
  700. /// filterLab: ...
  701. /// ...
  702. /// filterHandler : ...
  703. /// ...
  704. /// </summary>
  705. /// <param name="filterLab">the label where the filter code is</param>
  706. /// <param name="tryBlock">the try block associated with this filter block</param>
  707. public void EndFilterBlock(CILLabel filterLab, TryBlock tryBlock) {
  708. Filter filBlock = new Filter(filterLab, (CILLabel)blockStack.Pop(), NewCodedLabel());
  709. tryBlock.AddHandler(filBlock);
  710. }
  711. /// <summary>
  712. /// Mark this position as the end of the last started block and
  713. /// make it a finally block. This finally block is associated with the
  714. /// specified try block.
  715. /// </summary>
  716. /// <param name="tryBlock">the try block associated with this finally block</param>
  717. public void EndFinallyBlock(TryBlock tryBlock) {
  718. Finally finBlock = new Finally((CILLabel)blockStack.Pop(), NewCodedLabel());
  719. tryBlock.AddHandler(finBlock);
  720. }
  721. /// <summary>
  722. /// Mark this position as the end of the last started block and
  723. /// make it a fault block. This fault block is associated with the
  724. /// specified try block.
  725. /// </summary>
  726. /// <param name="tryBlock">the try block associated with this fault block</param>
  727. public void EndFaultBlock(TryBlock tryBlock) {
  728. Fault fBlock = new Fault((CILLabel)blockStack.Pop(), NewCodedLabel());
  729. tryBlock.AddHandler(fBlock);
  730. }
  731. public void AddTryBlock(TryBlock tryBlock) {
  732. if (exceptions == null)
  733. exceptions = new ArrayList();
  734. else if (exceptions.Contains(tryBlock)) return;
  735. exceptions.Add(tryBlock);
  736. }
  737. /*------------------------- private methods ----------------------------*/
  738. private void AddToBuffer(CILInstruction inst) {
  739. if (tide >= buffer.Length) {
  740. CILInstruction[] tmp = buffer;
  741. buffer = new CILInstruction[tmp.Length * 2];
  742. for (int i = 0; i < tide; i++) {
  743. buffer[i] = tmp[i];
  744. }
  745. }
  746. //Console.WriteLine("Adding instruction at offset " + offset + " with size " + inst.size);
  747. //inst.offset = offset;
  748. //offset += inst.size;
  749. inst.index = (uint)tide;
  750. buffer[tide++] = inst;
  751. }
  752. private void UpdateIndexesFrom(int ix) {
  753. for (int i = ix; i < tide; i++) {
  754. buffer[i].index = (uint)i;
  755. }
  756. }
  757. private void InsertInstructions(int ix, CILInstruction[] newInsts, int numNew) {
  758. CILInstruction[] newBuff = buffer, oldBuff = buffer;
  759. int newSize = tide + numNew - numReplace;
  760. if (buffer.Length < newSize) {
  761. newBuff = new CILInstruction[newSize];
  762. for (int i = 0; i < ix; i++) {
  763. newBuff[i] = oldBuff[i];
  764. }
  765. }
  766. // shuffle up
  767. int offset = numNew - numReplace;
  768. int end = ix + numReplace;
  769. for (int i = tide - 1; i >= end; i--) {
  770. newBuff[i + offset] = oldBuff[i];
  771. }
  772. // insert new instructions
  773. for (int i = 0; i < numNew; i++) {
  774. newBuff[ix + i] = newInsts[i];
  775. }
  776. buffer = newBuff;
  777. tide += numNew - numReplace;
  778. UpdateIndexesFrom(ix);
  779. }
  780. internal bool IsEmpty() {
  781. return tide == 0;
  782. }
  783. internal static CILLabel GetLabel(ArrayList labs, uint targetOffset) {
  784. CILLabel lab;
  785. int i = 0;
  786. while ((i < labs.Count) && (((CILLabel)labs[i]).offset < targetOffset)) i++;
  787. if (i < labs.Count) {
  788. if (((CILLabel)labs[i]).offset == targetOffset) // existing label
  789. lab = (CILLabel)labs[i];
  790. else {
  791. lab = new CILLabel(targetOffset);
  792. labs.Insert(i, lab);
  793. }
  794. }
  795. else {
  796. lab = new CILLabel(targetOffset);
  797. labs.Add(lab);
  798. }
  799. return lab;
  800. }
  801. internal void AddEHClause(EHClause ehc) {
  802. if (exceptions == null)
  803. exceptions = new ArrayList();
  804. exceptions.Add(ehc);
  805. }
  806. internal void SetAndResolveInstructions(CILInstruction[] insts) {
  807. offset = 0;
  808. ArrayList labels = new ArrayList();
  809. for (int i = 0; i < insts.Length; i++) {
  810. insts[i].offset = offset;
  811. offset += insts[i].size;
  812. if (insts[i] is BranchInstr) {
  813. ((BranchInstr)insts[i]).MakeTargetLabel(labels);
  814. }
  815. else if (insts[i] is SwitchInstr) {
  816. ((SwitchInstr)insts[i]).MakeTargetLabels(labels);
  817. }
  818. }
  819. if (exceptions != null) {
  820. for (int i = 0; i < exceptions.Count; i++) {
  821. exceptions[i] = ((EHClause)exceptions[i]).MakeTryBlock(labels);
  822. }
  823. }
  824. if (labels.Count == 0) { buffer = insts; tide = buffer.Length; return; }
  825. buffer = new CILInstruction[insts.Length + labels.Count];
  826. int currentPos = 0;
  827. tide = 0;
  828. for (int i = 0; i < labels.Count; i++) {
  829. CILLabel lab = (CILLabel)labels[i];
  830. while ((currentPos < insts.Length) && (insts[currentPos].offset < lab.offset))
  831. buffer[tide++] = insts[currentPos++];
  832. buffer[tide++] = lab;
  833. }
  834. while (currentPos < insts.Length) {
  835. buffer[tide++] = insts[currentPos++];
  836. }
  837. }
  838. internal uint GetCodeSize() {
  839. return codeSize + paddingNeeded + exceptSize;
  840. }
  841. internal void BuildTables(MetaDataOut md) {
  842. for (int i = 0; i < tide; i++) {
  843. buffer[i].BuildTables(md);
  844. }
  845. if (exceptions != null) {
  846. for (int i = 0; i < exceptions.Count; i++) {
  847. ((TryBlock)exceptions[i]).BuildTables(md);
  848. }
  849. }
  850. }
  851. internal void BuildCILInfo(CILWriter output) {
  852. for (int i = 0; i < tide; i++) {
  853. buffer[i].BuildCILInfo(output);
  854. }
  855. if (exceptions != null) {
  856. for (int i = 0; i < exceptions.Count; i++) {
  857. ((TryBlock)exceptions[i]).BuildCILInfo(output);
  858. }
  859. }
  860. }
  861. internal void ChangeRefsToDefs(ClassDef newType, ClassDef[] oldTypes) {
  862. for (int i = 0; i < tide; i++) {
  863. if (buffer[i] is SigInstr) {
  864. CalliSig sig = ((SigInstr)buffer[i]).GetSig();
  865. sig.ChangeRefsToDefs(newType, oldTypes);
  866. }
  867. else if (buffer[i] is TypeInstr) {
  868. TypeInstr tinst = (TypeInstr)buffer[i];
  869. if (tinst.GetTypeArg() is ClassDef) {
  870. ClassDef iType = (ClassDef)tinst.GetTypeArg();
  871. bool changed = false;
  872. for (int j = 0; (j < oldTypes.Length) && !changed; j++) {
  873. if (iType == oldTypes[j])
  874. tinst.SetTypeArg(newType);
  875. }
  876. }
  877. }
  878. }
  879. }
  880. internal void AddToLines(Line line) {
  881. if ((line.sourceFile == null) || (line.sourceFile.Match(defaultSourceFile))) {
  882. if (defaultLines == null) {
  883. if (defaultSourceFile == null)
  884. throw new Exception("No Default Source File Set");
  885. defaultLines = new ArrayList();
  886. }
  887. defaultLines.Add(line);
  888. return;
  889. }
  890. if (sourceLines == null) {
  891. sourceLines = new ArrayList();
  892. }
  893. else {
  894. for (int i = 0; i < sourceLines.Count; i++) {
  895. ArrayList lineList = (ArrayList)sourceLines[i];
  896. if (((Line)lineList[0]).sourceFile.Match(line.sourceFile)) {
  897. lineList.Add(line);
  898. return;
  899. }
  900. }
  901. ArrayList newList = new ArrayList();
  902. newList.Add(line);
  903. sourceLines.Add(newList);
  904. }
  905. }
  906. internal void CheckCode(uint locSigIx, bool initLocals, int maxStack, MetaDataOut metaData) {
  907. if (tide == 0) return;
  908. offset = 0;
  909. for (int i = 0; i < tide; i++) {
  910. buffer[i].offset = offset;
  911. offset += buffer[i].size;
  912. if (buffer[i] is Line)
  913. AddToLines((Line)buffer[i]);
  914. }
  915. bool changed = true;
  916. while (changed) {
  917. changed = false;
  918. Line prevLine = null;
  919. for (int i = 0; i < tide; i++) {
  920. if (buffer[i] is Line) {
  921. if (prevLine != null)
  922. prevLine.CalcEnd((Line)buffer[i]);
  923. prevLine = (Line)buffer[i];
  924. }
  925. changed = buffer[i].Check(metaData) || changed;
  926. }
  927. if (prevLine != null) prevLine.Last();
  928. if (changed) {
  929. for (int i = 1; i < tide; i++) {
  930. buffer[i].offset = buffer[i - 1].offset + buffer[i - 1].size;
  931. }
  932. offset = buffer[tide - 1].offset + buffer[tide - 1].size;
  933. }
  934. }
  935. codeSize = offset;
  936. if (Diag.DiagOn) Console.WriteLine("codeSize before header added = " + codeSize);
  937. if (maxStack == 0) this.maxStack = 8;
  938. else this.maxStack = (short)maxStack;
  939. if ((offset < smallSize) && (maxStack <= 8) && (locSigIx == 0) && (exceptions == null)) {
  940. // can use tiny header
  941. if (Diag.DiagOn) Console.WriteLine("Tiny Header");
  942. tinyFormat = true;
  943. headerFlags = (ushort)(TinyFormat | ((ushort)codeSize << 2));
  944. codeSize++;
  945. if ((codeSize % 4) != 0) { paddingNeeded = 4 - (codeSize % 4); }
  946. }
  947. else {
  948. if (Diag.DiagOn) Console.WriteLine("Fat Header");
  949. tinyFormat = false;
  950. localSigIx = locSigIx;
  951. //this.maxStack = (short)maxStack;
  952. headerFlags = FatFormatHeader;
  953. if (exceptions != null) {
  954. // Console.WriteLine("Got exceptions");
  955. headerFlags |= MoreSects;
  956. uint numExceptClauses = 0;
  957. for (int i = 0; i < exceptions.Count; i++) {
  958. TryBlock tryBlock = (TryBlock)exceptions[i];
  959. tryBlock.SetSize();
  960. numExceptClauses += (uint)tryBlock.NumHandlers();
  961. if (tryBlock.isFat()) fatExceptionFormat = true;
  962. }
  963. if (numExceptClauses > MaxClauses) fatExceptionFormat = true;
  964. if (Diag.DiagOn) Console.WriteLine("numexceptclauses = " + numExceptClauses);
  965. if (fatExceptionFormat) {
  966. if (Diag.DiagOn) Console.WriteLine("Fat exception format");
  967. exceptHeader = FatExceptTable;
  968. exceptSize = ExHeaderSize + numExceptClauses * FatExClauseSize;
  969. }
  970. else {
  971. if (Diag.DiagOn) Console.WriteLine("Tiny exception format");
  972. exceptHeader = SmlExceptTable;
  973. exceptSize = ExHeaderSize + numExceptClauses * SmlExClauseSize;
  974. }
  975. if (Diag.DiagOn) Console.WriteLine("exceptSize = " + exceptSize);
  976. }
  977. if (initLocals) headerFlags |= InitLocals;
  978. if ((offset % 4) != 0) { paddingNeeded = 4 - (offset % 4); }
  979. codeSize += FatSize;
  980. }
  981. if (Diag.DiagOn)
  982. Console.WriteLine("codeSize = " + codeSize + " headerFlags = " + Hex.Short(headerFlags));
  983. }
  984. /// <summary>
  985. /// Returns the maximum stack depth required by these CIL instructions.
  986. /// </summary>
  987. /// <returns>The integer value of the stck depth.</returns>
  988. public int GetMaxStackDepthRequired() {
  989. if (tide == 0) return 0;
  990. // Store the code blocks we find
  991. SCG.List<CodeBlock> codeBlocks = new SCG.List<CodeBlock>();
  992. SCG.Dictionary<CILLabel, CodeBlock> cbTable = new SCG.Dictionary<CILLabel, CodeBlock>();
  993. SCG.List<CodeBlock> extraStartingBlocks = new SCG.List<CodeBlock>();
  994. // Start a default code block
  995. CodeBlock codeBlock = new CodeBlock(this);
  996. codeBlock.StartIndex = 0;
  997. //
  998. // Identify the code blocks
  999. //
  1000. for (int i = 0; i < tide; i++) {
  1001. /* Handling the tail instruction:
  1002. * The tail instruction has not been handled even though
  1003. * it indicates the end of a code block is coming. The
  1004. * reason for this is because any valid tail instruction
  1005. * must be followed by a call* instruction and then a ret
  1006. * instruction. Given a ret instruction must be the second
  1007. * next instruction anyway it has been decided to just let
  1008. * the end block be caught then.
  1009. */
  1010. // If we reach a branch instruction or a switch instruction
  1011. // then end the current code block inclusive of the instruction.
  1012. if ((buffer[i] is BranchInstr) || (buffer[i] is SwitchInstr)) {
  1013. // Close the old block
  1014. codeBlock.EndIndex = i;
  1015. if (codeBlock.EndIndex >= codeBlock.StartIndex) // Don't add empty blocks
  1016. codeBlocks.Add(codeBlock);
  1017. // Open a new block
  1018. codeBlock = new CodeBlock(this);
  1019. codeBlock.StartIndex = i + 1;
  1020. // If we reach a label then we need to start a new
  1021. // code block as the label is an entry point.
  1022. }
  1023. else if (buffer[i] is CILLabel) {
  1024. // Close the old block
  1025. codeBlock.EndIndex = i - 1;
  1026. if (codeBlock.EndIndex >= codeBlock.StartIndex) // Don't add empty blocks
  1027. codeBlocks.Add(codeBlock);
  1028. // Open a new block
  1029. codeBlock = new CodeBlock(this);
  1030. codeBlock.StartIndex = i;
  1031. // Set this label as the entry point for the code block
  1032. codeBlock.EntryLabel = (CILLabel)buffer[i];
  1033. // AND ... list in the dictionary.
  1034. cbTable.Add(codeBlock.EntryLabel, codeBlock);
  1035. // Check for the ret, throw, rethrow, or jmp instruction as they also end a block
  1036. }
  1037. else if (buffer[i] is Instr) {
  1038. if (
  1039. (((Instr)buffer[i]).GetOp() == Op.ret) ||
  1040. (((Instr)buffer[i]).GetOp() == Op.throwOp) ||
  1041. (((Instr)buffer[i]).GetOp() == Op.rethrow) ||
  1042. ((buffer[i] is MethInstr) && (((MethInstr)buffer[i]).GetMethodOp() == MethodOp.jmp))
  1043. ) {
  1044. // Close the old block
  1045. codeBlock.EndIndex = i;
  1046. if (codeBlock.EndIndex >= codeBlock.StartIndex) // Don't add empty blocks
  1047. codeBlocks.Add(codeBlock);
  1048. // Open a new block
  1049. // In theory this should never happen but just in case
  1050. // someone feels like adding dead code it is supported.
  1051. codeBlock = new CodeBlock(this);
  1052. codeBlock.StartIndex = i + 1;
  1053. }
  1054. }
  1055. }
  1056. // Close the last block
  1057. codeBlock.EndIndex = tide - 1;
  1058. if (codeBlock.EndIndex >= codeBlock.StartIndex) // Don't add empty blocks
  1059. codeBlocks.Add(codeBlock);
  1060. codeBlock = null;
  1061. // Check how many code blocks there are. If an blocks return 0.
  1062. if (codeBlocks.Count == 0) return 0;
  1063. //
  1064. // Loop through each code block and calculate the delta distance
  1065. //
  1066. for (int j = 0; j < codeBlocks.Count; j++) {
  1067. CodeBlock block = codeBlocks[j];
  1068. int maxDepth = 0;
  1069. int currentDepth = 0;
  1070. // Loop through each instruction to work out the max depth
  1071. for (int i = block.StartIndex; i <= block.EndIndex; i++) {
  1072. // Get the depth after the next instruction
  1073. currentDepth += buffer[i].GetDeltaDistance();
  1074. // If the new current depth is greater then the maxDepth adjust the maxDepth to reflect
  1075. if (currentDepth > maxDepth)
  1076. maxDepth = currentDepth;
  1077. }
  1078. // Set the depth of the block
  1079. block.MaxDepth = maxDepth;
  1080. block.DeltaDistance = currentDepth;
  1081. //
  1082. // Link up the next blocks
  1083. //
  1084. // If the block ends with a branch statement set the jump and fall through.
  1085. if (buffer[block.EndIndex] is BranchInstr) {
  1086. BranchInstr branchInst = (BranchInstr)buffer[block.EndIndex];
  1087. // If this is not a "br" or "br.s" then set the fall through code block
  1088. if ((branchInst.GetBranchOp() != BranchOp.br) &&
  1089. (branchInst.GetBranchOp() != BranchOp.br_s))
  1090. // If there is a following code block set it as the fall through
  1091. if (j < (codeBlocks.Count - 1))
  1092. block.NextBlocks.Add(codeBlocks[j + 1]);
  1093. // Set the code block we are jumping to
  1094. CodeBlock cb = null;
  1095. cbTable.TryGetValue(branchInst.GetDest(), out cb);
  1096. if (cb == null)
  1097. throw new Exception("Missing Branch Label");
  1098. block.NextBlocks.Add(cb);
  1099. // If the block ends in a switch instruction work out the possible next blocks
  1100. }
  1101. else if (buffer[block.EndIndex] is SwitchInstr) {
  1102. SwitchInstr switchInstr = (SwitchInstr)buffer[block.EndIndex];
  1103. // If there is a following code block set it as the fall through
  1104. if (j < (codeBlocks.Count - 1))
  1105. block.NextBlocks.Add(codeBlocks[j + 1]);
  1106. // Add each destination block
  1107. foreach (CILLabel label in switchInstr.GetDests()) {
  1108. // Check all of the code blocks to find the jump destination
  1109. CodeBlock cb = null;
  1110. cbTable.TryGetValue(label, out cb);
  1111. if (cb == null) throw new Exception("Missing Case Label");
  1112. block.NextBlocks.Add(cb);
  1113. }
  1114. // So long as the block doesn't end with a terminating instruction like ret or throw, just fall through to the next block
  1115. }
  1116. else if (!IsTerminatingInstruction(buffer[block.EndIndex])) {
  1117. // If there is a following code block set it as the fall through
  1118. if (j < (codeBlocks.Count - 1))
  1119. block.NextBlocks.Add(codeBlocks[j + 1]);
  1120. }
  1121. }
  1122. //
  1123. // Join up any exception blocks
  1124. //
  1125. if (exceptions != null) {
  1126. foreach (TryBlock tryBlock in exceptions) {
  1127. // Try to find the code block where this try block starts
  1128. CodeBlock tryCodeBlock;
  1129. cbTable.TryGetValue(tryBlock.Start, out tryCodeBlock);
  1130. // Declare that the entry to this code block must be empty
  1131. tryCodeBlock.RequireEmptyEntry = true;
  1132. // Work with each of the handlers
  1133. foreach (HandlerBlock hb in tryBlock.GetHandlers()) {
  1134. // Find the code block where this handler block starts.
  1135. CodeBlock handlerCodeBlock;
  1136. cbTable.TryGetValue(hb.Start, out handlerCodeBlock);
  1137. // If the code block is a catch or filter block increment the delta
  1138. // distance by 1. This is to factor in the exception object that will
  1139. // be secretly placed on the stack by the runtime engine.
  1140. // However, this also means that the MaxDepth is up by one also!
  1141. if (hb is Catch || hb is Filter) {
  1142. handlerCodeBlock.DeltaDistance++;
  1143. handlerCodeBlock.MaxDepth++;
  1144. }
  1145. // If the code block is a filter block increment the delta distance by 1
  1146. // This is to factor in the exception object that will be placed on the stack.
  1147. // if (hb is Filter) handlerCodeBlock.DeltaDistance++;
  1148. // Add this handler to the list of starting places
  1149. extraStartingBlocks.Add(handlerCodeBlock);
  1150. }
  1151. }
  1152. }
  1153. //
  1154. // Traverse the code blocks and get the depth
  1155. //
  1156. // Get the max depth at the starting entry point
  1157. int finalMaxDepth = this.TraverseMaxDepth(codeBlocks[0]);
  1158. // Check the additional entry points
  1159. // If the additional points have a greater depth update the max depth
  1160. foreach (CodeBlock cb in extraStartingBlocks) {
  1161. // int tmpMaxDepth = cb.TraverseMaxDepth();
  1162. int tmpMaxDepth = this.TraverseMaxDepth(cb);
  1163. if (tmpMaxDepth > finalMaxDepth) finalMaxDepth = tmpMaxDepth;
  1164. }
  1165. // Return the max depth we have found
  1166. return finalMaxDepth;
  1167. }
  1168. int TraverseMaxDepth(CodeBlock entryBlock) {
  1169. int max = 0;
  1170. SCG.Queue<CodeBlock> worklist = new SCG.Queue<CodeBlock>();
  1171. entryBlock.Visited = true;
  1172. entryBlock.LastVisitEntryDepth = 0;
  1173. worklist.Enqueue(entryBlock);
  1174. while (worklist.Count > 0) {
  1175. int count = worklist.Count;
  1176. CodeBlock unit = worklist.Dequeue();
  1177. int maxDepth = unit.LastVisitEntryDepth + unit.MaxDepth;
  1178. int exitDepth = unit.LastVisitEntryDepth + unit.DeltaDistance;
  1179. if (maxDepth > max) max = maxDepth;
  1180. foreach (CodeBlock succ in unit.NextBlocks) {
  1181. if (succ.Visited) {
  1182. if (succ.LastVisitEntryDepth != exitDepth)
  1183. throw new InvalidStackDepth("inconsistent stack depth at offset " + succ.StartIndex.ToString());
  1184. }
  1185. else {
  1186. succ.Visited = true;
  1187. succ.LastVisitEntryDepth = exitDepth;
  1188. worklist.Enqueue(succ);
  1189. }
  1190. }
  1191. }
  1192. return max;
  1193. }
  1194. private bool IsTerminatingInstruction(CILInstruction cilInstr) {
  1195. // Return or throw instructions are terminating instructions
  1196. if (cilInstr is Instr) {
  1197. if (((Instr)cilInstr).GetOp() == Op.ret) return true;
  1198. if (((Instr)cilInstr).GetOp() == Op.throwOp) return true;
  1199. if (((Instr)cilInstr).GetOp() == Op.rethrow) return true;
  1200. }
  1201. // jmp is a terminating instruction
  1202. if (cilInstr is MethInstr) {
  1203. if (((MethInstr)cilInstr).GetMethodOp() == MethodOp.jmp) return true;
  1204. }
  1205. return false;
  1206. }
  1207. internal void Write(PEWriter output) {
  1208. if (Diag.DiagOn) Console.WriteLine("Writing header flags = " + Hex.Short(headerFlags));
  1209. if (tinyFormat) {
  1210. if (Diag.DiagOn) Console.WriteLine("Writing tiny code");
  1211. output.Write((byte)headerFlags);
  1212. }
  1213. else {
  1214. if (Diag.DiagOn) Console.WriteLine("Writing fat code");
  1215. output.Write(headerFlags);
  1216. output.Write((ushort)maxStack);
  1217. output.Write(offset);
  1218. output.Write(localSigIx);
  1219. }
  1220. if (Diag.DiagOn) {
  1221. Console.WriteLine(Hex.Int(tide) + " CIL instructions");
  1222. Console.WriteLine("starting instructions at " + output.Seek(0, SeekOrigin.Current));
  1223. }
  1224. // Added to enable PDB generation
  1225. if (output.pdbWriter != null) {
  1226. // Open the method
  1227. output.pdbWriter.OpenMethod((int)thisMeth.Token());
  1228. // Check if this is the entry point method
  1229. if (thisMeth.HasEntryPoint()) output.pdbWriter.SetEntryPoint((int)thisMeth.Token());
  1230. }
  1231. // Write out each memember of the buffer
  1232. for (int i = 0; i < tide; i++) {
  1233. buffer[i].Write(output);
  1234. }
  1235. // Added to enable PDB generation
  1236. if (output.pdbWriter != null && tide > 0) {
  1237. output.pdbWriter.CloseMethod();
  1238. }
  1239. if (Diag.DiagOn) Console.WriteLine("ending instructions at " + output.Seek(0, SeekOrigin.Current));
  1240. for (int i = 0; i < paddingNeeded; i++) { output.Write((byte)0); }
  1241. if (exceptions != null) {
  1242. // Console.WriteLine("Writing exceptions");
  1243. // Console.WriteLine("header = " + Hex.Short(exceptHeader) + " exceptSize = " + Hex.Int(exceptSize));
  1244. output.Write(exceptHeader);
  1245. output.Write3Bytes((uint)exceptSize);
  1246. for (int i = 0; i < exceptions.Count; i++) {
  1247. TryBlock tryBlock = (TryBlock)exceptions[i];
  1248. tryBlock.Write(output, fatExceptionFormat);
  1249. }
  1250. }
  1251. }
  1252. internal void Write(CILWriter output) {
  1253. for (int i = 0; i < tide; i++) {
  1254. if (!(buffer[i] is CILLabel)) {
  1255. output.Write(" ");
  1256. }
  1257. output.Write(" ");
  1258. buffer[i].Write(output);
  1259. }
  1260. if (exceptions != null) {
  1261. throw new NotYetImplementedException("Exceptions not yet implemented for CIL Instructions");
  1262. // Console.WriteLine("Writing exceptions");
  1263. // Console.WriteLine("header = " + Hex.Short(exceptHeader) + " exceptSize = " + Hex.Int(exceptSize));
  1264. //output.Write(exceptHeader);
  1265. //output.Write3Bytes((uint)exceptSize);
  1266. //for (int i = 0; i < exceptions.Count; i++) {
  1267. // TryBlock tryBlock = (TryBlock)exceptions[i];
  1268. // tryBlock.Write(output, fatExceptionFormat);
  1269. //}
  1270. }
  1271. }
  1272. /// <summary>
  1273. /// Stores the details of a given code block
  1274. /// </summary>
  1275. private class CodeBlock {
  1276. internal int StartIndex;
  1277. internal int EndIndex;
  1278. internal int DeltaDistance;
  1279. internal int MaxDepth;
  1280. internal CILLabel EntryLabel;
  1281. internal ArrayList NextBlocks = new ArrayList(); // List of CodeBlock objects
  1282. // internal int Visits;
  1283. internal int LastVisitEntryDepth;
  1284. internal bool RequireEmptyEntry;
  1285. internal bool Visited = false;
  1286. private CILInstructions cilInstr;
  1287. /// <summary>
  1288. /// Create a new code block definition
  1289. /// </summary>
  1290. /// <param name="instructions">The buffer the code block relates to</param>
  1291. internal CodeBlock(CILInstructions instructions) {
  1292. cilInstr = instructions;
  1293. }
  1294. }
  1295. }
  1296. /**************************************************************************/
  1297. /// <summary>
  1298. /// Descriptor for an IL instruction
  1299. /// </summary>
  1300. public abstract class CILInstruction {
  1301. protected static readonly sbyte maxByteVal = 127;
  1302. protected static readonly sbyte minByteVal = -128;
  1303. protected static readonly byte leadByte = 0xFE;
  1304. protected static readonly uint USHeapIndex = 0x70000000;
  1305. protected static readonly uint longInstrStart = (uint)Op.arglist;
  1306. protected static readonly string[] opcode = {
  1307. "nop", "break", "ldarg.0", "ldarg.1", "ldarg.2", "ldarg.3", "ldloc.0", "ldloc.1",
  1308. "ldloc.2", "ldloc.3", "stloc.0", "stloc.1", "stloc.2", "stloc.3", "ldarg.s", "ldarga.s",
  1309. "starg.s", "ldloc.s", "ldloca.s","stloc.s", "ldnull", "ldc.i4.m1","ldc.i4.0","ldc.i4.1",
  1310. "ldc.i4.2","ldc.i4.3","ldc.i4.4","ldc.i4.5","ldc.i4.6","ldc.i4.7","ldc.i4.8","ldc.i4.s",
  1311. "ldc.i4", "ldc.i8", "ldc.r4", "ldc.r8", "ERROR", "dup", "pop", "jmp",
  1312. "call", "calli", "ret", "br.s", "brfalse.s","brtrue.s","beq.s", "bge.s",
  1313. "bgt.s", "ble.s", "blt.s", "bne.un.s","bge.un.s","bgt.un.s","ble.un.s","blt.un.s",
  1314. "br", "brfalse", "brtrue", "beq", "bge", "bgt", "ble", "blt",
  1315. "bne.un", "bge.un", "bgt.un", "ble.un", "blt.un", "switch", "ldind.i1","ldind.u1",
  1316. "ldind.i2","ldind.u2","ldind.i4","ldind.u4","ldind.i8","ldind.i", "ldind.r4","ldind.r8",
  1317. "ldind.ref","stind.ref","stind.i1","stind.i2","stind.i4","stind.i8","stind.r4","stind.r8",
  1318. "add", "sub", "mul", "div", "div.un", "rem", "rem.un", "and",
  1319. "or", "xor", "shl", "shr", "shr.un", "neg", "not", "conv.i1",
  1320. "conv.i2", "conv.i4", "conv.i8", "conv.r4", "conv.r8", "conv.u4", "conv.u8", "callvirt",
  1321. "cpobj", "ldobj", "ldstr", "newobj", "castclass","isinst", "conv.r.un","ERROR",
  1322. "ERROR", "unbox", "throw", "ldfld", "ldflda", "stfld", "ldsfld", "ldsflda",
  1323. "stsfld", "stobj", "conv.ovf.i1.un", "conv.ovf.i2.un",
  1324. "conv.ovf.i4.un", "conv.ovf.i8.un", "conv.ovf.u1.un", "conv.ovf.u2.un",
  1325. "conv.ovf.u4.un", "conv.ovf.u8.un", "conv.ovf.i.un", "conv.ovf.u.un",
  1326. "box", "newarr", "ldlen", "ldelema",
  1327. "ldelem.i1", "ldelem.u1", "ldelem.i2", "ldelem.u2",
  1328. "ldelem.i4", "ldelem.u4", "ldelem.i8", "ldelem.i",
  1329. "ldelem.r4", "ldelem.r8", "ldelem.ref", "stelem.i",
  1330. "stelem.i1", "stelem.i2", "stelem.i4", "stelem.i8",
  1331. "stelem.r4", "stelem.r8", "stelem.ref", "ERROR",
  1332. "ERROR", "ERROR", "ERROR", "ERROR",
  1333. "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR",
  1334. "ERROR", "ERROR", "ERROR", "conv.ovf.i1",
  1335. "conv.ovf.u1", "conv.ovf.i2", "conv.ovf.u2", "conv.ovf.i4",
  1336. "conv.ovf.u4", "conv.ovf.i8", "conv.ovf.u8", "ERROR",
  1337. "ERROR", "ERROR", "ERROR", "ERROR",
  1338. "ERROR", "ERROR", "refanyval","ckfinite","ERROR", "ERROR", "mkrefany","ERROR",
  1339. "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR",
  1340. "ldtoken","conv.u2","conv.u1","conv.i","conv.ovf.i","conv.ovf.u","add.ovf","add.ovf.un",
  1341. "mul.ovf","mul.ovf.un","sub.ovf","sub.ovf.un","endfinally","leave","leave.s","stind.i",
  1342. "conv.u"};
  1343. protected static readonly int[] opDeltaDistance = {
  1344. 0 /* nop */, 0 /* break */, 1 /* ldarg.0 */, 1 /* ldarg.1 */, 1 /* ldarg.2 */, 1 /* ldarg.3 */, 1 /* ldloc.0 */, 1 /* ldloc.1 */,
  1345. 1 /* ldloc.2 */, 1 /* ldloc.3 */, -1 /* stloc.0 */, -1 /* stloc.1 */, -1 /* stloc.2 */, -1 /* stloc.3 */, 1 /* ldarg.s */, 1 /* ldarga.s */,
  1346. -1 /* starg.s */, 1 /* ldloc.s */, 1 /* ldloca.s */, -1 /* stloc.s */, 1 /* ldnull */, 1 /* ldc.i4.m1 */, 1 /* ldc.i4.0 */, 1 /* ldc.i4.1 */,
  1347. 1 /* ldc.i4.2 */, 1 /* ldc.i4.3 */, 1 /* ldc.i4.4 */, 1 /* ldc.i4.5 */, 1 /* ldc.i4.6 */, 1 /* ldc.i4.7 */, 1 /* ldc.i4.8 */, 1 /* ldc.i4.s */,
  1348. 1 /* ldc.i4 */, 1 /* ldc.i8 */, 1 /* ldc.r4 */, 1 /* ldc.r8 */, -99 /* ERROR */, 1 /* dup */, -1 /* pop */, 0 /* jmp */,
  1349. -99 /* call */, -99 /* calli */, 0 /* ret */, 0 /* br.s */, -1 /* brfalse.s */,-1 /* brtrue.s */, -2 /* beq.s */, -2 /* bge.s */,
  1350. -2 /* bgt.s */, -2 /* ble.s */, -2 /* blt.s */, -2 /* bne.un.s */, -2 /* bge.un.s */, -2 /* bgt.un.s */, -2 /* ble.un.s */, -2 /* blt.un.s */,
  1351. 0 /* br */, -1 /* brfalse */, -1 /* brtrue */, -2 /* beq */, -2 /* bge */, -2 /* bgt */, -2 /* ble */, -2 /* blt */,
  1352. -2 /* bne.un */, -2 /* bge.un */, -2 /* bgt.un */, -2 /* ble.un */, -2 /* blt.un */, -1 /* switch */, 0 /* ldind.i1 */, 0 /* ldind.u1 */,
  1353. 0 /* ldind.i2 */, 0 /* ldind.u2 */, 0 /* ldind.i4 */, 0 /* ldind.u4 */, 0 /* ldind.i8 */, 0 /* ldind.i */, 0 /* ldind.r4 */, 0 /* ldind.r8 */,
  1354. 0 /* ldind.ref */, -2 /* stind.ref */, -2 /* stind.i1 */, -2 /* stind.i2 */, -2 /* stind.i4 */, -2 /* stind.i8 */, -2 /* stind.r4 */, -2 /* stind.r8 */,
  1355. -1 /* add */, -1 /* sub */, -1 /* mul */, -1 /* div */, -1 /* div.un */, -1 /* rem */, -1 /* rem.un */, -1 /* and */,
  1356. -1 /* or */, -1 /* xor */, -1 /* shl */, -1 /* shr */, -1 /* shr.un */, 0 /* neg */, 0 /* not */, 0 /* conv.i1 */,
  1357. 0 /* conv.i2 */, 0 /* conv.i4 */, 0 /* conv.i8 */, 0 /* conv.r4 */, 0 /* conv.r8 */, 0 /* conv.u4 */, 0 /* conv.u8 */, -99 /* callvirt */,
  1358. -2 /* cpobj */, 0 /* ldobj */, 1 /* ldstr */, -99 /* newobj */, 0 /* castclass */, 0 /* isinst */, 0 /* conv.r.un */, -99 /* ERROR */,
  1359. -99 /* ERROR */, 0 /* unbox */, -1 /* throw */, 0 /* ldfld */, 0 /* ldflda */, -2 /* stfld */, 1 /* ldsfld */, 1 /* ldsflda */,
  1360. -1 /* stsfld */, -2 /* stobj */, 0 /* conv.ovf.i1.un */, 0 /* conv.ovf.i2.un */,
  1361. 0 /* conv.ovf.i4.un */, 0 /* conv.ovf.i8.un */, 0 /* conv.ovf.u1.un */, 0 /* conv.ovf.u2.un */,
  1362. 0 /* conv.ovf.u4.un */, 0 /* conv.ovf.u8.un */, 0 /* conv.ovf.i.un */, 0 /* conv.ovf.u.un */,
  1363. 0 /* box */, 0 /* newarr */, 0 /* ldlen */, -1 /* ldelema */,
  1364. -1 /* ldelem.i1 */, -1 /* ldelem.u1 */, -1 /* ldelem.i2 */, -1 /* ldelem.u2 */,
  1365. -1 /* ldelem.i4 */, -1 /* ldelem.u4 */, -1 /* ldelem.i8 */, -1 /* ldelem.i */,
  1366. -1 /* ldelem.r4 */, -1 /* ldelem.r8 */, -1 /* ldelem.ref */, -3 /* stelem.i */,
  1367. -3 /* stelem.i1 */, -3 /* stelem.i2 */, -3 /* stelem.i4 */, -3 /* stelem.i8 */,
  1368. -3 /* stelem.r4 */, -3 /* stelem.r8 */, -3 /* stelem.ref */, -99 /* ERROR */,
  1369. -99 /* ERROR */, -99 /* ERROR */, -99 /* ERROR */, -99 /* ERROR */,
  1370. -99 /* ERROR */, -99 /* ERROR */, -99 /* ERROR */, -99 /* ERROR */, -99 /* ERROR */, -99 /* ERROR */, -99 /* ERROR */, -99 /* ERROR */,
  1371. -99 /* ERROR */, -99 /* ERROR */, -99 /* ERROR */, 0 /* conv.ovf.i1 */,
  1372. 0 /* conv.ovf.u1 */, 0 /* conv.ovf.i2 */, 0 /* conv.ovf.u2 */, 0 /* conv.ovf.i4 */,
  1373. 0 /* conv.ovf.u4 */, 0 /* conv.ovf.i8 */, 0 /* conv.ovf.u8 */, -99 /* ERROR */,
  1374. -99 /* ERROR */, -99 /* ERROR */, -99 /* ERROR */, -99 /* ERROR */,
  1375. -99 /* ERROR */, -99 /* ERROR */, 0 /* refanyval */, 0 /* ckfinite */, -99 /* ERROR */, -99 /* ERROR */, 0 /* mkrefany */, -99 /* ERROR */,
  1376. -99 /* ERROR */, -99 /* ERROR */, -99 /* ERROR */, -99 /* ERROR */, -99 /* ERROR */, -99 /* ERROR */, -99 /* ERROR */, -99 /* ERROR */,
  1377. 1 /* ldtoken */, 0 /* conv.u2 */, 0 /* conv.u1 */, 0 /* conv.i */, 0 /* conv.ovf.i */,0 /* conv.ovf.u */,-1 /* add.ovf */, -1 /* add.ovf.un */,
  1378. -1 /* mul.ovf */, -1 /* mul.ovf.un */, -1 /* sub.ovf */, -1 /* sub.ovf.un */, 0 /* endfinally */,0 /* leave */, 0 /* leave.s */, -2 /* stind.i */,
  1379. 0 /* conv.u */};
  1380. /// <summary>
  1381. /// A list of the delta distances for the given CIL instructions.
  1382. /// </summary>
  1383. protected static readonly string[] FEopcode = {
  1384. "arglist", "ceq", "cgt", "cgt.un", "clt", "clt.un", "ldftn", "ldvirtftn",
  1385. "ERROR", "ldarg", "ldarga", "starg", "ldloc", "ldloca", "stloc", "localloc",
  1386. "ERROR", "endfilter", "unaligned", "volatile", "tail", "initobj", "constrained", "cpblk",
  1387. "initblk", "no.", "rethrow", "ERROR", "sizeof", "refanytype", "readonly"};
  1388. /// <summary>
  1389. /// A list of the delta distances for the given FE CIL instructions.
  1390. /// </summary>
  1391. protected static readonly int[] FEopDeltaDistance = {
  1392. 1 /* arglist */, -1 /* ceq */, -1 /* cgt */, -1 /* cgt.un */, -1 /* clt */, -1 /* clt.un */, 1 /* ldftn */, 0 /* ldvirtftn */,
  1393. -99 /* ERROR */, 1 /* ldarg */, 1 /* ldarga */, -1 /* starg */, 1 /* ldloc */, 1 /* ldloca */, -1 /* stloc */, 0 /* localloc */,
  1394. -99 /* ERROR */, -1 /* endfilter */, 0 /* unaligned */, 0 /* volatile */, 0 /* tail */, -1 /* initobj */, 0 /* constrained */, -3 /* cpblk */,
  1395. -3 /* initblk */, 0 /* no. */, 0 /* rethrow */, -99 /* ERROR */, 1 /* sizeof */, 0 /* refanytype */, 0 /* readonly */};
  1396. internal bool twoByteInstr = false;
  1397. internal uint size = 1;
  1398. internal uint offset, index;
  1399. internal virtual bool Check(MetaDataOut md) {
  1400. return false;
  1401. }
  1402. internal virtual void Resolve() { }
  1403. public int GetPos() { return (int)index; }
  1404. internal abstract string GetInstName();
  1405. /// <summary>
  1406. /// Get the delta distance for this instruction.
  1407. /// </summary>
  1408. /// <remarks>
  1409. /// The delta distance is the resulting difference of items
  1410. /// left on the stack after calling this instruction.
  1411. /// </remarks>
  1412. /// <returns>An integer value representing the delta distance.</returns>
  1413. internal abstract int GetDeltaDistance();
  1414. internal virtual void BuildTables(MetaDataOut md) { }
  1415. internal virtual void BuildCILInfo(CILWriter output) { }
  1416. internal virtual void Write(PEWriter output) { }
  1417. internal virtual void Write(CILWriter output) { }
  1418. }
  1419. /**************************************************************************/
  1420. public class CILByte : CILInstruction {
  1421. byte byteVal;
  1422. /*-------------------- Constructors ---------------------------------*/
  1423. internal CILByte(byte bVal) {
  1424. byteVal = bVal;
  1425. }
  1426. public byte GetByte() { return byteVal; }
  1427. internal override string GetInstName() {
  1428. return Hex.Byte(byteVal);
  1429. }
  1430. /// <summary>
  1431. /// Get the delta distance for this instruction.
  1432. /// </summary>
  1433. /// <remarks>
  1434. /// The delta distance is the resulting difference of items
  1435. /// left on the stack after calling this instruction.
  1436. /// </remarks>
  1437. /// <returns>Zero, the delta distance for a CILByte</returns>
  1438. internal override int GetDeltaDistance() {
  1439. return 0;
  1440. }
  1441. internal override void Write(PEWriter output) {
  1442. output.Write(byteVal);
  1443. }
  1444. internal override void Write(CILWriter output) {
  1445. output.WriteLine(".emitbyte " + Hex.Byte(byteVal)); // ???? CHECK THIS ????
  1446. }
  1447. }
  1448. /**************************************************************************/
  1449. public class Instr : CILInstruction {
  1450. protected uint instr;
  1451. /*-------------------- Constructors ---------------------------------*/
  1452. public Instr(Op inst) {
  1453. instr = (uint)inst;
  1454. if (instr >= longInstrStart) {
  1455. instr -= longInstrStart;
  1456. twoByteInstr = true;
  1457. size++;
  1458. }
  1459. }
  1460. internal Instr(uint inst) {
  1461. instr = (uint)inst;
  1462. if (instr >= longInstrStart) {
  1463. instr -= longInstrStart;
  1464. twoByteInstr = true;
  1465. size++;
  1466. }
  1467. }
  1468. public Op GetOp() {
  1469. if (twoByteInstr)
  1470. return (Op)(longInstrStart + instr);
  1471. return (Op)instr;
  1472. }
  1473. internal override string GetInstName() {
  1474. Op opInst = GetOp();
  1475. return "" + opInst;
  1476. }
  1477. internal override void Write(PEWriter output) {
  1478. //Console.WriteLine("Writing instruction " + instr + " with size " + size);
  1479. if (twoByteInstr) output.Write(leadByte);
  1480. output.Write((byte)instr);
  1481. }
  1482. internal string GetInstrString() {
  1483. if (twoByteInstr) {
  1484. return FEopcode[instr] + " ";
  1485. }
  1486. else {
  1487. return opcode[instr] + " ";
  1488. }
  1489. }
  1490. public override string ToString() { return this.GetInstrString(); }
  1491. /// <summary>
  1492. /// Get the delta distance for this instruction.
  1493. /// </summary>
  1494. /// <remarks>
  1495. /// The delta distance is the resulting difference of items
  1496. /// left on the stack after calling this instruction.
  1497. /// </remarks>
  1498. /// <returns>An integer value representing the delta distance.</returns>
  1499. internal override int GetDeltaDistance() {
  1500. if (twoByteInstr) {
  1501. return FEopDeltaDistance[instr];
  1502. }
  1503. else {
  1504. return opDeltaDistance[instr];
  1505. }
  1506. }
  1507. internal override void Write(CILWriter output) {
  1508. if (twoByteInstr) {
  1509. output.WriteLine(FEopcode[instr]);
  1510. }
  1511. else {
  1512. output.WriteLine(opcode[instr]);
  1513. }
  1514. }
  1515. }
  1516. /**************************************************************************/
  1517. public class IntInstr : Instr {
  1518. int val;
  1519. bool byteNum;
  1520. /*-------------------- Constructors ---------------------------------*/
  1521. public IntInstr(IntOp inst, int num)
  1522. : base((uint)inst) {
  1523. byteNum = inst == IntOp.ldc_i4_s;
  1524. val = num;
  1525. if (byteNum) size++;
  1526. else size += 4;
  1527. }
  1528. public int GetInt() { return val; }
  1529. public void SetInt(int num) { val = num; }
  1530. internal sealed override void Write(PEWriter output) {
  1531. base.Write(output);
  1532. if (byteNum)
  1533. output.Write((sbyte)val);
  1534. else
  1535. output.Write(val);
  1536. }
  1537. /// <summary>
  1538. /// Get the delta distance for this instruction.
  1539. /// </summary>
  1540. /// <remarks>
  1541. /// The delta distance is the resulting difference of items
  1542. /// left on the stack after calling this instruction.
  1543. /// </remarks>
  1544. /// <returns>An integer value representing the delta distance.</returns>
  1545. internal override int GetDeltaDistance() {
  1546. return opDeltaDistance[instr];
  1547. }
  1548. internal override void Write(CILWriter output) {
  1549. output.WriteLine(opcode[instr] + " " + val);
  1550. }
  1551. }
  1552. /**************************************************************************/
  1553. public class UIntInstr : Instr {
  1554. uint val;
  1555. bool byteNum;
  1556. /*-------------------- Constructors ---------------------------------*/
  1557. public UIntInstr(IntOp inst, uint num)
  1558. : base((uint)inst) {
  1559. byteNum = (inst < IntOp.ldc_i4_s) || (inst == IntOp.unaligned);
  1560. val = num;
  1561. if (byteNum) size++;
  1562. else size += 2;
  1563. }
  1564. public uint GetUInt() { return val; }
  1565. public void SetUInt(uint num) { val = num; }
  1566. /// <summary>
  1567. /// Get the delta distance for this instruction.
  1568. /// </summary>
  1569. /// <remarks>
  1570. /// The delta distance is the resulting difference of items
  1571. /// left on the stack after calling this instruction.
  1572. /// </remarks>
  1573. /// <returns>An integer value representing the delta distance.</returns>
  1574. internal override int GetDeltaDistance() {
  1575. if (twoByteInstr) {
  1576. return FEopDeltaDistance[instr];
  1577. }
  1578. else {
  1579. return opDeltaDistance[instr];
  1580. }
  1581. }
  1582. internal sealed override void Write(PEWriter output) {
  1583. base.Write(output);
  1584. if (byteNum)
  1585. output.Write((byte)val);
  1586. else
  1587. output.Write((ushort)val);
  1588. }
  1589. internal override void Write(CILWriter output) {
  1590. if (twoByteInstr) {
  1591. output.Write(FEopcode[instr]);
  1592. }
  1593. else {
  1594. output.Write(opcode[instr]);
  1595. }
  1596. output.WriteLine(" " + val);
  1597. }
  1598. }
  1599. /**************************************************************************/
  1600. public class LongInstr : Instr {
  1601. long val;
  1602. /*-------------------- Constructors ---------------------------------*/
  1603. public LongInstr(SpecialOp inst, long l)
  1604. : base((uint)inst) {
  1605. val = l;
  1606. size += 8;
  1607. }
  1608. public long GetLong() { return val; }
  1609. public void SetLong(long num) { val = num; }
  1610. internal sealed override void Write(PEWriter output) {
  1611. base.Write(output);
  1612. output.Write(val);
  1613. }
  1614. internal override void Write(CILWriter output) {
  1615. output.WriteLine("ldc.i8 " + val);
  1616. }
  1617. }
  1618. /**************************************************************************/
  1619. public class FloatInstr : Instr {
  1620. float fVal;
  1621. /*-------------------- Constructors ---------------------------------*/
  1622. public FloatInstr(SpecialOp inst, float f)
  1623. : base((uint)inst) {
  1624. fVal = f;
  1625. size += 4;
  1626. }
  1627. public float GetFloat() { return fVal; }
  1628. public void SetFloat(float num) { fVal = num; }
  1629. internal sealed override void Write(PEWriter output) {
  1630. output.Write((byte)0x22);
  1631. output.Write(fVal);
  1632. }
  1633. internal override void Write(CILWriter output) {
  1634. output.WriteLine("ldc.r4 " + fVal);
  1635. }
  1636. }
  1637. /**************************************************************************/
  1638. public class DoubleInstr : Instr {
  1639. double val;
  1640. /*-------------------- Constructors ---------------------------------*/
  1641. public DoubleInstr(SpecialOp inst, double d)
  1642. : base((uint)inst) {
  1643. val = d;
  1644. size += 8;
  1645. }
  1646. public double GetDouble() { return val; }
  1647. public void SetDouble(double num) { val = num; }
  1648. internal sealed override void Write(PEWriter output) {
  1649. base.Write(output);
  1650. output.Write(val);
  1651. }
  1652. internal override void Write(CILWriter output) {
  1653. output.WriteLine("ldc.r8 " + val);
  1654. }
  1655. }
  1656. /**************************************************************************/
  1657. public class StringInstr : Instr {
  1658. string val;
  1659. uint strIndex;
  1660. /*-------------------- Constructors ---------------------------------*/
  1661. public StringInstr(SpecialOp inst, string str)
  1662. : base((uint)inst) {
  1663. val = str;
  1664. size += 4;
  1665. }
  1666. public string GetString() { return val; }
  1667. public void SetString(string str) { val = str; }
  1668. internal sealed override void BuildTables(MetaDataOut md) {
  1669. if (Diag.DiagOn) Console.WriteLine("Adding a code string to the US heap");
  1670. strIndex = md.AddToUSHeap(val);
  1671. }
  1672. internal sealed override void Write(PEWriter output) {
  1673. base.Write(output);
  1674. output.Write(USHeapIndex | strIndex);
  1675. }
  1676. internal override void Write(CILWriter output) {
  1677. output.WriteLine("ldstr \"" + val + "\"");
  1678. }
  1679. }
  1680. /**************************************************************************/
  1681. public class CILLabel : CILInstruction {
  1682. private static int labelNum = 0;
  1683. private int num = -1;
  1684. private CILInstructions buffer;
  1685. /*-------------------- Constructors ---------------------------------*/
  1686. public CILLabel() {
  1687. size = 0;
  1688. }
  1689. internal CILLabel(uint offs) {
  1690. size = 0;
  1691. offset = offs;
  1692. }
  1693. internal uint GetLabelOffset() {
  1694. return offset;
  1695. }
  1696. internal override string GetInstName() {
  1697. return "Label" + num;
  1698. }
  1699. internal CILInstructions Buffer {
  1700. get { return buffer; }
  1701. set { buffer = value; }
  1702. }
  1703. internal override void BuildCILInfo(CILWriter output) {
  1704. if (num == -1) {
  1705. num = labelNum++;
  1706. }
  1707. }
  1708. /// <summary>
  1709. /// Get the delta distance for this instruction.
  1710. /// </summary>
  1711. /// <remarks>
  1712. /// The delta distance is the resulting difference of items
  1713. /// left on the stack after calling this instruction.
  1714. /// </remarks>
  1715. /// <returns>An integer value representing the delta distance.</returns>
  1716. internal override int GetDeltaDistance() {
  1717. return 0;
  1718. }
  1719. internal override void Write(CILWriter output) {
  1720. output.WriteLine("Label" + num + ":");
  1721. }
  1722. public override string ToString() { return "label"; }
  1723. }
  1724. /**************************************************************************/
  1725. /// <summary>
  1726. /// Abstract model for debug instructions.
  1727. /// </summary>
  1728. public abstract class DebugInst : CILInstruction { }
  1729. /**************************************************************************/
  1730. /// <summary>
  1731. /// Defines a line instruction.
  1732. /// </summary>
  1733. public class Line : DebugInst {
  1734. private static uint MaxCol = 100;
  1735. uint startLine, startCol, endLine, endCol;
  1736. bool hasEnd = false;
  1737. internal SourceFile sourceFile;
  1738. /*-------------------- Constructors ---------------------------------*/
  1739. /// <summary>
  1740. /// Create a new line instruction.
  1741. /// </summary>
  1742. /// <param name="sLine">Start of the line in the source file.</param>
  1743. /// <param name="sCol">Starting column in the source file.</param>
  1744. /// <param name="sFile">The filename of the souce file.</param>
  1745. internal Line(uint sLine, uint sCol, SourceFile sFile) {
  1746. startLine = sLine;
  1747. startCol = sCol;
  1748. sourceFile = sFile;
  1749. size = 0;
  1750. }
  1751. /// <summary>
  1752. /// Create a new line instruction.
  1753. /// </summary>
  1754. /// <param name="sLine">Start of the line in the source file.</param>
  1755. /// <param name="sCol">Starting column in the source file.</param>
  1756. /// <param name="eLine">Ending line in the source file.</param>
  1757. /// <param name="eCol">Ending column in the source file.</param>
  1758. /// <param name="sFile">The filename of the souce file.</param>
  1759. internal Line(uint sLine, uint sCol, uint eLine, uint eCol, SourceFile sFile) {
  1760. startLine = sLine;
  1761. startCol = sCol;
  1762. endLine = eLine;
  1763. endCol = eCol;
  1764. hasEnd = true;
  1765. sourceFile = sFile;
  1766. size = 0;
  1767. }
  1768. public int LineNum {
  1769. get { return (int)startLine; }
  1770. }
  1771. internal void CalcEnd(Line next) {
  1772. if (hasEnd) return;
  1773. if (sourceFile != next.sourceFile) {
  1774. endLine = startLine;
  1775. endCol = MaxCol;
  1776. }
  1777. else {
  1778. endLine = next.startLine;
  1779. endCol = next.startCol;
  1780. if (endCol < 0) endCol = MaxCol;
  1781. }
  1782. hasEnd = true;
  1783. }
  1784. internal void Last() {
  1785. if (hasEnd) return;
  1786. endLine = startLine;
  1787. endCol = MaxCol;
  1788. hasEnd = true;
  1789. }
  1790. /// <summary>
  1791. /// Get the name of this instruction.
  1792. /// </summary>
  1793. /// <returns>A string with the value ".line".</returns>
  1794. internal override string GetInstName() {
  1795. return ".line";
  1796. }
  1797. /// <summary>
  1798. /// Write this instruction to a PDB file.
  1799. /// </summary>
  1800. /// <param name="output">The PE writer being used to write the PE and PDB files.</param>
  1801. internal override void Write(PEWriter output) {
  1802. string sf = "";
  1803. Guid doclang = Guid.Empty;
  1804. Guid docvend = Guid.Empty;
  1805. Guid doctype = Guid.Empty;
  1806. if (sourceFile != null) {
  1807. sf = sourceFile.name;
  1808. doclang = sourceFile.language;
  1809. docvend = sourceFile.vendor;
  1810. doctype = sourceFile.document;
  1811. }
  1812. if (output.pdbWriter != null)
  1813. output.pdbWriter.AddSequencePoint(sf, doclang, docvend, doctype, (int)offset,
  1814. (int)startLine, (int)startCol, (int)endLine, (int)endCol);
  1815. }
  1816. /// <summary>
  1817. /// Get the delta distance for this instruction.
  1818. /// </summary>
  1819. /// <remarks>
  1820. /// The delta distance is the resulting difference of items
  1821. /// left on the stack after calling this instruction.
  1822. /// </remarks>
  1823. /// <returns>An integer value representing the delta distance.</returns>
  1824. internal override int GetDeltaDistance() {
  1825. return 0;
  1826. }
  1827. /// <summary>
  1828. /// Write out a line instruction to the CIL file.
  1829. /// </summary>
  1830. /// <param name="output">The CIL instruction writer to use to write this instruction.</param>
  1831. internal override void Write(CILWriter output) {
  1832. if (output.Debug) {
  1833. string lineDetails = startLine + ", " + startCol;
  1834. if (hasEnd) {
  1835. lineDetails += ", " + endLine + ", " + endCol;
  1836. if (sourceFile != null) {
  1837. lineDetails += ", " + sourceFile.Name;
  1838. }
  1839. }
  1840. output.WriteLine(".line " + lineDetails);
  1841. }
  1842. }
  1843. public override string ToString() {
  1844. return String.Format("line {0}:{1}-{2}:{3}", this.startLine, this.startCol, this.endLine, this.endCol);
  1845. }
  1846. }
  1847. /**************************************************************************/
  1848. /// <summary>
  1849. /// A local binding instruction that can be added to a list of CILInstructions.
  1850. /// </summary>
  1851. public class LocalBinding : DebugInst {
  1852. internal int _index;
  1853. internal string _name;
  1854. internal DebugLocalSig _debugsig;
  1855. /*-------------------- Constructors ---------------------------------*/
  1856. /// <summary>
  1857. /// Create a new local binding object.
  1858. /// </summary>
  1859. /// <param name="index">The index of the local in the locals tables.</param>
  1860. /// <param name="name">The name of the local.</param>
  1861. internal LocalBinding(int index, string name) {
  1862. _index = index;
  1863. _name = name;
  1864. }
  1865. /// <summary>
  1866. /// The index of the local in the locals table.
  1867. /// </summary>
  1868. public int Index {
  1869. get { return _index; }
  1870. }
  1871. /// <summary>
  1872. /// The name of the local binding.
  1873. /// </summary>
  1874. public string Name {
  1875. get { return _name; }
  1876. }
  1877. /// <summary>
  1878. /// Get the delta distance for this instruction.
  1879. /// </summary>
  1880. /// <remarks>
  1881. /// The delta distance is the resulting difference of items
  1882. /// left on the stack after calling this instruction.
  1883. /// </remarks>
  1884. /// <returns>An integer value representing the delta distance.</returns>
  1885. internal override int GetDeltaDistance() {
  1886. return 0;
  1887. }
  1888. /// <summary>
  1889. /// Get the name of this instruction.
  1890. /// </summary>
  1891. /// <returns>A string with the name of this instruction.</returns>
  1892. internal override string GetInstName() {
  1893. return "debug - local binding";
  1894. }
  1895. }
  1896. /**************************************************************************/
  1897. /// <summary>
  1898. /// Used to declare constants that exist in a given scope.
  1899. /// </summary>
  1900. public class ConstantBinding : DebugInst {
  1901. private string _name;
  1902. private object _value;
  1903. private Type _type;
  1904. private uint _token;
  1905. /*-------------------- Constructors ---------------------------------*/
  1906. /// <summary>
  1907. /// Create a new constant binding.
  1908. /// </summary>
  1909. /// <param name="name">The name of the constant.</param>
  1910. /// <param name="value">The value of the constant.</param>
  1911. /// <param name="type">The data type of the constant.</param>
  1912. internal ConstantBinding(string name, object value, Type type, uint token) {
  1913. _value = value;
  1914. _name = name;
  1915. _type = type;
  1916. _token = token;
  1917. }
  1918. /// <summary>
  1919. /// Value of the constant.
  1920. /// </summary>
  1921. public object Value {
  1922. get { return _value; }
  1923. }
  1924. /// <summary>
  1925. /// The name of the constant.
  1926. /// </summary>
  1927. public string Name {
  1928. get { return _name; }
  1929. }
  1930. /// <summary>
  1931. /// The data type of the constant.
  1932. /// </summary>
  1933. public Type Type {
  1934. get { return _type; }
  1935. }
  1936. /// <summary>
  1937. /// The token for this constant.
  1938. /// </summary>
  1939. public uint Token {
  1940. get { return _token; }
  1941. }
  1942. /// <summary>
  1943. /// Get the type signature for this constant.
  1944. /// </summary>
  1945. /// <returns>A byte array of the type signature.</returns>
  1946. public byte[] GetSig() {
  1947. MemoryStream str = new MemoryStream();
  1948. _type.TypeSig(str);
  1949. return str.ToArray();
  1950. }
  1951. /// <summary>
  1952. /// Get the name of this instruction.
  1953. /// </summary>
  1954. /// <returns>A string with the name of this instruction.</returns>
  1955. internal override string GetInstName() {
  1956. return "debug - constant binding";
  1957. }
  1958. /// <summary>
  1959. /// Get the delta distance for this instruction.
  1960. /// </summary>
  1961. /// <remarks>
  1962. /// The delta distance is the resulting difference of items
  1963. /// left on the stack after calling this instruction.
  1964. /// </remarks>
  1965. /// <returns>An integer value representing the delta distance.</returns>
  1966. internal override int GetDeltaDistance() {
  1967. return 0;
  1968. }
  1969. }
  1970. /**************************************************************************/
  1971. public class SwitchInstr : Instr {
  1972. CILLabel[] cases;
  1973. uint numCases = 0;
  1974. int[] targets;
  1975. /*-------------------- Constructors ---------------------------------*/
  1976. public SwitchInstr(CILLabel[] dsts)
  1977. : base(0x45) {
  1978. cases = dsts;
  1979. if (cases != null) numCases = (uint)cases.Length;
  1980. size += 4 + (numCases * 4);
  1981. }
  1982. internal SwitchInstr(int[] offsets)
  1983. : base(0x45) {
  1984. numCases = (uint)offsets.Length;
  1985. targets = offsets;
  1986. size += 4 + (numCases * 4);
  1987. }
  1988. public CILLabel[] GetDests() { return cases; }
  1989. public void SetDests(CILLabel[] dests) { cases = dests; }
  1990. internal override string GetInstName() {
  1991. return "switch";
  1992. }
  1993. internal void MakeTargetLabels(ArrayList labs) {
  1994. cases = new CILLabel[numCases];
  1995. for (int i = 0; i < numCases; i++) {
  1996. cases[i] = CILInstructions.GetLabel(labs, (uint)(offset + size + targets[i]));
  1997. }
  1998. }
  1999. internal sealed override void Write(PEWriter output) {
  2000. base.Write(output);
  2001. output.Write(numCases);
  2002. for (int i = 0; i < numCases; i++) {
  2003. int target = (int)cases[i].GetLabelOffset() - (int)(offset + size);
  2004. output.Write(target);
  2005. }
  2006. }
  2007. internal override void Write(CILWriter output) {
  2008. throw new NotImplementedException("Switch instruction for CIL");
  2009. }
  2010. }
  2011. public class Scope {
  2012. private ArrayList _localBindings = new ArrayList();
  2013. private ArrayList _constantBindings = new ArrayList();
  2014. internal Scope _parent;
  2015. internal MethodDef _thisMeth;
  2016. internal Scope(MethodDef thisMeth)
  2017. : this(null, thisMeth) {
  2018. }
  2019. internal Scope(Scope parent, MethodDef thisMeth) {
  2020. _thisMeth = thisMeth;
  2021. _parent = parent;
  2022. }
  2023. /// <summary>
  2024. /// Add a constant to this scope.
  2025. /// </summary>
  2026. /// <param name="name">The name of the constant.</param>
  2027. /// <param name="value">The value of the constant.</param>
  2028. /// <param name="type">The type of the constant.</param>
  2029. /// <returns>The ConstantBinding object for the new constant.</returns>
  2030. internal ConstantBinding AddConstantBinding(string name, object value, Type type) {
  2031. ConstantBinding binding;
  2032. if ((binding = FindConstantBinding(name)) != null)
  2033. return binding;
  2034. binding = new ConstantBinding(name, value, type, _thisMeth.locToken);
  2035. _constantBindings.Add(binding);
  2036. return binding;
  2037. }
  2038. /// <summary>
  2039. /// Find a constant in this scope.
  2040. /// </summary>
  2041. /// <param name="name">The name of the constant.</param>
  2042. /// <returns>The ConstantBinding object of this constant.</returns>
  2043. internal ConstantBinding FindConstantBinding(string name) {
  2044. foreach (ConstantBinding binding in _constantBindings)
  2045. if (binding.Name == name)
  2046. return binding;
  2047. return null;
  2048. }
  2049. /// <summary>
  2050. /// Provide a complete list of all constants bound in this scope.
  2051. /// </summary>
  2052. public ConstantBinding[] ConstantBindings {
  2053. get { return (ConstantBinding[])_constantBindings.ToArray(typeof(ConstantBinding)); }
  2054. }
  2055. internal LocalBinding AddLocalBinding(string name, int index) {
  2056. LocalBinding binding;
  2057. if ((binding = FindLocalBinding(name)) != null)
  2058. return binding;
  2059. binding = new LocalBinding(index, name);
  2060. _localBindings.Add(binding);
  2061. return binding;
  2062. }
  2063. internal LocalBinding FindLocalBinding(string name) {
  2064. foreach (LocalBinding binding in _localBindings)
  2065. if (binding._name == name)
  2066. return binding;
  2067. return null;
  2068. }
  2069. internal LocalBinding FindLocalBinding(int index) {
  2070. foreach (LocalBinding binding in _localBindings)
  2071. if (binding._index == index)
  2072. return binding;
  2073. return null;
  2074. }
  2075. public LocalBinding[] LocalBindings {
  2076. get { return (LocalBinding[])_localBindings.ToArray(typeof(LocalBinding)); }
  2077. }
  2078. internal void BuildSignatures(MetaDataOut md) {
  2079. if (!md.Debug) return;
  2080. try {
  2081. Local[] locals = _thisMeth.GetLocals();
  2082. foreach (LocalBinding binding in _localBindings) {
  2083. if (binding._debugsig == null) {
  2084. locals[binding._index].BuildTables(md);
  2085. binding._debugsig = md.GetDebugSig(locals[binding._index]);
  2086. }
  2087. binding._debugsig.BuildMDTables(md);
  2088. }
  2089. }
  2090. catch (Exception e) {
  2091. throw new Exception("Exception while writing debug info for: " +
  2092. this._thisMeth.NameString() + "\r\n" + e.ToString());
  2093. }
  2094. }
  2095. internal void WriteLocals(PDBWriter writer) {
  2096. try {
  2097. Local[] locals = _thisMeth.GetLocals();
  2098. foreach (LocalBinding binding in _localBindings) {
  2099. writer.BindLocal(binding._name, binding._index, _thisMeth.locToken, 0, 0);
  2100. }
  2101. }
  2102. catch (Exception e) {
  2103. throw new Exception("Exception while writing debug info for: " +
  2104. this._thisMeth.NameString() + "\r\n" + e.ToString(), e);
  2105. }
  2106. }
  2107. /* Constants does not work. AKB 2007-02-03
  2108. internal void WriteConstants(PDBWriter writer) {
  2109. try {
  2110. // Add each constant to the current scope
  2111. foreach (ConstantBinding binding in _constantBindings)
  2112. writer.BindConstant(binding);
  2113. } catch (Exception e) {
  2114. throw new Exception("Exception while writing debug info for: " +
  2115. this._thisMeth.NameString() + "\r\n" + e.ToString(), e);
  2116. }
  2117. }
  2118. */
  2119. }
  2120. /*************************************************************************/
  2121. /// <summary>
  2122. /// A marker instruction for when a scope should be opened in the sequence of instructions.
  2123. /// </summary>
  2124. public class OpenScope : DebugInst {
  2125. internal Scope _scope;
  2126. /// <summary>
  2127. /// Create a new OpenScope instruction.
  2128. /// </summary>
  2129. /// <param name="scope">The scope that is being opened.</param>
  2130. public OpenScope(Scope scope) {
  2131. size = 0;
  2132. _scope = scope;
  2133. }
  2134. /// <summary>
  2135. /// Get the name for this instruction.
  2136. /// </summary>
  2137. /// <returns>A string with the name of the instruction.</returns>
  2138. internal override string GetInstName() {
  2139. return "debug - open scope";
  2140. }
  2141. /// <summary>
  2142. /// Build the signatures for this instruction.
  2143. /// </summary>
  2144. /// <param name="md">The meta data table to write the instructions to.</param>
  2145. internal void BuildSignatures(MetaDataOut md) {
  2146. _scope.BuildSignatures(md);
  2147. }
  2148. /// <summary>
  2149. /// Get the delta distance for this instruction.
  2150. /// </summary>
  2151. /// <remarks>
  2152. /// The delta distance is the resulting difference of items
  2153. /// left on the stack after calling this instruction.
  2154. /// </remarks>
  2155. /// <returns>An integer value representing the delta distance.</returns>
  2156. ///
  2157. internal override int GetDeltaDistance() {
  2158. return 0;
  2159. }
  2160. /// <summary>
  2161. /// Write this instruction to the PDB file.
  2162. /// </summary>
  2163. /// <param name="output">The PEWriter being used to write the PE and PDB files.</param>
  2164. internal override void Write(PEWriter output) {
  2165. if (output.pdbWriter != null) {
  2166. output.pdbWriter.OpenScope((int)offset);
  2167. _scope.WriteLocals(output.pdbWriter);
  2168. /* Constants do not work. AKB 2007-02-03
  2169. * _scope.WriteConstants(output.pdbWriter);
  2170. */
  2171. }
  2172. }
  2173. public override string ToString() { return "Open scope"; }
  2174. }
  2175. /************************************************************************/
  2176. /// <summary>
  2177. /// A marker instruction for when a scope should be closed.
  2178. /// </summary>
  2179. public class CloseScope : DebugInst {
  2180. internal Scope _scope;
  2181. /// <summary>
  2182. /// The constructor to build a new CloseScope instruction.
  2183. /// </summary>
  2184. /// <param name="scope">The scope to close.</param>
  2185. public CloseScope(Scope scope) {
  2186. size = 0;
  2187. _scope = scope;
  2188. }
  2189. /// <summary>
  2190. /// Provide access to the name of this instruction.
  2191. /// </summary>
  2192. /// <returns>A string containing the name of this instruction.</returns>
  2193. internal override string GetInstName() {
  2194. return "debug - close scope";
  2195. }
  2196. /// <summary>
  2197. /// Get the delta distance for this instruction.
  2198. /// </summary>
  2199. /// <remarks>
  2200. /// The delta distance is the resulting difference of items
  2201. /// left on the stack after calling this instruction.
  2202. /// </remarks>
  2203. /// <returns>An integer value representing the delta distance.</returns>
  2204. internal override int GetDeltaDistance() {
  2205. return 0;
  2206. }
  2207. /// <summary>
  2208. /// Write this instruction. This instruction does not get written
  2209. /// to the PE file. It only applys to the PDB file.
  2210. /// </summary>
  2211. /// <param name="output">The PEWriter that is writing the PE file.</param>
  2212. internal override void Write(PEWriter output) {
  2213. if (output.pdbWriter != null)
  2214. output.pdbWriter.CloseScope((int)offset);
  2215. }
  2216. public override string ToString() { return "Close scope"; }
  2217. }
  2218. /**************************************************************************/
  2219. public class FieldInstr : Instr {
  2220. Field field;
  2221. /*-------------------- Constructors ---------------------------------*/
  2222. public FieldInstr(FieldOp inst, Field f)
  2223. : base((uint)inst) {
  2224. field = f;
  2225. size += 4;
  2226. }
  2227. public Field GetField() { return field; }
  2228. public void SetField(Field fld) { field = fld; }
  2229. internal override string GetInstName() {
  2230. return "" + (FieldOp)instr;
  2231. }
  2232. internal sealed override void BuildTables(MetaDataOut md) {
  2233. if (field == null) throw new InstructionException(IType.fieldOp, instr);
  2234. if (field is FieldRef) field.BuildMDTables(md);
  2235. }
  2236. internal override void BuildCILInfo(CILWriter output) {
  2237. if (field == null) throw new InstructionException(IType.fieldOp, instr);
  2238. if (field is FieldRef) field.BuildCILInfo(output);
  2239. }
  2240. internal sealed override void Write(PEWriter output) {
  2241. base.Write(output);
  2242. output.Write(field.Token());
  2243. }
  2244. internal override void Write(CILWriter output) {
  2245. output.Write(GetInstrString());
  2246. field.WriteType(output);
  2247. output.WriteLine();
  2248. }
  2249. }
  2250. /**************************************************************************/
  2251. public class MethInstr : Instr {
  2252. Method meth;
  2253. /*-------------------- Constructors ---------------------------------*/
  2254. public MethInstr(MethodOp inst, Method m)
  2255. : base((uint)inst) {
  2256. meth = m;
  2257. size += 4;
  2258. }
  2259. public Method GetMethod() { return meth; }
  2260. public void SetMethod(Method mth) { meth = mth; }
  2261. internal override string GetInstName() {
  2262. return "" + (MethodOp)instr;
  2263. }
  2264. internal sealed override void BuildTables(MetaDataOut md) {
  2265. if (meth == null)
  2266. throw new InstructionException(IType.methOp, instr);
  2267. if ((meth is MethodRef) || (meth is MethodSpec)) meth.BuildMDTables(md);
  2268. }
  2269. internal override void BuildCILInfo(CILWriter output) {
  2270. if (meth == null) throw new InstructionException(IType.methOp, instr);
  2271. if ((meth is MethodRef) || (meth is MethodSpec)) meth.BuildCILInfo(output);
  2272. }
  2273. /// <summary>
  2274. /// Get the MethodOp this instruction represents.
  2275. /// </summary>
  2276. /// <returns>The method operator from the MethodOp enum.</returns>
  2277. public MethodOp GetMethodOp() {
  2278. return (MethodOp)instr;
  2279. }
  2280. /// <summary>
  2281. /// Get the delta distance for this instruction.
  2282. /// </summary>
  2283. /// <remarks>
  2284. /// The delta distance is the resulting difference of items
  2285. /// left on the stack after calling this instruction.
  2286. /// </remarks>
  2287. /// <returns>An integer value representing the delta distance.</returns>
  2288. internal override int GetDeltaDistance() {
  2289. MethSig mSig = null;
  2290. switch ((MethodOp)(this.twoByteInstr ? instr + 0xFE00 : instr)) {
  2291. case MethodOp.callvirt:
  2292. case MethodOp.call: {
  2293. mSig = meth.GetSig();
  2294. // Add the parameter count to the depth
  2295. int depth = (int)mSig.numPars * -1;
  2296. // Check to see if this is an instance method
  2297. if (mSig.HasCallConv(CallConv.Instance)) depth--;
  2298. // Check to see if this method uses the optional parameters
  2299. if (mSig.HasCallConv(CallConv.Vararg)) depth += (int)mSig.numOptPars * -1;
  2300. // Check to see if this method uses the generic parameters
  2301. if (mSig.HasCallConv(CallConv.Generic)) depth += (int)mSig.numGenPars * -1;
  2302. // Check if a return value will be placed on the stack.
  2303. if (!meth.GetRetType().SameType(PrimitiveType.Void)) depth++;
  2304. return depth;
  2305. }
  2306. case MethodOp.newobj: {
  2307. mSig = meth.GetSig();
  2308. // Add the parameter count to the depth
  2309. int depth = (int)mSig.numPars * -1;
  2310. // Check to see if this method uses the optional parameters
  2311. if (mSig.HasCallConv(CallConv.Vararg)) depth += (int)mSig.numOptPars * -1;
  2312. // Check to see if this method uses the generic parameters
  2313. if (mSig.HasCallConv(CallConv.Generic)) depth += (int)mSig.numGenPars * -1;
  2314. // Add the object reference that is loaded onto the stack
  2315. depth++;
  2316. return depth;
  2317. }
  2318. case MethodOp.ldtoken:
  2319. case MethodOp.ldftn:
  2320. return 1;
  2321. case MethodOp.jmp:
  2322. case MethodOp.ldvirtfn:
  2323. return 0;
  2324. default:
  2325. // Someone has added a new MethodOp and not added a case for it here.
  2326. throw new Exception("The MethodOp for this MethInstr is not supported.");
  2327. }
  2328. }
  2329. internal sealed override void Write(PEWriter output) {
  2330. base.Write(output);
  2331. output.Write(meth.Token());
  2332. }
  2333. internal override void Write(CILWriter output) {
  2334. output.Write(GetInstrString());
  2335. meth.WriteType(output);
  2336. output.WriteLine();
  2337. }
  2338. }
  2339. /**************************************************************************/
  2340. public class SigInstr : Instr {
  2341. CalliSig signature;
  2342. /*-------------------- Constructors ---------------------------------*/
  2343. public SigInstr(SpecialOp inst, CalliSig sig)
  2344. : base((uint)inst) {
  2345. signature = sig;
  2346. size += 4;
  2347. }
  2348. public CalliSig GetSig() { return signature; }
  2349. public void SetSig(CalliSig sig) { signature = sig; }
  2350. internal override string GetInstName() {
  2351. return "" + (SpecialOp)instr;
  2352. }
  2353. /// <summary>
  2354. /// Get the delta distance for this instruction.
  2355. /// </summary>
  2356. /// <remarks>
  2357. /// The delta distance is the resulting difference of items
  2358. /// left on the stack after calling this instruction.
  2359. /// </remarks>
  2360. /// <returns>An integer value representing the delta distance.</returns>
  2361. internal override int GetDeltaDistance() {
  2362. // Add the parameter count to the depth
  2363. int depth = (int)signature.NumPars * -1;
  2364. // Check to see if this is an instance method
  2365. if (signature.HasCallConv(CallConv.Instance)) depth--;
  2366. // Check to see if this method uses the optional parameters
  2367. if (signature.HasCallConv(CallConv.Vararg)) depth += (int)signature.NumOptPars * -1;
  2368. // Check if a return value will be placed on the stack.
  2369. if (signature.ReturnType.SameType(PrimitiveType.Void)) depth++;
  2370. return depth;
  2371. }
  2372. internal sealed override void BuildTables(MetaDataOut md) {
  2373. if (signature == null) throw new InstructionException(IType.specialOp, instr);
  2374. signature.BuildMDTables(md);
  2375. }
  2376. internal override void BuildCILInfo(CILWriter output) {
  2377. if (signature == null) throw new InstructionException(IType.specialOp, instr);
  2378. signature.BuildCILInfo(output);
  2379. }
  2380. internal sealed override void Write(PEWriter output) {
  2381. base.Write(output);
  2382. output.Write(signature.Token());
  2383. }
  2384. internal override void Write(CILWriter output) {
  2385. output.Write(GetInstrString());
  2386. signature.Write(output);
  2387. output.WriteLine();
  2388. }
  2389. }
  2390. /**************************************************************************/
  2391. public class TypeInstr : Instr {
  2392. Type theType;
  2393. /*-------------------- Constructors ---------------------------------*/
  2394. public TypeInstr(TypeOp inst, Type aType)
  2395. : base((uint)inst) {
  2396. theType = aType;
  2397. size += 4;
  2398. }
  2399. public Type GetTypeArg() { return theType; }
  2400. public void SetTypeArg(Type ty) { theType = ty; }
  2401. internal override string GetInstName() {
  2402. return "" + (TypeOp)instr;
  2403. }
  2404. internal sealed override void BuildTables(MetaDataOut md) {
  2405. if (theType == null) throw new InstructionException(IType.typeOp, instr);
  2406. theType = theType.AddTypeSpec(md);
  2407. }
  2408. internal override void BuildCILInfo(CILWriter output) {
  2409. if (theType == null) throw new InstructionException(IType.typeOp, instr);
  2410. if (!theType.isDef()) {
  2411. theType.BuildCILInfo(output);
  2412. }
  2413. }
  2414. internal sealed override void Write(PEWriter output) {
  2415. base.Write(output);
  2416. output.Write(theType.Token());
  2417. }
  2418. internal override void Write(CILWriter output) {
  2419. output.Write(GetInstrString());
  2420. theType.WriteName(output);
  2421. output.WriteLine();
  2422. }
  2423. }
  2424. /**************************************************************************/
  2425. public class BranchInstr : Instr {
  2426. CILLabel dest;
  2427. private bool shortVer = true;
  2428. private static readonly byte longInstrOffset = 13;
  2429. private int target = 0;
  2430. /*-------------------- Constructors ---------------------------------*/
  2431. public BranchInstr(BranchOp inst, CILLabel dst)
  2432. : base((uint)inst) {
  2433. dest = dst;
  2434. shortVer = (inst < BranchOp.br) || (inst == BranchOp.leave_s);
  2435. if (shortVer)
  2436. size++;
  2437. else
  2438. size += 4;
  2439. }
  2440. internal BranchInstr(uint inst, int dst)
  2441. : base(inst) {
  2442. target = dst;
  2443. shortVer = (inst < (uint)BranchOp.br) || (inst == (uint)BranchOp.leave_s);
  2444. if (shortVer)
  2445. size++;
  2446. else
  2447. size += 4;
  2448. }
  2449. public CILLabel GetDest() { return dest; }
  2450. public void SetDest(CILLabel lab) { dest = lab; }
  2451. /// <summary>
  2452. /// Provide access to the branch operator
  2453. /// </summary>
  2454. /// <returns>The branch operator from the BranchOp enum that this instruction represents.</returns>
  2455. public BranchOp GetBranchOp() {
  2456. return (BranchOp)instr;
  2457. }
  2458. internal override string GetInstName() {
  2459. return "" + (BranchOp)instr;
  2460. }
  2461. internal void MakeTargetLabel(ArrayList labs) {
  2462. uint targetOffset = (uint)(offset + size + target);
  2463. dest = CILInstructions.GetLabel(labs, targetOffset);
  2464. }
  2465. internal sealed override bool Check(MetaDataOut md) {
  2466. target = (int)dest.GetLabelOffset() - (int)(offset + size);
  2467. if ((target < minByteVal) || (target > maxByteVal)) { // check for longver
  2468. if (shortVer) {
  2469. if (instr == (uint)BranchOp.leave_s)
  2470. instr = (uint)BranchOp.leave;
  2471. else
  2472. instr = instr += longInstrOffset;
  2473. size += 3;
  2474. shortVer = false;
  2475. return true;
  2476. }
  2477. }
  2478. else if (!shortVer) { // check for short ver
  2479. if (instr == (uint)BranchOp.leave)
  2480. instr = (uint)BranchOp.leave_s;
  2481. else
  2482. instr = instr -= longInstrOffset;
  2483. size -= 3;
  2484. shortVer = true;
  2485. return true;
  2486. }
  2487. return false;
  2488. }
  2489. internal sealed override void Write(PEWriter output) {
  2490. base.Write(output);
  2491. if (shortVer)
  2492. output.Write((sbyte)target);
  2493. else
  2494. output.Write(target);
  2495. }
  2496. internal override void Write(CILWriter output) {
  2497. output.WriteLine(GetInstrString() + dest.GetInstName());
  2498. }
  2499. }
  2500. /*************************************************************************/
  2501. }