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