XMRSDTypeClObj.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  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 System;
  28. using System.Reflection.Emit;
  29. using LSL_Float = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLFloat;
  30. using LSL_Integer = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger;
  31. using LSL_Key = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
  32. using LSL_List = OpenSim.Region.ScriptEngine.Shared.LSL_Types.list;
  33. using LSL_Rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion;
  34. using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
  35. using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
  36. namespace OpenSim.Region.ScriptEngine.Yengine
  37. {
  38. public class XMRSDTypeClObj
  39. {
  40. /*
  41. * Which script instance we are part of so we can access
  42. * the script's global variables and functions.
  43. */
  44. public XMRInstAbstract xmrInst;
  45. /*
  46. * What class we actually are in the hierarchy
  47. * used for casting.
  48. */
  49. public TokenDeclSDTypeClass sdtcClass;
  50. /*
  51. * Our VTable array, used for calling virtual functions.
  52. * And ITable array, used for calling our implementation of interface functions.
  53. */
  54. public Delegate[] sdtcVTable;
  55. public Delegate[][] sdtcITable;
  56. /*
  57. * These arrays hold the insance variable values.
  58. * The array lengths are determined by the script compilation,
  59. * and are found in TokenDeclSDTypeClass.instSizes.
  60. */
  61. public XMRInstArrays instVars;
  62. /**
  63. * @brief Called by script's $new() to initialize a new object.
  64. */
  65. public XMRSDTypeClObj(XMRInstAbstract inst, int classindex)
  66. {
  67. Construct(inst, classindex);
  68. instVars.AllocVarArrays(sdtcClass.instSizes);
  69. }
  70. /**
  71. * @brief Set up everything except the instVars arrays.
  72. * @param inst = script instance this object is part of
  73. * @param classindex = which script-defined type class this object is an onstance of
  74. * @returns with the vtables filled in
  75. */
  76. private void Construct(XMRInstAbstract inst, int classindex)
  77. {
  78. Delegate[] thisMid = null;
  79. TokenDeclSDTypeClass clas = (TokenDeclSDTypeClass)inst.m_ObjCode.sdObjTypesIndx[classindex];
  80. xmrInst = inst;
  81. sdtcClass = clas;
  82. instVars = new XMRInstArrays(inst);
  83. /*
  84. * VTable consists of delegates built from DynamicMethods and the 'this' pointer.
  85. * Yes, yes, lots of shitty little mallocs.
  86. */
  87. DynamicMethod[] vDynMeths = clas.vDynMeths;
  88. if(vDynMeths != null)
  89. {
  90. int n = vDynMeths.Length;
  91. Type[] vMethTypes = clas.vMethTypes;
  92. sdtcVTable = new Delegate[n];
  93. for(int i = 0; i < n; i++)
  94. {
  95. sdtcVTable[i] = vDynMeths[i].CreateDelegate(vMethTypes[i], this);
  96. }
  97. }
  98. /*
  99. * Fill in interface vtables.
  100. * There is one array of delegates for each implemented interface.
  101. * The array of delegates IS the interface's object, ie, the 'this' value of the interface.
  102. * To cast from the class type to the interface type, just get the correct array from the table.
  103. * To cast from the interface type to the class type, just get Target of entry 0.
  104. *
  105. * So we end up with this:
  106. * sdtcITable[interfacenumber][methodofintfnumber] = delegate of this.ourimplementationofinterfacesmethod
  107. */
  108. if(clas.iDynMeths != null)
  109. {
  110. int nIFaces = clas.iDynMeths.Length;
  111. sdtcITable = new Delegate[nIFaces][];
  112. for(int i = 0; i < nIFaces; i++)
  113. {
  114. // get vector of entrypoints of our instance methods that implement that interface
  115. DynamicMethod[] iDynMeths = clas.iDynMeths[i];
  116. Type[] iMethTypes = clas.iMethTypes[i];
  117. // allocate an array with a slot for each method the interface defines
  118. int nMeths = iDynMeths.Length;
  119. Delegate[] ivec;
  120. if(nMeths > 0)
  121. {
  122. // fill in the array with delegates that reference back to this class instance
  123. ivec = new Delegate[nMeths];
  124. for(int j = 0; j < nMeths; j++)
  125. {
  126. ivec[j] = iDynMeths[j].CreateDelegate(iMethTypes[j], this);
  127. }
  128. }
  129. else
  130. {
  131. // just a marker interface with no methods,
  132. // allocate a one-element array and fill
  133. // with a dummy entry. this will allow casting
  134. // back to the original class instance (this)
  135. // by reading Target of entry 0.
  136. if(thisMid == null)
  137. {
  138. thisMid = new Delegate[1];
  139. thisMid[0] = markerInterfaceDummy.CreateDelegate(typeof(MarkerInterfaceDummy), this);
  140. }
  141. ivec = thisMid;
  142. }
  143. // save whatever we ended up allocating
  144. sdtcITable[i] = ivec;
  145. }
  146. }
  147. }
  148. private delegate void MarkerInterfaceDummy();
  149. private static DynamicMethod markerInterfaceDummy = MakeMarkerInterfaceDummy();
  150. private static DynamicMethod MakeMarkerInterfaceDummy()
  151. {
  152. DynamicMethod dm = new DynamicMethod("XMRSDTypeClObj.MarkerInterfaceDummy", null, new Type[] { typeof(XMRSDTypeClObj) });
  153. ILGenerator ilGen = dm.GetILGenerator();
  154. ilGen.Emit(OpCodes.Ret);
  155. return dm;
  156. }
  157. /**
  158. * @brief Perform runtime casting of script-defined interface object to
  159. * its corresponding script-defined class object.
  160. * @param da = interface object (array of delegates pointing to class's implementations of interface's methods)
  161. * @param classindex = what class those implementations are supposedly part of
  162. * @returns original script-defined class object
  163. */
  164. public static XMRSDTypeClObj CastIFace2Class(Delegate[] da, int classindex)
  165. {
  166. return CastClass2Class(da[0].Target, classindex);
  167. }
  168. /**
  169. * @brief Perform runtime casting of XMRSDTypeClObj's.
  170. * @param ob = XMRSDTypeClObj of unknown script-defined class to cast
  171. * @param classindex = script-defined class to cast it to
  172. * @returns ob is a valid instance of classindex; else exception thrown
  173. */
  174. public static XMRSDTypeClObj CastClass2Class(object ob, int classindex)
  175. {
  176. /*
  177. * Let mono check to see if we at least have an XMRSDTypeClObj.
  178. */
  179. XMRSDTypeClObj ci = (XMRSDTypeClObj)ob;
  180. if(ci != null)
  181. {
  182. /*
  183. * This is the target class, ie, what we are hoping the object can cast to.
  184. */
  185. TokenDeclSDTypeClass tc = (TokenDeclSDTypeClass)ci.xmrInst.m_ObjCode.sdObjTypesIndx[classindex];
  186. /*
  187. * Step from the object's actual class rootward.
  188. * If we find the target class along the way, the cast is valid.
  189. * If we run off the end of the root, the cast is not valid.
  190. */
  191. for(TokenDeclSDTypeClass ac = ci.sdtcClass; ac != tc; ac = ac.extends)
  192. {
  193. if(ac == null)
  194. throw new InvalidCastException("invalid cast from " + ci.sdtcClass.longName.val +
  195. " to " + tc.longName.val);
  196. }
  197. /*
  198. * The target class is at or rootward of the actual class,
  199. * so the cast is valid.
  200. */
  201. }
  202. return ci;
  203. }
  204. /**
  205. * @brief Cast an arbitrary object to the given interface.
  206. * @param ob = object to be cast of unknown type
  207. * @returns ob cast to the interface type
  208. */
  209. public static Delegate[] CastObj2IFace(object ob, string ifacename)
  210. {
  211. if(ob == null)
  212. return null;
  213. /*
  214. * If it is already one of our interfaces, extract the script-defined class object from it.
  215. */
  216. if(ob is Delegate[])
  217. {
  218. Delegate[] da = (Delegate[])ob;
  219. ob = da[0].Target;
  220. }
  221. /*
  222. * Now that we have a presumed script-defined class object, cast that to the requested interface
  223. * by picking the array of delegates that corresponds to the requested interface.
  224. */
  225. XMRSDTypeClObj ci = (XMRSDTypeClObj)ob;
  226. int iFaceIndex = ci.sdtcClass.intfIndices[ifacename];
  227. return ci.sdtcITable[iFaceIndex];
  228. }
  229. /**
  230. * @brief Write the whole thing out to a stream.
  231. */
  232. public void Capture(XMRInstArrays.Sender sendValue)
  233. {
  234. sendValue(this.sdtcClass.sdTypeIndex);
  235. this.instVars.SendArrays(sendValue);
  236. }
  237. /**
  238. * @brief Read the whole thing in from a stream.
  239. */
  240. public XMRSDTypeClObj()
  241. {
  242. }
  243. public void Restore(XMRInstAbstract inst, XMRInstArrays.Recver recvValue)
  244. {
  245. int classindex = (int)recvValue();
  246. Construct(inst, classindex);
  247. this.instVars.RecvArrays(recvValue);
  248. }
  249. }
  250. }