MMRScriptObjWriter.cs 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986
  1. /*
  2. * Copyright (c) Contributors, http://opensimulator.org/
  3. * See CONTRIBUTORS.TXT for a full list of copyright holders.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are met:
  7. * * Redistributions of source code must retain the above copyright
  8. * notice, this list of conditions and the following disclaimer.
  9. * * Redistributions in binary form must reproduce the above copyright
  10. * notice, this list of conditions and the following disclaimer in the
  11. * documentation and/or other materials provided with the distribution.
  12. * * Neither the name of the OpenSimulator Project nor the
  13. * names of its contributors may be used to endorse or promote products
  14. * derived from this software without specific prior written permission.
  15. *
  16. * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
  17. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  18. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  19. * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
  20. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  21. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  22. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  23. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  24. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  25. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26. */
  27. using OpenSim.Region.ScriptEngine.Shared.ScriptBase;
  28. using System;
  29. using System.Collections.Generic;
  30. using System.IO;
  31. using System.Reflection;
  32. using System.Reflection.Emit;
  33. using System.Text;
  34. using LSL_Float = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLFloat;
  35. using LSL_Integer = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger;
  36. using LSL_Key = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
  37. using LSL_List = OpenSim.Region.ScriptEngine.Shared.LSL_Types.list;
  38. using LSL_Rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion;
  39. using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
  40. using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
  41. /**
  42. * @brief Wrapper class for ILGenerator.
  43. * It writes the object code to a file and can then make real ILGenerator calls
  44. * based on the file's contents.
  45. */
  46. namespace OpenSim.Region.ScriptEngine.Yengine
  47. {
  48. public enum ScriptObjWriterCode: byte
  49. {
  50. BegMethod, EndMethod, TheEnd,
  51. DclLabel, DclLocal, DclMethod, MarkLabel,
  52. EmitNull, EmitField, EmitLocal, EmitType, EmitLabel, EmitMethodExt,
  53. EmitMethodInt, EmitCtor, EmitDouble, EmitFloat, EmitInteger, EmitString,
  54. EmitLabels,
  55. BegExcBlk, BegCatBlk, BegFinBlk, EndExcBlk
  56. }
  57. public class ScriptObjWriter: ScriptMyILGen
  58. {
  59. private static Dictionary<short, OpCode> opCodes = PopulateOpCodes();
  60. private static Dictionary<string, Type> string2Type = PopulateS2T();
  61. private static Dictionary<Type, string> type2String = PopulateT2S();
  62. private static MethodInfo monoGetCurrentOffset = typeof(ILGenerator).GetMethod("Mono_GetCurrentOffset",
  63. BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null,
  64. new Type[] { typeof(ILGenerator) }, null);
  65. private static readonly OpCode[] opCodesLdcI4M1P8 = new OpCode[] {
  66. OpCodes.Ldc_I4_M1, OpCodes.Ldc_I4_0, OpCodes.Ldc_I4_1, OpCodes.Ldc_I4_2, OpCodes.Ldc_I4_3,
  67. OpCodes.Ldc_I4_4, OpCodes.Ldc_I4_5, OpCodes.Ldc_I4_6, OpCodes.Ldc_I4_7, OpCodes.Ldc_I4_8
  68. };
  69. private BinaryWriter objFileWriter;
  70. private string lastErrorAtFile = "";
  71. private int lastErrorAtLine = 0;
  72. private int lastErrorAtPosn = 0;
  73. private Dictionary<Type, string> sdTypesRev = new Dictionary<Type, string>();
  74. public int labelNumber = 0;
  75. public int localNumber = 0;
  76. private string _methName;
  77. public string methName
  78. {
  79. get
  80. {
  81. return _methName;
  82. }
  83. }
  84. public Type retType;
  85. public Type[] argTypes;
  86. /**
  87. * @brief Begin function declaration
  88. * @param sdTypes = script-defined types
  89. * @param methName = name of the method being declared, eg, "Verify(array,list,string)"
  90. * @param retType = its return value type
  91. * @param argTypes[] = its argument types
  92. * @param objFileWriter = file to write its object code to
  93. *
  94. * After calling this function, the following functions should be called:
  95. * this.BegMethod ();
  96. * this.<as required> ();
  97. * this.EndMethod ();
  98. *
  99. * The design of this object is such that many constructors may be called,
  100. * but once a BegMethod() is called for one of the objects, no method may
  101. * called for any of the other objects until EndMethod() is called (or it
  102. * would break up the object stream for that method). But we need to have
  103. * many constructors possible so we get function headers at the beginning
  104. * of the object file in case there are forward references to the functions.
  105. */
  106. public ScriptObjWriter(TokenScript tokenScript, string methName, Type retType, Type[] argTypes, string[] argNames, BinaryWriter objFileWriter)
  107. {
  108. this._methName = methName;
  109. this.retType = retType;
  110. this.argTypes = argTypes;
  111. this.objFileWriter = objFileWriter;
  112. // Build list that translates system-defined types to script defined types.
  113. foreach(TokenDeclSDType sdt in tokenScript.sdSrcTypesValues)
  114. {
  115. Type sys = sdt.GetSysType();
  116. if(sys != null)
  117. sdTypesRev[sys] = sdt.longName.val;
  118. }
  119. // This tells the reader to call 'new DynamicMethod()' to create
  120. // the function header. Then any forward reference calls to this
  121. // method will have a MethodInfo struct to call.
  122. objFileWriter.Write((byte)ScriptObjWriterCode.DclMethod);
  123. objFileWriter.Write(methName);
  124. objFileWriter.Write(GetStrFromType(retType));
  125. int nArgs = argTypes.Length;
  126. objFileWriter.Write(nArgs);
  127. for(int i = 0; i < nArgs; i++)
  128. {
  129. objFileWriter.Write(GetStrFromType(argTypes[i]));
  130. objFileWriter.Write(argNames[i]);
  131. }
  132. }
  133. /**
  134. * @brief Begin outputting object code for the function
  135. */
  136. public void BegMethod()
  137. {
  138. // This tells the reader to call methodInfo.GetILGenerator()
  139. // so it can start writing CIL code for the method.
  140. objFileWriter.Write((byte)ScriptObjWriterCode.BegMethod);
  141. objFileWriter.Write(methName);
  142. }
  143. /**
  144. * @brief End of object code for the function
  145. */
  146. public void EndMethod()
  147. {
  148. // This tells the reader that all code for the method has
  149. // been written and so it will typically call CreateDelegate()
  150. // to finalize the method and create an entrypoint.
  151. objFileWriter.Write((byte)ScriptObjWriterCode.EndMethod);
  152. objFileWriter = null;
  153. }
  154. /**
  155. * @brief Declare a local variable for use by the function
  156. */
  157. public ScriptMyLocal DeclareLocal(Type type, string name)
  158. {
  159. ScriptMyLocal myLocal = new ScriptMyLocal();
  160. myLocal.type = type;
  161. myLocal.name = name;
  162. myLocal.number = localNumber++;
  163. myLocal.isReferenced = true; // so ScriptCollector won't optimize references away
  164. return DeclareLocal(myLocal);
  165. }
  166. public ScriptMyLocal DeclareLocal(ScriptMyLocal myLocal)
  167. {
  168. objFileWriter.Write((byte)ScriptObjWriterCode.DclLocal);
  169. objFileWriter.Write(myLocal.number);
  170. objFileWriter.Write(myLocal.name);
  171. objFileWriter.Write(GetStrFromType(myLocal.type));
  172. return myLocal;
  173. }
  174. /**
  175. * @brief Define a label for use by the function
  176. */
  177. public ScriptMyLabel DefineLabel(string name)
  178. {
  179. ScriptMyLabel myLabel = new ScriptMyLabel();
  180. myLabel.name = name;
  181. myLabel.number = labelNumber++;
  182. return DefineLabel(myLabel);
  183. }
  184. public ScriptMyLabel DefineLabel(ScriptMyLabel myLabel)
  185. {
  186. objFileWriter.Write((byte)ScriptObjWriterCode.DclLabel);
  187. objFileWriter.Write(myLabel.number);
  188. objFileWriter.Write(myLabel.name);
  189. return myLabel;
  190. }
  191. /**
  192. * @brief try/catch blocks.
  193. */
  194. public void BeginExceptionBlock()
  195. {
  196. objFileWriter.Write((byte)ScriptObjWriterCode.BegExcBlk);
  197. }
  198. public void BeginCatchBlock(Type excType)
  199. {
  200. objFileWriter.Write((byte)ScriptObjWriterCode.BegCatBlk);
  201. objFileWriter.Write(GetStrFromType(excType));
  202. }
  203. public void BeginFinallyBlock()
  204. {
  205. objFileWriter.Write((byte)ScriptObjWriterCode.BegFinBlk);
  206. }
  207. public void EndExceptionBlock()
  208. {
  209. objFileWriter.Write((byte)ScriptObjWriterCode.EndExcBlk);
  210. }
  211. public void Emit(Token errorAt, OpCode opcode)
  212. {
  213. objFileWriter.Write((byte)ScriptObjWriterCode.EmitNull);
  214. WriteOpCode(errorAt, opcode);
  215. }
  216. public void Emit(Token errorAt, OpCode opcode, FieldInfo field)
  217. {
  218. objFileWriter.Write((byte)ScriptObjWriterCode.EmitField);
  219. WriteOpCode(errorAt, opcode);
  220. objFileWriter.Write(GetStrFromType(field.ReflectedType));
  221. objFileWriter.Write(field.Name);
  222. }
  223. public void Emit(Token errorAt, OpCode opcode, ScriptMyLocal myLocal)
  224. {
  225. objFileWriter.Write((byte)ScriptObjWriterCode.EmitLocal);
  226. WriteOpCode(errorAt, opcode);
  227. objFileWriter.Write(myLocal.number);
  228. }
  229. public void Emit(Token errorAt, OpCode opcode, Type type)
  230. {
  231. objFileWriter.Write((byte)ScriptObjWriterCode.EmitType);
  232. WriteOpCode(errorAt, opcode);
  233. objFileWriter.Write(GetStrFromType(type));
  234. }
  235. public void Emit(Token errorAt, OpCode opcode, ScriptMyLabel myLabel)
  236. {
  237. objFileWriter.Write((byte)ScriptObjWriterCode.EmitLabel);
  238. WriteOpCode(errorAt, opcode);
  239. objFileWriter.Write(myLabel.number);
  240. }
  241. public void Emit(Token errorAt, OpCode opcode, ScriptMyLabel[] myLabels)
  242. {
  243. objFileWriter.Write((byte)ScriptObjWriterCode.EmitLabels);
  244. WriteOpCode(errorAt, opcode);
  245. int nLabels = myLabels.Length;
  246. objFileWriter.Write(nLabels);
  247. for(int i = 0; i < nLabels; i++)
  248. {
  249. objFileWriter.Write(myLabels[i].number);
  250. }
  251. }
  252. public void Emit(Token errorAt, OpCode opcode, ScriptObjWriter method)
  253. {
  254. if(method == null)
  255. throw new ArgumentNullException("method");
  256. objFileWriter.Write((byte)ScriptObjWriterCode.EmitMethodInt);
  257. WriteOpCode(errorAt, opcode);
  258. objFileWriter.Write(method.methName);
  259. }
  260. public void Emit(Token errorAt, OpCode opcode, MethodInfo method)
  261. {
  262. objFileWriter.Write((byte)ScriptObjWriterCode.EmitMethodExt);
  263. WriteOpCode(errorAt, opcode);
  264. objFileWriter.Write(method.Name);
  265. objFileWriter.Write(GetStrFromType(method.ReflectedType));
  266. ParameterInfo[] parms = method.GetParameters();
  267. int nArgs = parms.Length;
  268. objFileWriter.Write(nArgs);
  269. for(int i = 0; i < nArgs; i++)
  270. {
  271. objFileWriter.Write(GetStrFromType(parms[i].ParameterType));
  272. }
  273. }
  274. public void Emit(Token errorAt, OpCode opcode, ConstructorInfo ctor)
  275. {
  276. objFileWriter.Write((byte)ScriptObjWriterCode.EmitCtor);
  277. WriteOpCode(errorAt, opcode);
  278. objFileWriter.Write(GetStrFromType(ctor.ReflectedType));
  279. ParameterInfo[] parms = ctor.GetParameters();
  280. int nArgs = parms.Length;
  281. objFileWriter.Write(nArgs);
  282. for(int i = 0; i < nArgs; i++)
  283. {
  284. objFileWriter.Write(GetStrFromType(parms[i].ParameterType));
  285. }
  286. }
  287. public void Emit(Token errorAt, OpCode opcode, double value)
  288. {
  289. if(opcode != OpCodes.Ldc_R8)
  290. {
  291. throw new Exception("bad opcode " + opcode.ToString());
  292. }
  293. objFileWriter.Write((byte)ScriptObjWriterCode.EmitDouble);
  294. WriteOpCode(errorAt, opcode);
  295. objFileWriter.Write(value);
  296. }
  297. public void Emit(Token errorAt, OpCode opcode, float value)
  298. {
  299. if(opcode != OpCodes.Ldc_R4)
  300. {
  301. throw new Exception("bad opcode " + opcode.ToString());
  302. }
  303. objFileWriter.Write((byte)ScriptObjWriterCode.EmitFloat);
  304. WriteOpCode(errorAt, opcode);
  305. objFileWriter.Write(value);
  306. }
  307. public void Emit(Token errorAt, OpCode opcode, int value)
  308. {
  309. objFileWriter.Write((byte)ScriptObjWriterCode.EmitInteger);
  310. WriteOpCode(errorAt, opcode);
  311. objFileWriter.Write(value);
  312. }
  313. public void Emit(Token errorAt, OpCode opcode, string value)
  314. {
  315. objFileWriter.Write((byte)ScriptObjWriterCode.EmitString);
  316. WriteOpCode(errorAt, opcode);
  317. objFileWriter.Write(value);
  318. }
  319. /**
  320. * @brief Declare that the target of a label is the next instruction.
  321. */
  322. public void MarkLabel(ScriptMyLabel myLabel)
  323. {
  324. objFileWriter.Write((byte)ScriptObjWriterCode.MarkLabel);
  325. objFileWriter.Write(myLabel.number);
  326. }
  327. /**
  328. * @brief Write end-of-file marker to binary file.
  329. */
  330. public static void TheEnd(BinaryWriter objFileWriter)
  331. {
  332. objFileWriter.Write((byte)ScriptObjWriterCode.TheEnd);
  333. }
  334. /**
  335. * @brief Take an object file created by ScriptObjWriter() and convert it to a series of dynamic methods.
  336. * @param sdTypes = script-defined types
  337. * @param objReader = where to read object file from (as written by ScriptObjWriter above).
  338. * @param scriptObjCode.EndMethod = called for each method defined at the end of the methods definition
  339. * @param objectTokens = write disassemble/decompile data (or null if not wanted)
  340. */
  341. public static void CreateObjCode(Dictionary<string, TokenDeclSDType> sdTypes, BinaryReader objReader,
  342. ScriptObjCode scriptObjCode, ObjectTokens objectTokens)
  343. {
  344. Dictionary<string, DynamicMethod> methods = new Dictionary<string, DynamicMethod>();
  345. DynamicMethod method = null;
  346. ILGenerator ilGen = null;
  347. Dictionary<int, Label> labels = new Dictionary<int, Label>();
  348. Dictionary<int, LocalBuilder> locals = new Dictionary<int, LocalBuilder>();
  349. Dictionary<int, string> labelNames = new Dictionary<int, string>();
  350. Dictionary<int, string> localNames = new Dictionary<int, string>();
  351. object[] ilGenArg = new object[1];
  352. int offset = 0;
  353. Dictionary<int, ScriptSrcLoc> srcLocs = null;
  354. string srcFile = "";
  355. int srcLine = 0;
  356. int srcPosn = 0;
  357. while(true)
  358. {
  359. // Get IL instruction offset at beginning of instruction.
  360. offset = 0;
  361. if((ilGen != null) && (monoGetCurrentOffset != null))
  362. {
  363. offset = (int)monoGetCurrentOffset.Invoke(null, ilGenArg);
  364. }
  365. // Read and decode next internal format code from input file (.xmrobj file).
  366. ScriptObjWriterCode code = (ScriptObjWriterCode)objReader.ReadByte();
  367. switch(code)
  368. {
  369. // Reached end-of-file so we are all done.
  370. case ScriptObjWriterCode.TheEnd:
  371. return;
  372. // Beginning of method's contents.
  373. // Method must have already been declared via DclMethod
  374. // so all we need is its name to retrieve from methods[].
  375. case ScriptObjWriterCode.BegMethod:
  376. {
  377. string methName = objReader.ReadString();
  378. method = methods[methName];
  379. ilGen = method.GetILGenerator();
  380. ilGenArg[0] = ilGen;
  381. labels.Clear();
  382. locals.Clear();
  383. labelNames.Clear();
  384. localNames.Clear();
  385. srcLocs = new Dictionary<int, ScriptSrcLoc>();
  386. if(objectTokens != null)
  387. objectTokens.BegMethod(method);
  388. break;
  389. }
  390. // End of method's contents (ie, an OpCodes.Ret was probably just output).
  391. // Call the callback to tell it the method is complete, and it can do whatever
  392. // it wants with the method.
  393. case ScriptObjWriterCode.EndMethod:
  394. {
  395. ilGen = null;
  396. ilGenArg[0] = null;
  397. scriptObjCode.EndMethod(method, srcLocs);
  398. srcLocs = null;
  399. if(objectTokens != null)
  400. objectTokens.EndMethod();
  401. break;
  402. }
  403. // Declare a label for branching to.
  404. case ScriptObjWriterCode.DclLabel:
  405. {
  406. int number = objReader.ReadInt32();
  407. string name = objReader.ReadString();
  408. labels.Add(number, ilGen.DefineLabel());
  409. labelNames.Add(number, name + "_" + number.ToString());
  410. if(objectTokens != null)
  411. objectTokens.DefineLabel(number, name);
  412. break;
  413. }
  414. // Declare a local variable to store into.
  415. case ScriptObjWriterCode.DclLocal:
  416. {
  417. int number = objReader.ReadInt32();
  418. string name = objReader.ReadString();
  419. string type = objReader.ReadString();
  420. Type syType = GetTypeFromStr(sdTypes, type);
  421. locals.Add(number, ilGen.DeclareLocal(syType));
  422. localNames.Add(number, name + "_" + number.ToString());
  423. if(objectTokens != null)
  424. objectTokens.DefineLocal(number, name, type, syType);
  425. break;
  426. }
  427. // Declare a method that will subsequently be defined.
  428. // We create the DynamicMethod object at this point in case there
  429. // are forward references from other method bodies.
  430. case ScriptObjWriterCode.DclMethod:
  431. {
  432. string methName = objReader.ReadString();
  433. Type retType = GetTypeFromStr(sdTypes, objReader.ReadString());
  434. int nArgs = objReader.ReadInt32();
  435. Type[] argTypes = new Type[nArgs];
  436. string[] argNames = new string[nArgs];
  437. for(int i = 0; i < nArgs; i++)
  438. {
  439. argTypes[i] = GetTypeFromStr(sdTypes, objReader.ReadString());
  440. argNames[i] = objReader.ReadString();
  441. }
  442. methods.Add(methName, new DynamicMethod(methName, retType, argTypes));
  443. if(objectTokens != null)
  444. objectTokens.DefineMethod(methName, retType, argTypes, argNames);
  445. break;
  446. }
  447. // Mark a previously declared label at this spot.
  448. case ScriptObjWriterCode.MarkLabel:
  449. {
  450. int number = objReader.ReadInt32();
  451. ilGen.MarkLabel(labels[number]);
  452. if(objectTokens != null)
  453. objectTokens.MarkLabel(offset, number);
  454. break;
  455. }
  456. // Try/Catch blocks.
  457. case ScriptObjWriterCode.BegExcBlk:
  458. {
  459. ilGen.BeginExceptionBlock();
  460. if(objectTokens != null)
  461. objectTokens.BegExcBlk(offset);
  462. break;
  463. }
  464. case ScriptObjWriterCode.BegCatBlk:
  465. {
  466. Type excType = GetTypeFromStr(sdTypes, objReader.ReadString());
  467. ilGen.BeginCatchBlock(excType);
  468. if(objectTokens != null)
  469. objectTokens.BegCatBlk(offset, excType);
  470. break;
  471. }
  472. case ScriptObjWriterCode.BegFinBlk:
  473. {
  474. ilGen.BeginFinallyBlock();
  475. if(objectTokens != null)
  476. objectTokens.BegFinBlk(offset);
  477. break;
  478. }
  479. case ScriptObjWriterCode.EndExcBlk:
  480. {
  481. ilGen.EndExceptionBlock();
  482. if(objectTokens != null)
  483. objectTokens.EndExcBlk(offset);
  484. break;
  485. }
  486. // Emit an opcode with no operand.
  487. case ScriptObjWriterCode.EmitNull:
  488. {
  489. OpCode opCode = ReadOpCode(objReader, ref srcFile, ref srcLine, ref srcPosn);
  490. SaveSrcLoc(srcLocs, offset, srcFile, srcLine, srcPosn);
  491. ilGen.Emit(opCode);
  492. if(objectTokens != null)
  493. objectTokens.EmitNull(offset, opCode);
  494. break;
  495. }
  496. // Emit an opcode with a FieldInfo operand.
  497. case ScriptObjWriterCode.EmitField:
  498. {
  499. OpCode opCode = ReadOpCode(objReader, ref srcFile, ref srcLine, ref srcPosn);
  500. Type reflectedType = GetTypeFromStr(sdTypes, objReader.ReadString());
  501. string fieldName = objReader.ReadString();
  502. FieldInfo field = reflectedType.GetField(fieldName);
  503. SaveSrcLoc(srcLocs, offset, srcFile, srcLine, srcPosn);
  504. ilGen.Emit(opCode, field);
  505. if(objectTokens != null)
  506. objectTokens.EmitField(offset, opCode, field);
  507. break;
  508. }
  509. // Emit an opcode with a LocalBuilder operand.
  510. case ScriptObjWriterCode.EmitLocal:
  511. {
  512. OpCode opCode = ReadOpCode(objReader, ref srcFile, ref srcLine, ref srcPosn);
  513. int number = objReader.ReadInt32();
  514. SaveSrcLoc(srcLocs, offset, srcFile, srcLine, srcPosn);
  515. ilGen.Emit(opCode, locals[number]);
  516. if(objectTokens != null)
  517. objectTokens.EmitLocal(offset, opCode, number);
  518. break;
  519. }
  520. // Emit an opcode with a Type operand.
  521. case ScriptObjWriterCode.EmitType:
  522. {
  523. OpCode opCode = ReadOpCode(objReader, ref srcFile, ref srcLine, ref srcPosn);
  524. string name = objReader.ReadString();
  525. Type type = GetTypeFromStr(sdTypes, name);
  526. SaveSrcLoc(srcLocs, offset, srcFile, srcLine, srcPosn);
  527. ilGen.Emit(opCode, type);
  528. if(objectTokens != null)
  529. objectTokens.EmitType(offset, opCode, type);
  530. break;
  531. }
  532. // Emit an opcode with a Label operand.
  533. case ScriptObjWriterCode.EmitLabel:
  534. {
  535. OpCode opCode = ReadOpCode(objReader, ref srcFile, ref srcLine, ref srcPosn);
  536. int number = objReader.ReadInt32();
  537. SaveSrcLoc(srcLocs, offset, srcFile, srcLine, srcPosn);
  538. ilGen.Emit(opCode, labels[number]);
  539. if(objectTokens != null)
  540. objectTokens.EmitLabel(offset, opCode, number);
  541. break;
  542. }
  543. // Emit an opcode with a Label array operand.
  544. case ScriptObjWriterCode.EmitLabels:
  545. {
  546. OpCode opCode = ReadOpCode(objReader, ref srcFile, ref srcLine, ref srcPosn);
  547. int nLabels = objReader.ReadInt32();
  548. Label[] lbls = new Label[nLabels];
  549. int[] nums = new int[nLabels];
  550. for(int i = 0; i < nLabels; i++)
  551. {
  552. nums[i] = objReader.ReadInt32();
  553. lbls[i] = labels[nums[i]];
  554. }
  555. SaveSrcLoc(srcLocs, offset, srcFile, srcLine, srcPosn);
  556. ilGen.Emit(opCode, lbls);
  557. if(objectTokens != null)
  558. objectTokens.EmitLabels(offset, opCode, nums);
  559. break;
  560. }
  561. // Emit an opcode with a MethodInfo operand (such as a call) of an external function.
  562. case ScriptObjWriterCode.EmitMethodExt:
  563. {
  564. OpCode opCode = ReadOpCode(objReader, ref srcFile, ref srcLine, ref srcPosn);
  565. string methName = objReader.ReadString();
  566. Type methType = GetTypeFromStr(sdTypes, objReader.ReadString());
  567. int nArgs = objReader.ReadInt32();
  568. Type[] argTypes = new Type[nArgs];
  569. for(int i = 0; i < nArgs; i++)
  570. {
  571. argTypes[i] = GetTypeFromStr(sdTypes, objReader.ReadString());
  572. }
  573. MethodInfo methInfo = methType.GetMethod(methName, argTypes);
  574. SaveSrcLoc(srcLocs, offset, srcFile, srcLine, srcPosn);
  575. ilGen.Emit(opCode, methInfo);
  576. if(objectTokens != null)
  577. objectTokens.EmitMethod(offset, opCode, methInfo);
  578. break;
  579. }
  580. // Emit an opcode with a MethodInfo operand of an internal function
  581. // (previously declared via DclMethod).
  582. case ScriptObjWriterCode.EmitMethodInt:
  583. {
  584. OpCode opCode = ReadOpCode(objReader, ref srcFile, ref srcLine, ref srcPosn);
  585. string methName = objReader.ReadString();
  586. MethodInfo methInfo = methods[methName];
  587. SaveSrcLoc(srcLocs, offset, srcFile, srcLine, srcPosn);
  588. ilGen.Emit(opCode, methInfo);
  589. if(objectTokens != null)
  590. objectTokens.EmitMethod(offset, opCode, methInfo);
  591. break;
  592. }
  593. // Emit an opcode with a ConstructorInfo operand.
  594. case ScriptObjWriterCode.EmitCtor:
  595. {
  596. OpCode opCode = ReadOpCode(objReader, ref srcFile, ref srcLine, ref srcPosn);
  597. Type ctorType = GetTypeFromStr(sdTypes, objReader.ReadString());
  598. int nArgs = objReader.ReadInt32();
  599. Type[] argTypes = new Type[nArgs];
  600. for(int i = 0; i < nArgs; i++)
  601. {
  602. argTypes[i] = GetTypeFromStr(sdTypes, objReader.ReadString());
  603. }
  604. ConstructorInfo ctorInfo = ctorType.GetConstructor(argTypes);
  605. SaveSrcLoc(srcLocs, offset, srcFile, srcLine, srcPosn);
  606. ilGen.Emit(opCode, ctorInfo);
  607. if(objectTokens != null)
  608. objectTokens.EmitCtor(offset, opCode, ctorInfo);
  609. break;
  610. }
  611. // Emit an opcode with a constant operand of various types.
  612. case ScriptObjWriterCode.EmitDouble:
  613. {
  614. OpCode opCode = ReadOpCode(objReader, ref srcFile, ref srcLine, ref srcPosn);
  615. double value = objReader.ReadDouble();
  616. if(opCode != OpCodes.Ldc_R8)
  617. {
  618. throw new Exception("bad opcode " + opCode.ToString());
  619. }
  620. SaveSrcLoc(srcLocs, offset, srcFile, srcLine, srcPosn);
  621. ilGen.Emit(opCode, value);
  622. if(objectTokens != null)
  623. objectTokens.EmitDouble(offset, opCode, value);
  624. break;
  625. }
  626. case ScriptObjWriterCode.EmitFloat:
  627. {
  628. OpCode opCode = ReadOpCode(objReader, ref srcFile, ref srcLine, ref srcPosn);
  629. float value = objReader.ReadSingle();
  630. if(opCode != OpCodes.Ldc_R4)
  631. {
  632. throw new Exception("bad opcode " + opCode.ToString());
  633. }
  634. SaveSrcLoc(srcLocs, offset, srcFile, srcLine, srcPosn);
  635. ilGen.Emit(opCode, value);
  636. if(objectTokens != null)
  637. objectTokens.EmitFloat(offset, opCode, value);
  638. break;
  639. }
  640. case ScriptObjWriterCode.EmitInteger:
  641. {
  642. OpCode opCode = ReadOpCode(objReader, ref srcFile, ref srcLine, ref srcPosn);
  643. int value = objReader.ReadInt32();
  644. SaveSrcLoc(srcLocs, offset, srcFile, srcLine, srcPosn);
  645. if(opCode == OpCodes.Ldc_I4)
  646. {
  647. if((value >= -1) && (value <= 8))
  648. {
  649. opCode = opCodesLdcI4M1P8[value + 1];
  650. ilGen.Emit(opCode);
  651. if(objectTokens != null)
  652. objectTokens.EmitNull(offset, opCode);
  653. break;
  654. }
  655. if((value >= 0) && (value <= 127))
  656. {
  657. opCode = OpCodes.Ldc_I4_S;
  658. ilGen.Emit(OpCodes.Ldc_I4_S, (sbyte)value);
  659. goto pemitint;
  660. }
  661. }
  662. ilGen.Emit(opCode, value);
  663. pemitint:
  664. if(objectTokens != null)
  665. objectTokens.EmitInteger(offset, opCode, value);
  666. break;
  667. }
  668. case ScriptObjWriterCode.EmitString:
  669. {
  670. OpCode opCode = ReadOpCode(objReader, ref srcFile, ref srcLine, ref srcPosn);
  671. string value = objReader.ReadString();
  672. SaveSrcLoc(srcLocs, offset, srcFile, srcLine, srcPosn);
  673. ilGen.Emit(opCode, value);
  674. if(objectTokens != null)
  675. objectTokens.EmitString(offset, opCode, value);
  676. break;
  677. }
  678. // Who knows what?
  679. default:
  680. throw new Exception("bad ScriptObjWriterCode " + ((byte)code).ToString());
  681. }
  682. }
  683. }
  684. /**
  685. * @brief Generate array to quickly translate OpCode.Value to full OpCode struct.
  686. */
  687. private static Dictionary<short, OpCode> PopulateOpCodes()
  688. {
  689. Dictionary<short, OpCode> opCodeDict = new Dictionary<short, OpCode>();
  690. FieldInfo[] fields = typeof(OpCodes).GetFields();
  691. for(int i = 0; i < fields.Length; i++)
  692. {
  693. OpCode opcode = (OpCode)fields[i].GetValue(null);
  694. opCodeDict.Add(opcode.Value, opcode);
  695. }
  696. return opCodeDict;
  697. }
  698. /**
  699. * @brief Write opcode out to file.
  700. */
  701. private void WriteOpCode(Token errorAt, OpCode opcode)
  702. {
  703. if(errorAt == null)
  704. {
  705. objFileWriter.Write("");
  706. objFileWriter.Write(lastErrorAtLine);
  707. objFileWriter.Write(lastErrorAtPosn);
  708. }
  709. else
  710. {
  711. if(errorAt.file != lastErrorAtFile)
  712. {
  713. objFileWriter.Write(errorAt.file);
  714. lastErrorAtFile = errorAt.file;
  715. }
  716. else
  717. {
  718. objFileWriter.Write("");
  719. }
  720. objFileWriter.Write(errorAt.line);
  721. objFileWriter.Write(errorAt.posn);
  722. lastErrorAtLine = errorAt.line;
  723. lastErrorAtPosn = errorAt.posn;
  724. }
  725. objFileWriter.Write(opcode.Value);
  726. }
  727. /**
  728. * @brief Read opcode in from file.
  729. */
  730. private static OpCode ReadOpCode(BinaryReader objReader, ref string srcFile, ref int srcLine, ref int srcPosn)
  731. {
  732. string f = objReader.ReadString();
  733. if(f != "")
  734. srcFile = f;
  735. srcLine = objReader.ReadInt32();
  736. srcPosn = objReader.ReadInt32();
  737. short value = objReader.ReadInt16();
  738. return opCodes[value];
  739. }
  740. /**
  741. * @brief Save an IL_offset -> source location translation entry
  742. * @param srcLocs = saved entries for the current function
  743. * @param offset = offset in IL object code for next instruction
  744. * @param src{File,Line,Posn} = location in source file corresponding to opcode
  745. * @returns with entry added to srcLocs
  746. */
  747. private static void SaveSrcLoc(Dictionary<int, ScriptSrcLoc> srcLocs, int offset, string srcFile, int srcLine, int srcPosn)
  748. {
  749. ScriptSrcLoc srcLoc = new ScriptSrcLoc();
  750. srcLoc.file = srcFile;
  751. srcLoc.line = srcLine;
  752. srcLoc.posn = srcPosn;
  753. srcLocs[offset] = srcLoc;
  754. }
  755. /**
  756. * @brief Create type<->string conversions.
  757. * Using Type.AssemblyQualifiedName is horribly inefficient
  758. * and all our types should be known.
  759. */
  760. private static Dictionary<string, Type> PopulateS2T()
  761. {
  762. Dictionary<string, Type> s2t = new Dictionary<string, Type>();
  763. s2t.Add("badcallx", typeof(ScriptBadCallNoException));
  764. s2t.Add("binopstr", typeof(BinOpStr));
  765. s2t.Add("bool", typeof(bool));
  766. s2t.Add("char", typeof(char));
  767. s2t.Add("delegate", typeof(Delegate));
  768. s2t.Add("delarr[]", typeof(Delegate[]));
  769. s2t.Add("double", typeof(double));
  770. s2t.Add("exceptn", typeof(Exception));
  771. s2t.Add("float", typeof(float));
  772. s2t.Add("htlist", typeof(HeapTrackerList));
  773. s2t.Add("htobject", typeof(HeapTrackerObject));
  774. s2t.Add("htstring", typeof(HeapTrackerString));
  775. s2t.Add("inlfunc", typeof(CompValuInline));
  776. s2t.Add("int", typeof(int));
  777. s2t.Add("int*", typeof(int).MakeByRefType());
  778. s2t.Add("intrlokd", typeof(System.Threading.Interlocked));
  779. s2t.Add("lslfloat", typeof(LSL_Float));
  780. s2t.Add("lslint", typeof(LSL_Integer));
  781. s2t.Add("lsllist", typeof(LSL_List));
  782. s2t.Add("lslrot", typeof(LSL_Rotation));
  783. s2t.Add("lslstr", typeof(LSL_String));
  784. s2t.Add("lslvec", typeof(LSL_Vector));
  785. s2t.Add("math", typeof(Math));
  786. s2t.Add("midround", typeof(MidpointRounding));
  787. s2t.Add("object", typeof(object));
  788. s2t.Add("object*", typeof(object).MakeByRefType());
  789. s2t.Add("object[]", typeof(object[]));
  790. s2t.Add("scrbase", typeof(ScriptBaseClass));
  791. s2t.Add("scrcode", typeof(ScriptCodeGen));
  792. s2t.Add("sdtclobj", typeof(XMRSDTypeClObj));
  793. s2t.Add("string", typeof(string));
  794. s2t.Add("typecast", typeof(TypeCast));
  795. s2t.Add("undstatx", typeof(ScriptUndefinedStateException));
  796. s2t.Add("void", typeof(void));
  797. s2t.Add("xmrarray", typeof(XMR_Array));
  798. s2t.Add("xmrinst", typeof(XMRInstAbstract));
  799. return s2t;
  800. }
  801. private static Dictionary<Type, string> PopulateT2S()
  802. {
  803. Dictionary<string, Type> s2t = PopulateS2T();
  804. Dictionary<Type, string> t2s = new Dictionary<Type, string>();
  805. foreach(KeyValuePair<string, Type> kvp in s2t)
  806. {
  807. t2s.Add(kvp.Value, kvp.Key);
  808. }
  809. return t2s;
  810. }
  811. /**
  812. * @brief Add to list of internally recognized types.
  813. */
  814. public static void DefineInternalType(string name, Type type)
  815. {
  816. if(!string2Type.ContainsKey(name))
  817. {
  818. string2Type.Add(name, type);
  819. type2String.Add(type, name);
  820. }
  821. }
  822. private string GetStrFromType(Type t)
  823. {
  824. string s = GetStrFromTypeWork(t);
  825. return s;
  826. }
  827. private string GetStrFromTypeWork(Type t)
  828. {
  829. string s;
  830. // internal fixed types like int and xmrarray etc
  831. if(type2String.TryGetValue(t, out s))
  832. return s;
  833. // script-defined types
  834. if(sdTypesRev.TryGetValue(t, out s))
  835. return "sdt$" + s;
  836. // inline function types
  837. s = TokenDeclSDTypeDelegate.TryGetInlineName(t);
  838. if(s != null)
  839. return s;
  840. // last resort
  841. return t.AssemblyQualifiedName;
  842. }
  843. private static Type GetTypeFromStr(Dictionary<string, TokenDeclSDType> sdTypes, string s)
  844. {
  845. Type t;
  846. // internal fixed types like int and xmrarray etc
  847. if(string2Type.TryGetValue(s, out t))
  848. return t;
  849. // script-defined types
  850. if(s.StartsWith("sdt$"))
  851. return sdTypes[s.Substring(4)].GetSysType();
  852. // inline function types
  853. t = TokenDeclSDTypeDelegate.TryGetInlineSysType(s);
  854. if(t != null)
  855. return t;
  856. // last resort
  857. return Type.GetType(s, true);
  858. }
  859. }
  860. public class ScriptSrcLoc
  861. {
  862. public string file;
  863. public int line;
  864. public int posn;
  865. }
  866. }