MMRScriptObjCode.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  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.Yengine;
  28. using System;
  29. using System.Collections.Generic;
  30. using System.IO;
  31. using System.Reflection;
  32. using System.Reflection.Emit;
  33. namespace OpenSim.Region.ScriptEngine.Yengine
  34. {
  35. public delegate void ScriptEventHandler(XMRInstAbstract instance);
  36. /*
  37. * This object represents the output of the compilation.
  38. * Once the compilation is complete, its contents should be
  39. * considered 'read-only', so it can be shared among multiple
  40. * instances of the script.
  41. *
  42. * It gets created by ScriptCodeGen.
  43. * It gets used by XMRInstance to create script instances.
  44. */
  45. public class ScriptObjCode
  46. {
  47. public string sourceHash; // source text hash code
  48. public XMRInstArSizes glblSizes = new XMRInstArSizes();
  49. // number of global variables of various types
  50. public string[] stateNames; // convert state number to corresponding string
  51. public ScriptEventHandler[,] scriptEventHandlerTable;
  52. // entrypoints to all event handler functions
  53. // 1st subscript = state code number (0=default)
  54. // 2nd subscript = event code number
  55. // null entry means no handler defined for that state,event
  56. public Dictionary<string, TokenDeclSDType> sdObjTypesName;
  57. // all script-defined types by name
  58. public TokenDeclSDType[] sdObjTypesIndx;
  59. // all script-defined types by sdTypeIndex
  60. public Dictionary<Type, string> sdDelTypes;
  61. // all script-defined delegates (including anonymous)
  62. public Dictionary<string, DynamicMethod> dynamicMethods;
  63. // all dyanmic methods
  64. public Dictionary<string, KeyValuePair<int, ScriptSrcLoc>[]> scriptSrcLocss;
  65. // method,iloffset -> source file,line,posn
  66. public int refCount; // used by engine to keep track of number of
  67. // instances that are using this object code
  68. public Dictionary<string, Dictionary<int, string>> globalVarNames = new Dictionary<string, Dictionary<int, string>>();
  69. /**
  70. * @brief Fill in ScriptObjCode from an YEngine object file.
  71. * 'objFileReader' is a serialized form of the CIL code we generated
  72. * 'asmFileWriter' is where we write the disassembly to (or null if not wanted)
  73. * 'srcFileWriter' is where we write the decompilation to (or null if not wanted)
  74. * Throws an exception if there is any error (theoretically).
  75. */
  76. public ScriptObjCode(BinaryReader objFileReader, TextWriter asmFileWriter, TextWriter srcFileWriter)
  77. {
  78. // Check version number to make sure we know how to process file contents.
  79. char[] ocm = objFileReader.ReadChars(ScriptCodeGen.OBJECT_CODE_MAGIC.Length);
  80. if(new String(ocm) != ScriptCodeGen.OBJECT_CODE_MAGIC)
  81. throw new CVVMismatchException("Not an Yengine object file (bad magic)");
  82. int cvv = objFileReader.ReadInt32();
  83. if(cvv != ScriptCodeGen.COMPILED_VERSION_VALUE)
  84. throw new CVVMismatchException(
  85. "Object version is " + cvv.ToString() + " but accept only " + ScriptCodeGen.COMPILED_VERSION_VALUE.ToString());
  86. // Fill in simple parts of scriptObjCode object.
  87. sourceHash = objFileReader.ReadString();
  88. glblSizes.ReadFromFile(objFileReader);
  89. int nStates = objFileReader.ReadInt32();
  90. stateNames = new string[nStates];
  91. for(int i = 0; i < nStates; i++)
  92. {
  93. stateNames[i] = objFileReader.ReadString();
  94. if(asmFileWriter != null)
  95. asmFileWriter.WriteLine(" state[{0}] = {1}", i, stateNames[i]);
  96. }
  97. if(asmFileWriter != null)
  98. glblSizes.WriteAsmFile(asmFileWriter, "numGbl");
  99. string gblName;
  100. while((gblName = objFileReader.ReadString()) != "")
  101. {
  102. string gblType = objFileReader.ReadString();
  103. int gblIndex = objFileReader.ReadInt32();
  104. Dictionary<int, string> names;
  105. if(!globalVarNames.TryGetValue(gblType, out names))
  106. {
  107. names = new Dictionary<int, string>();
  108. globalVarNames.Add(gblType, names);
  109. }
  110. names.Add(gblIndex, gblName);
  111. if(asmFileWriter != null)
  112. asmFileWriter.WriteLine(" {0} = {1}[{2}]", gblName, gblType, gblIndex);
  113. }
  114. // Read in script-defined types.
  115. sdObjTypesName = new Dictionary<string, TokenDeclSDType>();
  116. sdDelTypes = new Dictionary<Type, string>();
  117. int maxIndex = -1;
  118. while((gblName = objFileReader.ReadString()) != "")
  119. {
  120. TokenDeclSDType sdt = TokenDeclSDType.ReadFromFile(sdObjTypesName,
  121. gblName, objFileReader, asmFileWriter);
  122. sdObjTypesName.Add(gblName, sdt);
  123. if(maxIndex < sdt.sdTypeIndex)
  124. maxIndex = sdt.sdTypeIndex;
  125. if(sdt is TokenDeclSDTypeDelegate)
  126. sdDelTypes.Add(sdt.GetSysType(), gblName);
  127. }
  128. sdObjTypesIndx = new TokenDeclSDType[maxIndex + 1];
  129. foreach(TokenDeclSDType sdt in sdObjTypesName.Values)
  130. sdObjTypesIndx[sdt.sdTypeIndex] = sdt;
  131. // Now fill in the methods (the hard part).
  132. scriptEventHandlerTable = new ScriptEventHandler[nStates, (int)ScriptEventCode.Size];
  133. dynamicMethods = new Dictionary<string, DynamicMethod>();
  134. scriptSrcLocss = new Dictionary<string, KeyValuePair<int, ScriptSrcLoc>[]>();
  135. ObjectTokens objectTokens = null;
  136. if(asmFileWriter != null)
  137. objectTokens = new OTDisassemble(this, asmFileWriter);
  138. else if(srcFileWriter != null)
  139. objectTokens = new OTDecompile(this, srcFileWriter);
  140. try
  141. {
  142. ScriptObjWriter.CreateObjCode(sdObjTypesName, objFileReader, this, objectTokens);
  143. }
  144. finally
  145. {
  146. objectTokens?.Close();
  147. }
  148. // We enter all script event handler methods in the ScriptEventHandler table.
  149. // They are named: <statename> <eventname>
  150. foreach(KeyValuePair<string, DynamicMethod> kvp in dynamicMethods)
  151. {
  152. string methName = kvp.Key;
  153. int i = methName.IndexOf(' ');
  154. if(i < 0)
  155. continue;
  156. string stateName = methName.Substring(0, i);
  157. string eventName = methName.Substring(++i);
  158. int stateCode;
  159. for(stateCode = stateNames.Length; --stateCode >= 0;)
  160. if(stateNames[stateCode] == stateName)
  161. break;
  162. int eventCode = (int)Enum.Parse(typeof(ScriptEventCode), eventName);
  163. scriptEventHandlerTable[stateCode, eventCode] =
  164. (ScriptEventHandler)kvp.Value.CreateDelegate(typeof(ScriptEventHandler));
  165. }
  166. // Fill in all script-defined class vtables.
  167. foreach(TokenDeclSDType sdt in sdObjTypesIndx)
  168. {
  169. if((sdt != null) && (sdt is TokenDeclSDTypeClass))
  170. {
  171. TokenDeclSDTypeClass sdtc = (TokenDeclSDTypeClass)sdt;
  172. sdtc.FillVTables(this);
  173. }
  174. }
  175. }
  176. /**
  177. * @brief Called once for every method found in objFileReader file.
  178. * It enters the method in the ScriptObjCode object table so it can be called.
  179. */
  180. public void EndMethod(DynamicMethod method, Dictionary<int, ScriptSrcLoc> srcLocs)
  181. {
  182. // Save method object code pointer.
  183. dynamicMethods.Add(method.Name, method);
  184. // Build and sort iloffset -> source code location array.
  185. int n = srcLocs.Count;
  186. KeyValuePair<int, ScriptSrcLoc>[] srcLocArray = new KeyValuePair<int, ScriptSrcLoc>[n];
  187. n = 0;
  188. foreach(KeyValuePair<int, ScriptSrcLoc> kvp in srcLocs)
  189. srcLocArray[n++] = kvp;
  190. Array.Sort(srcLocArray, endMethodWrapper);
  191. // Save sorted array.
  192. scriptSrcLocss.Add(method.Name, srcLocArray);
  193. }
  194. /**
  195. * @brief Called once for every method found in objFileReader file.
  196. * It enters the method in the ScriptObjCode object table so it can be called.
  197. */
  198. private static EndMethodWrapper endMethodWrapper = new EndMethodWrapper();
  199. private class EndMethodWrapper: System.Collections.IComparer
  200. {
  201. public int Compare(object x, object y)
  202. {
  203. KeyValuePair<int, ScriptSrcLoc> kvpx = (KeyValuePair<int, ScriptSrcLoc>)x;
  204. KeyValuePair<int, ScriptSrcLoc> kvpy = (KeyValuePair<int, ScriptSrcLoc>)y;
  205. return kvpx.Key - kvpy.Key;
  206. }
  207. }
  208. }
  209. }