MMRScriptInlines.cs 29 KB

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