MMRScriptInlines.cs 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708
  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.Collections.Generic;
  29. using System.Reflection;
  30. using System.Reflection.Emit;
  31. using System.Text;
  32. using LSL_Float = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLFloat;
  33. using LSL_Integer = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger;
  34. using LSL_Key = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
  35. using LSL_List = OpenSim.Region.ScriptEngine.Shared.LSL_Types.list;
  36. using LSL_Rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion;
  37. using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
  38. using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
  39. /**
  40. * @brief Generate code for the backend API calls.
  41. */
  42. namespace OpenSim.Region.ScriptEngine.Yengine
  43. {
  44. public abstract class TokenDeclInline: TokenDeclVar
  45. {
  46. public static VarDict inlineFunctions = CreateDictionary();
  47. public abstract void CodeGen(ScriptCodeGen scg, Token errorAt, CompValuTemp result, CompValu[] args);
  48. private static HashSet<string> noCheckRuns;
  49. private static string[] keyReturns;
  50. protected bool isTaggedCallsCheckRun;
  51. /**
  52. * @brief Create a dictionary of inline backend API functions.
  53. */
  54. private static VarDict CreateDictionary()
  55. {
  56. /*
  57. * For those listed in noCheckRun, we just generate the call (simple computations).
  58. * For all others, we generate the call then a call to CheckRun().
  59. * note to self: a change here implies change on magic numbers to invalidate older code and
  60. * script state
  61. */
  62. noCheckRuns = new HashSet<string>() {
  63. "llBase64ToString",
  64. "llCSV2List",
  65. "llDeleteSubList",
  66. "llDeleteSubString",
  67. "llDumpList2String",
  68. "llEscapeURL",
  69. "llEuler2Rot",
  70. "llGetListEntryType",
  71. "llGetListLength",
  72. "llGetSubString",
  73. "llGetUnixTime",
  74. "llInsertString",
  75. "llList2CSV",
  76. "llList2Float",
  77. "llList2Integer",
  78. "llList2Key",
  79. "llList2Rot",
  80. "llList2String",
  81. "llList2Vector",
  82. "llListFindList",
  83. "llListInsertList",
  84. "llListRandomize",
  85. "llListReplaceList",
  86. "llListSort",
  87. "llListStatistics",
  88. "llMD5String",
  89. "llParseString2List",
  90. "llParseStringKeepNulls",
  91. "llRot2Euler",
  92. "llStringLength",
  93. "llStringToBase64",
  94. "llStringTrim",
  95. "llSubStringIndex",
  96. "llUnescapeURL",
  97. "osGetSitActiveRange",
  98. "osIsNotValidNumber",
  99. "osSlerp",
  100. "osApproxEquals",
  101. "osVecDistSquare",
  102. "osVecMagSquare",
  103. "osRound",
  104. "osGetLinkNumber",
  105. "osMax",
  106. "osMin",
  107. "osIsUUID"
  108. };
  109. /*
  110. * These functions really return a 'key' even though we see them as
  111. * returning 'string' because OpenSim has key and string as same type.
  112. */
  113. keyReturns = new string[] {
  114. "llAvatarOnLinkSitTarget",
  115. "llAvatarOnSitTarget",
  116. "llDetectedKey",
  117. "llDetectedOwner",
  118. "llGenerateKey",
  119. "llGetCreator",
  120. "llGetInventoryCreator",
  121. "llGetInventoryKey",
  122. "llGetKey",
  123. "llGetLandOwnerAt",
  124. "llGetLinkKey",
  125. "llGetNotecardLine",
  126. "llGetNumberOfNotecardLines",
  127. "llGetOwner",
  128. "llGetOwnerKey",
  129. "llGetPermissionsKey",
  130. "llHTTPRequest",
  131. "llList2Key",
  132. "llRequestAgentData",
  133. "llRequestDisplayName",
  134. "llRequestInventoryData",
  135. "llRequestSecureURL",
  136. "llRequestSimulatorData",
  137. "llRequestURL",
  138. "llRequestUsername",
  139. "llSendRemoteData",
  140. "llTransferLindenDollars"
  141. };
  142. VarDict ifd = new VarDict(false);
  143. Type[] oneDoub = new Type[] { typeof(double) };
  144. Type[] twoDoubs = new Type[] { typeof(double), typeof(double) };
  145. /*
  146. * Something weird about the code generation for these calls, so they all have their own handwritten code generators.
  147. */
  148. new TokenDeclInline_GetFreeMemory(ifd);
  149. new TokenDeclInline_GetUsedMemory(ifd);
  150. /*
  151. * These are all the xmr...() calls directly in XMRInstAbstract.
  152. * Includes the calls from ScriptBaseClass that has all the stubs
  153. * which convert XMRInstAbstract to the various <NAME>_Api contexts.
  154. */
  155. MethodInfo[] absmeths = typeof(XMRInstAbstract).GetMethods();
  156. AddInterfaceMethods(ifd, absmeths, null);
  157. return ifd;
  158. }
  159. /**
  160. * @brief Add API functions from the given interface to list of built-in functions.
  161. * Only functions beginning with a lower-case letter are entered, all others ignored.
  162. * @param ifd = internal function dictionary to add them to
  163. * @param ifaceMethods = list of API functions
  164. * @param acf = which field in XMRInstanceSuperType holds method's 'this' pointer
  165. */
  166. // this one accepts only names beginning with a lower-case letter
  167. public static void AddInterfaceMethods(VarDict ifd, MethodInfo[] ifaceMethods, FieldInfo acf)
  168. {
  169. List<MethodInfo> lcms = new List<MethodInfo>(ifaceMethods.Length);
  170. foreach(MethodInfo meth in ifaceMethods)
  171. {
  172. string name = meth.Name;
  173. if((name[0] >= 'a') && (name[0] <= 'z'))
  174. {
  175. lcms.Add(meth);
  176. }
  177. }
  178. AddInterfaceMethods(ifd, lcms.GetEnumerator(), acf);
  179. }
  180. // this one accepts all methods given to it
  181. public static void AddInterfaceMethods(VarDict ifd, IEnumerator<MethodInfo> ifaceMethods, FieldInfo acf)
  182. {
  183. ifd ??= inlineFunctions;
  184. for(ifaceMethods.Reset(); ifaceMethods.MoveNext();)
  185. {
  186. MethodInfo ifaceMethod = ifaceMethods.Current;
  187. try
  188. {
  189. /*
  190. * See if we will generate a call to CheckRun() right
  191. * after we generate a call to the function.
  192. * If function begins with xmr, assume we will not call CheckRun()
  193. * Otherwise, assume we will call CheckRun()
  194. */
  195. bool dcr = !(ifaceMethod.Name.StartsWith("xmr") || noCheckRuns.Contains(ifaceMethod.Name));
  196. /*
  197. * Add function to dictionary.
  198. */
  199. new TokenDeclInline_BEApi(ifd, dcr, ifaceMethod, acf);
  200. }
  201. catch
  202. {
  203. ///??? IGNORE ANY THAT FAIL - LIKE UNRECOGNIZED TYPE ???///
  204. ///??? and OVERLOADED NAMES ???///
  205. }
  206. }
  207. }
  208. /**
  209. * @brief Add an inline function definition to the dictionary.
  210. * @param ifd = dictionary to add inline definition to
  211. * @param doCheckRun = true iff the generated code or the function itself can possibly call CheckRun()
  212. * @param nameArgSig = inline function signature string, in form <name>(<arglsltypes>,...)
  213. * @param retType = return type, use TokenTypeVoid if no return value
  214. */
  215. protected TokenDeclInline(VarDict ifd,
  216. bool doCheckRun,
  217. string nameArgSig,
  218. TokenType retType)
  219. : base(null, null, null)
  220. {
  221. this.retType = retType;
  222. this.triviality = doCheckRun ? Triviality.complex : Triviality.trivial;
  223. int j = nameArgSig.IndexOf('(');
  224. this.name = new TokenName(null, nameArgSig.Substring(0, j++));
  225. this.argDecl = new TokenArgDecl(null);
  226. if(nameArgSig[j] != ')')
  227. {
  228. int i;
  229. TokenName name;
  230. TokenType type;
  231. for(i = j; nameArgSig[i] != ')'; i++)
  232. {
  233. if(nameArgSig[i] == ',')
  234. {
  235. type = TokenType.FromLSLType(null, nameArgSig.Substring(j, i - j));
  236. name = new TokenName(null, "arg" + this.argDecl.varDict.Count);
  237. this.argDecl.AddArg(type, name);
  238. j = i + 1;
  239. }
  240. }
  241. type = TokenType.FromLSLType(null, nameArgSig.Substring(j, i - j));
  242. name = new TokenName(null, "arg" + this.argDecl.varDict.Count);
  243. this.argDecl.AddArg(type, name);
  244. }
  245. this.location = new CompValuInline(this);
  246. if(ifd == null)
  247. ifd = inlineFunctions;
  248. ifd.AddEntry(this);
  249. }
  250. protected TokenDeclInline(VarDict ifd,
  251. bool doCheckRun,
  252. MethodInfo methInfo)
  253. : base(null, null, null)
  254. {
  255. isTaggedCallsCheckRun = IsTaggedCallsCheckRun(methInfo);
  256. name = new TokenName(null, methInfo.Name);
  257. retType = GetRetType(methInfo, TokenType.FromSysType(null, methInfo.ReturnType));
  258. argDecl = GetArgDecl(methInfo.GetParameters());
  259. triviality = (doCheckRun || isTaggedCallsCheckRun) ? Triviality.complex : Triviality.trivial;
  260. location = new CompValuInline(this);
  261. ifd ??= inlineFunctions;
  262. ifd.AddEntry(this);
  263. }
  264. private static TokenArgDecl GetArgDecl(ParameterInfo[] parameters)
  265. {
  266. TokenArgDecl argDecl = new TokenArgDecl(null);
  267. foreach(ParameterInfo pi in parameters)
  268. {
  269. TokenType type = TokenType.FromSysType(null, pi.ParameterType);
  270. TokenName name = new TokenName(null, pi.Name);
  271. argDecl.AddArg(type, name);
  272. }
  273. return argDecl;
  274. }
  275. /**
  276. * @brief The above code assumes all methods beginning with 'xmr' are trivial, ie,
  277. * they do not call CheckRun() and also we do not generate a CheckRun()
  278. * call after they return. So if an 'xmr' method does call CheckRun(), it
  279. * must be tagged with attribute 'xmrMethodCallsCheckRunAttribute' so we know
  280. * the method is not trivial. But in neither case do we emit our own call
  281. * to CheckRun(), the 'xmr' method must do its own. We do however set up a
  282. * call label before the call to the non-trivial 'xmr' method so when we are
  283. * restoring the call stack, the restore will call directly in to the 'xmr'
  284. * method without re-executing any code before the call to the 'xmr' method.
  285. */
  286. private static bool IsTaggedCallsCheckRun(MethodInfo methInfo)
  287. {
  288. return (methInfo != null) &&
  289. Attribute.IsDefined(methInfo, typeof(xmrMethodCallsCheckRunAttribute));
  290. }
  291. /**
  292. * @brief The dumbass OpenSim has key and string as the same type so non-ll
  293. * methods must be tagged with xmrMethodReturnsKeyAttribute if we
  294. * are to think they return a key type, otherwise we will think they
  295. * return string.
  296. */
  297. private static TokenType GetRetType(MethodInfo methInfo, TokenType retType)
  298. {
  299. if((methInfo != null) && (retType != null) && (retType is TokenTypeStr))
  300. {
  301. if(Attribute.IsDefined(methInfo, typeof(xmrMethodReturnsKeyAttribute)))
  302. {
  303. return ChangeToKeyType(retType);
  304. }
  305. string mn = methInfo.Name;
  306. foreach(string kr in keyReturns)
  307. {
  308. if(kr == mn)
  309. return ChangeToKeyType(retType);
  310. }
  311. }
  312. return retType;
  313. }
  314. private static TokenType ChangeToKeyType(TokenType retType)
  315. {
  316. if(retType is TokenTypeLSLString)
  317. {
  318. retType = new TokenTypeLSLKey(null);
  319. }
  320. else
  321. {
  322. retType = new TokenTypeKey(null);
  323. }
  324. return retType;
  325. }
  326. public virtual MethodInfo GetMethodInfo()
  327. {
  328. return null;
  329. }
  330. /**
  331. * @brief Print out a list of all the built-in functions and constants.
  332. */
  333. public delegate void WriteLine(string str);
  334. public static void PrintBuiltins(bool inclNoisyTag, WriteLine writeLine)
  335. {
  336. writeLine("\nBuilt-in functions:\n");
  337. SortedDictionary<string, TokenDeclInline> bifs = new SortedDictionary<string, TokenDeclInline>();
  338. foreach(TokenDeclVar bif in TokenDeclInline.inlineFunctions)
  339. {
  340. bifs.Add(bif.fullName, (TokenDeclInline)bif);
  341. }
  342. foreach(TokenDeclInline bif in bifs.Values)
  343. {
  344. char noisy = (!inclNoisyTag || !IsTaggedNoisy(bif.GetMethodInfo())) ? ' ' : (bif.retType is TokenTypeVoid) ? 'N' : 'R';
  345. writeLine(noisy + " " + bif.retType.ToString().PadLeft(8) + " " + bif.fullName);
  346. }
  347. if(inclNoisyTag)
  348. {
  349. writeLine("\nN - stub that writes name and arguments to stdout");
  350. writeLine("R - stub that writes name and arguments to stdout then reads return value from stdin");
  351. writeLine(" format is: function_name : return_value");
  352. writeLine(" example: llKey2Name:\"Kunta Kinte\"");
  353. }
  354. writeLine("\nBuilt-in constants:\n");
  355. SortedDictionary<string, ScriptConst> scs = new SortedDictionary<string, ScriptConst>();
  356. int widest = 0;
  357. foreach(ScriptConst sc in ScriptConst.scriptConstants.Values)
  358. {
  359. if(widest < sc.name.Length)
  360. widest = sc.name.Length;
  361. scs.Add(sc.name, sc);
  362. }
  363. foreach(ScriptConst sc in scs.Values)
  364. {
  365. writeLine(" " + sc.rVal.type.ToString().PadLeft(8) + " " + sc.name.PadRight(widest) + " = " + BuiltInConstVal(sc.rVal));
  366. }
  367. }
  368. public static bool IsTaggedNoisy(MethodInfo methInfo)
  369. {
  370. return (methInfo != null) && Attribute.IsDefined(methInfo, typeof(xmrMethodIsNoisyAttribute));
  371. }
  372. public static string BuiltInConstVal(CompValu rVal)
  373. {
  374. if(rVal is CompValuInteger)
  375. {
  376. int x = ((CompValuInteger)rVal).x;
  377. return "0x" + x.ToString("X8") + " = " + x.ToString().PadLeft(11);
  378. }
  379. if(rVal is CompValuFloat)
  380. return ((CompValuFloat)rVal).x.ToString();
  381. if(rVal is CompValuString)
  382. {
  383. StringBuilder sb = new StringBuilder();
  384. PrintParam(sb, ((CompValuString)rVal).x);
  385. return sb.ToString();
  386. }
  387. if(rVal is CompValuSField)
  388. {
  389. FieldInfo fi = ((CompValuSField)rVal).field;
  390. StringBuilder sb = new StringBuilder();
  391. PrintParam(sb, fi.GetValue(null));
  392. return sb.ToString();
  393. }
  394. return rVal.ToString(); // just prints the type
  395. }
  396. public static void PrintParam(StringBuilder sb, object p)
  397. {
  398. if(p == null)
  399. {
  400. sb.Append("null");
  401. }
  402. else if(p is LSL_List)
  403. {
  404. sb.Append('[');
  405. object[] d = ((LSL_List)p).Data;
  406. for(int i = 0; i < d.Length; i++)
  407. {
  408. if(i > 0)
  409. sb.Append(',');
  410. PrintParam(sb, d[i]);
  411. }
  412. sb.Append(']');
  413. }
  414. else if(p is LSL_Rotation)
  415. {
  416. LSL_Rotation r = (LSL_Rotation)p;
  417. sb.Append('<');
  418. sb.Append(r.x);
  419. sb.Append(',');
  420. sb.Append(r.y);
  421. sb.Append(',');
  422. sb.Append(r.z);
  423. sb.Append(',');
  424. sb.Append(r.s);
  425. sb.Append('>');
  426. }
  427. else if(p is LSL_String)
  428. {
  429. PrintParamString(sb, (string)(LSL_String)p);
  430. }
  431. else if(p is LSL_Vector)
  432. {
  433. LSL_Vector v = (LSL_Vector)p;
  434. sb.Append('<');
  435. sb.Append(v.x);
  436. sb.Append(',');
  437. sb.Append(v.y);
  438. sb.Append(',');
  439. sb.Append(v.z);
  440. sb.Append('>');
  441. }
  442. else if(p is string)
  443. {
  444. PrintParamString(sb, (string)p);
  445. }
  446. else
  447. {
  448. sb.Append(p.ToString());
  449. }
  450. }
  451. public static void PrintParamString(StringBuilder sb, string p)
  452. {
  453. sb.Append('"');
  454. foreach(char c in p)
  455. {
  456. if(c == '\b')
  457. {
  458. sb.Append("\\b");
  459. continue;
  460. }
  461. if(c == '\n')
  462. {
  463. sb.Append("\\n");
  464. continue;
  465. }
  466. if(c == '\r')
  467. {
  468. sb.Append("\\r");
  469. continue;
  470. }
  471. if(c == '\t')
  472. {
  473. sb.Append("\\t");
  474. continue;
  475. }
  476. if(c == '"')
  477. {
  478. sb.Append("\\\"");
  479. continue;
  480. }
  481. if(c == '\\')
  482. {
  483. sb.Append("\\\\");
  484. continue;
  485. }
  486. sb.Append(c);
  487. }
  488. sb.Append('"');
  489. }
  490. }
  491. /**
  492. * @brief Code generators...
  493. * @param scg = script we are generating code for
  494. * @param result = type/location for result (type matches function definition)
  495. * @param args = type/location of arguments (types match function definition)
  496. */
  497. /*
  498. public class TokenDeclInline_LLAbs: TokenDeclInline
  499. {
  500. public TokenDeclInline_LLAbs(VarDict ifd)
  501. : base(ifd, false, "llAbs(integer)", new TokenTypeInt(null)) { }
  502. public override void CodeGen(ScriptCodeGen scg, Token errorAt, CompValuTemp result, CompValu[] args)
  503. {
  504. ScriptMyLabel itsPosLabel = scg.ilGen.DefineLabel("llAbstemp");
  505. args[0].PushVal(scg, errorAt);
  506. scg.ilGen.Emit(errorAt, OpCodes.Dup);
  507. scg.ilGen.Emit(errorAt, OpCodes.Ldc_I4_0);
  508. scg.ilGen.Emit(errorAt, OpCodes.Bge_S, itsPosLabel);
  509. scg.ilGen.Emit(errorAt, OpCodes.Neg);
  510. scg.ilGen.MarkLabel(itsPosLabel);
  511. result.Pop(scg, errorAt, retType);
  512. }
  513. }
  514. public class TokenDeclInline_Math: TokenDeclInline
  515. {
  516. private MethodInfo methInfo;
  517. public TokenDeclInline_Math(VarDict ifd, string sig, string name, Type[] args)
  518. : base(ifd, false, sig, new TokenTypeFloat(null))
  519. {
  520. methInfo = ScriptCodeGen.GetStaticMethod(typeof(System.Math), name, args);
  521. }
  522. public override void CodeGen(ScriptCodeGen scg, Token errorAt, CompValuTemp result, CompValu[] args)
  523. {
  524. for(int i = 0; i < args.Length; i++)
  525. {
  526. args[i].PushVal(scg, errorAt, argDecl.types[i]);
  527. }
  528. scg.ilGen.Emit(errorAt, OpCodes.Call, methInfo);
  529. result.Pop(scg, errorAt, retType);
  530. }
  531. }
  532. public class TokenDeclInline_LLRound: TokenDeclInline
  533. {
  534. private static MethodInfo roundMethInfo = ScriptCodeGen.GetStaticMethod(typeof(System.Math), "Round",
  535. new Type[] { typeof(double), typeof(MidpointRounding) });
  536. public TokenDeclInline_LLRound(VarDict ifd)
  537. : base(ifd, false, "llRound(float)", new TokenTypeInt(null)) { }
  538. public override void CodeGen(ScriptCodeGen scg, Token errorAt, CompValuTemp result, CompValu[] args)
  539. {
  540. args[0].PushVal(scg, errorAt, new TokenTypeFloat(null));
  541. scg.ilGen.Emit(errorAt, OpCodes.Ldc_I4, (int)System.MidpointRounding.AwayFromZero);
  542. scg.ilGen.Emit(errorAt, OpCodes.Call, roundMethInfo);
  543. result.Pop(scg, errorAt, new TokenTypeFloat(null));
  544. }
  545. }
  546. */
  547. public class TokenDeclInline_GetFreeMemory: TokenDeclInline
  548. {
  549. private static readonly MethodInfo getFreeMemMethInfo = typeof(XMRInstAbstract).GetMethod("xmrHeapLeft", new Type[] { });
  550. public TokenDeclInline_GetFreeMemory(VarDict ifd)
  551. : base(ifd, false, "llGetFreeMemory()", new TokenTypeInt(null)) { }
  552. // appears as llGetFreeMemory() in script source code
  553. // but actually calls xmrHeapLeft()
  554. public override void CodeGen(ScriptCodeGen scg, Token errorAt, CompValuTemp result, CompValu[] args)
  555. {
  556. scg.PushXMRInst();
  557. scg.ilGen.Emit(errorAt, OpCodes.Call, getFreeMemMethInfo);
  558. result.Pop(scg, errorAt, new TokenTypeInt(null));
  559. }
  560. }
  561. public class TokenDeclInline_GetUsedMemory: TokenDeclInline
  562. {
  563. private static readonly MethodInfo getUsedMemMethInfo = typeof(XMRInstAbstract).GetMethod("xmrHeapUsed", new Type[] { });
  564. public TokenDeclInline_GetUsedMemory(VarDict ifd)
  565. : base(ifd, false, "llGetUsedMemory()", new TokenTypeInt(null)) { }
  566. // appears as llGetUsedMemory() in script source code
  567. // but actually calls xmrHeapUsed()
  568. public override void CodeGen(ScriptCodeGen scg, Token errorAt, CompValuTemp result, CompValu[] args)
  569. {
  570. scg.PushXMRInst();
  571. scg.ilGen.Emit(errorAt, OpCodes.Call, getUsedMemMethInfo);
  572. result.Pop(scg, errorAt, new TokenTypeInt(null));
  573. }
  574. }
  575. /**
  576. * @brief Generate code for the usual ll...() functions.
  577. */
  578. public class TokenDeclInline_BEApi: TokenDeclInline
  579. {
  580. // private static readonly MethodInfo fixLLParcelMediaQuery = ScriptCodeGen.GetStaticMethod
  581. // (typeof (XMRInstAbstract), "FixLLParcelMediaQuery", new Type[] { typeof (LSL_List) });
  582. // private static readonly MethodInfo fixLLParcelMediaCommandList = ScriptCodeGen.GetStaticMethod
  583. // (typeof (XMRInstAbstract), "FixLLParcelMediaCommandList", new Type[] { typeof (LSL_List) });
  584. public bool doCheckRun;
  585. private FieldInfo apiContextField;
  586. private MethodInfo methInfo;
  587. /**
  588. * @brief Constructor
  589. * @param ifd = dictionary to add the function to
  590. * @param dcr = append a call to CheckRun()
  591. * @param methInfo = ll...() method to be called
  592. */
  593. public TokenDeclInline_BEApi(VarDict ifd, bool dcr, MethodInfo methInfo, FieldInfo acf)
  594. : base(ifd, dcr, methInfo)
  595. {
  596. this.methInfo = methInfo;
  597. doCheckRun = dcr;
  598. apiContextField = acf;
  599. }
  600. public override MethodInfo GetMethodInfo()
  601. {
  602. return methInfo;
  603. }
  604. /**
  605. * @brief Generate call to backend API function (eg llSay()) maybe followed by a call to CheckRun().
  606. * @param scg = script being compiled
  607. * @param result = where to place result (might be void)
  608. * @param args = script-visible arguments to pass to API function
  609. */
  610. public override void CodeGen(ScriptCodeGen scg, Token errorAt, CompValuTemp result, CompValu[] args)
  611. {
  612. if(isTaggedCallsCheckRun)
  613. { // see if 'xmr' method that calls CheckRun() internally
  614. new ScriptCodeGen.CallLabel(scg, errorAt); // if so, put a call label immediately before it
  615. // .. so restoring the frame will jump immediately to the
  616. // .. call without re-executing any code before this
  617. }
  618. if(!methInfo.IsStatic)
  619. {
  620. scg.PushXMRInst(); // XMRInstanceSuperType pointer
  621. if(apiContextField != null) // 'this' pointer for API function
  622. scg.ilGen.Emit(errorAt, OpCodes.Ldfld, apiContextField);
  623. }
  624. for(int i = 0; i < args.Length; i++) // push arguments, boxing/unboxing as needed
  625. args[i].PushVal(scg, errorAt, argDecl.types[i]);
  626. // this should not be needed
  627. // if (methInfo.Name == "llParcelMediaQuery") {
  628. // scg.ilGen.Emit (errorAt, OpCodes.Call, fixLLParcelMediaQuery);
  629. // }
  630. // this should not be needed
  631. // if (methInfo.Name == "llParcelMediaCommandList") {
  632. // scg.ilGen.Emit (errorAt, OpCodes.Call, fixLLParcelMediaCommandList);
  633. // }
  634. if(methInfo.IsVirtual) // call API function
  635. scg.ilGen.Emit(errorAt, OpCodes.Callvirt, methInfo);
  636. else
  637. scg.ilGen.Emit(errorAt, OpCodes.Call, methInfo);
  638. result.Pop(scg, errorAt, retType); // pop result, boxing/unboxing as needed
  639. if(isTaggedCallsCheckRun)
  640. scg.openCallLabel = null;
  641. if(doCheckRun)
  642. scg.EmitCallCheckRun(errorAt, false); // maybe call CheckRun()
  643. }
  644. }
  645. }