12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915 |
- /*
- * PERWAPI - An API for Reading and Writing PE Files
- *
- * Copyright (c) Diane Corney, Queensland University of Technology, 2004.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the PERWAPI Copyright as included with this
- * distribution in the file PERWAPIcopyright.rtf.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY as is explained in the copyright notice.
- *
- * The author may be contacted at d.corney@qut.edu.au
- *
- * Version Date: 26/01/07
- */
- using System;
- using System.IO;
- using System.Collections;
- using System.Diagnostics;
- using SCG = System.Collections.Generic;
- namespace QUT.PERWAPI {
- /**************************************************************************/
- // Classes to represent CIL Byte Codes
- /**************************************************************************/
- /// <summary>
- /// The IL instructions for a method
- /// </summary>
- public class CILInstructions {
- private static readonly uint MaxClauses = 10;
- private static readonly uint ExHeaderSize = 4;
- private static readonly uint FatExClauseSize = 24;
- private static readonly uint SmlExClauseSize = 12;
- private static readonly sbyte maxByteVal = 127;
- private static readonly sbyte minByteVal = -128;
- private static readonly byte maxUByteVal = 255;
- private static readonly int smallSize = 64;
- internal static readonly ushort TinyFormat = 0x2;
- internal static readonly ushort FatFormat = 0x03;
- internal static readonly ushort FatFormatHeader = 0x3003;
- internal static readonly ushort MoreSects = 0x8;
- internal static readonly ushort InitLocals = 0x10;
- private static readonly uint FatSize = 12;
- private static readonly uint FatWords = FatSize / 4;
- internal static readonly byte FatExceptTable = 0x41;
- internal static readonly byte SmlExceptTable = 0x01;
- internal static readonly uint EHTable = 0x1;
- internal static readonly uint SectFatFormat = 0x40;
- internal static readonly uint SectMoreSects = 0x80;
- private ArrayList exceptions, sourceLines, defaultLines;
- private SourceFile defaultSourceFile;
- private Stack blockStack;
- //private bool codeChecked = false;
- private static readonly int INITSIZE = 5;
- private CILInstruction[] buffer = new CILInstruction[INITSIZE];
- // REPLACE with ArrayList<CILInstruction> for next version of .NET
- private CILInstruction[] saveBuffer;
- private int tide = 0, saveTide = 0;
- private uint offset = 0;
- private ushort headerFlags = 0;
- private short maxStack;
- private uint paddingNeeded = 0;
- private byte exceptHeader = 0;
- private int currI = -1;
- uint localSigIx = 0;
- int numReplace = 0;
- uint codeSize = 0, exceptSize = 0;
- bool tinyFormat, fatExceptionFormat = false, inserting = false;
- MethodDef thisMeth;
- internal Scope currentScope;
- /// <summary>
- /// Shows if return statements in this code block require a value on the stack or not.
- /// </summary>
- internal bool ReturnsVoid;
- /*-------------------- Constructors ---------------------------------*/
- internal CILInstructions(MethodDef meth) {
- thisMeth = meth;
- }
- /*--------------------- public general editing methods ---------------------------*/
- /// <summary>
- /// The source file containing these IL instructions
- /// </summary>
- public SourceFile DefaultSourceFile {
- get { return defaultSourceFile; }
- set { defaultSourceFile = value; }
- }
- /// <summary>
- /// The number of instructions currently in the buffer.
- /// </summary>
- public int NumInstructions() {
- if (inserting) return tide + saveTide;
- return tide;
- }
- /// <summary>
- /// Get the next instruction in the instruction buffer in sequence.
- /// An internal index is kept to keep track of which instruction was the last
- /// retrieved by this method. On the first call, the first instruction in
- /// the buffer is retrieved. The instruction index may be zeroed
- /// using ResetInstCounter(). This method cannot be called when in "insert" mode.
- /// </summary>
- /// <returns></returns>
- public CILInstruction GetNextInstruction() {
- if (inserting) throw new Exception("Cannot access next instruction during insert");
- if (currI + 1 < tide)
- return buffer[++currI];
- return null;
- }
- /// <summary>
- /// Get the previous instruction in the instruction buffer in sequence.
- /// An internal index is kept to keep track of which instruction was the last
- /// retrieved by this method. This method cannot be called when in "insert" mode.
- /// </summary>
- /// <returns></returns>
- public CILInstruction GetPrevInstruction() {
- if (inserting) throw new Exception("Cannot access previous instruction during insert");
- if (currI > 0)
- return buffer[--currI];
- return null;
- }
- /// <summary>
- /// Reset the counter for GetNextInstuction to the first instruction.
- /// This method cannot be called when in "insert" mode.
- /// </summary>
- public void ResetInstCounter() {
- if (inserting) throw new Exception("Cannot reset instruction counter during insert");
- currI = -1;
- }
- /// <summary>
- /// Reset the counter for GetNextInstuction to the first instruction.
- /// This method cannot be called when in "insert" mode.
- /// </summary>
- public void EndInstCounter() {
- if (inserting) throw new Exception("Cannot reset instruction counter during insert");
- currI = tide;
- }
- /// <summary>
- /// Get all the IL instructions.
- /// This method cannot be called when in "insert" mode.
- /// </summary>
- /// <returns></returns>
- public CILInstruction[] GetInstructions() {
- if (inserting) throw new Exception("Cannot get instructions during insert");
- return buffer;
- }
- /// <summary>
- /// Set the instruction to be the new array of instructions, this will replace
- /// any existing instructions. This method cannot be called when in "insert" mode.
- /// </summary>
- /// <param name="insts">The new instructions</param>
- public void SetInstructions(CILInstruction[] insts) {
- if (inserting) throw new Exception("Cannot replace instructions during insert.");
- buffer = insts;
- tide = buffer.Length;
- for (int i = 0; i < tide; i++) {
- if (insts[i] == null)
- tide = i;
- insts[i].index = (uint)i;
- }
- }
- /// <summary>
- /// This method should only be used to insert instructions into a buffer which
- /// already contains some instructions.
- /// Start inserting instructions into the instruction buffer ie. set the buffer
- /// to "insert" mode. The position of the insertion will be directly after
- /// the "current instruction" as used be GetNextInstruction(). The
- /// instructions to be inserted are any calls to the instruction specific
- /// methods - Inst, TypeInst, MethodInst, etc.
- /// This method cannot be called if already in "insert" mode.
- /// </summary>
- public void StartInsert() {
- if (inserting)
- throw new Exception("Cannot insert into an instruction buffer already in insert mode");
- inserting = true;
- saveTide = tide;
- saveBuffer = buffer;
- tide = 0;
- buffer = new CILInstruction[INITSIZE];
- }
- /// <summary>
- /// Stop inserting instructions into the buffer. Any instructions added after
- /// this call will go at the end of the instruction buffer.
- /// To be used with StartInsert().
- /// This method cannot be called if not in "insert" mode.
- /// </summary>
- public void EndInsert() {
- if (!inserting)
- throw new Exception("Cannot stop inserting if not in insert mode");
- CILInstruction[] newInsts = buffer;
- buffer = saveBuffer;
- int numNew = tide;
- tide = saveTide;
- int insPos = currI + 1;
- if (numReplace > 0) insPos--;
- InsertInstructions(insPos, newInsts, numNew);
- inserting = false;
- numReplace = 0;
- }
- /// <summary>
- /// Check if the buffer is ready for insertion of extra instructions.
- /// The buffer only needs to be in insert mode when instructions need
- /// to be added to existing instructions, not for addition of instructions
- /// to the end of the buffer.
- /// </summary>
- /// <returns></returns>
- public bool InInsertMode() { return inserting; }
- /// <summary>
- /// Remove the instruction at a specified position from the buffer. If you
- /// remove the "current" instruction (from GetNext or GetPrev) then the
- /// "current" instruction becomes the instruction before that in the buffer.
- /// </summary>
- /// <param name="pos">position of the instruction to be removed</param>
- public void RemoveInstruction(int pos) {
- if (pos < 0) return;
- for (int i = pos; i < tide - 1; i++) {
- buffer[i] = buffer[i + 1];
- buffer[i].index = (uint)i;
- }
- tide--;
- if (pos == currI) currI = pos - 1;
- }
- /// <summary>
- /// Remove the instructions from position "startRange" to (and including)
- /// position "endRange" from the buffer. If the range removed contains the
- /// "current" instruction (from GetNext or GetPrev) then the "current"
- /// instruction becomes the instruction before startRange in the buffer.
- /// </summary>
- public void RemoveInstructions(int startRange, int endRange) {
- if (startRange < 0) startRange = 0;
- if (endRange >= tide - 1) {// cut to startRange
- tide = startRange;
- return;
- }
- int offset = endRange - startRange + 1;
- for (int i = endRange + 1; i < tide; i++) {
- buffer[i - offset] = buffer[i];
- buffer[i - offset].index = (uint)(i - offset);
- }
- tide -= offset;
- if ((currI >= startRange) && (currI <= endRange)) currI = startRange - 1;
- }
- /// <summary>
- /// Replace a single IL instruction at position pos in the buffer
- /// with some new instruction(s). This removes the instruction and puts
- /// the instruction buffer into "insert" mode at the position of the removed
- /// instruction. EndInsert must be called to insert the new instructions.
- /// This method cannot be called when in "insert" mode.
- /// </summary>
- /// <param name="pos">position of the instruction to be replaced</param>
- public void ReplaceInstruction(int pos) {
- if (inserting) throw new Exception("Cannot replace instructions during insert.");
- currI = pos;
- if ((pos > 0) || (pos < tide)) {
- numReplace = 1;
- StartInsert();
- }
- }
- /// <summary>
- /// Replace a number of IL instructions beginning at position pos in the buffer
- /// with some new instruction(s). This removes the instructions and puts
- /// the instruction buffer into "insert" mode at the position of the removed
- /// instructions. EndInsert must be called to insert the new instructions.
- /// The instructions from index "from" up to and including index "to" will
- /// be replaced by the new instructions entered.
- /// This method cannot be called when in "insert" mode.
- /// </summary>
- /// <param name="from">the index to start replacing instruction from</param>
- /// <param name="to">the last index of the instructions to be replaced</param>
- public void ReplaceInstruction(int from, int to) {
- if (inserting) throw new Exception("Cannot replace instructions during insert.");
- currI = from;
- if ((from < 0) || (from >= tide) || (to < 0))
- throw new Exception("replace index is out of range");
- if (to >= tide) to = tide - 1;
- numReplace = to - from + 1;
- StartInsert();
- }
- /*---------------- public instruction specific methods ------------------------*/
- /// <summary>
- /// Add a simple IL instruction
- /// </summary>
- /// <param name="inst">the IL instruction</param>
- public void Inst(Op inst) {
- AddToBuffer(new Instr(inst));
- }
- /// <summary>
- /// Add an IL instruction with an integer parameter
- /// </summary>
- /// <param name="inst">the IL instruction</param>
- /// <param name="val">the integer parameter value</param>
- public void IntInst(IntOp inst, int val) {
- if ((inst == IntOp.ldc_i4_s) || (inst == IntOp.ldc_i4)) {
- if ((val < 9) && (val >= -1)) {
- AddToBuffer(new Instr((Op)((int)Op.ldc_i4_0 + val)));
- }
- else {
- AddToBuffer(new IntInstr(inst, val));
- }
- }
- else
- AddToBuffer(new UIntInstr(inst, (uint)val));
- }
- /// <summary>
- /// Add the load long instruction
- /// </summary>
- /// <param name="cVal">the long value</param>
- public void ldc_i8(long cVal) {
- AddToBuffer(new LongInstr(SpecialOp.ldc_i8, cVal));
- }
- /// <summary>
- /// Add the load float32 instruction
- /// </summary>
- /// <param name="cVal">the float value</param>
- public void ldc_r4(float cVal) {
- AddToBuffer(new FloatInstr(SpecialOp.ldc_r4, cVal));
- }
- /// <summary>
- /// Add the load float64 instruction
- /// </summary>
- /// <param name="cVal">the float value</param>
- public void ldc_r8(double cVal) {
- AddToBuffer(new DoubleInstr(SpecialOp.ldc_r8, cVal));
- }
- /// <summary>
- /// Add the load string instruction
- /// </summary>
- /// <param name="str">the string value</param>
- public void ldstr(string str) {
- AddToBuffer(new StringInstr(SpecialOp.ldstr, str));
- }
- /// <summary>
- /// Add the calli instruction
- /// </summary>
- /// <param name="sig">the signature for the calli</param>
- public void calli(CalliSig sig) {
- AddToBuffer(new SigInstr(SpecialOp.calli, sig));
- }
- /// <summary>
- /// Create a new CIL label. To place the label in the CIL instruction
- /// stream use CodeLabel.
- /// </summary>
- /// <returns>a new CIL label</returns>
- public CILLabel NewLabel() {
- return new CILLabel();
- }
- /// <summary>
- /// Create a new label at this position in the code buffer
- /// </summary>
- /// <returns>the label at the current position</returns>
- public CILLabel NewCodedLabel() {
- CILLabel lab = new CILLabel();
- lab.Buffer = this;
- AddToBuffer(lab);
- return lab;
- }
- /// <summary>
- /// Add a label to the CIL instructions
- /// </summary>
- /// <param name="lab">the label to be added</param>
- public void CodeLabel(CILLabel lab) {
- if (lab.Buffer == null) {
- lab.Buffer = this;
- }
- else if (lab.Buffer != this) {
- throw new DescriptorException("Cannot add a label to two different code buffers");
- }
- AddToBuffer(lab);
- }
- /// <summary>
- /// Add an instruction with a field parameter
- /// </summary>
- /// <param name="inst">the CIL instruction</param>
- /// <param name="f">the field parameter</param>
- public void FieldInst(FieldOp inst, Field f) {
- Debug.Assert(f != null);
- if (f is FieldDef)
- if (((FieldDef)f).GetScope() != thisMeth.GetScope())
- throw new DescriptorException();
- AddToBuffer(new FieldInstr(inst, f));
- }
- /// <summary>
- /// Add an instruction with a method parameter
- /// </summary>
- /// <param name="inst">the CIL instruction</param>
- /// <param name="m">the method parameter</param>
- public void MethInst(MethodOp inst, Method m) {
- Debug.Assert(m != null);
- if (m is MethodDef)
- if (((MethodDef)m).GetScope() != thisMeth.GetScope())
- throw new DescriptorException();
- AddToBuffer(new MethInstr(inst, m));
- }
- /// <summary>
- /// Add an instruction with a type parameter
- /// </summary>
- /// <param name="inst">the CIL instruction</param>
- /// <param name="aType">the type argument for the CIL instruction</param>
- public void TypeInst(TypeOp inst, Type aType) {
- Debug.Assert(aType != null);
- if (aType is ClassDef) {
- if (((ClassDef)aType).GetScope() != thisMeth.GetScope())
- throw new DescriptorException();
- }
- AddToBuffer(new TypeInstr(inst, aType));
- }
- /// <summary>
- /// Add a branch instruction
- /// </summary>
- /// <param name="inst">the branch instruction</param>
- /// <param name="lab">the label that is the target of the branch</param>
- public void Branch(BranchOp inst, CILLabel lab) {
- Debug.Assert(lab != null);
- AddToBuffer(new BranchInstr(inst, lab));
- }
- /// <summary>
- /// Add a switch instruction
- /// </summary>
- /// <param name="labs">the target labels for the switch</param>
- public void Switch(CILLabel[] labs) {
- AddToBuffer(new SwitchInstr(labs));
- }
- /// <summary>
- /// Add a byte to the CIL instructions (.emitbyte)
- /// </summary>
- /// <param name="bVal"></param>
- public void emitbyte(byte bVal) {
- AddToBuffer(new CILByte(bVal));
- }
- /// <summary>
- /// Add an instruction which puts an integer on TOS. This method
- /// selects the correct instruction based on the value of the integer.
- /// </summary>
- /// <param name="i">the integer value</param>
- public void PushInt(int i) {
- if (i == -1) {
- AddToBuffer(new Instr(Op.ldc_i4_m1));
- }
- else if ((i >= 0) && (i <= 8)) {
- Op op = (Op)(Op.ldc_i4_0 + i);
- AddToBuffer(new Instr(op));
- }
- else if ((i >= minByteVal) && (i <= maxByteVal)) {
- AddToBuffer(new IntInstr(IntOp.ldc_i4_s, i));
- }
- else {
- AddToBuffer(new IntInstr(IntOp.ldc_i4, i));
- }
- }
- /// <summary>
- /// Add the instruction to load a long on TOS
- /// </summary>
- /// <param name="l">the long value</param>
- public void PushLong(long l) {
- AddToBuffer(new LongInstr(SpecialOp.ldc_i8, l));
- }
- /// <summary>
- /// Add an instruction to push the boolean value true on TOS
- /// </summary>
- public void PushTrue() {
- AddToBuffer(new Instr(Op.ldc_i4_1));
- }
- /// <summary>
- /// Add an instruction to push the boolean value false on TOS
- /// </summary>
- public void PushFalse() {
- AddToBuffer(new Instr(Op.ldc_i4_0));
- }
- /// <summary>
- /// Add the instruction to load an argument on TOS. This method
- /// selects the correct instruction based on the value of argNo
- /// </summary>
- /// <param name="argNo">the number of the argument</param>
- public void LoadArg(int argNo) {
- if (argNo < 4) {
- Op op = (Op)Op.ldarg_0 + argNo;
- AddToBuffer(new Instr(op));
- }
- else if (argNo <= maxUByteVal) {
- AddToBuffer(new UIntInstr(IntOp.ldarg_s, (uint)argNo));
- }
- else {
- AddToBuffer(new UIntInstr(IntOp.ldarg, (uint)argNo));
- }
- }
- /// <summary>
- /// Add the instruction to load the address of an argument on TOS.
- /// This method selects the correct instruction based on the value
- /// of argNo.
- /// </summary>
- /// <param name="argNo">the number of the argument</param>
- public void LoadArgAdr(int argNo) {
- if (argNo <= maxUByteVal) {
- AddToBuffer(new UIntInstr(IntOp.ldarga_s, (uint)argNo));
- }
- else {
- AddToBuffer(new UIntInstr(IntOp.ldarga, (uint)argNo));
- }
- }
- /// <summary>
- /// Add the instruction to load a local on TOS. This method selects
- /// the correct instruction based on the value of locNo.
- /// </summary>
- /// <param name="locNo">the number of the local to load</param>
- public void LoadLocal(int locNo) {
- if (locNo < 4) {
- Op op = (Op)Op.ldloc_0 + locNo;
- AddToBuffer(new Instr(op));
- }
- else if (locNo <= maxUByteVal) {
- AddToBuffer(new UIntInstr(IntOp.ldloc_s, (uint)locNo));
- }
- else {
- AddToBuffer(new UIntInstr(IntOp.ldloc, (uint)locNo));
- }
- }
- /// <summary>
- /// Add the instruction to load the address of a local on TOS.
- /// This method selects the correct instruction based on the
- /// value of locNo.
- /// </summary>
- /// <param name="locNo">the number of the local</param>
- public void LoadLocalAdr(int locNo) {
- if (locNo <= maxUByteVal) {
- AddToBuffer(new UIntInstr(IntOp.ldloca_s, (uint)locNo));
- }
- else {
- AddToBuffer(new UIntInstr(IntOp.ldloca, (uint)locNo));
- }
- }
- /// <summary>
- /// Add the instruction to store to an argument. This method
- /// selects the correct instruction based on the value of argNo.
- /// </summary>
- /// <param name="argNo">the argument to be stored to</param>
- public void StoreArg(int argNo) {
- if (argNo <= maxUByteVal) {
- AddToBuffer(new UIntInstr(IntOp.starg_s, (uint)argNo));
- }
- else {
- AddToBuffer(new UIntInstr(IntOp.starg, (uint)argNo));
- }
- }
- /// <summary>
- /// Add the instruction to store to a local. This method selects
- /// the correct instruction based on the value of locNo.
- /// </summary>
- /// <param name="locNo">the local to be stored to</param>
- public void StoreLocal(int locNo) {
- if (locNo < 4) {
- Op op = (Op)Op.stloc_0 + locNo;
- AddToBuffer(new Instr(op));
- }
- else if (locNo <= maxUByteVal) {
- AddToBuffer(new UIntInstr(IntOp.stloc_s, (uint)locNo));
- }
- else {
- AddToBuffer(new UIntInstr(IntOp.stloc, (uint)locNo));
- }
- }
- public void IntLine(int num) {
- Line((uint)num, 1);
- }
- /// <summary>
- /// CLS compliant version of Line()
- /// </summary>
- /// <param name="sLin">The start line</param>
- /// <param name="sCol">The start column</param>
- /// <param name="eLin">The end line</param>
- /// <param name="eCol">The end column</param>
- public void IntLine(int sLin, int sCol, int eLin, int eCol) {
- Line((uint)sLin, (uint)sCol, (uint)eLin, (uint)eCol);
- }
- /// <summary>
- /// Create a new line instruction.
- /// </summary>
- /// <param name="num">The line for the given code segment.</param>
- /// <param name="startCol">The starting column for the code segment.</param>
- public void Line(uint num, uint startCol) {
- if (this.DefaultSourceFile == null) throw new Exception("Method can only be used if DefaultSourceFile has been set.");
- AddToBuffer(new Line(num, startCol, this.DefaultSourceFile));
- }
- /// <summary>
- /// Create a new line instruction.
- /// </summary>
- /// <param name="num">The line for the given code segment.</param>
- /// <param name="startCol">The starting column for the code segment.</param>
- /// <param name="endCol">The ending column for the code segment.</param>
- public void Line(uint num, uint startCol, uint endCol) {
- if (this.DefaultSourceFile == null) throw new Exception("Method can only be used if DefaultSourceFile has been set.");
- AddToBuffer(new Line(num, startCol, num, endCol, this.DefaultSourceFile));
- }
- /// <summary>
- /// Create a new line instruction.
- /// </summary>
- /// <param name="startNum">The starting line for the code segment.</param>
- /// <param name="startCol">The starting column for the code segment.</param>
- /// <param name="endNum">The ending line for the code segment.</param>
- /// <param name="endCol">The ending column for the code segment.</param>
- public void Line(uint startNum, uint startCol, uint endNum, uint endCol) {
- if (this.DefaultSourceFile == null) throw new Exception("Method can only be used if DefaultSourceFile has bene set.");
- AddToBuffer(new Line(startNum, startCol, endNum, endCol, this.DefaultSourceFile));
- }
- /// <summary>
- /// Create a new line instruction.
- /// </summary>
- /// <param name="startNum">The starting line for the code segment.</param>
- /// <param name="startCol">The starting column for the code segment.</param>
- /// <param name="endNum">The ending line for the code segment.</param>
- /// <param name="endCol">The ending column for the code segment.</param>
- /// <param name="sFile">The source file for the given code segment.</param>
- public void Line(uint startNum, uint startCol, uint endNum, uint endCol, SourceFile sFile) {
- AddToBuffer(new Line(startNum, startCol, endNum, endCol, sFile));
- }
- /// <summary>
- /// The current scope.
- /// </summary>
- public Scope CurrentScope {
- get { return currentScope; }
- }
- /// <summary>
- /// Open a new scope.
- /// </summary>
- public void OpenScope() {
- currentScope = new Scope(currentScope, thisMeth);
- AddToBuffer(new OpenScope(currentScope));
- //Console.WriteLine("Open scope on " + currentScope._thisMeth.Name());
- }
- /// <summary>
- /// Close the current scope.
- /// </summary>
- public void CloseScope() {
- //Console.WriteLine("Close scope on " + currentScope._thisMeth.Name());
- AddToBuffer(new CloseScope(currentScope));
- currentScope = currentScope._parent;
- }
- /// <summary>
- /// Bind a local to the CIL instructions.
- /// </summary>
- /// <param name="name">The name of the local variable..</param>
- /// <param name="index">The index of the local variable.</param>
- /// <returns>The LocalBinding object created with the given values.</returns>
- public LocalBinding BindLocal(string name, int index) {
- if (currentScope == null)
- throw new Exception("Scope must be opened before locals can be bound.");
- return currentScope.AddLocalBinding(name, index);
- }
- /// <summary>
- /// Bind a local to the CIL instructions.
- /// </summary>
- /// <param name="local">The local variable to load.</param>
- /// <returns>The LocalBinding object created for the given Local object.</returns>
- public LocalBinding BindLocal(Local local) {
- return BindLocal(local.Name, local.GetIndex());
- }
- /// <summary>
- /// Bind a constant to the CIL instructions.
- /// </summary>
- /// <param name="name">The name of the constant.</param>
- /// <param name="value">The value of the constant.</param>
- /// <param name="type">The type of the constant.</param>
- /// <returns>Return the ConstantBinding created with the given values.</returns>
- public ConstantBinding BindConstant(string name, object value, Type type) {
- if (currentScope == null)
- throw new Exception("Scope must be opened before constants can be bound.");
- return currentScope.AddConstantBinding(name, value, type);
- }
- /// <summary>
- /// Mark this position as the start of a new block
- /// (try, catch, filter, finally or fault)
- /// </summary>
- public void StartBlock() {
- if (blockStack == null) blockStack = new Stack();
- blockStack.Push(NewCodedLabel());
- }
- /// <summary>
- /// Mark this position as the end of the last started block and
- /// make it a try block. This try block is added to the current
- /// instructions (ie do not need to call AddTryBlock)
- /// </summary>
- /// <returns>The try block just ended</returns>
- public TryBlock EndTryBlock() {
- TryBlock tBlock = new TryBlock((CILLabel)blockStack.Pop(), NewCodedLabel());
- AddTryBlock(tBlock);
- return tBlock;
- }
- /// <summary>
- /// Mark this position as the end of the last started block and
- /// make it a catch block. This catch block is associated with the
- /// specified try block.
- /// </summary>
- /// <param name="exceptType">the exception type to be caught</param>
- /// <param name="tryBlock">the try block associated with this catch block</param>
- public void EndCatchBlock(Class exceptType, TryBlock tryBlock) {
- Catch catchBlock = new Catch(exceptType, (CILLabel)blockStack.Pop(), NewCodedLabel());
- tryBlock.AddHandler(catchBlock);
- }
- /// <summary>
- /// Mark this position as the end of the last started block and
- /// make it a filter block. This filter block is associated with the
- /// specified try block. The format is:
- /// filterLab: ...
- /// ...
- /// filterHandler : ...
- /// ...
- /// </summary>
- /// <param name="filterLab">the label where the filter code is</param>
- /// <param name="tryBlock">the try block associated with this filter block</param>
- public void EndFilterBlock(CILLabel filterLab, TryBlock tryBlock) {
- Filter filBlock = new Filter(filterLab, (CILLabel)blockStack.Pop(), NewCodedLabel());
- tryBlock.AddHandler(filBlock);
- }
- /// <summary>
- /// Mark this position as the end of the last started block and
- /// make it a finally block. This finally block is associated with the
- /// specified try block.
- /// </summary>
- /// <param name="tryBlock">the try block associated with this finally block</param>
- public void EndFinallyBlock(TryBlock tryBlock) {
- Finally finBlock = new Finally((CILLabel)blockStack.Pop(), NewCodedLabel());
- tryBlock.AddHandler(finBlock);
- }
- /// <summary>
- /// Mark this position as the end of the last started block and
- /// make it a fault block. This fault block is associated with the
- /// specified try block.
- /// </summary>
- /// <param name="tryBlock">the try block associated with this fault block</param>
- public void EndFaultBlock(TryBlock tryBlock) {
- Fault fBlock = new Fault((CILLabel)blockStack.Pop(), NewCodedLabel());
- tryBlock.AddHandler(fBlock);
- }
- public void AddTryBlock(TryBlock tryBlock) {
- if (exceptions == null)
- exceptions = new ArrayList();
- else if (exceptions.Contains(tryBlock)) return;
- exceptions.Add(tryBlock);
- }
- /*------------------------- private methods ----------------------------*/
- private void AddToBuffer(CILInstruction inst) {
- if (tide >= buffer.Length) {
- CILInstruction[] tmp = buffer;
- buffer = new CILInstruction[tmp.Length * 2];
- for (int i = 0; i < tide; i++) {
- buffer[i] = tmp[i];
- }
- }
- //Console.WriteLine("Adding instruction at offset " + offset + " with size " + inst.size);
- //inst.offset = offset;
- //offset += inst.size;
- inst.index = (uint)tide;
- buffer[tide++] = inst;
- }
- private void UpdateIndexesFrom(int ix) {
- for (int i = ix; i < tide; i++) {
- buffer[i].index = (uint)i;
- }
- }
- private void InsertInstructions(int ix, CILInstruction[] newInsts, int numNew) {
- CILInstruction[] newBuff = buffer, oldBuff = buffer;
- int newSize = tide + numNew - numReplace;
- if (buffer.Length < newSize) {
- newBuff = new CILInstruction[newSize];
- for (int i = 0; i < ix; i++) {
- newBuff[i] = oldBuff[i];
- }
- }
- // shuffle up
- int offset = numNew - numReplace;
- int end = ix + numReplace;
- for (int i = tide - 1; i >= end; i--) {
- newBuff[i + offset] = oldBuff[i];
- }
- // insert new instructions
- for (int i = 0; i < numNew; i++) {
- newBuff[ix + i] = newInsts[i];
- }
- buffer = newBuff;
- tide += numNew - numReplace;
- UpdateIndexesFrom(ix);
- }
- internal bool IsEmpty() {
- return tide == 0;
- }
- internal static CILLabel GetLabel(ArrayList labs, uint targetOffset) {
- CILLabel lab;
- int i = 0;
- while ((i < labs.Count) && (((CILLabel)labs[i]).offset < targetOffset)) i++;
- if (i < labs.Count) {
- if (((CILLabel)labs[i]).offset == targetOffset) // existing label
- lab = (CILLabel)labs[i];
- else {
- lab = new CILLabel(targetOffset);
- labs.Insert(i, lab);
- }
- }
- else {
- lab = new CILLabel(targetOffset);
- labs.Add(lab);
- }
- return lab;
- }
- internal void AddEHClause(EHClause ehc) {
- if (exceptions == null)
- exceptions = new ArrayList();
- exceptions.Add(ehc);
- }
- internal void SetAndResolveInstructions(CILInstruction[] insts) {
- offset = 0;
- ArrayList labels = new ArrayList();
- for (int i = 0; i < insts.Length; i++) {
- insts[i].offset = offset;
- offset += insts[i].size;
- if (insts[i] is BranchInstr) {
- ((BranchInstr)insts[i]).MakeTargetLabel(labels);
- }
- else if (insts[i] is SwitchInstr) {
- ((SwitchInstr)insts[i]).MakeTargetLabels(labels);
- }
- }
- if (exceptions != null) {
- for (int i = 0; i < exceptions.Count; i++) {
- exceptions[i] = ((EHClause)exceptions[i]).MakeTryBlock(labels);
- }
- }
- if (labels.Count == 0) { buffer = insts; tide = buffer.Length; return; }
- buffer = new CILInstruction[insts.Length + labels.Count];
- int currentPos = 0;
- tide = 0;
- for (int i = 0; i < labels.Count; i++) {
- CILLabel lab = (CILLabel)labels[i];
- while ((currentPos < insts.Length) && (insts[currentPos].offset < lab.offset))
- buffer[tide++] = insts[currentPos++];
- buffer[tide++] = lab;
- }
- while (currentPos < insts.Length) {
- buffer[tide++] = insts[currentPos++];
- }
- }
- internal uint GetCodeSize() {
- return codeSize + paddingNeeded + exceptSize;
- }
- internal void BuildTables(MetaDataOut md) {
- for (int i = 0; i < tide; i++) {
- buffer[i].BuildTables(md);
- }
- if (exceptions != null) {
- for (int i = 0; i < exceptions.Count; i++) {
- ((TryBlock)exceptions[i]).BuildTables(md);
- }
- }
- }
- internal void BuildCILInfo(CILWriter output) {
- for (int i = 0; i < tide; i++) {
- buffer[i].BuildCILInfo(output);
- }
- if (exceptions != null) {
- for (int i = 0; i < exceptions.Count; i++) {
- ((TryBlock)exceptions[i]).BuildCILInfo(output);
- }
- }
- }
- internal void ChangeRefsToDefs(ClassDef newType, ClassDef[] oldTypes) {
- for (int i = 0; i < tide; i++) {
- if (buffer[i] is SigInstr) {
- CalliSig sig = ((SigInstr)buffer[i]).GetSig();
- sig.ChangeRefsToDefs(newType, oldTypes);
- }
- else if (buffer[i] is TypeInstr) {
- TypeInstr tinst = (TypeInstr)buffer[i];
- if (tinst.GetTypeArg() is ClassDef) {
- ClassDef iType = (ClassDef)tinst.GetTypeArg();
- bool changed = false;
- for (int j = 0; (j < oldTypes.Length) && !changed; j++) {
- if (iType == oldTypes[j])
- tinst.SetTypeArg(newType);
- }
- }
- }
- }
- }
- internal void AddToLines(Line line) {
- if ((line.sourceFile == null) || (line.sourceFile.Match(defaultSourceFile))) {
- if (defaultLines == null) {
- if (defaultSourceFile == null)
- throw new Exception("No Default Source File Set");
- defaultLines = new ArrayList();
- }
- defaultLines.Add(line);
- return;
- }
- if (sourceLines == null) {
- sourceLines = new ArrayList();
- }
- else {
- for (int i = 0; i < sourceLines.Count; i++) {
- ArrayList lineList = (ArrayList)sourceLines[i];
- if (((Line)lineList[0]).sourceFile.Match(line.sourceFile)) {
- lineList.Add(line);
- return;
- }
- }
- ArrayList newList = new ArrayList();
- newList.Add(line);
- sourceLines.Add(newList);
- }
- }
- internal void CheckCode(uint locSigIx, bool initLocals, int maxStack, MetaDataOut metaData) {
- if (tide == 0) return;
- offset = 0;
- for (int i = 0; i < tide; i++) {
- buffer[i].offset = offset;
- offset += buffer[i].size;
- if (buffer[i] is Line)
- AddToLines((Line)buffer[i]);
- }
- bool changed = true;
- while (changed) {
- changed = false;
- Line prevLine = null;
- for (int i = 0; i < tide; i++) {
- if (buffer[i] is Line) {
- if (prevLine != null)
- prevLine.CalcEnd((Line)buffer[i]);
- prevLine = (Line)buffer[i];
- }
- changed = buffer[i].Check(metaData) || changed;
- }
- if (prevLine != null) prevLine.Last();
- if (changed) {
- for (int i = 1; i < tide; i++) {
- buffer[i].offset = buffer[i - 1].offset + buffer[i - 1].size;
- }
- offset = buffer[tide - 1].offset + buffer[tide - 1].size;
- }
- }
- codeSize = offset;
- if (Diag.DiagOn) Console.WriteLine("codeSize before header added = " + codeSize);
- if (maxStack == 0) this.maxStack = 8;
- else this.maxStack = (short)maxStack;
- if ((offset < smallSize) && (maxStack <= 8) && (locSigIx == 0) && (exceptions == null)) {
- // can use tiny header
- if (Diag.DiagOn) Console.WriteLine("Tiny Header");
- tinyFormat = true;
- headerFlags = (ushort)(TinyFormat | ((ushort)codeSize << 2));
- codeSize++;
- if ((codeSize % 4) != 0) { paddingNeeded = 4 - (codeSize % 4); }
- }
- else {
- if (Diag.DiagOn) Console.WriteLine("Fat Header");
- tinyFormat = false;
- localSigIx = locSigIx;
- //this.maxStack = (short)maxStack;
- headerFlags = FatFormatHeader;
- if (exceptions != null) {
- // Console.WriteLine("Got exceptions");
- headerFlags |= MoreSects;
- uint numExceptClauses = 0;
- for (int i = 0; i < exceptions.Count; i++) {
- TryBlock tryBlock = (TryBlock)exceptions[i];
- tryBlock.SetSize();
- numExceptClauses += (uint)tryBlock.NumHandlers();
- if (tryBlock.isFat()) fatExceptionFormat = true;
- }
- if (numExceptClauses > MaxClauses) fatExceptionFormat = true;
- if (Diag.DiagOn) Console.WriteLine("numexceptclauses = " + numExceptClauses);
- if (fatExceptionFormat) {
- if (Diag.DiagOn) Console.WriteLine("Fat exception format");
- exceptHeader = FatExceptTable;
- exceptSize = ExHeaderSize + numExceptClauses * FatExClauseSize;
- }
- else {
- if (Diag.DiagOn) Console.WriteLine("Tiny exception format");
- exceptHeader = SmlExceptTable;
- exceptSize = ExHeaderSize + numExceptClauses * SmlExClauseSize;
- }
- if (Diag.DiagOn) Console.WriteLine("exceptSize = " + exceptSize);
- }
- if (initLocals) headerFlags |= InitLocals;
- if ((offset % 4) != 0) { paddingNeeded = 4 - (offset % 4); }
- codeSize += FatSize;
- }
- if (Diag.DiagOn)
- Console.WriteLine("codeSize = " + codeSize + " headerFlags = " + Hex.Short(headerFlags));
- }
- /// <summary>
- /// Returns the maximum stack depth required by these CIL instructions.
- /// </summary>
- /// <returns>The integer value of the stck depth.</returns>
- public int GetMaxStackDepthRequired() {
- if (tide == 0) return 0;
- // Store the code blocks we find
- SCG.List<CodeBlock> codeBlocks = new SCG.List<CodeBlock>();
- SCG.Dictionary<CILLabel, CodeBlock> cbTable = new SCG.Dictionary<CILLabel, CodeBlock>();
- SCG.List<CodeBlock> extraStartingBlocks = new SCG.List<CodeBlock>();
- // Start a default code block
- CodeBlock codeBlock = new CodeBlock(this);
- codeBlock.StartIndex = 0;
- //
- // Identify the code blocks
- //
- for (int i = 0; i < tide; i++) {
- /* Handling the tail instruction:
- * The tail instruction has not been handled even though
- * it indicates the end of a code block is coming. The
- * reason for this is because any valid tail instruction
- * must be followed by a call* instruction and then a ret
- * instruction. Given a ret instruction must be the second
- * next instruction anyway it has been decided to just let
- * the end block be caught then.
- */
- // If we reach a branch instruction or a switch instruction
- // then end the current code block inclusive of the instruction.
- if ((buffer[i] is BranchInstr) || (buffer[i] is SwitchInstr)) {
- // Close the old block
- codeBlock.EndIndex = i;
- if (codeBlock.EndIndex >= codeBlock.StartIndex) // Don't add empty blocks
- codeBlocks.Add(codeBlock);
- // Open a new block
- codeBlock = new CodeBlock(this);
- codeBlock.StartIndex = i + 1;
- // If we reach a label then we need to start a new
- // code block as the label is an entry point.
- }
- else if (buffer[i] is CILLabel) {
- // Close the old block
- codeBlock.EndIndex = i - 1;
- if (codeBlock.EndIndex >= codeBlock.StartIndex) // Don't add empty blocks
- codeBlocks.Add(codeBlock);
- // Open a new block
- codeBlock = new CodeBlock(this);
- codeBlock.StartIndex = i;
- // Set this label as the entry point for the code block
- codeBlock.EntryLabel = (CILLabel)buffer[i];
- // AND ... list in the dictionary.
- cbTable.Add(codeBlock.EntryLabel, codeBlock);
- // Check for the ret, throw, rethrow, or jmp instruction as they also end a block
- }
- else if (buffer[i] is Instr) {
- if (
- (((Instr)buffer[i]).GetOp() == Op.ret) ||
- (((Instr)buffer[i]).GetOp() == Op.throwOp) ||
- (((Instr)buffer[i]).GetOp() == Op.rethrow) ||
- ((buffer[i] is MethInstr) && (((MethInstr)buffer[i]).GetMethodOp() == MethodOp.jmp))
- ) {
- // Close the old block
- codeBlock.EndIndex = i;
- if (codeBlock.EndIndex >= codeBlock.StartIndex) // Don't add empty blocks
- codeBlocks.Add(codeBlock);
- // Open a new block
- // In theory this should never happen but just in case
- // someone feels like adding dead code it is supported.
- codeBlock = new CodeBlock(this);
- codeBlock.StartIndex = i + 1;
- }
- }
- }
- // Close the last block
- codeBlock.EndIndex = tide - 1;
- if (codeBlock.EndIndex >= codeBlock.StartIndex) // Don't add empty blocks
- codeBlocks.Add(codeBlock);
- codeBlock = null;
- // Check how many code blocks there are. If an blocks return 0.
- if (codeBlocks.Count == 0) return 0;
- //
- // Loop through each code block and calculate the delta distance
- //
- for (int j = 0; j < codeBlocks.Count; j++) {
- CodeBlock block = codeBlocks[j];
- int maxDepth = 0;
- int currentDepth = 0;
- // Loop through each instruction to work out the max depth
- for (int i = block.StartIndex; i <= block.EndIndex; i++) {
- // Get the depth after the next instruction
- currentDepth += buffer[i].GetDeltaDistance();
- // If the new current depth is greater then the maxDepth adjust the maxDepth to reflect
- if (currentDepth > maxDepth)
- maxDepth = currentDepth;
- }
- // Set the depth of the block
- block.MaxDepth = maxDepth;
- block.DeltaDistance = currentDepth;
- //
- // Link up the next blocks
- //
- // If the block ends with a branch statement set the jump and fall through.
- if (buffer[block.EndIndex] is BranchInstr) {
- BranchInstr branchInst = (BranchInstr)buffer[block.EndIndex];
- // If this is not a "br" or "br.s" then set the fall through code block
- if ((branchInst.GetBranchOp() != BranchOp.br) &&
- (branchInst.GetBranchOp() != BranchOp.br_s))
- // If there is a following code block set it as the fall through
- if (j < (codeBlocks.Count - 1))
- block.NextBlocks.Add(codeBlocks[j + 1]);
- // Set the code block we are jumping to
- CodeBlock cb = null;
- cbTable.TryGetValue(branchInst.GetDest(), out cb);
- if (cb == null)
- throw new Exception("Missing Branch Label");
- block.NextBlocks.Add(cb);
- // If the block ends in a switch instruction work out the possible next blocks
- }
- else if (buffer[block.EndIndex] is SwitchInstr) {
- SwitchInstr switchInstr = (SwitchInstr)buffer[block.EndIndex];
- // If there is a following code block set it as the fall through
- if (j < (codeBlocks.Count - 1))
- block.NextBlocks.Add(codeBlocks[j + 1]);
- // Add each destination block
- foreach (CILLabel label in switchInstr.GetDests()) {
- // Check all of the code blocks to find the jump destination
- CodeBlock cb = null;
- cbTable.TryGetValue(label, out cb);
- if (cb == null) throw new Exception("Missing Case Label");
- block.NextBlocks.Add(cb);
- }
- // So long as the block doesn't end with a terminating instruction like ret or throw, just fall through to the next block
- }
- else if (!IsTerminatingInstruction(buffer[block.EndIndex])) {
- // If there is a following code block set it as the fall through
- if (j < (codeBlocks.Count - 1))
- block.NextBlocks.Add(codeBlocks[j + 1]);
- }
- }
- //
- // Join up any exception blocks
- //
- if (exceptions != null) {
- foreach (TryBlock tryBlock in exceptions) {
- // Try to find the code block where this try block starts
- CodeBlock tryCodeBlock;
- cbTable.TryGetValue(tryBlock.Start, out tryCodeBlock);
- // Declare that the entry to this code block must be empty
- tryCodeBlock.RequireEmptyEntry = true;
- // Work with each of the handlers
- foreach (HandlerBlock hb in tryBlock.GetHandlers()) {
- // Find the code block where this handler block starts.
- CodeBlock handlerCodeBlock;
- cbTable.TryGetValue(hb.Start, out handlerCodeBlock);
- // If the code block is a catch or filter block increment the delta
- // distance by 1. This is to factor in the exception object that will
- // be secretly placed on the stack by the runtime engine.
- // However, this also means that the MaxDepth is up by one also!
- if (hb is Catch || hb is Filter) {
- handlerCodeBlock.DeltaDistance++;
- handlerCodeBlock.MaxDepth++;
- }
- // If the code block is a filter block increment the delta distance by 1
- // This is to factor in the exception object that will be placed on the stack.
- // if (hb is Filter) handlerCodeBlock.DeltaDistance++;
- // Add this handler to the list of starting places
- extraStartingBlocks.Add(handlerCodeBlock);
- }
- }
- }
- //
- // Traverse the code blocks and get the depth
- //
- // Get the max depth at the starting entry point
- int finalMaxDepth = this.TraverseMaxDepth(codeBlocks[0]);
- // Check the additional entry points
- // If the additional points have a greater depth update the max depth
- foreach (CodeBlock cb in extraStartingBlocks) {
- // int tmpMaxDepth = cb.TraverseMaxDepth();
- int tmpMaxDepth = this.TraverseMaxDepth(cb);
- if (tmpMaxDepth > finalMaxDepth) finalMaxDepth = tmpMaxDepth;
- }
- // Return the max depth we have found
- return finalMaxDepth;
- }
- int TraverseMaxDepth(CodeBlock entryBlock) {
- int max = 0;
- SCG.Queue<CodeBlock> worklist = new SCG.Queue<CodeBlock>();
- entryBlock.Visited = true;
- entryBlock.LastVisitEntryDepth = 0;
- worklist.Enqueue(entryBlock);
- while (worklist.Count > 0) {
- int count = worklist.Count;
- CodeBlock unit = worklist.Dequeue();
- int maxDepth = unit.LastVisitEntryDepth + unit.MaxDepth;
- int exitDepth = unit.LastVisitEntryDepth + unit.DeltaDistance;
- if (maxDepth > max) max = maxDepth;
- foreach (CodeBlock succ in unit.NextBlocks) {
- if (succ.Visited) {
- if (succ.LastVisitEntryDepth != exitDepth)
- throw new InvalidStackDepth("inconsistent stack depth at offset " + succ.StartIndex.ToString());
- }
- else {
- succ.Visited = true;
- succ.LastVisitEntryDepth = exitDepth;
- worklist.Enqueue(succ);
- }
- }
- }
- return max;
- }
- private bool IsTerminatingInstruction(CILInstruction cilInstr) {
- // Return or throw instructions are terminating instructions
- if (cilInstr is Instr) {
- if (((Instr)cilInstr).GetOp() == Op.ret) return true;
- if (((Instr)cilInstr).GetOp() == Op.throwOp) return true;
- if (((Instr)cilInstr).GetOp() == Op.rethrow) return true;
- }
- // jmp is a terminating instruction
- if (cilInstr is MethInstr) {
- if (((MethInstr)cilInstr).GetMethodOp() == MethodOp.jmp) return true;
- }
- return false;
- }
- internal void Write(PEWriter output) {
- if (Diag.DiagOn) Console.WriteLine("Writing header flags = " + Hex.Short(headerFlags));
- if (tinyFormat) {
- if (Diag.DiagOn) Console.WriteLine("Writing tiny code");
- output.Write((byte)headerFlags);
- }
- else {
- if (Diag.DiagOn) Console.WriteLine("Writing fat code");
- output.Write(headerFlags);
- output.Write((ushort)maxStack);
- output.Write(offset);
- output.Write(localSigIx);
- }
- if (Diag.DiagOn) {
- Console.WriteLine(Hex.Int(tide) + " CIL instructions");
- Console.WriteLine("starting instructions at " + output.Seek(0, SeekOrigin.Current));
- }
- // Added to enable PDB generation
- if (output.pdbWriter != null) {
- // Open the method
- output.pdbWriter.OpenMethod((int)thisMeth.Token());
- // Check if this is the entry point method
- if (thisMeth.HasEntryPoint()) output.pdbWriter.SetEntryPoint((int)thisMeth.Token());
- }
- // Write out each memember of the buffer
- for (int i = 0; i < tide; i++) {
- buffer[i].Write(output);
- }
- // Added to enable PDB generation
- if (output.pdbWriter != null && tide > 0) {
- output.pdbWriter.CloseMethod();
- }
- if (Diag.DiagOn) Console.WriteLine("ending instructions at " + output.Seek(0, SeekOrigin.Current));
- for (int i = 0; i < paddingNeeded; i++) { output.Write((byte)0); }
- if (exceptions != null) {
- // Console.WriteLine("Writing exceptions");
- // Console.WriteLine("header = " + Hex.Short(exceptHeader) + " exceptSize = " + Hex.Int(exceptSize));
- output.Write(exceptHeader);
- output.Write3Bytes((uint)exceptSize);
- for (int i = 0; i < exceptions.Count; i++) {
- TryBlock tryBlock = (TryBlock)exceptions[i];
- tryBlock.Write(output, fatExceptionFormat);
- }
- }
- }
- internal void Write(CILWriter output) {
- for (int i = 0; i < tide; i++) {
- if (!(buffer[i] is CILLabel)) {
- output.Write(" ");
- }
- output.Write(" ");
- buffer[i].Write(output);
- }
- if (exceptions != null) {
- throw new NotYetImplementedException("Exceptions not yet implemented for CIL Instructions");
- // Console.WriteLine("Writing exceptions");
- // Console.WriteLine("header = " + Hex.Short(exceptHeader) + " exceptSize = " + Hex.Int(exceptSize));
- //output.Write(exceptHeader);
- //output.Write3Bytes((uint)exceptSize);
- //for (int i = 0; i < exceptions.Count; i++) {
- // TryBlock tryBlock = (TryBlock)exceptions[i];
- // tryBlock.Write(output, fatExceptionFormat);
- //}
- }
- }
- /// <summary>
- /// Stores the details of a given code block
- /// </summary>
- private class CodeBlock {
- internal int StartIndex;
- internal int EndIndex;
- internal int DeltaDistance;
- internal int MaxDepth;
- internal CILLabel EntryLabel;
- internal ArrayList NextBlocks = new ArrayList(); // List of CodeBlock objects
- // internal int Visits;
- internal int LastVisitEntryDepth;
- internal bool RequireEmptyEntry;
- internal bool Visited = false;
- private CILInstructions cilInstr;
- /// <summary>
- /// Create a new code block definition
- /// </summary>
- /// <param name="instructions">The buffer the code block relates to</param>
- internal CodeBlock(CILInstructions instructions) {
- cilInstr = instructions;
- }
- }
- }
- /**************************************************************************/
- /// <summary>
- /// Descriptor for an IL instruction
- /// </summary>
- public abstract class CILInstruction {
- protected static readonly sbyte maxByteVal = 127;
- protected static readonly sbyte minByteVal = -128;
- protected static readonly byte leadByte = 0xFE;
- protected static readonly uint USHeapIndex = 0x70000000;
- protected static readonly uint longInstrStart = (uint)Op.arglist;
- protected static readonly string[] opcode = {
- "nop", "break", "ldarg.0", "ldarg.1", "ldarg.2", "ldarg.3", "ldloc.0", "ldloc.1",
- "ldloc.2", "ldloc.3", "stloc.0", "stloc.1", "stloc.2", "stloc.3", "ldarg.s", "ldarga.s",
- "starg.s", "ldloc.s", "ldloca.s","stloc.s", "ldnull", "ldc.i4.m1","ldc.i4.0","ldc.i4.1",
- "ldc.i4.2","ldc.i4.3","ldc.i4.4","ldc.i4.5","ldc.i4.6","ldc.i4.7","ldc.i4.8","ldc.i4.s",
- "ldc.i4", "ldc.i8", "ldc.r4", "ldc.r8", "ERROR", "dup", "pop", "jmp",
- "call", "calli", "ret", "br.s", "brfalse.s","brtrue.s","beq.s", "bge.s",
- "bgt.s", "ble.s", "blt.s", "bne.un.s","bge.un.s","bgt.un.s","ble.un.s","blt.un.s",
- "br", "brfalse", "brtrue", "beq", "bge", "bgt", "ble", "blt",
- "bne.un", "bge.un", "bgt.un", "ble.un", "blt.un", "switch", "ldind.i1","ldind.u1",
- "ldind.i2","ldind.u2","ldind.i4","ldind.u4","ldind.i8","ldind.i", "ldind.r4","ldind.r8",
- "ldind.ref","stind.ref","stind.i1","stind.i2","stind.i4","stind.i8","stind.r4","stind.r8",
- "add", "sub", "mul", "div", "div.un", "rem", "rem.un", "and",
- "or", "xor", "shl", "shr", "shr.un", "neg", "not", "conv.i1",
- "conv.i2", "conv.i4", "conv.i8", "conv.r4", "conv.r8", "conv.u4", "conv.u8", "callvirt",
- "cpobj", "ldobj", "ldstr", "newobj", "castclass","isinst", "conv.r.un","ERROR",
- "ERROR", "unbox", "throw", "ldfld", "ldflda", "stfld", "ldsfld", "ldsflda",
- "stsfld", "stobj", "conv.ovf.i1.un", "conv.ovf.i2.un",
- "conv.ovf.i4.un", "conv.ovf.i8.un", "conv.ovf.u1.un", "conv.ovf.u2.un",
- "conv.ovf.u4.un", "conv.ovf.u8.un", "conv.ovf.i.un", "conv.ovf.u.un",
- "box", "newarr", "ldlen", "ldelema",
- "ldelem.i1", "ldelem.u1", "ldelem.i2", "ldelem.u2",
- "ldelem.i4", "ldelem.u4", "ldelem.i8", "ldelem.i",
- "ldelem.r4", "ldelem.r8", "ldelem.ref", "stelem.i",
- "stelem.i1", "stelem.i2", "stelem.i4", "stelem.i8",
- "stelem.r4", "stelem.r8", "stelem.ref", "ERROR",
- "ERROR", "ERROR", "ERROR", "ERROR",
- "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR",
- "ERROR", "ERROR", "ERROR", "conv.ovf.i1",
- "conv.ovf.u1", "conv.ovf.i2", "conv.ovf.u2", "conv.ovf.i4",
- "conv.ovf.u4", "conv.ovf.i8", "conv.ovf.u8", "ERROR",
- "ERROR", "ERROR", "ERROR", "ERROR",
- "ERROR", "ERROR", "refanyval","ckfinite","ERROR", "ERROR", "mkrefany","ERROR",
- "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR",
- "ldtoken","conv.u2","conv.u1","conv.i","conv.ovf.i","conv.ovf.u","add.ovf","add.ovf.un",
- "mul.ovf","mul.ovf.un","sub.ovf","sub.ovf.un","endfinally","leave","leave.s","stind.i",
- "conv.u"};
- protected static readonly int[] opDeltaDistance = {
- 0 /* nop */, 0 /* break */, 1 /* ldarg.0 */, 1 /* ldarg.1 */, 1 /* ldarg.2 */, 1 /* ldarg.3 */, 1 /* ldloc.0 */, 1 /* ldloc.1 */,
- 1 /* ldloc.2 */, 1 /* ldloc.3 */, -1 /* stloc.0 */, -1 /* stloc.1 */, -1 /* stloc.2 */, -1 /* stloc.3 */, 1 /* ldarg.s */, 1 /* ldarga.s */,
- -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 */,
- 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 */,
- 1 /* ldc.i4 */, 1 /* ldc.i8 */, 1 /* ldc.r4 */, 1 /* ldc.r8 */, -99 /* ERROR */, 1 /* dup */, -1 /* pop */, 0 /* jmp */,
- -99 /* call */, -99 /* calli */, 0 /* ret */, 0 /* br.s */, -1 /* brfalse.s */,-1 /* brtrue.s */, -2 /* beq.s */, -2 /* bge.s */,
- -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 */,
- 0 /* br */, -1 /* brfalse */, -1 /* brtrue */, -2 /* beq */, -2 /* bge */, -2 /* bgt */, -2 /* ble */, -2 /* blt */,
- -2 /* bne.un */, -2 /* bge.un */, -2 /* bgt.un */, -2 /* ble.un */, -2 /* blt.un */, -1 /* switch */, 0 /* ldind.i1 */, 0 /* ldind.u1 */,
- 0 /* ldind.i2 */, 0 /* ldind.u2 */, 0 /* ldind.i4 */, 0 /* ldind.u4 */, 0 /* ldind.i8 */, 0 /* ldind.i */, 0 /* ldind.r4 */, 0 /* ldind.r8 */,
- 0 /* ldind.ref */, -2 /* stind.ref */, -2 /* stind.i1 */, -2 /* stind.i2 */, -2 /* stind.i4 */, -2 /* stind.i8 */, -2 /* stind.r4 */, -2 /* stind.r8 */,
- -1 /* add */, -1 /* sub */, -1 /* mul */, -1 /* div */, -1 /* div.un */, -1 /* rem */, -1 /* rem.un */, -1 /* and */,
- -1 /* or */, -1 /* xor */, -1 /* shl */, -1 /* shr */, -1 /* shr.un */, 0 /* neg */, 0 /* not */, 0 /* conv.i1 */,
- 0 /* conv.i2 */, 0 /* conv.i4 */, 0 /* conv.i8 */, 0 /* conv.r4 */, 0 /* conv.r8 */, 0 /* conv.u4 */, 0 /* conv.u8 */, -99 /* callvirt */,
- -2 /* cpobj */, 0 /* ldobj */, 1 /* ldstr */, -99 /* newobj */, 0 /* castclass */, 0 /* isinst */, 0 /* conv.r.un */, -99 /* ERROR */,
- -99 /* ERROR */, 0 /* unbox */, -1 /* throw */, 0 /* ldfld */, 0 /* ldflda */, -2 /* stfld */, 1 /* ldsfld */, 1 /* ldsflda */,
- -1 /* stsfld */, -2 /* stobj */, 0 /* conv.ovf.i1.un */, 0 /* conv.ovf.i2.un */,
- 0 /* conv.ovf.i4.un */, 0 /* conv.ovf.i8.un */, 0 /* conv.ovf.u1.un */, 0 /* conv.ovf.u2.un */,
- 0 /* conv.ovf.u4.un */, 0 /* conv.ovf.u8.un */, 0 /* conv.ovf.i.un */, 0 /* conv.ovf.u.un */,
- 0 /* box */, 0 /* newarr */, 0 /* ldlen */, -1 /* ldelema */,
- -1 /* ldelem.i1 */, -1 /* ldelem.u1 */, -1 /* ldelem.i2 */, -1 /* ldelem.u2 */,
- -1 /* ldelem.i4 */, -1 /* ldelem.u4 */, -1 /* ldelem.i8 */, -1 /* ldelem.i */,
- -1 /* ldelem.r4 */, -1 /* ldelem.r8 */, -1 /* ldelem.ref */, -3 /* stelem.i */,
- -3 /* stelem.i1 */, -3 /* stelem.i2 */, -3 /* stelem.i4 */, -3 /* stelem.i8 */,
- -3 /* stelem.r4 */, -3 /* stelem.r8 */, -3 /* stelem.ref */, -99 /* ERROR */,
- -99 /* ERROR */, -99 /* ERROR */, -99 /* ERROR */, -99 /* ERROR */,
- -99 /* ERROR */, -99 /* ERROR */, -99 /* ERROR */, -99 /* ERROR */, -99 /* ERROR */, -99 /* ERROR */, -99 /* ERROR */, -99 /* ERROR */,
- -99 /* ERROR */, -99 /* ERROR */, -99 /* ERROR */, 0 /* conv.ovf.i1 */,
- 0 /* conv.ovf.u1 */, 0 /* conv.ovf.i2 */, 0 /* conv.ovf.u2 */, 0 /* conv.ovf.i4 */,
- 0 /* conv.ovf.u4 */, 0 /* conv.ovf.i8 */, 0 /* conv.ovf.u8 */, -99 /* ERROR */,
- -99 /* ERROR */, -99 /* ERROR */, -99 /* ERROR */, -99 /* ERROR */,
- -99 /* ERROR */, -99 /* ERROR */, 0 /* refanyval */, 0 /* ckfinite */, -99 /* ERROR */, -99 /* ERROR */, 0 /* mkrefany */, -99 /* ERROR */,
- -99 /* ERROR */, -99 /* ERROR */, -99 /* ERROR */, -99 /* ERROR */, -99 /* ERROR */, -99 /* ERROR */, -99 /* ERROR */, -99 /* ERROR */,
- 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 */,
- -1 /* mul.ovf */, -1 /* mul.ovf.un */, -1 /* sub.ovf */, -1 /* sub.ovf.un */, 0 /* endfinally */,0 /* leave */, 0 /* leave.s */, -2 /* stind.i */,
- 0 /* conv.u */};
- /// <summary>
- /// A list of the delta distances for the given CIL instructions.
- /// </summary>
- protected static readonly string[] FEopcode = {
- "arglist", "ceq", "cgt", "cgt.un", "clt", "clt.un", "ldftn", "ldvirtftn",
- "ERROR", "ldarg", "ldarga", "starg", "ldloc", "ldloca", "stloc", "localloc",
- "ERROR", "endfilter", "unaligned", "volatile", "tail", "initobj", "constrained", "cpblk",
- "initblk", "no.", "rethrow", "ERROR", "sizeof", "refanytype", "readonly"};
- /// <summary>
- /// A list of the delta distances for the given FE CIL instructions.
- /// </summary>
- protected static readonly int[] FEopDeltaDistance = {
- 1 /* arglist */, -1 /* ceq */, -1 /* cgt */, -1 /* cgt.un */, -1 /* clt */, -1 /* clt.un */, 1 /* ldftn */, 0 /* ldvirtftn */,
- -99 /* ERROR */, 1 /* ldarg */, 1 /* ldarga */, -1 /* starg */, 1 /* ldloc */, 1 /* ldloca */, -1 /* stloc */, 0 /* localloc */,
- -99 /* ERROR */, -1 /* endfilter */, 0 /* unaligned */, 0 /* volatile */, 0 /* tail */, -1 /* initobj */, 0 /* constrained */, -3 /* cpblk */,
- -3 /* initblk */, 0 /* no. */, 0 /* rethrow */, -99 /* ERROR */, 1 /* sizeof */, 0 /* refanytype */, 0 /* readonly */};
- internal bool twoByteInstr = false;
- internal uint size = 1;
- internal uint offset, index;
- internal virtual bool Check(MetaDataOut md) {
- return false;
- }
- internal virtual void Resolve() { }
- public int GetPos() { return (int)index; }
- internal abstract string GetInstName();
- /// <summary>
- /// Get the delta distance for this instruction.
- /// </summary>
- /// <remarks>
- /// The delta distance is the resulting difference of items
- /// left on the stack after calling this instruction.
- /// </remarks>
- /// <returns>An integer value representing the delta distance.</returns>
- internal abstract int GetDeltaDistance();
- internal virtual void BuildTables(MetaDataOut md) { }
- internal virtual void BuildCILInfo(CILWriter output) { }
- internal virtual void Write(PEWriter output) { }
- internal virtual void Write(CILWriter output) { }
- }
- /**************************************************************************/
- public class CILByte : CILInstruction {
- byte byteVal;
- /*-------------------- Constructors ---------------------------------*/
- internal CILByte(byte bVal) {
- byteVal = bVal;
- }
- public byte GetByte() { return byteVal; }
- internal override string GetInstName() {
- return Hex.Byte(byteVal);
- }
- /// <summary>
- /// Get the delta distance for this instruction.
- /// </summary>
- /// <remarks>
- /// The delta distance is the resulting difference of items
- /// left on the stack after calling this instruction.
- /// </remarks>
- /// <returns>Zero, the delta distance for a CILByte</returns>
- internal override int GetDeltaDistance() {
- return 0;
- }
- internal override void Write(PEWriter output) {
- output.Write(byteVal);
- }
- internal override void Write(CILWriter output) {
- output.WriteLine(".emitbyte " + Hex.Byte(byteVal)); // ???? CHECK THIS ????
- }
- }
- /**************************************************************************/
- public class Instr : CILInstruction {
- protected uint instr;
- /*-------------------- Constructors ---------------------------------*/
- public Instr(Op inst) {
- instr = (uint)inst;
- if (instr >= longInstrStart) {
- instr -= longInstrStart;
- twoByteInstr = true;
- size++;
- }
- }
- internal Instr(uint inst) {
- instr = (uint)inst;
- if (instr >= longInstrStart) {
- instr -= longInstrStart;
- twoByteInstr = true;
- size++;
- }
- }
- public Op GetOp() {
- if (twoByteInstr)
- return (Op)(longInstrStart + instr);
- return (Op)instr;
- }
- internal override string GetInstName() {
- Op opInst = GetOp();
- return "" + opInst;
- }
- internal override void Write(PEWriter output) {
- //Console.WriteLine("Writing instruction " + instr + " with size " + size);
- if (twoByteInstr) output.Write(leadByte);
- output.Write((byte)instr);
- }
- internal string GetInstrString() {
- if (twoByteInstr) {
- return FEopcode[instr] + " ";
- }
- else {
- return opcode[instr] + " ";
- }
- }
- public override string ToString() { return this.GetInstrString(); }
- /// <summary>
- /// Get the delta distance for this instruction.
- /// </summary>
- /// <remarks>
- /// The delta distance is the resulting difference of items
- /// left on the stack after calling this instruction.
- /// </remarks>
- /// <returns>An integer value representing the delta distance.</returns>
- internal override int GetDeltaDistance() {
- if (twoByteInstr) {
- return FEopDeltaDistance[instr];
- }
- else {
- return opDeltaDistance[instr];
- }
- }
- internal override void Write(CILWriter output) {
- if (twoByteInstr) {
- output.WriteLine(FEopcode[instr]);
- }
- else {
- output.WriteLine(opcode[instr]);
- }
- }
- }
- /**************************************************************************/
- public class IntInstr : Instr {
- int val;
- bool byteNum;
- /*-------------------- Constructors ---------------------------------*/
- public IntInstr(IntOp inst, int num)
- : base((uint)inst) {
- byteNum = inst == IntOp.ldc_i4_s;
- val = num;
- if (byteNum) size++;
- else size += 4;
- }
- public int GetInt() { return val; }
- public void SetInt(int num) { val = num; }
- internal sealed override void Write(PEWriter output) {
- base.Write(output);
- if (byteNum)
- output.Write((sbyte)val);
- else
- output.Write(val);
- }
- /// <summary>
- /// Get the delta distance for this instruction.
- /// </summary>
- /// <remarks>
- /// The delta distance is the resulting difference of items
- /// left on the stack after calling this instruction.
- /// </remarks>
- /// <returns>An integer value representing the delta distance.</returns>
- internal override int GetDeltaDistance() {
- return opDeltaDistance[instr];
- }
- internal override void Write(CILWriter output) {
- output.WriteLine(opcode[instr] + " " + val);
- }
- }
- /**************************************************************************/
- public class UIntInstr : Instr {
- uint val;
- bool byteNum;
- /*-------------------- Constructors ---------------------------------*/
- public UIntInstr(IntOp inst, uint num)
- : base((uint)inst) {
- byteNum = (inst < IntOp.ldc_i4_s) || (inst == IntOp.unaligned);
- val = num;
- if (byteNum) size++;
- else size += 2;
- }
- public uint GetUInt() { return val; }
- public void SetUInt(uint num) { val = num; }
- /// <summary>
- /// Get the delta distance for this instruction.
- /// </summary>
- /// <remarks>
- /// The delta distance is the resulting difference of items
- /// left on the stack after calling this instruction.
- /// </remarks>
- /// <returns>An integer value representing the delta distance.</returns>
- internal override int GetDeltaDistance() {
- if (twoByteInstr) {
- return FEopDeltaDistance[instr];
- }
- else {
- return opDeltaDistance[instr];
- }
- }
- internal sealed override void Write(PEWriter output) {
- base.Write(output);
- if (byteNum)
- output.Write((byte)val);
- else
- output.Write((ushort)val);
- }
- internal override void Write(CILWriter output) {
- if (twoByteInstr) {
- output.Write(FEopcode[instr]);
- }
- else {
- output.Write(opcode[instr]);
- }
- output.WriteLine(" " + val);
- }
- }
- /**************************************************************************/
- public class LongInstr : Instr {
- long val;
- /*-------------------- Constructors ---------------------------------*/
- public LongInstr(SpecialOp inst, long l)
- : base((uint)inst) {
- val = l;
- size += 8;
- }
- public long GetLong() { return val; }
- public void SetLong(long num) { val = num; }
- internal sealed override void Write(PEWriter output) {
- base.Write(output);
- output.Write(val);
- }
- internal override void Write(CILWriter output) {
- output.WriteLine("ldc.i8 " + val);
- }
- }
- /**************************************************************************/
- public class FloatInstr : Instr {
- float fVal;
- /*-------------------- Constructors ---------------------------------*/
- public FloatInstr(SpecialOp inst, float f)
- : base((uint)inst) {
- fVal = f;
- size += 4;
- }
- public float GetFloat() { return fVal; }
- public void SetFloat(float num) { fVal = num; }
- internal sealed override void Write(PEWriter output) {
- output.Write((byte)0x22);
- output.Write(fVal);
- }
- internal override void Write(CILWriter output) {
- output.WriteLine("ldc.r4 " + fVal);
- }
- }
- /**************************************************************************/
- public class DoubleInstr : Instr {
- double val;
- /*-------------------- Constructors ---------------------------------*/
- public DoubleInstr(SpecialOp inst, double d)
- : base((uint)inst) {
- val = d;
- size += 8;
- }
- public double GetDouble() { return val; }
- public void SetDouble(double num) { val = num; }
- internal sealed override void Write(PEWriter output) {
- base.Write(output);
- output.Write(val);
- }
- internal override void Write(CILWriter output) {
- output.WriteLine("ldc.r8 " + val);
- }
- }
- /**************************************************************************/
- public class StringInstr : Instr {
- string val;
- uint strIndex;
- /*-------------------- Constructors ---------------------------------*/
- public StringInstr(SpecialOp inst, string str)
- : base((uint)inst) {
- val = str;
- size += 4;
- }
- public string GetString() { return val; }
- public void SetString(string str) { val = str; }
- internal sealed override void BuildTables(MetaDataOut md) {
- if (Diag.DiagOn) Console.WriteLine("Adding a code string to the US heap");
- strIndex = md.AddToUSHeap(val);
- }
- internal sealed override void Write(PEWriter output) {
- base.Write(output);
- output.Write(USHeapIndex | strIndex);
- }
- internal override void Write(CILWriter output) {
- output.WriteLine("ldstr \"" + val + "\"");
- }
- }
- /**************************************************************************/
- public class CILLabel : CILInstruction {
- private static int labelNum = 0;
- private int num = -1;
- private CILInstructions buffer;
- /*-------------------- Constructors ---------------------------------*/
- public CILLabel() {
- size = 0;
- }
- internal CILLabel(uint offs) {
- size = 0;
- offset = offs;
- }
- internal uint GetLabelOffset() {
- return offset;
- }
- internal override string GetInstName() {
- return "Label" + num;
- }
- internal CILInstructions Buffer {
- get { return buffer; }
- set { buffer = value; }
- }
- internal override void BuildCILInfo(CILWriter output) {
- if (num == -1) {
- num = labelNum++;
- }
- }
- /// <summary>
- /// Get the delta distance for this instruction.
- /// </summary>
- /// <remarks>
- /// The delta distance is the resulting difference of items
- /// left on the stack after calling this instruction.
- /// </remarks>
- /// <returns>An integer value representing the delta distance.</returns>
- internal override int GetDeltaDistance() {
- return 0;
- }
- internal override void Write(CILWriter output) {
- output.WriteLine("Label" + num + ":");
- }
- public override string ToString() { return "label"; }
- }
- /**************************************************************************/
- /// <summary>
- /// Abstract model for debug instructions.
- /// </summary>
- public abstract class DebugInst : CILInstruction { }
- /**************************************************************************/
- /// <summary>
- /// Defines a line instruction.
- /// </summary>
- public class Line : DebugInst {
- private static uint MaxCol = 100;
- uint startLine, startCol, endLine, endCol;
- bool hasEnd = false;
- internal SourceFile sourceFile;
- /*-------------------- Constructors ---------------------------------*/
- /// <summary>
- /// Create a new line instruction.
- /// </summary>
- /// <param name="sLine">Start of the line in the source file.</param>
- /// <param name="sCol">Starting column in the source file.</param>
- /// <param name="sFile">The filename of the souce file.</param>
- internal Line(uint sLine, uint sCol, SourceFile sFile) {
- startLine = sLine;
- startCol = sCol;
- sourceFile = sFile;
- size = 0;
- }
- /// <summary>
- /// Create a new line instruction.
- /// </summary>
- /// <param name="sLine">Start of the line in the source file.</param>
- /// <param name="sCol">Starting column in the source file.</param>
- /// <param name="eLine">Ending line in the source file.</param>
- /// <param name="eCol">Ending column in the source file.</param>
- /// <param name="sFile">The filename of the souce file.</param>
- internal Line(uint sLine, uint sCol, uint eLine, uint eCol, SourceFile sFile) {
- startLine = sLine;
- startCol = sCol;
- endLine = eLine;
- endCol = eCol;
- hasEnd = true;
- sourceFile = sFile;
- size = 0;
- }
- public int LineNum {
- get { return (int)startLine; }
- }
- internal void CalcEnd(Line next) {
- if (hasEnd) return;
- if (sourceFile != next.sourceFile) {
- endLine = startLine;
- endCol = MaxCol;
- }
- else {
- endLine = next.startLine;
- endCol = next.startCol;
- if (endCol < 0) endCol = MaxCol;
- }
- hasEnd = true;
- }
- internal void Last() {
- if (hasEnd) return;
- endLine = startLine;
- endCol = MaxCol;
- hasEnd = true;
- }
- /// <summary>
- /// Get the name of this instruction.
- /// </summary>
- /// <returns>A string with the value ".line".</returns>
- internal override string GetInstName() {
- return ".line";
- }
- /// <summary>
- /// Write this instruction to a PDB file.
- /// </summary>
- /// <param name="output">The PE writer being used to write the PE and PDB files.</param>
- internal override void Write(PEWriter output) {
- string sf = "";
- Guid doclang = Guid.Empty;
- Guid docvend = Guid.Empty;
- Guid doctype = Guid.Empty;
- if (sourceFile != null) {
- sf = sourceFile.name;
- doclang = sourceFile.language;
- docvend = sourceFile.vendor;
- doctype = sourceFile.document;
- }
- if (output.pdbWriter != null)
- output.pdbWriter.AddSequencePoint(sf, doclang, docvend, doctype, (int)offset,
- (int)startLine, (int)startCol, (int)endLine, (int)endCol);
- }
- /// <summary>
- /// Get the delta distance for this instruction.
- /// </summary>
- /// <remarks>
- /// The delta distance is the resulting difference of items
- /// left on the stack after calling this instruction.
- /// </remarks>
- /// <returns>An integer value representing the delta distance.</returns>
- internal override int GetDeltaDistance() {
- return 0;
- }
- /// <summary>
- /// Write out a line instruction to the CIL file.
- /// </summary>
- /// <param name="output">The CIL instruction writer to use to write this instruction.</param>
- internal override void Write(CILWriter output) {
- if (output.Debug) {
- string lineDetails = startLine + ", " + startCol;
- if (hasEnd) {
- lineDetails += ", " + endLine + ", " + endCol;
- if (sourceFile != null) {
- lineDetails += ", " + sourceFile.Name;
- }
- }
- output.WriteLine(".line " + lineDetails);
- }
- }
- public override string ToString() {
- return String.Format("line {0}:{1}-{2}:{3}", this.startLine, this.startCol, this.endLine, this.endCol);
- }
- }
- /**************************************************************************/
- /// <summary>
- /// A local binding instruction that can be added to a list of CILInstructions.
- /// </summary>
- public class LocalBinding : DebugInst {
- internal int _index;
- internal string _name;
- internal DebugLocalSig _debugsig;
- /*-------------------- Constructors ---------------------------------*/
- /// <summary>
- /// Create a new local binding object.
- /// </summary>
- /// <param name="index">The index of the local in the locals tables.</param>
- /// <param name="name">The name of the local.</param>
- internal LocalBinding(int index, string name) {
- _index = index;
- _name = name;
- }
- /// <summary>
- /// The index of the local in the locals table.
- /// </summary>
- public int Index {
- get { return _index; }
- }
- /// <summary>
- /// The name of the local binding.
- /// </summary>
- public string Name {
- get { return _name; }
- }
- /// <summary>
- /// Get the delta distance for this instruction.
- /// </summary>
- /// <remarks>
- /// The delta distance is the resulting difference of items
- /// left on the stack after calling this instruction.
- /// </remarks>
- /// <returns>An integer value representing the delta distance.</returns>
- internal override int GetDeltaDistance() {
- return 0;
- }
- /// <summary>
- /// Get the name of this instruction.
- /// </summary>
- /// <returns>A string with the name of this instruction.</returns>
- internal override string GetInstName() {
- return "debug - local binding";
- }
- }
- /**************************************************************************/
- /// <summary>
- /// Used to declare constants that exist in a given scope.
- /// </summary>
- public class ConstantBinding : DebugInst {
- private string _name;
- private object _value;
- private Type _type;
- private uint _token;
- /*-------------------- Constructors ---------------------------------*/
- /// <summary>
- /// Create a new constant binding.
- /// </summary>
- /// <param name="name">The name of the constant.</param>
- /// <param name="value">The value of the constant.</param>
- /// <param name="type">The data type of the constant.</param>
- internal ConstantBinding(string name, object value, Type type, uint token) {
- _value = value;
- _name = name;
- _type = type;
- _token = token;
- }
- /// <summary>
- /// Value of the constant.
- /// </summary>
- public object Value {
- get { return _value; }
- }
- /// <summary>
- /// The name of the constant.
- /// </summary>
- public string Name {
- get { return _name; }
- }
- /// <summary>
- /// The data type of the constant.
- /// </summary>
- public Type Type {
- get { return _type; }
- }
- /// <summary>
- /// The token for this constant.
- /// </summary>
- public uint Token {
- get { return _token; }
- }
- /// <summary>
- /// Get the type signature for this constant.
- /// </summary>
- /// <returns>A byte array of the type signature.</returns>
- public byte[] GetSig() {
- MemoryStream str = new MemoryStream();
- _type.TypeSig(str);
- return str.ToArray();
- }
- /// <summary>
- /// Get the name of this instruction.
- /// </summary>
- /// <returns>A string with the name of this instruction.</returns>
- internal override string GetInstName() {
- return "debug - constant binding";
- }
- /// <summary>
- /// Get the delta distance for this instruction.
- /// </summary>
- /// <remarks>
- /// The delta distance is the resulting difference of items
- /// left on the stack after calling this instruction.
- /// </remarks>
- /// <returns>An integer value representing the delta distance.</returns>
- internal override int GetDeltaDistance() {
- return 0;
- }
- }
- /**************************************************************************/
- public class SwitchInstr : Instr {
- CILLabel[] cases;
- uint numCases = 0;
- int[] targets;
- /*-------------------- Constructors ---------------------------------*/
- public SwitchInstr(CILLabel[] dsts)
- : base(0x45) {
- cases = dsts;
- if (cases != null) numCases = (uint)cases.Length;
- size += 4 + (numCases * 4);
- }
- internal SwitchInstr(int[] offsets)
- : base(0x45) {
- numCases = (uint)offsets.Length;
- targets = offsets;
- size += 4 + (numCases * 4);
- }
- public CILLabel[] GetDests() { return cases; }
- public void SetDests(CILLabel[] dests) { cases = dests; }
- internal override string GetInstName() {
- return "switch";
- }
- internal void MakeTargetLabels(ArrayList labs) {
- cases = new CILLabel[numCases];
- for (int i = 0; i < numCases; i++) {
- cases[i] = CILInstructions.GetLabel(labs, (uint)(offset + size + targets[i]));
- }
- }
- internal sealed override void Write(PEWriter output) {
- base.Write(output);
- output.Write(numCases);
- for (int i = 0; i < numCases; i++) {
- int target = (int)cases[i].GetLabelOffset() - (int)(offset + size);
- output.Write(target);
- }
- }
- internal override void Write(CILWriter output) {
- throw new NotImplementedException("Switch instruction for CIL");
- }
- }
- public class Scope {
- private ArrayList _localBindings = new ArrayList();
- private ArrayList _constantBindings = new ArrayList();
- internal Scope _parent;
- internal MethodDef _thisMeth;
- internal Scope(MethodDef thisMeth)
- : this(null, thisMeth) {
- }
- internal Scope(Scope parent, MethodDef thisMeth) {
- _thisMeth = thisMeth;
- _parent = parent;
- }
- /// <summary>
- /// Add a constant to this scope.
- /// </summary>
- /// <param name="name">The name of the constant.</param>
- /// <param name="value">The value of the constant.</param>
- /// <param name="type">The type of the constant.</param>
- /// <returns>The ConstantBinding object for the new constant.</returns>
- internal ConstantBinding AddConstantBinding(string name, object value, Type type) {
- ConstantBinding binding;
- if ((binding = FindConstantBinding(name)) != null)
- return binding;
- binding = new ConstantBinding(name, value, type, _thisMeth.locToken);
- _constantBindings.Add(binding);
- return binding;
- }
- /// <summary>
- /// Find a constant in this scope.
- /// </summary>
- /// <param name="name">The name of the constant.</param>
- /// <returns>The ConstantBinding object of this constant.</returns>
- internal ConstantBinding FindConstantBinding(string name) {
- foreach (ConstantBinding binding in _constantBindings)
- if (binding.Name == name)
- return binding;
- return null;
- }
- /// <summary>
- /// Provide a complete list of all constants bound in this scope.
- /// </summary>
- public ConstantBinding[] ConstantBindings {
- get { return (ConstantBinding[])_constantBindings.ToArray(typeof(ConstantBinding)); }
- }
- internal LocalBinding AddLocalBinding(string name, int index) {
- LocalBinding binding;
- if ((binding = FindLocalBinding(name)) != null)
- return binding;
- binding = new LocalBinding(index, name);
- _localBindings.Add(binding);
- return binding;
- }
- internal LocalBinding FindLocalBinding(string name) {
- foreach (LocalBinding binding in _localBindings)
- if (binding._name == name)
- return binding;
- return null;
- }
- internal LocalBinding FindLocalBinding(int index) {
- foreach (LocalBinding binding in _localBindings)
- if (binding._index == index)
- return binding;
- return null;
- }
- public LocalBinding[] LocalBindings {
- get { return (LocalBinding[])_localBindings.ToArray(typeof(LocalBinding)); }
- }
- internal void BuildSignatures(MetaDataOut md) {
- if (!md.Debug) return;
- try {
- Local[] locals = _thisMeth.GetLocals();
- foreach (LocalBinding binding in _localBindings) {
- if (binding._debugsig == null) {
- locals[binding._index].BuildTables(md);
- binding._debugsig = md.GetDebugSig(locals[binding._index]);
- }
- binding._debugsig.BuildMDTables(md);
- }
- }
- catch (Exception e) {
- throw new Exception("Exception while writing debug info for: " +
- this._thisMeth.NameString() + "\r\n" + e.ToString());
- }
- }
- internal void WriteLocals(PDBWriter writer) {
- try {
- Local[] locals = _thisMeth.GetLocals();
- foreach (LocalBinding binding in _localBindings) {
- writer.BindLocal(binding._name, binding._index, _thisMeth.locToken, 0, 0);
- }
- }
- catch (Exception e) {
- throw new Exception("Exception while writing debug info for: " +
- this._thisMeth.NameString() + "\r\n" + e.ToString(), e);
- }
- }
- /* Constants does not work. AKB 2007-02-03
- internal void WriteConstants(PDBWriter writer) {
- try {
- // Add each constant to the current scope
- foreach (ConstantBinding binding in _constantBindings)
- writer.BindConstant(binding);
- } catch (Exception e) {
- throw new Exception("Exception while writing debug info for: " +
- this._thisMeth.NameString() + "\r\n" + e.ToString(), e);
- }
- }
- */
- }
- /*************************************************************************/
- /// <summary>
- /// A marker instruction for when a scope should be opened in the sequence of instructions.
- /// </summary>
- public class OpenScope : DebugInst {
- internal Scope _scope;
- /// <summary>
- /// Create a new OpenScope instruction.
- /// </summary>
- /// <param name="scope">The scope that is being opened.</param>
- public OpenScope(Scope scope) {
- size = 0;
- _scope = scope;
- }
- /// <summary>
- /// Get the name for this instruction.
- /// </summary>
- /// <returns>A string with the name of the instruction.</returns>
- internal override string GetInstName() {
- return "debug - open scope";
- }
- /// <summary>
- /// Build the signatures for this instruction.
- /// </summary>
- /// <param name="md">The meta data table to write the instructions to.</param>
- internal void BuildSignatures(MetaDataOut md) {
- _scope.BuildSignatures(md);
- }
- /// <summary>
- /// Get the delta distance for this instruction.
- /// </summary>
- /// <remarks>
- /// The delta distance is the resulting difference of items
- /// left on the stack after calling this instruction.
- /// </remarks>
- /// <returns>An integer value representing the delta distance.</returns>
- ///
- internal override int GetDeltaDistance() {
- return 0;
- }
- /// <summary>
- /// Write this instruction to the PDB file.
- /// </summary>
- /// <param name="output">The PEWriter being used to write the PE and PDB files.</param>
- internal override void Write(PEWriter output) {
- if (output.pdbWriter != null) {
- output.pdbWriter.OpenScope((int)offset);
- _scope.WriteLocals(output.pdbWriter);
- /* Constants do not work. AKB 2007-02-03
- * _scope.WriteConstants(output.pdbWriter);
- */
- }
- }
- public override string ToString() { return "Open scope"; }
- }
- /************************************************************************/
- /// <summary>
- /// A marker instruction for when a scope should be closed.
- /// </summary>
- public class CloseScope : DebugInst {
- internal Scope _scope;
- /// <summary>
- /// The constructor to build a new CloseScope instruction.
- /// </summary>
- /// <param name="scope">The scope to close.</param>
- public CloseScope(Scope scope) {
- size = 0;
- _scope = scope;
- }
- /// <summary>
- /// Provide access to the name of this instruction.
- /// </summary>
- /// <returns>A string containing the name of this instruction.</returns>
- internal override string GetInstName() {
- return "debug - close scope";
- }
- /// <summary>
- /// Get the delta distance for this instruction.
- /// </summary>
- /// <remarks>
- /// The delta distance is the resulting difference of items
- /// left on the stack after calling this instruction.
- /// </remarks>
- /// <returns>An integer value representing the delta distance.</returns>
- internal override int GetDeltaDistance() {
- return 0;
- }
- /// <summary>
- /// Write this instruction. This instruction does not get written
- /// to the PE file. It only applys to the PDB file.
- /// </summary>
- /// <param name="output">The PEWriter that is writing the PE file.</param>
- internal override void Write(PEWriter output) {
- if (output.pdbWriter != null)
- output.pdbWriter.CloseScope((int)offset);
- }
- public override string ToString() { return "Close scope"; }
- }
- /**************************************************************************/
- public class FieldInstr : Instr {
- Field field;
- /*-------------------- Constructors ---------------------------------*/
- public FieldInstr(FieldOp inst, Field f)
- : base((uint)inst) {
- field = f;
- size += 4;
- }
- public Field GetField() { return field; }
- public void SetField(Field fld) { field = fld; }
- internal override string GetInstName() {
- return "" + (FieldOp)instr;
- }
- internal sealed override void BuildTables(MetaDataOut md) {
- if (field == null) throw new InstructionException(IType.fieldOp, instr);
- if (field is FieldRef) field.BuildMDTables(md);
- }
- internal override void BuildCILInfo(CILWriter output) {
- if (field == null) throw new InstructionException(IType.fieldOp, instr);
- if (field is FieldRef) field.BuildCILInfo(output);
- }
- internal sealed override void Write(PEWriter output) {
- base.Write(output);
- output.Write(field.Token());
- }
- internal override void Write(CILWriter output) {
- output.Write(GetInstrString());
- field.WriteType(output);
- output.WriteLine();
- }
- }
- /**************************************************************************/
- public class MethInstr : Instr {
- Method meth;
- /*-------------------- Constructors ---------------------------------*/
- public MethInstr(MethodOp inst, Method m)
- : base((uint)inst) {
- meth = m;
- size += 4;
- }
- public Method GetMethod() { return meth; }
- public void SetMethod(Method mth) { meth = mth; }
- internal override string GetInstName() {
- return "" + (MethodOp)instr;
- }
- internal sealed override void BuildTables(MetaDataOut md) {
- if (meth == null)
- throw new InstructionException(IType.methOp, instr);
- if ((meth is MethodRef) || (meth is MethodSpec)) meth.BuildMDTables(md);
- }
- internal override void BuildCILInfo(CILWriter output) {
- if (meth == null) throw new InstructionException(IType.methOp, instr);
- if ((meth is MethodRef) || (meth is MethodSpec)) meth.BuildCILInfo(output);
- }
- /// <summary>
- /// Get the MethodOp this instruction represents.
- /// </summary>
- /// <returns>The method operator from the MethodOp enum.</returns>
- public MethodOp GetMethodOp() {
- return (MethodOp)instr;
- }
- /// <summary>
- /// Get the delta distance for this instruction.
- /// </summary>
- /// <remarks>
- /// The delta distance is the resulting difference of items
- /// left on the stack after calling this instruction.
- /// </remarks>
- /// <returns>An integer value representing the delta distance.</returns>
- internal override int GetDeltaDistance() {
- MethSig mSig = null;
- switch ((MethodOp)(this.twoByteInstr ? instr + 0xFE00 : instr)) {
- case MethodOp.callvirt:
- case MethodOp.call: {
- mSig = meth.GetSig();
- // Add the parameter count to the depth
- int depth = (int)mSig.numPars * -1;
- // Check to see if this is an instance method
- if (mSig.HasCallConv(CallConv.Instance)) depth--;
- // Check to see if this method uses the optional parameters
- if (mSig.HasCallConv(CallConv.Vararg)) depth += (int)mSig.numOptPars * -1;
- // Check to see if this method uses the generic parameters
- if (mSig.HasCallConv(CallConv.Generic)) depth += (int)mSig.numGenPars * -1;
- // Check if a return value will be placed on the stack.
- if (!meth.GetRetType().SameType(PrimitiveType.Void)) depth++;
- return depth;
- }
- case MethodOp.newobj: {
- mSig = meth.GetSig();
- // Add the parameter count to the depth
- int depth = (int)mSig.numPars * -1;
- // Check to see if this method uses the optional parameters
- if (mSig.HasCallConv(CallConv.Vararg)) depth += (int)mSig.numOptPars * -1;
- // Check to see if this method uses the generic parameters
- if (mSig.HasCallConv(CallConv.Generic)) depth += (int)mSig.numGenPars * -1;
- // Add the object reference that is loaded onto the stack
- depth++;
- return depth;
- }
- case MethodOp.ldtoken:
- case MethodOp.ldftn:
- return 1;
- case MethodOp.jmp:
- case MethodOp.ldvirtfn:
- return 0;
- default:
- // Someone has added a new MethodOp and not added a case for it here.
- throw new Exception("The MethodOp for this MethInstr is not supported.");
- }
- }
- internal sealed override void Write(PEWriter output) {
- base.Write(output);
- output.Write(meth.Token());
- }
- internal override void Write(CILWriter output) {
- output.Write(GetInstrString());
- meth.WriteType(output);
- output.WriteLine();
- }
- }
- /**************************************************************************/
- public class SigInstr : Instr {
- CalliSig signature;
- /*-------------------- Constructors ---------------------------------*/
- public SigInstr(SpecialOp inst, CalliSig sig)
- : base((uint)inst) {
- signature = sig;
- size += 4;
- }
- public CalliSig GetSig() { return signature; }
- public void SetSig(CalliSig sig) { signature = sig; }
- internal override string GetInstName() {
- return "" + (SpecialOp)instr;
- }
- /// <summary>
- /// Get the delta distance for this instruction.
- /// </summary>
- /// <remarks>
- /// The delta distance is the resulting difference of items
- /// left on the stack after calling this instruction.
- /// </remarks>
- /// <returns>An integer value representing the delta distance.</returns>
- internal override int GetDeltaDistance() {
- // Add the parameter count to the depth
- int depth = (int)signature.NumPars * -1;
- // Check to see if this is an instance method
- if (signature.HasCallConv(CallConv.Instance)) depth--;
- // Check to see if this method uses the optional parameters
- if (signature.HasCallConv(CallConv.Vararg)) depth += (int)signature.NumOptPars * -1;
- // Check if a return value will be placed on the stack.
- if (signature.ReturnType.SameType(PrimitiveType.Void)) depth++;
- return depth;
- }
- internal sealed override void BuildTables(MetaDataOut md) {
- if (signature == null) throw new InstructionException(IType.specialOp, instr);
- signature.BuildMDTables(md);
- }
- internal override void BuildCILInfo(CILWriter output) {
- if (signature == null) throw new InstructionException(IType.specialOp, instr);
- signature.BuildCILInfo(output);
- }
- internal sealed override void Write(PEWriter output) {
- base.Write(output);
- output.Write(signature.Token());
- }
- internal override void Write(CILWriter output) {
- output.Write(GetInstrString());
- signature.Write(output);
- output.WriteLine();
- }
- }
- /**************************************************************************/
- public class TypeInstr : Instr {
- Type theType;
- /*-------------------- Constructors ---------------------------------*/
- public TypeInstr(TypeOp inst, Type aType)
- : base((uint)inst) {
- theType = aType;
- size += 4;
- }
- public Type GetTypeArg() { return theType; }
- public void SetTypeArg(Type ty) { theType = ty; }
- internal override string GetInstName() {
- return "" + (TypeOp)instr;
- }
- internal sealed override void BuildTables(MetaDataOut md) {
- if (theType == null) throw new InstructionException(IType.typeOp, instr);
- theType = theType.AddTypeSpec(md);
- }
- internal override void BuildCILInfo(CILWriter output) {
- if (theType == null) throw new InstructionException(IType.typeOp, instr);
- if (!theType.isDef()) {
- theType.BuildCILInfo(output);
- }
- }
- internal sealed override void Write(PEWriter output) {
- base.Write(output);
- output.Write(theType.Token());
- }
- internal override void Write(CILWriter output) {
- output.Write(GetInstrString());
- theType.WriteName(output);
- output.WriteLine();
- }
- }
- /**************************************************************************/
- public class BranchInstr : Instr {
- CILLabel dest;
- private bool shortVer = true;
- private static readonly byte longInstrOffset = 13;
- private int target = 0;
- /*-------------------- Constructors ---------------------------------*/
- public BranchInstr(BranchOp inst, CILLabel dst)
- : base((uint)inst) {
- dest = dst;
- shortVer = (inst < BranchOp.br) || (inst == BranchOp.leave_s);
- if (shortVer)
- size++;
- else
- size += 4;
- }
- internal BranchInstr(uint inst, int dst)
- : base(inst) {
- target = dst;
- shortVer = (inst < (uint)BranchOp.br) || (inst == (uint)BranchOp.leave_s);
- if (shortVer)
- size++;
- else
- size += 4;
- }
- public CILLabel GetDest() { return dest; }
- public void SetDest(CILLabel lab) { dest = lab; }
- /// <summary>
- /// Provide access to the branch operator
- /// </summary>
- /// <returns>The branch operator from the BranchOp enum that this instruction represents.</returns>
- public BranchOp GetBranchOp() {
- return (BranchOp)instr;
- }
- internal override string GetInstName() {
- return "" + (BranchOp)instr;
- }
- internal void MakeTargetLabel(ArrayList labs) {
- uint targetOffset = (uint)(offset + size + target);
- dest = CILInstructions.GetLabel(labs, targetOffset);
- }
- internal sealed override bool Check(MetaDataOut md) {
- target = (int)dest.GetLabelOffset() - (int)(offset + size);
- if ((target < minByteVal) || (target > maxByteVal)) { // check for longver
- if (shortVer) {
- if (instr == (uint)BranchOp.leave_s)
- instr = (uint)BranchOp.leave;
- else
- instr = instr += longInstrOffset;
- size += 3;
- shortVer = false;
- return true;
- }
- }
- else if (!shortVer) { // check for short ver
- if (instr == (uint)BranchOp.leave)
- instr = (uint)BranchOp.leave_s;
- else
- instr = instr -= longInstrOffset;
- size -= 3;
- shortVer = true;
- return true;
- }
- return false;
- }
- internal sealed override void Write(PEWriter output) {
- base.Write(output);
- if (shortVer)
- output.Write((sbyte)target);
- else
- output.Write(target);
- }
- internal override void Write(CILWriter output) {
- output.WriteLine(GetInstrString() + dest.GetInstName());
- }
- }
- /*************************************************************************/
- }
|