Instructions.cs 119 KB

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