aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ScriptEngine/XMREngine/XMRObjectTokens.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/ScriptEngine/XMREngine/XMRObjectTokens.cs')
-rw-r--r--OpenSim/Region/ScriptEngine/XMREngine/XMRObjectTokens.cs5476
1 files changed, 0 insertions, 5476 deletions
diff --git a/OpenSim/Region/ScriptEngine/XMREngine/XMRObjectTokens.cs b/OpenSim/Region/ScriptEngine/XMREngine/XMRObjectTokens.cs
deleted file mode 100644
index f214f28..0000000
--- a/OpenSim/Region/ScriptEngine/XMREngine/XMRObjectTokens.cs
+++ /dev/null
@@ -1,5476 +0,0 @@
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 OpenSim.Region.ScriptEngine.Shared.ScriptBase;
29using System;
30using System.Collections.Generic;
31using System.IO;
32using System.Reflection;
33using System.Reflection.Emit;
34using System.Text;
35
36using LSL_Float = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLFloat;
37using LSL_Integer = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger;
38using LSL_Key = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
39using LSL_List = OpenSim.Region.ScriptEngine.Shared.LSL_Types.list;
40using LSL_Rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion;
41using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
42using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
43
44/**
45 * Contains classes that disassemble or decompile an xmrobj file.
46 * See xmrengcomp.cx utility program.
47 */
48
49namespace OpenSim.Region.ScriptEngine.XMREngine {
50
51 /*
52 * Encapsulate object code for a method.
53 */
54 public abstract class ObjectTokens {
55 public ScriptObjCode scriptObjCode;
56
57 public ObjectTokens (ScriptObjCode scriptObjCode)
58 {
59 this.scriptObjCode = scriptObjCode;
60 }
61
62 public abstract void Close ();
63 public abstract void BegMethod (DynamicMethod method);
64 public abstract void EndMethod ();
65 public abstract void DefineLabel (int number, string name);
66 public abstract void DefineLocal (int number, string name, string type, Type syType);
67 public abstract void DefineMethod (string methName, Type retType, Type[] argTypes, string[] argNames);
68 public abstract void MarkLabel (int offset, int number);
69 public abstract void BegExcBlk (int offset);
70 public abstract void BegCatBlk (int offset, Type excType);
71 public abstract void BegFinBlk (int offset);
72 public abstract void EndExcBlk (int offset);
73 public abstract void EmitNull (int offset, OpCode opCode);
74 public abstract void EmitField (int offset, OpCode opCode, FieldInfo field);
75 public abstract void EmitLocal (int offset, OpCode opCode, int number);
76 public abstract void EmitType (int offset, OpCode opCode, Type type);
77 public abstract void EmitLabel (int offset, OpCode opCode, int number);
78 public abstract void EmitLabels (int offset, OpCode opCode, int[] numbers);
79 public abstract void EmitMethod (int offset, OpCode opCode, MethodInfo method);
80 public abstract void EmitCtor (int offset, OpCode opCode, ConstructorInfo ctor);
81 public abstract void EmitDouble (int offset, OpCode opCode, double value);
82 public abstract void EmitFloat (int offset, OpCode opCode, float value);
83 public abstract void EmitInteger (int offset, OpCode opCode, int value);
84 public abstract void EmitString (int offset, OpCode opCode, string value);
85 }
86
87 /******************\
88 * DISASSEMBLER *
89 \******************/
90
91 public class OTDisassemble : ObjectTokens {
92 private static readonly int OPCSTRWIDTH = 12;
93
94 private Dictionary<int,string> labelNames;
95 private Dictionary<int,string> localNames;
96 private StringBuilder lbuf = new StringBuilder ();
97 private TextWriter twout;
98
99 public OTDisassemble (ScriptObjCode scriptObjCode, TextWriter twout) : base (scriptObjCode)
100 {
101 this.twout = twout;
102 }
103
104 public override void Close ()
105 {
106 twout.WriteLine ("TheEnd.");
107 }
108
109 /**
110 * About to generate object code for this method.
111 */
112 public override void BegMethod (DynamicMethod method)
113 {
114 labelNames = new Dictionary<int,string> ();
115 localNames = new Dictionary<int,string> ();
116
117 twout.WriteLine ("");
118
119 lbuf.Append (method.ReturnType.Name);
120 lbuf.Append (' ');
121 lbuf.Append (method.Name);
122
123 ParameterInfo[] parms = method.GetParameters ();
124 int nArgs = parms.Length;
125 lbuf.Append (" (");
126 for (int i = 0; i < nArgs; i ++) {
127 if (i > 0) lbuf.Append (", ");
128 lbuf.Append (parms[i].ParameterType.Name);
129 }
130 lbuf.Append (')');
131 FlushLine ();
132
133 lbuf.Append ('{');
134 FlushLine ();
135 }
136
137 /**
138 * Dump out reconstructed source for this method.
139 */
140 public override void EndMethod ()
141 {
142 lbuf.Append ('}');
143 FlushLine ();
144 }
145
146 /**
147 * Add instructions to stream.
148 */
149 public override void DefineLabel (int number, string name)
150 {
151 labelNames[number] = name + "$" + number;
152 }
153
154 public override void DefineLocal (int number, string name, string type, Type syType)
155 {
156 localNames[number] = name + "$" + number;
157
158 lbuf.Append (" ");
159 lbuf.Append (type.PadRight (OPCSTRWIDTH - 1));
160 lbuf.Append (' ');
161 lbuf.Append (localNames[number]);
162 FlushLine ();
163 }
164
165 public override void DefineMethod (string methName, Type retType, Type[] argTypes, string[] argNames)
166 { }
167
168 public override void MarkLabel (int offset, int number)
169 {
170 LinePrefix (offset);
171 lbuf.Append (labelNames[number]);
172 lbuf.Append (":");
173 FlushLine ();
174 }
175
176 public override void BegExcBlk (int offset)
177 {
178 LinePrefix (offset);
179 lbuf.Append (" BeginExceptionBlock");
180 FlushLine ();
181 }
182
183 public override void BegCatBlk (int offset, Type excType)
184 {
185 LinePrefix (offset);
186 lbuf.Append (" BeginCatchBlock ");
187 lbuf.Append (excType.Name);
188 FlushLine ();
189 }
190
191 public override void BegFinBlk (int offset)
192 {
193 LinePrefix (offset);
194 lbuf.Append (" BeginFinallyBlock");
195 FlushLine ();
196 }
197
198 public override void EndExcBlk (int offset)
199 {
200 LinePrefix (offset);
201 lbuf.Append (" EndExceptionBlock");
202 FlushLine ();
203 }
204
205 public override void EmitNull (int offset, OpCode opCode)
206 {
207 LinePrefix (offset, opCode);
208 FlushLine ();
209 }
210
211 public override void EmitField (int offset, OpCode opCode, FieldInfo field)
212 {
213 LinePrefix (offset, opCode);
214 lbuf.Append (field.DeclaringType.Name);
215 lbuf.Append (':');
216 lbuf.Append (field.Name);
217 lbuf.Append (" -> ");
218 lbuf.Append (field.FieldType.Name);
219 lbuf.Append (" (field)");
220 FlushLine ();
221 }
222
223 public override void EmitLocal (int offset, OpCode opCode, int number)
224 {
225 LinePrefix (offset, opCode);
226 lbuf.Append (localNames[number]);
227 lbuf.Append (" (local)");
228 FlushLine ();
229 }
230
231 public override void EmitType (int offset, OpCode opCode, Type type)
232 {
233 LinePrefix (offset, opCode);
234 lbuf.Append (type.Name);
235 lbuf.Append (" (type)");
236 FlushLine ();
237 }
238
239 public override void EmitLabel (int offset, OpCode opCode, int number)
240 {
241 LinePrefix (offset, opCode);
242 lbuf.Append (labelNames[number]);
243 lbuf.Append (" (label)");
244 FlushLine ();
245 }
246
247 public override void EmitLabels (int offset, OpCode opCode, int[] numbers)
248 {
249 LinePrefix (offset, opCode);
250
251 int lineLen = lbuf.Length;
252 int nLabels = numbers.Length;
253 for (int i = 0; i < nLabels; i ++) {
254 if (i > 0) {
255 lbuf.AppendLine ();
256 lbuf.Append (",".PadLeft (lineLen));
257 }
258 lbuf.Append (labelNames[numbers[i]]);
259 }
260
261 FlushLine ();
262 }
263
264 public override void EmitMethod (int offset, OpCode opCode, MethodInfo method)
265 {
266 LinePrefix (offset, opCode);
267
268 ParameterInfo[] parms = method.GetParameters ();
269 int nArgs = parms.Length;
270 if (method.DeclaringType != null) {
271 lbuf.Append (method.DeclaringType.Name);
272 lbuf.Append (':');
273 }
274 lbuf.Append (method.Name);
275 lbuf.Append ('(');
276 for (int i = 0; i < nArgs; i ++) {
277 if (i > 0) lbuf.Append (",");
278 lbuf.Append (parms[i].ParameterType.Name);
279 }
280 lbuf.Append (") -> ");
281 lbuf.Append (method.ReturnType.Name);
282
283 FlushLine ();
284 }
285
286 public override void EmitCtor (int offset, OpCode opCode, ConstructorInfo ctor)
287 {
288 LinePrefix (offset, opCode);
289
290 ParameterInfo[] parms = ctor.GetParameters ();
291 int nArgs = parms.Length;
292 lbuf.Append (ctor.DeclaringType.Name);
293 lbuf.Append (":(");
294 for (int i = 0; i < nArgs; i ++) {
295 if (i > 0) lbuf.Append (",");
296 lbuf.Append (parms[i].ParameterType.Name);
297 }
298 lbuf.Append (")");
299
300 FlushLine ();
301 }
302
303 public override void EmitDouble (int offset, OpCode opCode, double value)
304 {
305 LinePrefix (offset, opCode);
306 lbuf.Append (value.ToString ());
307 lbuf.Append (" (double)");
308 FlushLine ();
309 }
310
311 public override void EmitFloat (int offset, OpCode opCode, float value)
312 {
313 LinePrefix (offset, opCode);
314 lbuf.Append (value.ToString ());
315 lbuf.Append (" (float)");
316 FlushLine ();
317 }
318
319 public override void EmitInteger (int offset, OpCode opCode, int value)
320 {
321 LinePrefix (offset, opCode);
322 lbuf.Append (value.ToString ());
323 lbuf.Append (" (int)");
324 FlushLine ();
325 }
326
327 public override void EmitString (int offset, OpCode opCode, string value)
328 {
329 LinePrefix (offset, opCode);
330 lbuf.Append ("\"");
331 lbuf.Append (value);
332 lbuf.Append ("\" (string)");
333 FlushLine ();
334 }
335
336 /**
337 * Put offset and opcode at beginning of line.
338 */
339 private void LinePrefix (int offset, OpCode opCode)
340 {
341 LinePrefix (offset);
342 lbuf.Append (" ");
343 lbuf.Append (opCode.ToString ().PadRight (OPCSTRWIDTH - 1));
344 lbuf.Append (' ');
345 }
346
347 private void LinePrefix (int offset)
348 {
349 lbuf.Append (" ");
350 lbuf.Append (offset.ToString ("X4"));
351 lbuf.Append (" ");
352 }
353
354 /**
355 * Flush line buffer to output file.
356 */
357 private void FlushLine ()
358 {
359 if (lbuf.Length > 0) {
360 twout.WriteLine (lbuf.ToString ());
361 lbuf.Remove (0, lbuf.Length);
362 }
363 }
364 }
365
366 /****************\
367 * DECOMPILER *
368 \****************/
369
370 /**
371 * Note: The decompiler does not handle any xmroption extensions
372 * such as &&&, |||, ? operators and switch statements, as
373 * they do branches with a non-empty stack, which is way
374 * beyond this code's ability to analyze.
375 */
376
377 public class OTDecompile : ObjectTokens {
378 public const string _mainCallNo = "__mainCallNo$";
379 public const string _callLabel = "__call_";
380 public const string _callMode = "callMode";
381 public const string _checkRunQuick = "CheckRunQuick";
382 public const string _checkRunStack = "CheckRunStack";
383 public const string _cmRestore = "__cmRestore";
384 public const string _doBreak = "dobreak_";
385 public const string _doCont = "docont_";
386 public const string _doGblInit = "doGblInit";
387 public const string _doLoop = "doloop_";
388 public const string _ehArgs = "ehArgs";
389 public const string _forBreak = "forbreak_";
390 public const string _forCont = "forcont_";
391 public const string _forLoop = "forloop_";
392 public const string _globalvarinit = "$globalvarinit()";
393 public const string _heapTrackerPop = "Pop";
394 public const string _heapTrackerPush = "Push";
395 public const string _ifDone = "ifdone_";
396 public const string _ifElse = "ifelse_";
397 public const string _llAbstemp = "llAbstemp";
398 public const string _retlbl = "__retlbl";
399 public const string _retval = "__retval$";
400 public const string _whileBreak = "whilebreak_";
401 public const string _whileCont = "whilecont_";
402 public const string _whileLoop = "whileloop_";
403 public const string _xmrinst = "__xmrinst";
404 public const string _xmrinstlocal = "__xmrinst$";
405
406 private const string INDENT = " ";
407 private const string LABELINDENT = " ";
408
409 private static Dictionary<string,string> typeTranslator = InitTypeTranslator ();
410 private static Dictionary<string,string> InitTypeTranslator ()
411 {
412 Dictionary<string,string> d = new Dictionary<string,string> ();
413 d["Boolean"] = "integer";
414 d["bool"] = "integer";
415 d["Double"] = "float";
416 d["double"] = "float";
417 d["Int32"] = "integer";
418 d["int"] = "integer";
419 d["htlist"] = "list";
420 d["htobject"] = "object";
421 d["htstring"] = "string";
422 d["lslfloat"] = "float";
423 d["lslint"] = "integer";
424 d["lsllist"] = "list";
425 d["lslrot"] = "rotation";
426 d["lslstr"] = "string";
427 d["lslvec"] = "vector";
428 d["Quaternion"] = "rotation";
429 d["String"] = "string";
430 d["Vector3"] = "vector";
431 return d;
432 }
433
434 private Dictionary<int,OTLocal> eharglist;
435 private Dictionary<int,OTLabel> labels;
436 private Dictionary<int,OTLocal> locals;
437 private Dictionary<string,string[]> methargnames;
438 private LinkedList<OTCilInstr> cilinstrs;
439 private OTStmtBlock topBlock;
440 private Stack<OTOpnd> opstack;
441 private Stack<OTStmtBegExcBlk> trystack;
442 private Stack<OTStmtBlock> blockstack;
443
444 private int dupNo;
445 private DynamicMethod method;
446 private string laststate;
447 private TextWriter twout;
448
449 public OTDecompile (ScriptObjCode scriptObjCode, TextWriter twout) : base (scriptObjCode)
450 {
451 this.twout = twout;
452 twout.Write ("xmroption dollarsigns;");
453 methargnames = new Dictionary<string,string[]> ();
454 }
455
456 public override void Close ()
457 {
458 if (laststate != null) {
459 twout.Write ("\n}");
460 laststate = null;
461 }
462 twout.Write ('\n');
463 }
464
465 /**
466 * About to generate object code for this method.
467 */
468 public override void BegMethod (DynamicMethod method)
469 {
470 this.method = method;
471
472 eharglist = new Dictionary<int,OTLocal> ();
473 labels = new Dictionary<int,OTLabel> ();
474 locals = new Dictionary<int,OTLocal> ();
475 cilinstrs = new LinkedList<OTCilInstr> ();
476 opstack = new Stack<OTOpnd> ();
477 trystack = new Stack<OTStmtBegExcBlk> ();
478 blockstack = new Stack<OTStmtBlock> ();
479
480 dupNo = 0;
481 }
482
483 /**
484 * Dump out reconstructed source for this method.
485 */
486 public override void EndMethod ()
487 {
488 /*
489 * Convert CIL code to primitive statements.
490 * There are a bunch of labels and internal code such as call stack save restore.
491 */
492 topBlock = new OTStmtBlock ();
493 blockstack.Push (topBlock);
494 for (LinkedListNode<OTCilInstr> link = cilinstrs.First; link != null; link = link.Next) {
495 link.Value.BuildStatements (this, link);
496 }
497
498 /*
499 * Strip out stuff we don't want, such as references to callMode.
500 * This strips out stack frame capture and restore code.
501 */
502 topBlock.StripStuff (null);
503
504 // including a possible final return statement
505 // - delete if void return value
506 // - delete if returning __retval cuz we converted all __retval assignments to return statements
507 if ((topBlock.blkstmts.Last != null) && (topBlock.blkstmts.Last.Value is OTStmtRet)) {
508 OTStmtRet finalret = (OTStmtRet) topBlock.blkstmts.Last.Value;
509 if ((finalret.value == null) ||
510 ((finalret.value is OTOpndLocal) &&
511 ((OTOpndLocal) finalret.value).local.name.StartsWith (_retval))) {
512 topBlock.blkstmts.RemoveLast ();
513 }
514 }
515
516 /**
517 * At this point, all behind-the-scenes references are removed except
518 * that the do/for/if/while blocks are represented by OTStmtCont-style
519 * if/jumps. So try to convert them to the higher-level structures.
520 */
521 topBlock.DetectDoForIfWhile (null);
522
523 /*
524 * Final strip to get rid of unneeded @forbreak_<suffix>; labels and the like.
525 */
526 topBlock.StripStuff (null);
527
528 /*
529 * Build reference counts so we don't output unneeded declarations,
530 * especially temps and internal variables.
531 */
532 foreach (OTLocal local in locals.Values) {
533 local.nlclreads = 0;
534 local.nlclwrites = 0;
535 }
536 topBlock.CountRefs ();
537 for (IEnumerator<int> localenum = locals.Keys.GetEnumerator (); localenum.MoveNext ();) {
538 OTLocal local = locals[localenum.Current];
539 if (((local.nlclreads | local.nlclwrites) == 0) || local.name.StartsWith (_xmrinstlocal)) {
540 locals.Remove (localenum.Current);
541 localenum = locals.Keys.GetEnumerator ();
542 }
543 }
544
545 /*
546 * Strip the $n off of local vars that are not ambiguous.
547 * Make sure they don't mask globals and arguments as well.
548 */
549 Dictionary<string,int> namecounts = new Dictionary<string,int> ();
550 foreach (Dictionary<int,string> varnames in scriptObjCode.globalVarNames.Values) {
551 foreach (string varname in varnames.Values) {
552 int count;
553 if (!namecounts.TryGetValue (varname, out count)) count = 0;
554 namecounts[varname] = count + 1;
555 }
556 }
557 if (methargnames.ContainsKey (method.Name)) {
558 foreach (string argname in methargnames[method.Name]) {
559 int count;
560 if (!namecounts.TryGetValue (argname, out count)) count = 0;
561 namecounts[argname] = count + 1;
562 }
563 }
564 foreach (OTLocal local in locals.Values) {
565 int i = local.name.LastIndexOf ('$');
566 string name = local.name.Substring (0, i);
567 int count;
568 if (!namecounts.TryGetValue (name, out count)) count = 0;
569 namecounts[name] = count + 1;
570 }
571 foreach (OTLocal local in locals.Values) {
572 int i = local.name.LastIndexOf ('$');
573 string name = local.name.Substring (0, i);
574 int count = namecounts[name];
575 if (count == 1) local.name = name;
576 }
577
578 /*
579 * Print out result.
580 */
581 if (method.Name == _globalvarinit) {
582 GlobalsDump ();
583 } else {
584 MethodDump ();
585 }
586 }
587
588 /**
589 * Add instructions to stream.
590 */
591 public override void DefineLabel (int number, string name)
592 {
593 labels.Add (number, new OTLabel (number, name));
594 }
595 public override void DefineLocal (int number, string name, string type, Type syType)
596 {
597 locals.Add (number, new OTLocal (number, name, type));
598 }
599 public override void DefineMethod (string methName, Type retType, Type[] argTypes, string[] argNames)
600 {
601 methargnames[methName] = argNames;
602 }
603 public override void MarkLabel (int offset, int number)
604 {
605 OTCilInstr label = labels[number];
606 label.offset = offset;
607 cilinstrs.AddLast (label);
608 }
609 public override void BegExcBlk (int offset)
610 {
611 cilinstrs.AddLast (new OTCilBegExcBlk (offset));
612 }
613 public override void BegCatBlk (int offset, Type excType)
614 {
615 cilinstrs.AddLast (new OTCilBegCatBlk (offset, excType));
616 }
617 public override void BegFinBlk (int offset)
618 {
619 cilinstrs.AddLast (new OTCilBegFinBlk (offset));
620 }
621 public override void EndExcBlk (int offset)
622 {
623 cilinstrs.AddLast (new OTCilEndExcBlk (offset));
624 }
625 public override void EmitNull (int offset, OpCode opCode)
626 {
627 cilinstrs.AddLast (new OTCilNull (offset, opCode));
628 }
629 public override void EmitField (int offset, OpCode opCode, FieldInfo field)
630 {
631 cilinstrs.AddLast (new OTCilField (offset, opCode, field));
632 }
633 public override void EmitLocal (int offset, OpCode opCode, int number)
634 {
635 cilinstrs.AddLast (new OTCilLocal (offset, opCode, locals[number]));
636 }
637 public override void EmitType (int offset, OpCode opCode, Type type)
638 {
639 cilinstrs.AddLast (new OTCilType (offset, opCode, type));
640 }
641 public override void EmitLabel (int offset, OpCode opCode, int number)
642 {
643 cilinstrs.AddLast (new OTCilLabel (offset, opCode, labels[number]));
644 }
645 public override void EmitLabels (int offset, OpCode opCode, int[] numbers)
646 {
647 OTLabel[] labelarray = new OTLabel[numbers.Length];
648 for (int i = 0; i < numbers.Length; i ++) {
649 labelarray[i] = labels[numbers[i]];
650 }
651 cilinstrs.AddLast (new OTCilLabels (offset, opCode, labelarray));
652 }
653 public override void EmitMethod (int offset, OpCode opCode, MethodInfo method)
654 {
655 cilinstrs.AddLast (new OTCilMethod (offset, opCode, method));
656 }
657 public override void EmitCtor (int offset, OpCode opCode, ConstructorInfo ctor)
658 {
659 cilinstrs.AddLast (new OTCilCtor (offset, opCode, ctor));
660 }
661 public override void EmitDouble (int offset, OpCode opCode, double value)
662 {
663 cilinstrs.AddLast (new OTCilDouble (offset, opCode, value));
664 }
665 public override void EmitFloat (int offset, OpCode opCode, float value)
666 {
667 cilinstrs.AddLast (new OTCilFloat (offset, opCode, value));
668 }
669 public override void EmitInteger (int offset, OpCode opCode, int value)
670 {
671 cilinstrs.AddLast (new OTCilInteger (offset, opCode, value));
672 }
673 public override void EmitString (int offset, OpCode opCode, string value)
674 {
675 cilinstrs.AddLast (new OTCilString (offset, opCode, value));
676 }
677
678 /**
679 * Add the given statement to the end of the currently open block.
680 */
681 public void AddLastStmt (OTStmt stmt)
682 {
683 blockstack.Peek ().blkstmts.AddLast (stmt);
684 }
685
686 /**
687 * Generate output for $globalvarinit() function.
688 * Also outputs declarations for global variables.
689 */
690 private void GlobalsDump ()
691 {
692 /*
693 * Scan $globalvarinit(). It should only have global var assignments in it.
694 * Also gather up list of variables it initializes.
695 */
696 bool badinit = false;
697 Dictionary<string,string> inittypes = new Dictionary<string,string> ();
698 foreach (OTStmt stmt in topBlock.blkstmts) {
699 if (!(stmt is OTStmtStore)) {
700 badinit = true;
701 break;
702 }
703 OTStmtStore store = (OTStmtStore) stmt;
704 if (!(store.varwr is OTOpndGlobal)) {
705 badinit = true;
706 break;
707 }
708 OTOpndGlobal globalop = (OTOpndGlobal) store.varwr;
709 inittypes[globalop.PrintableString] = "";
710 }
711
712 /*
713 * Scan through list of all global variables in the script.
714 * Output declarations for those what don't have any init statement for them.
715 * Save the type for those that do have init statements.
716 */
717 bool first = true;
718 foreach (string iartypename in scriptObjCode.globalVarNames.Keys) {
719 Dictionary<int,string> varnames = scriptObjCode.globalVarNames[iartypename];
720 string typename = iartypename.ToLowerInvariant ();
721 if (typename.StartsWith ("iar")) typename = typename.Substring (3);
722 if (typename.EndsWith ("s")) typename = typename.Substring (0, typename.Length - 1);
723 foreach (string varname in varnames.Values) {
724 if (!badinit && inittypes.ContainsKey (varname)) {
725 inittypes[varname] = typename;
726 } else {
727 if (first) twout.Write ('\n');
728 twout.Write ('\n' + typename + ' ' + varname + ';');
729 first = false;
730 }
731 }
732 }
733
734 /*
735 * If $globalvarinit() has anything bad in it, output it as a function.
736 * Otherwise, output it as a series of global declarations with init values.
737 */
738 if (badinit) {
739 MethodDump ();
740 } else {
741 foreach (OTStmt stmt in topBlock.blkstmts) {
742 OTStmtStore store = (OTStmtStore) stmt;
743 OTOpndGlobal globalop = (OTOpndGlobal) store.varwr;
744 string name = globalop.PrintableString;
745 if (first) twout.Write ('\n');
746 twout.Write ('\n' + inittypes[name] + ' ');
747 store.PrintStmt (twout, "");
748 first = false;
749 }
750 }
751 }
752
753 /**
754 * Generate output for other functions.
755 */
756 private void MethodDump ()
757 {
758 string indent;
759
760 /*
761 * Event handlers don't have an argument list as such in the original
762 * code. Instead they have a series of assignments from ehargs[] to
763 * local variables. So make those local variables look like they are
764 * an argument list.
765 */
766 int i = method.Name.IndexOf (' ');
767 if (i >= 0) {
768
769 /*
770 * Maybe we have to output the state name.
771 */
772 string statename = method.Name.Substring (0, i);
773 string eventname = method.Name.Substring (++ i);
774
775 if (laststate != statename) {
776 if (laststate != null) twout.Write ("\n}");
777 if (statename == "default") {
778 twout.Write ("\n\ndefault {");
779 } else {
780 twout.Write ("\n\nstate " + statename + " {");
781 }
782 laststate = statename;
783 } else {
784 twout.Write ('\n');
785 }
786
787 /*
788 * Output event name and argument list.
789 * Remove from locals list so they don't print below.
790 */
791 twout.Write ('\n' + INDENT + eventname + " (");
792 MethodInfo meth = typeof (IEventHandlers).GetMethod (eventname);
793 i = 0;
794 foreach (ParameterInfo pi in meth.GetParameters ()) {
795 // skip the first param cuz it's the XMRInstance arg
796 if (i > 0) twout.Write (", ");
797 OTLocal local;
798 if (eharglist.TryGetValue (i, out local) && locals.ContainsKey (local.number)) {
799 twout.Write (local.DumpString ());
800 locals.Remove (local.number);
801 } else {
802 // maybe the assignment was removed
803 // eg, because the local was write-only (not referenced)
804 // so substitute in placeholder that won't be referenced
805 twout.Write (AbbrType (pi.ParameterType) + " arg$" + (i + 1));
806 }
807 i ++;
808 }
809 twout.Write (')');
810
811 /*
812 * Indent method body by 4 spaces.
813 */
814 indent = INDENT;
815 } else {
816
817 /*
818 * Maybe need to close out previous state.
819 */
820 if (laststate != null) {
821 twout.Write ("\n}");
822 laststate = null;
823 }
824
825 /*
826 * Output blank line and return type (if any).
827 */
828 twout.Write ("\n\n");
829 if (method.ReturnType != typeof (void)) {
830 twout.Write (AbbrType (method.ReturnType) + ' ');
831 }
832
833 /*
834 * Output method name and argument list.
835 */
836 int j = method.Name.IndexOf ('(');
837 if (j < 0) {
838 twout.Write (method.Name);
839 } else {
840 twout.Write (method.Name.Substring (0, j) + " (");
841 bool first = true;
842 j = 0;
843 foreach (ParameterInfo pi in method.GetParameters ()) {
844 if (j > 0) { // skip the XMRInstance arg$0 parameter
845 if (!first) twout.Write (", ");
846 twout.Write (AbbrType (pi.ParameterType) + ' ' + MethArgName (j));
847 first = false;
848 }
849 j ++;
850 }
851 twout.Write (')');
852 }
853
854 /*
855 * Don't indent method body at all.
856 */
857 indent = "";
858 }
859
860 /*
861 * Output local variable declarations.
862 */
863 twout.Write ('\n' + indent + '{');
864 bool didOne = false;
865 foreach (OTLocal local in locals.Values) {
866 twout.Write ('\n' + indent + INDENT + local.DumpString () + "; // r:" + local.nlclreads + " w:" + local.nlclwrites);
867 didOne = true;
868 }
869 if (didOne) twout.Write ('\n');
870
871 /*
872 * Output statements.
873 */
874 if (topBlock.blkstmts.Count == 0) {
875 twout.Write (" }");
876 } else {
877 topBlock.PrintBodyAndEnd (twout, indent);
878 }
879 }
880
881 /**
882 * Get abbreviated type string.
883 */
884 public static string AbbrType (Type type)
885 {
886 if (type == null) return "null";
887 return AbbrType (type.Name);
888 }
889 public static string AbbrType (string type)
890 {
891 if (type.StartsWith ("OpenSim.Region.ScriptEngine.XMREngine.")) {
892 type = type.Substring (38);
893 int i = type.IndexOf (',');
894 if (i > 0) type = type.Substring (0, i);
895 }
896 if (typeTranslator.ContainsKey (type)) {
897 type = typeTranslator[type];
898 }
899 return type;
900 }
901
902 /**
903 * Get current method's argument name.
904 */
905 public string MethArgName (int index)
906 {
907 string[] argnames;
908 if (methargnames.TryGetValue (method.Name, out argnames) && (index < argnames.Length)) {
909 return argnames[index];
910 }
911 return "arg$" + index;
912 }
913
914 /**
915 * Strip svperflvovs (float) cast from rotation/vector values.
916 */
917 public static OTOpnd StripFloatCast (OTOpnd op)
918 {
919 if (op is OTOpndCast) {
920 OTOpndCast opcast = (OTOpndCast) op;
921 if ((opcast.type == typeof (double)) && (opcast.value is OTOpndInt)) {
922 return opcast.value;
923 }
924 }
925 return op;
926 }
927
928 /**
929 * Strip svperflvovs Brtrues so we don't end up with stuff like 'if (!! someint) ...'.
930 */
931 public static OTOpnd StripBrtrue (OTOpnd op)
932 {
933 if (op is OTOpndUnOp) {
934 OTOpndUnOp opunop = (OTOpndUnOp) op;
935 if (opunop.opCode == MyOp.Brtrue) return opunop.value;
936 }
937 return op;
938 }
939
940 /*
941 * Local variable declaration.
942 */
943 private class OTLocal {
944 public int number;
945 public string name;
946 public string type;
947
948 public int nlclreads;
949 public int nlclwrites;
950
951 public OTLocal (int number, string name, string type)
952 {
953 this.number = number;
954 this.name = name.StartsWith ("tmp$") ? name : name + "$" + number;
955 this.type = type;
956 }
957
958 public string DumpString ()
959 {
960 return AbbrType (type) + ' ' + name;
961 }
962 }
963
964 /***********************************************\
965 * Tokens that are one-for-one with CIL code *
966 \***********************************************/
967
968 /*
969 * Part of instruction stream.
970 */
971 public abstract class OTCilInstr {
972 public int offset; // cil offset
973
974 public OTCilInstr (int offset)
975 {
976 this.offset = offset;
977 }
978
979 public abstract string DumpString ();
980 public abstract void BuildStatements (OTDecompile decompile, LinkedListNode<OTCilInstr> link);
981
982 protected void CheckEmptyStack (OTDecompile decompile, string opMnemonic)
983 {
984 if (decompile.opstack.Count > 0) {
985 Console.Error.WriteLine ("CheckEmptyStack: " + decompile.method.Name + " 0x" + offset.ToString ("X") + ": " +
986 opMnemonic + " stack depth " + decompile.opstack.Count);
987 }
988 }
989 }
990
991 /*
992 * Label mark point.
993 */
994 private class OTLabel : OTCilInstr {
995 public int number;
996 public string name;
997
998 public int lbljumps;
999
1000 public OTLabel (int number, string name) : base (-1)
1001 {
1002 this.number = number;
1003 this.name = name;
1004 }
1005
1006 public string PrintableName {
1007 get {
1008 if (name.StartsWith (_doBreak)) return _doBreak + "$" + number;
1009 if (name.StartsWith (_doCont)) return _doCont + "$" + number;
1010 if (name.StartsWith (_forBreak)) return _forBreak + "$" + number;
1011 if (name.StartsWith (_forCont)) return _forCont + "$" + number;
1012 if (name.StartsWith (_whileBreak)) return _whileBreak + "$" + number;
1013 if (name.StartsWith (_whileCont)) return _whileCont + "$" + number;
1014 return name;
1015 }
1016 }
1017
1018 public override string DumpString ()
1019 {
1020 return name + ":";
1021 }
1022
1023 public override void BuildStatements (OTDecompile decompile, LinkedListNode<OTCilInstr> link)
1024 {
1025 OTStmtLabel.AddLast (decompile, this);
1026 }
1027 }
1028
1029 /*
1030 * 'try {'
1031 */
1032 private class OTCilBegExcBlk : OTCilInstr {
1033 public LinkedList<OTCilBegCatBlk> catches = new LinkedList<OTCilBegCatBlk> ();
1034
1035 public OTCilBegExcBlk (int offset) : base (offset)
1036 { }
1037
1038 public override string DumpString ()
1039 {
1040 return "try {";
1041 }
1042
1043 public override void BuildStatements (OTDecompile decompile, LinkedListNode<OTCilInstr> link)
1044 {
1045 CheckEmptyStack (decompile, "try");
1046
1047 // link the try itself onto outer block
1048 OTStmtBegExcBlk trystmt = new OTStmtBegExcBlk ();
1049 decompile.AddLastStmt (trystmt);
1050
1051 // subsequent statements go to the try block
1052 trystmt.tryblock = new OTStmtBlock ();
1053 decompile.trystack.Push (trystmt);
1054 decompile.blockstack.Push (trystmt.tryblock);
1055 }
1056 }
1057
1058 /*
1059 * '} catch (...) {'
1060 */
1061 private class OTCilBegCatBlk : OTCilInstr {
1062 public Type excType;
1063
1064 public OTCilBegCatBlk (int offset, Type excType) : base (offset)
1065 {
1066 this.excType = excType;
1067 }
1068
1069 public override string DumpString ()
1070 {
1071 return "} catch (" + AbbrType (excType) + ") {";
1072 }
1073
1074 public override void BuildStatements (OTDecompile decompile, LinkedListNode<OTCilInstr> link)
1075 {
1076 CheckEmptyStack (decompile, "catch");
1077
1078 // link the catch itself onto the try statement
1079 OTStmtBegExcBlk trystmt = decompile.trystack.Peek ();
1080 OTStmtBegCatBlk catstmt = new OTStmtBegCatBlk (excType);
1081 trystmt.catches.AddLast (catstmt);
1082
1083 // start capturing statements into the catch block
1084 catstmt.tryblock = trystmt;
1085 catstmt.catchblock = new OTStmtBlock ();
1086 decompile.blockstack.Pop ();
1087 decompile.blockstack.Push (catstmt.catchblock);
1088
1089 // fill the stack slot with something for the exception argument
1090 OTOpndDup dup = new OTOpndDup (++ decompile.dupNo);
1091 decompile.opstack.Push (dup);
1092 }
1093 }
1094
1095 /*
1096 * '} finally {'
1097 */
1098 private class OTCilBegFinBlk : OTCilInstr {
1099 public OTCilBegFinBlk (int offset) : base (offset)
1100 { }
1101
1102 public override string DumpString ()
1103 {
1104 return "} finally {";
1105 }
1106
1107 public override void BuildStatements (OTDecompile decompile, LinkedListNode<OTCilInstr> link)
1108 {
1109 CheckEmptyStack (decompile, "finally");
1110
1111 // link the finally itself to the try statement
1112 OTStmtBegExcBlk trystmt = decompile.trystack.Peek ();
1113 OTStmtBegFinBlk finstmt = new OTStmtBegFinBlk ();
1114 trystmt.finblock = finstmt;
1115
1116 // start capturing statements into the finally block
1117 finstmt.tryblock = trystmt;
1118 finstmt.finblock = new OTStmtBlock ();
1119 decompile.blockstack.Pop ();
1120 decompile.blockstack.Push (finstmt.finblock);
1121 }
1122 }
1123
1124 /*
1125 * '}' end of try
1126 */
1127 private class OTCilEndExcBlk : OTCilInstr {
1128 public OTCilEndExcBlk (int offset) : base (offset)
1129 { }
1130
1131 public override string DumpString ()
1132 {
1133 return "} // end try";
1134 }
1135
1136 public override void BuildStatements (OTDecompile decompile, LinkedListNode<OTCilInstr> link)
1137 {
1138 CheckEmptyStack (decompile, "endtry");
1139
1140 // pop the try/catch/finally blocks from stacks
1141 decompile.blockstack.Pop ();
1142 decompile.trystack.Pop ();
1143
1144 // subsequent statements collect following the try
1145 }
1146 }
1147
1148 /*
1149 * Actual opcodes (instructions).
1150 */
1151 private class OTCilNull : OTCilInstr {
1152 public MyOp opCode;
1153
1154 public OTCilNull (int offset, OpCode opCode) : base (offset)
1155 {
1156 this.opCode = MyOp.GetByName (opCode.Name);
1157 }
1158
1159 public override string DumpString ()
1160 {
1161 return opCode.ToString ();
1162 }
1163
1164 public override void BuildStatements (OTDecompile decompile, LinkedListNode<OTCilInstr> link)
1165 {
1166 switch (opCode.ToString ()) {
1167 case "conv.i1":
1168 case "conv.i2":
1169 case "conv.i4":
1170 case "conv.i8": {
1171 OTOpnd value = decompile.opstack.Pop ();
1172 decompile.opstack.Push (new OTOpndCast (typeof (int), value));
1173 break;
1174 }
1175 case "conv.r4":
1176 case "conv.r8": {
1177 OTOpnd value = decompile.opstack.Pop ();
1178 decompile.opstack.Push (new OTOpndCast (typeof (double), value));
1179 break;
1180 }
1181 case "dup": {
1182 OTOpnd value = decompile.opstack.Pop ();
1183 if (!(value is OTOpndDup)) {
1184 OTOpndDup dup = new OTOpndDup (++ decompile.dupNo);
1185 OTStmtStore.AddLast (decompile, dup, value);
1186 value = dup;
1187 }
1188 decompile.opstack.Push (value);
1189 decompile.opstack.Push (value);
1190 break;
1191 }
1192 case "endfinally": break;
1193 case "ldarg.0": { decompile.opstack.Push (new OTOpndArg (0, false, decompile)); break; }
1194 case "ldarg.1": { decompile.opstack.Push (new OTOpndArg (1, false, decompile)); break; }
1195 case "ldarg.2": { decompile.opstack.Push (new OTOpndArg (2, false, decompile)); break; }
1196 case "ldarg.3": { decompile.opstack.Push (new OTOpndArg (3, false, decompile)); break; }
1197 case "ldc.i4.0": { decompile.opstack.Push (new OTOpndInt (0)); break; }
1198 case "ldc.i4.1": { decompile.opstack.Push (new OTOpndInt (1)); break; }
1199 case "ldc.i4.2": { decompile.opstack.Push (new OTOpndInt (2)); break; }
1200 case "ldc.i4.3": { decompile.opstack.Push (new OTOpndInt (3)); break; }
1201 case "ldc.i4.4": { decompile.opstack.Push (new OTOpndInt (4)); break; }
1202 case "ldc.i4.5": { decompile.opstack.Push (new OTOpndInt (5)); break; }
1203 case "ldc.i4.6": { decompile.opstack.Push (new OTOpndInt (6)); break; }
1204 case "ldc.i4.7": { decompile.opstack.Push (new OTOpndInt (7)); break; }
1205 case "ldc.i4.8": { decompile.opstack.Push (new OTOpndInt (8)); break; }
1206 case "ldc.i4.m1": { decompile.opstack.Push (new OTOpndInt (-1)); break; }
1207 case "ldelem.i4":
1208 case "ldelem.r4":
1209 case "ldelem.r8":
1210 case "ldelem.ref": {
1211 OTOpnd index = decompile.opstack.Pop ();
1212 OTOpnd array = decompile.opstack.Pop ();
1213 decompile.opstack.Push (OTOpndArrayElem.Make (array, index, false, decompile));
1214 break;
1215 }
1216 case "ldnull": {
1217 decompile.opstack.Push (new OTOpndNull ());
1218 break;
1219 }
1220 case "neg":
1221 case "not": {
1222 OTOpnd value = decompile.opstack.Pop ();
1223 decompile.opstack.Push (OTOpndUnOp.Make (opCode, value));
1224 break;
1225 }
1226 case "pop": {
1227 OTStmtVoid.AddLast (decompile, decompile.opstack.Pop ());
1228 break;
1229 }
1230 case "ret": {
1231 OTOpnd value = null;
1232 if (decompile.method.ReturnType != typeof (void)) {
1233 value = decompile.opstack.Pop ();
1234 }
1235 CheckEmptyStack (decompile);
1236 decompile.AddLastStmt (new OTStmtRet (value));
1237 break;
1238 }
1239 case "stelem.i4":
1240 case "stelem.r8":
1241 case "stelem.ref": {
1242 OTOpnd value = decompile.opstack.Pop ();
1243 OTOpnd index = decompile.opstack.Pop ();
1244 OTOpnd array = decompile.opstack.Pop ();
1245 OTStmtStore.AddLast (decompile, OTOpndArrayElem.Make (array, index, false, decompile), value);
1246 break;
1247 }
1248 case "throw": {
1249 OTOpnd value = decompile.opstack.Pop ();
1250 CheckEmptyStack (decompile);
1251 decompile.AddLastStmt (new OTStmtThrow (value, decompile));
1252 break;
1253 }
1254 case "add":
1255 case "and":
1256 case "ceq":
1257 case "cgt":
1258 case "cgt.un":
1259 case "clt":
1260 case "clt.un":
1261 case "div":
1262 case "div.un":
1263 case "mul":
1264 case "or":
1265 case "rem":
1266 case "rem.un":
1267 case "shl":
1268 case "shr":
1269 case "shr.un":
1270 case "sub":
1271 case "xor": {
1272 OTOpnd rite = decompile.opstack.Pop ();
1273 OTOpnd left = decompile.opstack.Pop ();
1274 decompile.opstack.Push (OTOpndBinOp.Make (left, opCode, rite));
1275 break;
1276 }
1277 default: throw new Exception ("unknown opcode " + opCode.ToString ());
1278 }
1279 }
1280
1281 protected void CheckEmptyStack (OTDecompile decompile)
1282 {
1283 CheckEmptyStack (decompile, opCode.ToString ());
1284 }
1285 }
1286
1287 private class OTCilField : OTCilNull {
1288 public FieldInfo field;
1289
1290 public OTCilField (int offset, OpCode opCode, FieldInfo field) : base (offset, opCode)
1291 {
1292 this.field = field;
1293 }
1294
1295 public override string DumpString ()
1296 {
1297 return opCode.ToString () + ' ' + field.Name;
1298 }
1299
1300 public override void BuildStatements (OTDecompile decompile, LinkedListNode<OTCilInstr> link)
1301 {
1302 switch (opCode.ToString ()) {
1303 case "ldfld": {
1304 OTOpnd obj = decompile.opstack.Pop ();
1305 decompile.opstack.Push (OTOpndField.Make (obj, field));
1306 break;
1307 }
1308 case "ldsfld": {
1309 decompile.opstack.Push (new OTOpndSField (field));
1310 break;
1311 }
1312 case "stfld": {
1313 OTOpnd val = decompile.opstack.Pop ();
1314 OTOpnd obj = decompile.opstack.Pop ();
1315 OTStmtStore.AddLast (decompile, OTOpndField.Make (obj, field), val);
1316 break;
1317 }
1318 case "stsfld": {
1319 OTOpnd val = decompile.opstack.Pop ();
1320 OTStmtStore.AddLast (decompile, new OTOpndSField (field), val);
1321 break;
1322 }
1323 default: throw new Exception ("unknown opcode " + opCode.ToString ());
1324 }
1325 }
1326 }
1327
1328 private class OTCilLocal : OTCilNull {
1329 public OTLocal local;
1330
1331 public OTCilLocal (int offset, OpCode opCode, OTLocal local) : base (offset, opCode)
1332 {
1333 this.local = local;
1334 }
1335
1336 public override string DumpString ()
1337 {
1338 return opCode.ToString () + ' ' + local.name;
1339 }
1340
1341 public override void BuildStatements (OTDecompile decompile, LinkedListNode<OTCilInstr> link)
1342 {
1343 switch (opCode.ToString ()) {
1344 case "ldloc": {
1345 decompile.opstack.Push (new OTOpndLocal (local));
1346 break;
1347 }
1348 case "ldloca": {
1349 decompile.opstack.Push (new OTOpndLocalRef (local));
1350 break;
1351 }
1352 case "stloc": {
1353 OTOpnd val = decompile.opstack.Pop ();
1354 OTStmtStore.AddLast (decompile, new OTOpndLocal (local), val);
1355 break;
1356 }
1357 default: throw new Exception ("unknown opcode " + opCode.ToString ());
1358 }
1359 }
1360 }
1361
1362 private class OTCilType : OTCilNull {
1363 public Type type;
1364
1365 public OTCilType (int offset, OpCode opCode, Type type) : base (offset, opCode)
1366 {
1367 this.type = type;
1368 }
1369
1370 public override string DumpString ()
1371 {
1372 return opCode.ToString () + ' ' + AbbrType (type);
1373 }
1374
1375 public override void BuildStatements (OTDecompile decompile, LinkedListNode<OTCilInstr> link)
1376 {
1377 switch (opCode.ToString ()) {
1378 case "box": {
1379 break;
1380 }
1381 case "castclass":
1382 case "unbox.any": {
1383 OTOpnd value = decompile.opstack.Pop ();
1384 decompile.opstack.Push (new OTOpndCast (type, value));
1385 break;
1386 }
1387 case "ldelem": {
1388 OTOpnd index = decompile.opstack.Pop ();
1389 OTOpnd array = decompile.opstack.Pop ();
1390 decompile.opstack.Push (OTOpndArrayElem.Make (array, index, false, decompile));
1391 break;
1392 }
1393 case "ldelema": {
1394 OTOpnd index = decompile.opstack.Pop ();
1395 OTOpnd array = decompile.opstack.Pop ();
1396 decompile.opstack.Push (OTOpndArrayElem.Make (array, index, true, decompile));
1397 break;
1398 }
1399 case "newarr": {
1400 OTOpnd index = decompile.opstack.Pop ();
1401 decompile.opstack.Push (new OTOpndNewarr (type, index));
1402 break;
1403 }
1404 case "stelem": {
1405 OTOpnd value = decompile.opstack.Pop ();
1406 OTOpnd index = decompile.opstack.Pop ();
1407 OTOpnd array = decompile.opstack.Pop ();
1408 OTStmtStore.AddLast (decompile, OTOpndArrayElem.Make (array, index, false, decompile), value);
1409 break;
1410 }
1411 default: throw new Exception ("unknown opcode " + opCode.ToString ());
1412 }
1413 }
1414 }
1415
1416 private class OTCilLabel : OTCilNull {
1417 public OTLabel label;
1418
1419 public OTCilLabel (int offset, OpCode opCode, OTLabel label) : base (offset, opCode)
1420 {
1421 this.label = label;
1422 }
1423
1424 public override string DumpString ()
1425 {
1426 return opCode.ToString () + ' ' + label.name;
1427 }
1428
1429 public override void BuildStatements (OTDecompile decompile, LinkedListNode<OTCilInstr> link)
1430 {
1431 switch (opCode.ToString ()) {
1432
1433 /*
1434 * We don't handle non-empty stack at branch points.
1435 *
1436 * So handle this case specially:
1437 *
1438 * dup
1439 * ldc.i4.0
1440 * bge.s llAbstemp << we are here
1441 * neg
1442 * llAbstemp:
1443 *
1444 * becomes:
1445 *
1446 * call llAbs
1447 */
1448 case "bge.s": {
1449 OTOpnd rite = decompile.opstack.Pop (); // alleged zero
1450 OTOpnd left = decompile.opstack.Pop (); // alleged dup
1451
1452 if ((label.name == _llAbstemp) && (decompile.opstack.Count > 0)) {
1453 LinkedListNode<OTCilInstr> linkneg = link.Next;
1454 if ((left is OTOpndDup) && (rite is OTOpndInt) &&
1455 (linkneg != null) && (linkneg.Value is OTCilNull) &&
1456 (((OTCilNull) linkneg.Value).opCode == MyOp.Neg)) {
1457 OTOpndInt riteint = (OTOpndInt) rite;
1458 LinkedListNode<OTCilInstr> linklbl = linkneg.Next;
1459 if ((riteint.value == 0) && (linklbl != null) && (linklbl.Value is OTLabel) &&
1460 (((OTLabel) linklbl.Value) == label)) {
1461 linkneg.List.Remove (linkneg);
1462 linklbl.List.Remove (linklbl);
1463 MethodInfo method = typeof (ScriptBaseClass).GetMethod ("llAbs");
1464 OTOpnd[] args = new OTOpnd[] { new OTOpndNull (), decompile.opstack.Pop () };
1465 OTOpndCall.AddLast (decompile, method, args);
1466 break;
1467 }
1468 }
1469 }
1470
1471 CheckEmptyStack (decompile);
1472 OTOpnd valu = OTOpndBinOp.Make (left, opCode, rite);
1473 OTStmt jump = OTStmtJump.Make (label);
1474 decompile.AddLastStmt (new OTStmtCond (valu, jump));
1475 break;
1476 }
1477
1478 case "beq":
1479 case "bge":
1480 case "bgt":
1481 case "ble":
1482 case "blt":
1483 case "bne.un":
1484 case "beq.s":
1485 case "bgt.s":
1486 case "ble.s":
1487 case "blt.s":
1488 case "bne.un.s": {
1489 OTOpnd rite = decompile.opstack.Pop ();
1490 OTOpnd left = decompile.opstack.Pop ();
1491 CheckEmptyStack (decompile);
1492 OTOpnd valu = OTOpndBinOp.Make (left, opCode, rite);
1493 OTStmt jump = OTStmtJump.Make (label);
1494 decompile.AddLastStmt (new OTStmtCond (valu, jump));
1495 break;
1496 }
1497 case "brfalse":
1498 case "brfalse.s":
1499 case "brtrue":
1500 case "brtrue.s": {
1501 OTOpnd value = decompile.opstack.Pop ();
1502 CheckEmptyStack (decompile);
1503 OTOpnd valu = OTOpndUnOp.Make (opCode, value);
1504 OTStmt jump = OTStmtJump.Make (label);
1505 decompile.AddLastStmt (new OTStmtCond (valu, jump));
1506 break;
1507 }
1508 case "br":
1509 case "br.s":
1510 case "leave": {
1511 CheckEmptyStack (decompile);
1512 OTStmt jump = OTStmtJump.Make (label);
1513 decompile.AddLastStmt (jump);
1514 break;
1515 }
1516 default: throw new Exception ("unknown opcode " + opCode.ToString ());
1517 }
1518 }
1519 }
1520
1521 private class OTCilLabels : OTCilNull {
1522 public OTLabel[] labels;
1523
1524 public OTCilLabels (int offset, OpCode opCode, OTLabel[] labels) : base (offset, opCode)
1525 {
1526 this.labels = labels;
1527 }
1528
1529 public override string DumpString ()
1530 {
1531 StringBuilder sb = new StringBuilder ();
1532 sb.Append (opCode.ToString ());
1533 foreach (OTLabel label in labels) {
1534 sb.Append (' ');
1535 sb.Append (label.name);
1536 }
1537 return sb.ToString ();
1538 }
1539
1540 public override void BuildStatements (OTDecompile decompile, LinkedListNode<OTCilInstr> link)
1541 {
1542 switch (opCode.ToString ()) {
1543 case "switch": {
1544 OTOpnd value = decompile.opstack.Pop ();
1545 CheckEmptyStack (decompile);
1546 decompile.AddLastStmt (new OTStmtSwitch (value, labels));
1547 break;
1548 }
1549 default: throw new Exception ("unknown opcode " + opCode.ToString ());
1550 }
1551 }
1552 }
1553
1554 private class OTCilMethod : OTCilNull {
1555 public MethodInfo method;
1556
1557 public OTCilMethod (int offset, OpCode opCode, MethodInfo method) : base (offset, opCode)
1558 {
1559 this.method = method;
1560 }
1561
1562 public override string DumpString ()
1563 {
1564 return opCode.ToString () + ' ' + method.Name;
1565 }
1566
1567 public override void BuildStatements (OTDecompile decompile, LinkedListNode<OTCilInstr> link)
1568 {
1569 switch (opCode.ToString ()) {
1570 case "call":
1571 case "callvirt": {
1572 int nargs = method.GetParameters ().Length;
1573 if (!method.IsStatic) nargs ++;
1574 OTOpnd[] args = new OTOpnd[nargs];
1575 for (int i = nargs; -- i >= 0;) {
1576 args[i] = decompile.opstack.Pop ();
1577 }
1578 OTOpndCall.AddLast (decompile, method, args);
1579 break;
1580 }
1581 default: throw new Exception ("unknown opcode " + opCode.ToString ());
1582 }
1583 }
1584 }
1585
1586 private class OTCilCtor : OTCilNull {
1587 public ConstructorInfo ctor;
1588
1589 public OTCilCtor (int offset, OpCode opCode, ConstructorInfo ctor) : base (offset, opCode)
1590 {
1591 this.ctor = ctor;
1592 }
1593
1594 public override string DumpString ()
1595 {
1596 return opCode.ToString () + ' ' + AbbrType (ctor.DeclaringType);
1597 }
1598
1599 public override void BuildStatements (OTDecompile decompile, LinkedListNode<OTCilInstr> link)
1600 {
1601 switch (opCode.ToString ()) {
1602 case "newobj": {
1603 int nargs = ctor.GetParameters ().Length;
1604 OTOpnd[] args = new OTOpnd[nargs];
1605 for (int i = nargs; -- i >= 0;) {
1606 args[i] = decompile.opstack.Pop ();
1607 }
1608 decompile.opstack.Push (OTOpndNewobj.Make (ctor, args));
1609 break;
1610 }
1611 default: throw new Exception ("unknown opcode " + opCode.ToString ());
1612 }
1613 }
1614 }
1615
1616 private class OTCilDouble : OTCilNull {
1617 public double value;
1618
1619 public OTCilDouble (int offset, OpCode opCode, double value) : base (offset, opCode)
1620 {
1621 this.value = value;
1622 }
1623
1624 public override string DumpString ()
1625 {
1626 return opCode.ToString () + ' ' + value;
1627 }
1628
1629 public override void BuildStatements (OTDecompile decompile, LinkedListNode<OTCilInstr> link)
1630 {
1631 switch (opCode.ToString ()) {
1632 case "ldc.r8": {
1633 decompile.opstack.Push (new OTOpndDouble (value));
1634 break;
1635 }
1636 default: throw new Exception ("unknown opcode " + opCode.ToString ());
1637 }
1638 }
1639 }
1640
1641 private class OTCilFloat : OTCilNull {
1642 public float value;
1643
1644 public OTCilFloat (int offset, OpCode opCode, float value) : base (offset, opCode)
1645 {
1646 this.value = value;
1647 }
1648
1649 public override string DumpString ()
1650 {
1651 return opCode.ToString () + ' ' + value;
1652 }
1653
1654 public override void BuildStatements (OTDecompile decompile, LinkedListNode<OTCilInstr> link)
1655 {
1656 switch (opCode.ToString ()) {
1657 case "ldc.r4": {
1658 decompile.opstack.Push (new OTOpndFloat (value));
1659 break;
1660 }
1661 default: throw new Exception ("unknown opcode " + opCode.ToString ());
1662 }
1663 }
1664 }
1665
1666 private class OTCilInteger : OTCilNull {
1667 public int value;
1668
1669 public OTCilInteger (int offset, OpCode opCode, int value) : base (offset, opCode)
1670 {
1671 this.value = value;
1672 }
1673
1674 public override string DumpString ()
1675 {
1676 return opCode.ToString () + ' ' + value;
1677 }
1678
1679 public override void BuildStatements (OTDecompile decompile, LinkedListNode<OTCilInstr> link)
1680 {
1681 switch (opCode.ToString ()) {
1682 case "ldarg":
1683 case "ldarg.s": {
1684 decompile.opstack.Push (new OTOpndArg (value, false, decompile));
1685 break;
1686 }
1687 case "ldarga":
1688 case "ldarga.s": {
1689 decompile.opstack.Push (new OTOpndArg (value, true, decompile));
1690 break;
1691 }
1692 case "ldc.i4":
1693 case "ldc.i4.s": {
1694 decompile.opstack.Push (new OTOpndInt (value));
1695 break;
1696 }
1697 case "starg": {
1698 OTOpnd val = decompile.opstack.Pop ();
1699 OTStmtStore.AddLast (decompile, new OTOpndArg (value, false, decompile), val);
1700 break;
1701 }
1702 default: throw new Exception ("unknown opcode " + opCode.ToString ());
1703 }
1704 }
1705 }
1706
1707 private class OTCilString : OTCilNull {
1708 public string value;
1709
1710 public OTCilString (int offset, OpCode opCode, string value) : base (offset, opCode)
1711 {
1712 this.value = value;
1713 }
1714
1715 public override string DumpString ()
1716 {
1717 StringBuilder sb = new StringBuilder ();
1718 sb.Append (opCode.ToString ());
1719 sb.Append (' ');
1720 TokenDeclInline.PrintParamString (sb, value);
1721 return sb.ToString ();
1722 }
1723
1724 public override void BuildStatements (OTDecompile decompile, LinkedListNode<OTCilInstr> link)
1725 {
1726 switch (opCode.ToString ()) {
1727 case "ldstr": {
1728 decompile.opstack.Push (new OTOpndString (value));
1729 break;
1730 }
1731 default: throw new Exception ("unknown opcode " + opCode.ToString ());
1732 }
1733 }
1734 }
1735
1736 /***************************************\
1737 * Tokens what are on operand stack. *
1738 \***************************************/
1739
1740 public abstract class OTOpnd {
1741
1742 /**
1743 * See if it possibly has any side effects.
1744 */
1745 public abstract bool HasSideEffects { get; }
1746
1747 /**
1748 * Increment reference counts.
1749 */
1750 public virtual void CountRefs (bool writing)
1751 { }
1752
1753 /**
1754 * If this operand is a 'by reference' operand,
1755 * return the corresponding 'by value' operand.
1756 */
1757 public virtual OTOpnd GetNonByRefOpnd ()
1758 {
1759 return this;
1760 }
1761
1762 /**
1763 * If this operand is same as oldopnd, replace it with newopnd.
1764 *
1765 * This default just does a shallow search which is ok if this operand does not have any sub-operands.
1766 * But it must be overridden for a deep search if this operand has any sub-operands.
1767 */
1768 public virtual OTOpnd ReplaceOperand (OTOpnd oldopnd, OTOpnd newopnd, ref bool rc)
1769 {
1770 if (SameAs (oldopnd)) {
1771 rc = true;
1772 return newopnd;
1773 }
1774 return this;
1775 }
1776
1777 /**
1778 * See if the two operands are the same value.
1779 * Note that calls might have side-effects so are never the same.
1780 */
1781 public abstract bool SameAs (OTOpnd other);
1782
1783 /**
1784 * Get a printable string representation of the operand.
1785 */
1786 public abstract string PrintableString { get; }
1787 }
1788
1789 /**
1790 * Argument variable.
1791 */
1792 private class OTOpndArg : OTOpnd {
1793 public int index;
1794 public bool byref;
1795
1796 private OTDecompile decompile;
1797
1798 public OTOpndArg (int index, bool byref, OTDecompile decompile)
1799 {
1800 this.index = index;
1801 this.byref = byref;
1802 this.decompile = decompile;
1803 }
1804
1805 public override bool HasSideEffects {
1806 get {
1807 return false;
1808 }
1809 }
1810
1811 public override OTOpnd GetNonByRefOpnd ()
1812 {
1813 if (!byref) return this;
1814 return new OTOpndArg (index, false, decompile);
1815 }
1816
1817 public override bool SameAs (OTOpnd other)
1818 {
1819 if (!(other is OTOpndArg)) return false;
1820 return (((OTOpndArg) other).byref == byref) && (((OTOpndArg) other).index == index);
1821 }
1822
1823 public override string PrintableString {
1824 get {
1825 string argname = decompile.MethArgName (index);
1826 return byref ? ("ref " + argname) : argname;
1827 }
1828 }
1829 }
1830
1831 /**
1832 * Element of an array.
1833 */
1834 private class OTOpndArrayElem : OTOpnd {
1835 public bool byref;
1836 public OTOpnd array;
1837 public OTOpnd index;
1838
1839 public static OTOpnd Make (OTOpnd array, OTOpnd index, bool byref, OTDecompile decompile)
1840 {
1841 /*
1842 * arg$0.glblVars.iar<type>[<intconst>] is a reference to a global variable
1843 * likewise so is __xmrinst.glblVars.iar<type>[<intconst>]
1844 */
1845 if ((array is OTOpndField) && (index is OTOpndInt)) {
1846
1847 /*
1848 * arrayfield = (arg$0.glblVars).iar<type>
1849 * arrayfieldobj = arg$0.glblVars
1850 * iartypename = iar<type>
1851 */
1852 OTOpndField arrayfield = (OTOpndField) array;
1853 OTOpnd arrayfieldobj = arrayfield.obj;
1854 string iartypename = arrayfield.field.Name;
1855
1856 /*
1857 * See if they are what they are supposed to be.
1858 */
1859 if ((arrayfieldobj is OTOpndField) && iartypename.StartsWith ("iar")) {
1860
1861 /*
1862 * arrayfieldobjfield = arg$0.glblVars
1863 */
1864 OTOpndField arrayfieldobjfield = (OTOpndField) arrayfieldobj;
1865
1866 /*
1867 * See if the parts are what they are supposed to be.
1868 */
1869 if (IsArg0OrXMRInst (arrayfieldobjfield.obj) && (arrayfieldobjfield.field.Name == "glblVars")) {
1870
1871 /*
1872 * Everything matches up, make a global variable instead of an array reference.
1873 */
1874 return new OTOpndGlobal (iartypename, ((OTOpndInt) index).value, byref, decompile.scriptObjCode);
1875 }
1876 }
1877 }
1878
1879 /*
1880 * Other array reference.
1881 */
1882 OTOpndArrayElem it = new OTOpndArrayElem ();
1883 it.array = array;
1884 it.index = index;
1885 it.byref = byref;
1886 return it;
1887 }
1888
1889 private OTOpndArrayElem () { }
1890
1891 public override bool HasSideEffects {
1892 get {
1893 return array.HasSideEffects || index.HasSideEffects;
1894 }
1895 }
1896
1897 public override void CountRefs (bool writing)
1898 {
1899 array.CountRefs (false);
1900 index.CountRefs (false);
1901 }
1902
1903 public override OTOpnd GetNonByRefOpnd ()
1904 {
1905 if (!byref) return this;
1906 OTOpndArrayElem it = new OTOpndArrayElem ();
1907 it.array = array;
1908 it.index = index;
1909 return it;
1910 }
1911
1912 public override OTOpnd ReplaceOperand (OTOpnd oldopnd, OTOpnd newopnd, ref bool rc)
1913 {
1914 if (SameAs (oldopnd)) {
1915 rc = true;
1916 return newopnd;
1917 }
1918 array = array.ReplaceOperand (oldopnd, newopnd, ref rc);
1919 index = index.ReplaceOperand (oldopnd, newopnd, ref rc);
1920 return this;
1921 }
1922
1923 public override bool SameAs (OTOpnd other)
1924 {
1925 if (!(other is OTOpndArrayElem)) return false;
1926 OTOpndArrayElem otherae = (OTOpndArrayElem) other;
1927 return array.SameAs (otherae.array) && index.SameAs (otherae.index);
1928 }
1929
1930 public override string PrintableString {
1931 get {
1932 return (byref ? "ref " : "") + array.PrintableString + "[" + index.PrintableString + "]";
1933 }
1934 }
1935
1936 /**
1937 * See if the argument is a reference to arg$0 or __xmrinst
1938 */
1939 public static bool IsArg0OrXMRInst (OTOpnd obj)
1940 {
1941 if (obj is OTOpndArg) {
1942 OTOpndArg objarg = (OTOpndArg) obj;
1943 return objarg.index == 0;
1944 }
1945 if (obj is OTOpndLocal) {
1946 OTOpndLocal objlcl = (OTOpndLocal) obj;
1947 return objlcl.local.name.StartsWith (_xmrinstlocal);
1948 }
1949 return false;
1950 }
1951 }
1952
1953 /**
1954 * Binary operator.
1955 */
1956 private class OTOpndBinOp : OTOpnd {
1957 public OTOpnd left;
1958 public MyOp opCode;
1959 public OTOpnd rite;
1960
1961 private static Dictionary<string,string> xor1ops = InitXor1Ops ();
1962
1963 private static Dictionary<string,string> InitXor1Ops ()
1964 {
1965 Dictionary<string,string> d = new Dictionary<string,string> ();
1966 d["ceq"] = "cne";
1967 d["cge"] = "clt";
1968 d["cgt"] = "cle";
1969 d["cle"] = "cgt";
1970 d["clt"] = "cge";
1971 d["cne"] = "ceq";
1972 return d;
1973 }
1974
1975 public static OTOpnd Make (OTOpnd left, MyOp opCode, OTOpnd rite)
1976 {
1977 // ((x clt y) xor 1) => (x cge y) etc
1978 string xor1op;
1979 if ((left is OTOpndBinOp) && xor1ops.TryGetValue (((OTOpndBinOp) left).opCode.name, out xor1op) &&
1980 (opCode == MyOp.Xor) &&
1981 (rite is OTOpndInt) && (((OTOpndInt) rite).value == 1)) {
1982 opCode = MyOp.GetByName (xor1op);
1983 }
1984
1985 // handle strcmp() cases (see OTOpndStrCmp)
1986 if (left is OTOpndStrCmp) {
1987 OTOpnd strcmp = ((OTOpndStrCmp) left).MakeBinOp (opCode, rite);
1988 if (strcmp != null) return strcmp;
1989 }
1990
1991 // nothing special, make as is
1992 OTOpndBinOp it = new OTOpndBinOp ();
1993 it.left = left;
1994 it.opCode = opCode;
1995 it.rite = rite;
1996 return it;
1997 }
1998
1999 private OTOpndBinOp () { }
2000
2001 public override bool HasSideEffects {
2002 get {
2003 return left.HasSideEffects || rite.HasSideEffects;
2004 }
2005 }
2006
2007 public override void CountRefs (bool writing)
2008 {
2009 left.CountRefs (false);
2010 rite.CountRefs (false);
2011 }
2012
2013 public override OTOpnd ReplaceOperand (OTOpnd oldopnd, OTOpnd newopnd, ref bool rc)
2014 {
2015 if (SameAs (oldopnd)) {
2016 rc = true;
2017 return newopnd;
2018 }
2019 left = left.ReplaceOperand (oldopnd, newopnd, ref rc);
2020 rite = rite.ReplaceOperand (oldopnd, newopnd, ref rc);
2021 return this;
2022 }
2023
2024 public override bool SameAs (OTOpnd other)
2025 {
2026 if (!(other is OTOpndBinOp)) return false;
2027 OTOpndBinOp otherbo = (OTOpndBinOp) other;
2028 return left.SameAs (otherbo.left) && (opCode.ToString () == otherbo.opCode.ToString ()) && rite.SameAs (otherbo.rite);
2029 }
2030
2031 public override string PrintableString {
2032 get {
2033 StringBuilder sb = new StringBuilder ();
2034
2035 bool leftneedsparen = ItNeedsParentheses (left, true);
2036 if (leftneedsparen) sb.Append ('(');
2037 sb.Append (left.PrintableString);
2038 if (leftneedsparen) sb.Append (')');
2039
2040 sb.Append (' ');
2041 sb.Append (opCode.source);
2042 sb.Append (' ');
2043
2044 bool riteneedsparen = ItNeedsParentheses (rite, false);
2045 if (riteneedsparen) sb.Append ('(');
2046 sb.Append (rite.PrintableString);
2047 if (riteneedsparen) sb.Append (')');
2048
2049 return sb.ToString ();
2050 }
2051 }
2052
2053 /**
2054 * See if source code representation requires parentheses around the given operand.
2055 * @param it = the other operand to decide about
2056 * @param itleft = true: 'it' is on the left of this operand (A $ B) # C
2057 * false: 'it' is on the right of this operand A $ (B # C)
2058 */
2059 private bool ItNeedsParentheses (OTOpnd it, bool itleft)
2060 {
2061 if (!(it is OTOpndBinOp)) return false;
2062 string itop = ((OTOpndBinOp) it).opCode.source;
2063 string myop = opCode.source;
2064
2065 // find them in table. higher number is for *, lower is for +.
2066 int itpi, mypi;
2067 if (!precedence.TryGetValue (itop, out itpi)) return true;
2068 if (!precedence.TryGetValue (myop, out mypi)) return true;
2069 int itpiabs = Math.Abs (itpi);
2070 int mypiabs = Math.Abs (mypi);
2071
2072 // if its precedence is lower (eg +) than my precedence (eg *), it needs parentheses
2073 if (itpiabs < mypiabs) return true;
2074
2075 // if its precedence is higher (eg *) than my precedence (eg +), it doesn't needs parentheses
2076 if (itpiabs > mypiabs) return false;
2077
2078 // if (A $ B) # C, we can safely go without the parentheses
2079 if (itleft) return false;
2080
2081 // my it
2082 // A $ (B # C) only works without parentheses for commutative $
2083 // A - (B + C) and A - (B - C) require parentheses
2084 // A + (B - C) does not
2085 return mypi < 0; // neg: things like -, /, etc require parentheses
2086 // pos: things like +, *, etc do not need parens
2087 }
2088
2089 // see MMRScriptReduce.PrecedenceInit()
2090 private static Dictionary<string,int> precedence = InitPrecedence ();
2091 private static Dictionary<string,int> InitPrecedence ()
2092 {
2093 Dictionary<string,int> d = new Dictionary<string,int> ();
2094 d["|"] = 140;
2095 d["^"] = 160;
2096 d["&"] = 180;
2097 d["<<"] = -260;
2098 d[">>"] = -260;
2099 d["+"] = 280;
2100 d["-"] = -280;
2101 d["*"] = 320;
2102 d["/"] = -320;
2103 d["%"] = -320;
2104 return d;
2105 }
2106 }
2107
2108 /**
2109 * Call with or without return value.
2110 */
2111 private class OTOpndCall : OTOpnd {
2112 private static Dictionary<string,MethodInfo> mathmeths = InitMathMeths ();
2113 private static Dictionary<string,MethodInfo> InitMathMeths ()
2114 {
2115 Dictionary<string,MethodInfo> d = new Dictionary<string,MethodInfo> ();
2116 d["Acos"] = typeof (ScriptBaseClass).GetMethod ("llAcos");
2117 d["Asin"] = typeof (ScriptBaseClass).GetMethod ("llAsin");
2118 d["Atan"] = typeof (ScriptBaseClass).GetMethod ("llAtan");
2119 d["Cos"] = typeof (ScriptBaseClass).GetMethod ("llCos");
2120 d["Abs"] = typeof (ScriptBaseClass).GetMethod ("llFabs");
2121 d["Log"] = typeof (ScriptBaseClass).GetMethod ("llLog");
2122 d["Log10"] = typeof (ScriptBaseClass).GetMethod ("llLog10");
2123 d["Round"] = typeof (ScriptBaseClass).GetMethod ("llRound");
2124 d["Sin"] = typeof (ScriptBaseClass).GetMethod ("llSin");
2125 d["Sqrt"] = typeof (ScriptBaseClass).GetMethod ("llSqrt");
2126 d["Tan"] = typeof (ScriptBaseClass).GetMethod ("llTan");
2127 return d;
2128 }
2129
2130 public MethodInfo method;
2131 public OTOpnd[] args;
2132
2133 // pushes on stack for return-value functions
2134 // pushes to end of instruction stream for return-void functions
2135 public static void AddLast (OTDecompile decompile, MethodInfo method, OTOpnd[] args)
2136 {
2137 int nargs = args.Length;
2138
2139 // heap tracker push is just the single arg value as far as we're concerned
2140 if ((nargs == 1) && (method.Name == _heapTrackerPush) && method.DeclaringType.Name.StartsWith ("HeapTracker")) {
2141 decompile.opstack.Push (args[0]);
2142 return;
2143 }
2144
2145 // heap tracker pop is just a store as far as we're concerned
2146 if ((nargs == 2) && (method.Name == _heapTrackerPop) && method.DeclaringType.Name.StartsWith ("HeapTracker")) {
2147 OTStmtStore.AddLast (decompile, args[0], args[1]);
2148 return;
2149 }
2150
2151 // string.Compare() is its own thing cuz it has to decompile many ways
2152 if ((nargs == 2) && (method.DeclaringType == typeof (string)) && (method.Name == "Compare")) {
2153 decompile.opstack.Push (new OTOpndStrCmp (args[0], args[1]));
2154 return;
2155 }
2156
2157 // ObjectToString, etc, should appear as casts
2158 if ((nargs == 1) && (method.DeclaringType == typeof (TypeCast)) && method.Name.EndsWith ("ToBool")) {
2159 MethodInfo meth = typeof (XMRInstAbstract).GetMethod ("xmr" + method.Name);
2160 AddLast (decompile, meth, new OTOpnd[] { new OTOpndNull (), args[0] });
2161 return;
2162 }
2163 if ((nargs == 1) && (method.DeclaringType == typeof (TypeCast)) && method.Name.EndsWith ("ToFloat")) {
2164 decompile.opstack.Push (new OTOpndCast (typeof (double), args[0]));
2165 return;
2166 }
2167 if ((nargs == 1) && (method.DeclaringType == typeof (TypeCast)) && method.Name.EndsWith ("ToInteger")) {
2168 decompile.opstack.Push (new OTOpndCast (typeof (int), args[0]));
2169 return;
2170 }
2171 if ((nargs == 1) && (method.DeclaringType == typeof (TypeCast)) && method.Name.EndsWith ("ToList")) {
2172 decompile.opstack.Push (new OTOpndCast (typeof (LSL_List), args[0]));
2173 return;
2174 }
2175 if ((nargs == 1) && (method.DeclaringType == typeof (TypeCast)) && method.Name.EndsWith ("ToRotation")) {
2176 decompile.opstack.Push (new OTOpndCast (typeof (LSL_Rotation), args[0]));
2177 return;
2178 }
2179 if ((nargs == 1) && (method.DeclaringType == typeof (TypeCast)) && method.Name.EndsWith ("ToString")) {
2180 decompile.opstack.Push (new OTOpndCast (typeof (string), args[0]));
2181 return;
2182 }
2183 if ((nargs == 1) && (method.DeclaringType == typeof (TypeCast)) && method.Name.EndsWith ("ToVector")) {
2184 decompile.opstack.Push (new OTOpndCast (typeof (LSL_Vector), args[0]));
2185 return;
2186 }
2187
2188 if ((method.DeclaringType == typeof (XMRInstAbstract)) && (method.Name == "xmrHeapLeft")) {
2189 AddLast (decompile, typeof (ScriptBaseClass).GetMethod ("llGetFreeMemory"), new OTOpnd[] { new OTOpndNull () });
2190 return;
2191 }
2192
2193 // pop to entry in the list/object/string array
2194 if (PopToGlobalArray (decompile, method, args)) return;
2195
2196 // strip off event handler argument unwrapper calls
2197 if ((nargs == 1) && (method.DeclaringType == typeof (TypeCast)) && method.Name.StartsWith ("EHArgUnwrap")) {
2198 decompile.opstack.Push (args[0]);
2199 return;
2200 }
2201
2202 // translate Math method to ll method
2203 MethodInfo mathmeth;
2204 if ((method.DeclaringType == typeof (Math)) && mathmeths.TryGetValue (method.Name, out mathmeth)) {
2205 AddLast (decompile, mathmeth, new OTOpnd[] { new OTOpndNull (), args[0] });
2206 return;
2207 }
2208 if ((method.DeclaringType == typeof (Math)) && (method.Name == "Atan2")) {
2209 AddLast (decompile, typeof (ScriptBaseClass).GetMethod ("llAtan2"), new OTOpnd[] { new OTOpndNull (), args[0], args[1] });
2210 return;
2211 }
2212 if ((method.DeclaringType == typeof (Math)) && (method.Name == "Pow")) {
2213 AddLast (decompile, typeof (ScriptBaseClass).GetMethod ("llPow"), new OTOpnd[] { new OTOpndNull (), args[0], args[1] });
2214 return;
2215 }
2216
2217 // string concat should be a bunch of adds
2218 if ((method.Name == "Concat") && (method.DeclaringType == typeof (string))) {
2219 int k = args.Length;
2220 while (k > 1) {
2221 int j = 0;
2222 int i;
2223 for (i = 0; i + 2 <= k; i += 2) {
2224 args[j++] = OTOpndBinOp.Make (args[i+0], MyOp.Add, args[i+1]);
2225 }
2226 while (i < k) args[j++] = args[i++];
2227 k = j;
2228 }
2229 if (k > 0) decompile.opstack.Push (args[0]);
2230 return;
2231 }
2232
2233 // bunch of calls for rotation and vector arithmetic
2234 if ((method.DeclaringType == typeof (BinOpStr)) && BinOpStrCall (decompile, method, args)) return;
2235 if ((method.DeclaringType == typeof (ScriptCodeGen)) && (method.Name == "LSLRotationNegate")) {
2236 decompile.opstack.Push (OTOpndUnOp.Make (MyOp.Neg, args[0]));
2237 return;
2238 }
2239 if ((method.DeclaringType == typeof (ScriptCodeGen)) && (method.Name == "LSLVectorNegate")) {
2240 decompile.opstack.Push (OTOpndUnOp.Make (MyOp.Neg, args[0]));
2241 return;
2242 }
2243
2244 // otherwise process it as a call
2245 OTOpndCall call = new OTOpndCall ();
2246 call.method = method;
2247 call.args = args;
2248 if (method.ReturnType == typeof (void)) {
2249 OTStmtVoid.AddLast (decompile, call);
2250 } else {
2251 decompile.opstack.Push (call);
2252 }
2253 }
2254
2255 public override bool HasSideEffects {
2256 get {
2257 return true;
2258 }
2259 }
2260
2261 /**
2262 * Handle a call to XMRInstArrays.Pop<List,Object,String>
2263 * by converting it to a store directly into the array.
2264 */
2265 private static bool PopToGlobalArray (OTDecompile decompile, MethodInfo method, OTOpnd[] args)
2266 {
2267 if (method.DeclaringType != typeof (XMRInstArrays)) return false;
2268 if (args.Length != 3) return false;
2269
2270 string array = null;
2271 if (method.Name == "PopList") array = "iarLists";
2272 if (method.Name == "PopObject") array = "iarObjects";
2273 if (method.Name == "PopString") array = "iarStrings";
2274 if (array == null) return false;
2275
2276 // make token that points to the iar<whatever> array
2277 FieldInfo field = typeof (XMRInstArrays).GetField (array);
2278 OTOpnd arrayfield = OTOpndField.Make (args[0], field);
2279
2280 // make token that points to the element to be popped to
2281 OTOpnd element = OTOpndArrayElem.Make (arrayfield, args[1], false, decompile);
2282
2283 // make a statement to store value in that element
2284 OTStmtStore.AddLast (decompile, element, args[2]);
2285
2286 return true;
2287 }
2288
2289 /**
2290 * BinOpStr has a bunch of calls to do funky arithmetic.
2291 * Instead of generating a call, put back the original source.
2292 */
2293 private static bool BinOpStrCall (OTDecompile decompile, MethodInfo method, OTOpnd[] args)
2294 {
2295 switch (method.Name) {
2296 case "MethFloatAddList":
2297 case "MethIntAddList":
2298 case "MethKeyAddList":
2299 case "MethListAddFloat":
2300 case "MethListAddInt":
2301 case "MethListAddKey":
2302 case "MethListAddList":
2303 case "MethListAddObj":
2304 case "MethListAddRot":
2305 case "MethListAddStr":
2306 case "MethListAddVec":
2307 case "MethObjAddList":
2308 case "MethRotAddList":
2309 case "MethRotAddRot":
2310 case "MethStrAddList":
2311 case "MethVecAddList":
2312 case "MethVecAddVec": {
2313 decompile.opstack.Push (OTOpndBinOp.Make (args[0], MyOp.Add, args[1]));
2314 return true;
2315 }
2316
2317 case "MethListEqList":
2318 case "MethRotEqRot":
2319 case "MethVecEqVec": {
2320 decompile.opstack.Push (OTOpndBinOp.Make (args[0], MyOp.Ceq, args[1]));
2321 return true;
2322 }
2323
2324 case "MethListNeList":
2325 case "MethRotNeRot":
2326 case "MethVecNeVec": {
2327 decompile.opstack.Push (OTOpndBinOp.Make (args[0], MyOp.Cne, args[1]));
2328 return true;
2329 }
2330
2331 case "MethRotSubRot":
2332 case "MethVecSubVec": {
2333 decompile.opstack.Push (OTOpndBinOp.Make (args[0], MyOp.Sub, args[1]));
2334 return true;
2335 }
2336
2337 case "MethFloatMulVec":
2338 case "MethIntMulVec":
2339 case "MethRotMulRot":
2340 case "MethVecMulFloat":
2341 case "MethVecMulInt":
2342 case "MethVecMulRot":
2343 case "MethVecMulVec": {
2344 decompile.opstack.Push (OTOpndBinOp.Make (args[0], MyOp.Mul, args[1]));
2345 return true;
2346 }
2347
2348 case "MethRotDivRot":
2349 case "MethVecDivFloat":
2350 case "MethVecDivInt":
2351 case "MethVecDivRot": {
2352 decompile.opstack.Push (OTOpndBinOp.Make (args[0], MyOp.Div, args[1]));
2353 return true;
2354 }
2355
2356 default: return false;
2357 }
2358 }
2359
2360 private OTOpndCall () { }
2361
2362 public override void CountRefs (bool writing)
2363 {
2364 foreach (OTOpnd arg in args) {
2365 arg.CountRefs (false);
2366 }
2367 }
2368
2369 public override OTOpnd ReplaceOperand (OTOpnd oldopnd, OTOpnd newopnd, ref bool rc)
2370 {
2371 for (int i = 0; i < args.Length; i ++) {
2372 args[i] = args[i].ReplaceOperand (oldopnd, newopnd, ref rc);
2373 }
2374 return this;
2375 }
2376
2377 public override bool SameAs (OTOpnd other)
2378 {
2379 return false;
2380 }
2381
2382 public override string PrintableString {
2383 get {
2384 StringBuilder sb = new StringBuilder ();
2385
2386 // GetByKey(a,i) => a[i]
2387 if ((method.DeclaringType == typeof (XMR_Array)) && (method.Name == "GetByKey") && (args.Length == 2)) {
2388 sb.Append (args[0].PrintableString);
2389 sb.Append ('[');
2390 sb.Append (args[1].PrintableString);
2391 sb.Append (']');
2392 return sb.ToString ();
2393 }
2394
2395 // SetByKey(a,i,v) => a[i] = v
2396 if ((method.DeclaringType == typeof (XMR_Array)) && (method.Name == "SetByKey") && (args.Length == 3)) {
2397 sb.Append (args[0].PrintableString);
2398 sb.Append ('[');
2399 sb.Append (args[1].PrintableString);
2400 sb.Append ("] = ");
2401 sb.Append (args[2].PrintableString);
2402 return sb.ToString ();
2403 }
2404
2405 // CompValuListEl.GetElementFromList accesses list elements like an array.
2406 if ((method.DeclaringType == typeof (CompValuListEl)) && (method.Name == "GetElementFromList")) {
2407 sb.Append (args[0].PrintableString);
2408 sb.Append ('[');
2409 sb.Append (args[1].PrintableString);
2410 sb.Append (']');
2411 return sb.ToString ();
2412 }
2413
2414 // methods that are part of ScriptBaseClass are LSL functions such as llSay()
2415 // so we want to skip outputting "arg$0," as it is the hidden "this" argument.
2416 // and there are also XMRInstAbstract functions such as xmrEventDequeue().
2417 int starti = 0;
2418 if ((method.DeclaringType == typeof (ScriptBaseClass)) && !method.IsStatic) starti = 1;
2419 if ((method.DeclaringType == typeof (XMRInstAbstract)) && !method.IsStatic) starti = 1;
2420
2421 // likewise, method that have null as the declaring type are script-defined
2422 // dynamic methods which have a hidden "this" argument passed as "arg$0".
2423 if (method.DeclaringType == null) starti = 1;
2424
2425 // all others we want to show the type name (such as Math.Abs, String.Compare, etc)
2426 if (starti == 0) {
2427 sb.Append (AbbrType (method.DeclaringType));
2428 sb.Append ('.');
2429 }
2430
2431 // script-defined functions have the param types as part of their name
2432 // so strip them off here so they don't clutter things up
2433 int i = method.Name.IndexOf ('(');
2434 if (i < 0) sb.Append (method.Name);
2435 else sb.Append (method.Name.Substring (0, i));
2436
2437 // now add the call arguments
2438 sb.Append (" (");
2439 bool first = true;
2440 foreach (OTOpnd arg in args) {
2441 if (-- starti < 0) {
2442 if (!first) sb.Append (", ");
2443 sb.Append (arg.PrintableString);
2444 first = false;
2445 }
2446 }
2447 sb.Append (')');
2448 return sb.ToString ();
2449 }
2450 }
2451 }
2452
2453 /**
2454 * Cast value to the given type.
2455 */
2456 private class OTOpndCast : OTOpnd {
2457 public Type type;
2458 public OTOpnd value;
2459
2460 public OTOpndCast (Type type, OTOpnd value)
2461 {
2462 this.type = type;
2463 this.value = value;
2464 }
2465
2466 public override bool HasSideEffects {
2467 get {
2468 return value.HasSideEffects;
2469 }
2470 }
2471
2472 public override void CountRefs (bool writing)
2473 {
2474 value.CountRefs (false);
2475 }
2476
2477 public override OTOpnd ReplaceOperand (OTOpnd oldopnd, OTOpnd newopnd, ref bool rc)
2478 {
2479 if (SameAs (oldopnd)) {
2480 rc = true;
2481 return newopnd;
2482 }
2483 value = value.ReplaceOperand (oldopnd, newopnd, ref rc);
2484 return this;
2485 }
2486
2487 public override bool SameAs (OTOpnd other)
2488 {
2489 if (!(other is OTOpndCast)) return false;
2490 OTOpndCast othercast = (OTOpndCast) other;
2491 return (type == othercast.type) && value.SameAs (othercast.value);
2492 }
2493
2494 public override string PrintableString {
2495 get {
2496 StringBuilder sb = new StringBuilder ();
2497 sb.Append ('(');
2498 sb.Append (AbbrType (type));
2499 sb.Append (") ");
2500 if (value is OTOpndBinOp) sb.Append ('(');
2501 sb.Append (value.PrintableString);
2502 if (value is OTOpndBinOp) sb.Append (')');
2503 return sb.ToString ();
2504 }
2505 }
2506 }
2507
2508 /**
2509 * Duplicate stack value without re-performing computation.
2510 * Semantics just like local var except it doesn't have a declaration.
2511 */
2512 private class OTOpndDup : OTOpnd {
2513 public int index;
2514 public int ndupreads;
2515
2516 public OTOpndDup (int index)
2517 {
2518 this.index = index;
2519 }
2520
2521 public override bool HasSideEffects {
2522 get {
2523 return false;
2524 }
2525 }
2526
2527 public override void CountRefs (bool writing)
2528 {
2529 if (!writing) ndupreads ++;
2530 }
2531
2532 public override bool SameAs (OTOpnd other)
2533 {
2534 if (!(other is OTOpndDup)) return false;
2535 return ((OTOpndDup) other).index == index;
2536 }
2537
2538 public override string PrintableString { get { return "dup$" + index; } }
2539 }
2540
2541 /**
2542 * Field of an object.
2543 */
2544 private class OTOpndField : OTOpnd {
2545 public OTOpnd obj;
2546 public FieldInfo field;
2547
2548 public static OTOpnd Make (OTOpnd obj, FieldInfo field)
2549 {
2550 // LSL_Float.value => the object itself
2551 if ((field.DeclaringType == typeof (LSL_Float)) && (field.Name == "value")) {
2552 return obj;
2553 }
2554
2555 // LSL_Integer.value => the object itself
2556 if ((field.DeclaringType == typeof (LSL_Integer)) && (field.Name == "value")) {
2557 return obj;
2558 }
2559
2560 // LSL_String.m_string => the object itself
2561 if ((field.DeclaringType == typeof (LSL_String)) && (field.Name == "m_string")) {
2562 return obj;
2563 }
2564
2565 // some other field, output code to access it
2566 // sometimes the object comes as by reference (value types), so we might need to deref it first
2567 OTOpndField it = new OTOpndField ();
2568 it.obj = obj.GetNonByRefOpnd ();
2569 it.field = field;
2570 return it;
2571 }
2572
2573 private OTOpndField () { }
2574
2575 public override bool HasSideEffects {
2576 get {
2577 return obj.HasSideEffects;
2578 }
2579 }
2580
2581 public override void CountRefs (bool writing)
2582 {
2583 // the field may be getting written to, but the object is being read
2584 obj.CountRefs (false);
2585 }
2586
2587 public override OTOpnd ReplaceOperand (OTOpnd oldopnd, OTOpnd newopnd, ref bool rc)
2588 {
2589 if (SameAs (oldopnd)) {
2590 rc = true;
2591 return newopnd;
2592 }
2593 obj = obj.ReplaceOperand (oldopnd, newopnd, ref rc);
2594 return this;
2595 }
2596
2597 public override bool SameAs (OTOpnd other)
2598 {
2599 if (!(other is OTOpndField)) return false;
2600 OTOpndField otherfield = (OTOpndField) other;
2601 return (field.Name == otherfield.field.Name) && obj.SameAs (otherfield.obj);
2602 }
2603
2604 public override string PrintableString {
2605 get {
2606 StringBuilder sb = new StringBuilder ();
2607 if (obj is OTOpndBinOp) sb.Append ('(');
2608 sb.Append (obj.PrintableString);
2609 if (obj is OTOpndBinOp) sb.Append (')');
2610 sb.Append ('.');
2611 sb.Append (field.Name);
2612 return sb.ToString ();
2613 }
2614 }
2615 }
2616
2617 /**
2618 * Script-level global variable.
2619 */
2620 private class OTOpndGlobal : OTOpnd {
2621 public string iartypename;
2622 public int iararrayidx;
2623 public bool byref;
2624 public ScriptObjCode scriptObjCode;
2625
2626 public OTOpndGlobal (string iartypename, int iararrayidx, bool byref, ScriptObjCode scriptObjCode)
2627 {
2628 this.iartypename = iartypename;
2629 this.iararrayidx = iararrayidx;
2630 this.byref = byref;
2631 this.scriptObjCode = scriptObjCode;
2632 }
2633
2634 public override bool HasSideEffects {
2635 get {
2636 return false;
2637 }
2638 }
2639
2640 public override OTOpnd GetNonByRefOpnd ()
2641 {
2642 if (!byref) return this;
2643 return new OTOpndGlobal (iartypename, iararrayidx, false, scriptObjCode);
2644 }
2645
2646 public override bool SameAs (OTOpnd other)
2647 {
2648 if (!(other is OTOpndGlobal)) return false;
2649 OTOpndGlobal otherglobal = (OTOpndGlobal) other;
2650 return (iartypename == otherglobal.iartypename) && (iararrayidx == otherglobal.iararrayidx);
2651 }
2652
2653 public override string PrintableString {
2654 get {
2655 return (byref ? "ref " : "") + scriptObjCode.globalVarNames[iartypename][iararrayidx];
2656 }
2657 }
2658 }
2659
2660 /**
2661 * List initialization.
2662 */
2663 private class OTOpndListIni : OTOpnd {
2664 public OTOpnd[] values;
2665
2666 /**
2667 * Try to detect list initialization building idiom:
2668 * dup$<n> = newarr object[<m>] << link points here
2669 * dup$<n>[0] = bla
2670 * dup$<n>[1] = bla
2671 * ...
2672 * ... newobj list (dup$<n>) ...
2673 */
2674 public static bool Detect (LinkedListNode<OTStmt> link)
2675 {
2676 if (link == null) return false;
2677
2678 /*
2679 * Check for 'dup$<n> = newarr object[<m>]' and get listsize from <m>.
2680 */
2681 OTStmtStore store = (OTStmtStore) link.Value;
2682 if (!(store.varwr is OTOpndDup)) return false;
2683 if (!(store.value is OTOpndNewarr)) return false;
2684 OTOpndDup storevar = (OTOpndDup) store.varwr;
2685 OTOpndNewarr storeval = (OTOpndNewarr) store.value;
2686 if (storeval.type != typeof (object)) return false;
2687 if (!(storeval.index is OTOpndInt)) return false;
2688 int listsize = ((OTOpndInt) storeval.index).value;
2689
2690 /*
2691 * Good chance of having list initializer, malloc an object to hold it.
2692 */
2693 OTOpndListIni it = new OTOpndListIni ();
2694 it.values = new OTOpnd[listsize];
2695
2696 /*
2697 * There should be exactly listsize statements following that of the form:
2698 * dup$<n>[<i>] = bla
2699 * If so, save the bla values in the values[] array.
2700 */
2701 LinkedListNode<OTStmt> vallink = link;
2702 for (int i = 0; i < listsize; i ++) {
2703 vallink = vallink.Next;
2704 if (vallink == null) return false;
2705 if (!(vallink.Value is OTStmtStore)) return false;
2706 OTStmtStore valstore = (OTStmtStore) vallink.Value;
2707 if (!(valstore.varwr is OTOpndArrayElem)) return false;
2708 OTOpndArrayElem varelem = (OTOpndArrayElem) valstore.varwr;
2709 if (varelem.array != storevar) return false;
2710 if (!(varelem.index is OTOpndInt)) return false;
2711 if (((OTOpndInt) varelem.index).value != i) return false;
2712 it.values[i] = valstore.value;
2713 }
2714
2715 /*
2716 * The next statement should have a 'newobj list (dup$<n>)' in it somewhere
2717 * that we want to replace with 'it'.
2718 */
2719 ConstructorInfo protoctor = typeof (LSL_List).GetConstructor (new Type[] { typeof (object[]) });
2720 OTOpnd[] protoargs = new OTOpnd[] { storevar };
2721 OTOpnd proto = OTOpndNewobj.Make (protoctor, protoargs);
2722
2723 vallink = vallink.Next;
2724 bool rc = vallink.Value.ReplaceOperand (proto, it);
2725
2726 /*
2727 * If successful, delete 'dup$n =' and all 'dup$n[i] =' statements.
2728 */
2729 if (rc) {
2730 do {
2731 LinkedListNode<OTStmt> nextlink = link.Next;
2732 link.List.Remove (link);
2733 link = nextlink;
2734 } while (link != vallink);
2735 }
2736
2737 return rc;
2738 }
2739
2740 public override bool HasSideEffects {
2741 get {
2742 foreach (OTOpnd value in values) {
2743 if (value.HasSideEffects) return true;
2744 }
2745 return false;
2746 }
2747 }
2748
2749 public override void CountRefs (bool writing)
2750 {
2751 foreach (OTOpnd value in values) {
2752 value.CountRefs (false);
2753 }
2754 }
2755
2756 public override OTOpnd ReplaceOperand (OTOpnd oldopnd, OTOpnd newopnd, ref bool rc)
2757 {
2758 if (SameAs (oldopnd)) {
2759 rc = true;
2760 return newopnd;
2761 }
2762 for (int i = 0; i < values.Length; i ++) {
2763 values[i] = values[i].ReplaceOperand (oldopnd, newopnd, ref rc);
2764 }
2765 return this;
2766 }
2767
2768 public override bool SameAs (OTOpnd other)
2769 {
2770 if (!(other is OTOpndListIni)) return false;
2771 OTOpndListIni otherli = (OTOpndListIni) other;
2772 if (otherli.values.Length != values.Length) return false;
2773 for (int i = 0; i < values.Length; i ++) {
2774 if (!values[i].SameAs (otherli.values[i])) return false;
2775 }
2776 return true;
2777 }
2778
2779 public override string PrintableString {
2780 get {
2781 StringBuilder sb = new StringBuilder ();
2782 sb.Append ('[');
2783 for (int i = 0; i < values.Length; i ++) {
2784 if (i > 0) sb.Append (',');
2785 sb.Append (' ');
2786 sb.Append (values[i].PrintableString);
2787 }
2788 sb.Append (" ]");
2789 return sb.ToString ();
2790 }
2791 }
2792 }
2793
2794 /**
2795 * Local variable.
2796 */
2797 private class OTOpndLocal : OTOpnd {
2798 public OTLocal local;
2799
2800 public OTOpndLocal (OTLocal local)
2801 {
2802 this.local = local;
2803 }
2804
2805 public override bool HasSideEffects {
2806 get {
2807 return false;
2808 }
2809 }
2810
2811 public override void CountRefs (bool writing)
2812 {
2813 if (writing) local.nlclwrites ++;
2814 else local.nlclreads ++;
2815 }
2816
2817 public override bool SameAs (OTOpnd other)
2818 {
2819 if (!(other is OTOpndLocal)) return false;
2820 OTOpndLocal otherlocal = (OTOpndLocal) other;
2821 return local == otherlocal.local;
2822 }
2823
2824 public override string PrintableString {
2825 get {
2826 return local.name;
2827 }
2828 }
2829 }
2830 private class OTOpndLocalRef : OTOpnd {
2831 public OTLocal local;
2832
2833 public OTOpndLocalRef (OTLocal local)
2834 {
2835 this.local = local;
2836 }
2837
2838 public override bool HasSideEffects {
2839 get {
2840 return true;
2841 }
2842 }
2843
2844 public override void CountRefs (bool writing)
2845 {
2846 local.nlclreads ++;
2847 local.nlclwrites ++;
2848 }
2849
2850 public override OTOpnd GetNonByRefOpnd ()
2851 {
2852 return new OTOpndLocal (local);
2853 }
2854
2855 public override bool SameAs (OTOpnd other)
2856 {
2857 if (!(other is OTOpndLocal)) return false;
2858 OTOpndLocal otherlocal = (OTOpndLocal) other;
2859 return local == otherlocal.local;
2860 }
2861
2862 public override string PrintableString { get { return "ref " + local.name; } }
2863 }
2864
2865 /**
2866 * New C#-level array.
2867 */
2868 private class OTOpndNewarr : OTOpnd {
2869 public Type type;
2870 public OTOpnd index;
2871
2872 public OTOpndNewarr (Type type, OTOpnd index)
2873 {
2874 this.type = type;
2875 this.index = index;
2876 }
2877
2878 public override bool HasSideEffects {
2879 get {
2880 return index.HasSideEffects;
2881 }
2882 }
2883
2884 public override void CountRefs (bool writing)
2885 {
2886 index.CountRefs (false);
2887 }
2888
2889 public override OTOpnd ReplaceOperand (OTOpnd oldopnd, OTOpnd newopnd, ref bool rc)
2890 {
2891 if (SameAs (oldopnd)) {
2892 rc = true;
2893 return newopnd;
2894 }
2895 index = index.ReplaceOperand (oldopnd, newopnd, ref rc);
2896 return this;
2897 }
2898
2899 public override bool SameAs (OTOpnd other)
2900 {
2901 return false;
2902 }
2903
2904 public override string PrintableString { get { return "newarr " + type.Name + "[" + index.PrintableString + "]"; } }
2905 }
2906
2907 /**
2908 * New C#-level object.
2909 */
2910 private class OTOpndNewobj : OTOpnd {
2911 public ConstructorInfo ctor;
2912 public OTOpnd[] args;
2913
2914 public static OTOpnd Make (ConstructorInfo ctor, OTOpnd[] args)
2915 {
2916 // newobj LSL_Float (x) => x
2917 if ((ctor.DeclaringType == typeof (LSL_Float)) && (args.Length == 1)) {
2918 Type ptype = ctor.GetParameters ()[0].ParameterType;
2919 if (ptype == typeof (string)) {
2920 return new OTOpndCast (typeof (double), args[0]);
2921 }
2922 return args[0];
2923 }
2924
2925 // newobj LSL_Integer (x) => x
2926 if ((ctor.DeclaringType == typeof (LSL_Integer)) && (args.Length == 1)) {
2927 Type ptype = ctor.GetParameters ()[0].ParameterType;
2928 if (ptype == typeof (string)) {
2929 return new OTOpndCast (typeof (int), args[0]);
2930 }
2931 return args[0];
2932 }
2933
2934 // newobj LSL_String (x) => x
2935 if ((ctor.DeclaringType == typeof (LSL_String)) && (args.Length == 1)) {
2936 return args[0];
2937 }
2938
2939 // newobj LSL_Rotation (x, y, z, w) => <x, y, z, w>
2940 if ((ctor.DeclaringType == typeof (LSL_Rotation)) && (args.Length == 4)) {
2941 return new OTOpndRot (args[0], args[1], args[2], args[3]);
2942 }
2943
2944 // newobj LSL_Vector (x, y, z) => <x, y, z>
2945 if ((ctor.DeclaringType == typeof (LSL_Vector)) && (args.Length == 3)) {
2946 return new OTOpndVec (args[0], args[1], args[2]);
2947 }
2948
2949 // newobj LSL_Rotation (string) => (rotation) string
2950 if ((ctor.DeclaringType == typeof (LSL_Rotation)) && (args.Length == 1)) {
2951 return new OTOpndCast (typeof (LSL_Rotation), args[0]);
2952 }
2953
2954 // newobj LSL_Vector (string) => (rotation) string
2955 if ((ctor.DeclaringType == typeof (LSL_Vector)) && (args.Length == 1)) {
2956 return new OTOpndCast (typeof (LSL_Vector), args[0]);
2957 }
2958
2959 // newobj LSL_List (newarr object[0]) => [ ]
2960 if ((ctor.DeclaringType == typeof (LSL_List)) && (args.Length == 1) && (args[0] is OTOpndNewarr)) {
2961 OTOpndNewarr arg0 = (OTOpndNewarr) args[0];
2962 if ((arg0.type == typeof (object)) && (arg0.index is OTOpndInt) && (((OTOpndInt) arg0.index).value == 0)) {
2963 OTOpndListIni listini = new OTOpndListIni ();
2964 listini.values = new OTOpnd[0];
2965 return listini;
2966 }
2967 }
2968
2969 // something else, output as is
2970 OTOpndNewobj it = new OTOpndNewobj ();
2971 it.ctor = ctor;
2972 it.args = args;
2973 return it;
2974 }
2975
2976 private OTOpndNewobj () { }
2977
2978 public override bool HasSideEffects {
2979 get {
2980 foreach (OTOpnd arg in args) {
2981 if (arg.HasSideEffects) return true;
2982 }
2983 return false;
2984 }
2985 }
2986
2987 public override void CountRefs (bool writing)
2988 {
2989 foreach (OTOpnd arg in args) {
2990 arg.CountRefs (false);
2991 }
2992 }
2993
2994 public override OTOpnd ReplaceOperand (OTOpnd oldopnd, OTOpnd newopnd, ref bool rc)
2995 {
2996 if (SameAs (oldopnd)) {
2997 rc = true;
2998 return newopnd;
2999 }
3000 for (int i = 0; i < args.Length; i ++) {
3001 args[i] = args[i].ReplaceOperand (oldopnd, newopnd, ref rc);
3002 }
3003 return this;
3004 }
3005
3006 public override bool SameAs (OTOpnd other)
3007 {
3008 if (!(other is OTOpndNewobj)) return false;
3009 OTOpndNewobj otherno = (OTOpndNewobj) other;
3010 if (otherno.ctor.DeclaringType != ctor.DeclaringType) return false;
3011 if (otherno.args.Length != args.Length) return false;
3012 for (int i = 0; i < args.Length; i ++) {
3013 if (!args[i].SameAs (otherno.args[i])) return false;
3014 }
3015 return true;
3016 }
3017
3018 public override string PrintableString {
3019 get {
3020 StringBuilder sb = new StringBuilder ();
3021 sb.Append ("newobj ");
3022 sb.Append (ctor.DeclaringType.Name);
3023 sb.Append (" (");
3024 bool first = true;
3025 foreach (OTOpnd arg in args) {
3026 if (!first) sb.Append (", ");
3027 sb.Append (arg.PrintableString);
3028 first = false;
3029 }
3030 sb.Append (')');
3031 return sb.ToString ();
3032 }
3033 }
3034 }
3035
3036 /**
3037 * Rotation value.
3038 */
3039 private class OTOpndRot : OTOpnd {
3040 private OTOpnd x, y, z, w;
3041
3042 public OTOpndRot (OTOpnd x, OTOpnd y, OTOpnd z, OTOpnd w)
3043 {
3044 this.x = StripFloatCast (x);
3045 this.y = StripFloatCast (y);
3046 this.z = StripFloatCast (z);
3047 this.w = StripFloatCast (w);
3048 }
3049
3050 public override bool HasSideEffects {
3051 get {
3052 return x.HasSideEffects || y.HasSideEffects || z.HasSideEffects || w.HasSideEffects;
3053 }
3054 }
3055
3056 public override void CountRefs (bool writing)
3057 {
3058 x.CountRefs (false);
3059 y.CountRefs (false);
3060 z.CountRefs (false);
3061 w.CountRefs (false);
3062 }
3063
3064 public override OTOpnd ReplaceOperand (OTOpnd oldopnd, OTOpnd newopnd, ref bool rc)
3065 {
3066 if (SameAs (oldopnd)) {
3067 rc = true;
3068 return newopnd;
3069 }
3070 x = x.ReplaceOperand (oldopnd, newopnd, ref rc);
3071 y = y.ReplaceOperand (oldopnd, newopnd, ref rc);
3072 z = z.ReplaceOperand (oldopnd, newopnd, ref rc);
3073 w = w.ReplaceOperand (oldopnd, newopnd, ref rc);
3074 return this;
3075 }
3076
3077 public override bool SameAs (OTOpnd other)
3078 {
3079 if (!(other is OTOpndRot)) return false;
3080 OTOpndRot otherv = (OTOpndRot) other;
3081 return otherv.x.SameAs (x) && otherv.y.SameAs (y) && otherv.z.SameAs (z) && otherv.w.SameAs (w);
3082 }
3083
3084 public override string PrintableString {
3085 get {
3086 return "<" + x.PrintableString + ", " + y.PrintableString + ", " + z.PrintableString + ", " + w.PrintableString + ">";
3087 }
3088 }
3089 }
3090
3091 /**
3092 * Static field.
3093 */
3094 private class OTOpndSField : OTOpnd {
3095 private FieldInfo field;
3096
3097 public OTOpndSField (FieldInfo field)
3098 {
3099 this.field = field;
3100 }
3101
3102 public override bool HasSideEffects {
3103 get {
3104 return false;
3105 }
3106 }
3107
3108 public override bool SameAs (OTOpnd other)
3109 {
3110 if (!(other is OTOpndSField)) return false;
3111 OTOpndSField othersfield = (OTOpndSField) other;
3112 return (field.Name == othersfield.field.Name) && (field.DeclaringType == othersfield.field.DeclaringType);
3113 }
3114
3115 public override string PrintableString {
3116 get {
3117 if (field.DeclaringType == typeof (ScriptBaseClass)) return field.Name;
3118 return field.DeclaringType.Name + "." + field.Name;
3119 }
3120 }
3121 }
3122
3123 /**
3124 * Call to string.Compare().
3125 * See use cases in BinOpStr:
3126 * strcmp (a, b) ceq 0
3127 * (strcmp (a, b) ceq 0) xor 1 => we translate to: strcmp (a, b) cne 0
3128 * strcmp (a, b) clt 0
3129 * strcmp (a, b) clt 1 // <=
3130 * strcmp (a, b) cgt 0
3131 * strcmp (a, b) cgt -1 // >=
3132 * ...but then optimized by ScriptCollector if followed by br{false,true}:
3133 * ceq + xor 1 + brtrue => bne.un
3134 * ceq + xor 1 + brfalse => beq
3135 * ceq + brtrue => beq
3136 * ceq + brfalse => bne.un
3137 * cgt + brtrue => bgt
3138 * cgt + brfalse => ble
3139 * clt + brtrue => blt
3140 * clt + brfalse => bge
3141 * So we end up with these cases:
3142 * strcmp (a, b) ceq 0
3143 * strcmp (a, b) cne 0
3144 * strcmp (a, b) clt 0
3145 * strcmp (a, b) clt 1
3146 * strcmp (a, b) cgt 0
3147 * strcmp (a, b) cgt -1
3148 * strcmp (a, b) beq 0
3149 * strcmp (a, b) bne.un 0
3150 * strcmp (a, b) bgt 0
3151 * strcmp (a, b) ble 0
3152 * strcmp (a, b) bgt -1
3153 * strcmp (a, b) ble -1
3154 * strcmp (a, b) blt 0
3155 * strcmp (a, b) bge 0
3156 * strcmp (a, b) blt 1
3157 * strcmp (a, b) bge 1
3158 * ... so we pretty them up in OTOpndBinOp
3159 */
3160 private class OTOpndStrCmp : OTOpnd {
3161 private static Dictionary<string,string> binops = InitBinops ();
3162 private static Dictionary<string,string> InitBinops ()
3163 {
3164 Dictionary<string,string> d = new Dictionary<string,string> ();
3165 d["ceq 0"] = "ceq";
3166 d["cne 0"] = "cne";
3167 d["clt 0"] = "clt";
3168 d["clt 1"] = "cle";
3169 d["cgt 0"] = "cgt";
3170 d["cgt -1"] = "cge";
3171 d["beq 0"] = "ceq";
3172 d["bne.un 0"] = "cne";
3173 d["bgt 0"] = "cgt";
3174 d["ble 0"] = "cle";
3175 d["bgt -1"] = "cge";
3176 d["ble -1"] = "clt";
3177 d["blt 0"] = "clt";
3178 d["bge 0"] = "cge";
3179 d["blt 1"] = "cle";
3180 d["bge 1"] = "cgt";
3181 return d;
3182 }
3183
3184 private OTOpnd arg0;
3185 private OTOpnd arg1;
3186
3187 public OTOpndStrCmp (OTOpnd arg0, OTOpnd arg1)
3188 {
3189 this.arg0 = arg0;
3190 this.arg1 = arg1;
3191 }
3192
3193 /**
3194 * Try to make something a script writer would recognize.
3195 * If we can't, then we leave it as a call to xmrStringCompare().
3196 * this = some strcmp(a,b)
3197 * opCode = hopefully some cxx or bxx from above table
3198 * rite = hopefully some constant from above table
3199 */
3200 public OTOpnd MakeBinOp (MyOp opCode, OTOpnd rite)
3201 {
3202 if (!(rite is OTOpndInt)) return null;
3203 int riteint = ((OTOpndInt) rite).value;
3204 string key = opCode.name + ' ' + riteint;
3205 string cxxopname;
3206 if (!binops.TryGetValue (key, out cxxopname)) return null;
3207 return OTOpndBinOp.Make (arg0, MyOp.GetByName (cxxopname), arg1);
3208 }
3209 public OTOpnd MakeUnOp (MyOp opCode)
3210 {
3211 if (opCode == MyOp.Brfalse) return OTOpndBinOp.Make (arg0, MyOp.Ceq, arg1);
3212 if (opCode == MyOp.Brtrue) return OTOpndBinOp.Make (arg0, MyOp.Cne, arg1);
3213 return null;
3214 }
3215
3216 public override bool HasSideEffects {
3217 get {
3218 return false;
3219 }
3220 }
3221
3222 public override void CountRefs (bool writing)
3223 {
3224 arg0.CountRefs (writing);
3225 arg1.CountRefs (writing);
3226 }
3227
3228 public override OTOpnd ReplaceOperand (OTOpnd oldopnd, OTOpnd newopnd, ref bool rc)
3229 {
3230 if (SameAs (oldopnd)) {
3231 rc = true;
3232 return newopnd;
3233 }
3234 arg0 = arg0.ReplaceOperand (oldopnd, newopnd, ref rc);
3235 arg1 = arg1.ReplaceOperand (oldopnd, newopnd, ref rc);
3236 return this;
3237 }
3238
3239 public override bool SameAs (OTOpnd other)
3240 {
3241 if (!(other is OTOpndStrCmp)) return false;
3242 return arg0.SameAs (((OTOpndStrCmp) other).arg0) && arg1.SameAs (((OTOpndStrCmp) other).arg1);
3243 }
3244
3245 public override string PrintableString {
3246 get {
3247 return "xmrStringCompare (" + arg0.PrintableString + ", " + arg1.PrintableString + ")";
3248 }
3249 }
3250 }
3251
3252 /**
3253 * Unary operator.
3254 */
3255 private class OTOpndUnOp : OTOpnd {
3256 public MyOp opCode;
3257 public OTOpnd value;
3258
3259 private static Dictionary<string,string> brfops = InitBrfOps ();
3260 private static Dictionary<string,string> InitBrfOps ()
3261 {
3262 Dictionary<string,string> d = new Dictionary<string,string> ();
3263 d["beq"] = "cne";
3264 d["bge"] = "clt";
3265 d["bgt"] = "cle";
3266 d["ble"] = "cgt";
3267 d["blt"] = "cge";
3268 d["bne.un"] = "ceq";
3269 d["ceq"] = "cne";
3270 d["cge"] = "clt";
3271 d["cgt"] = "cle";
3272 d["cle"] = "cgt";
3273 d["clt"] = "cge";
3274 d["cne"] = "ceq";
3275 return d;
3276 }
3277
3278 public static OTOpnd Make (MyOp opCode, OTOpnd value)
3279 {
3280 // (brfalse (brfalse (x))) => (brtrue (x))
3281 if ((opCode == MyOp.Brfalse) && (value is OTOpndUnOp) && (((OTOpndUnOp) value).opCode == MyOp.Brfalse)) {
3282 ((OTOpndUnOp) value).opCode = MyOp.Brtrue;
3283 return value;
3284 }
3285
3286 // (brfalse (brtrue (x))) => (brfalse (x))
3287 if ((opCode == MyOp.Brfalse) && (value is OTOpndUnOp) && (((OTOpndUnOp) value).opCode == MyOp.Brtrue)) {
3288 ((OTOpndUnOp) value).opCode = MyOp.Brfalse;
3289 return value;
3290 }
3291
3292 // (brtrue (brfalse (x))) => (brfalse (x))
3293 if ((opCode == MyOp.Brtrue) && (value is OTOpndUnOp) && (((OTOpndUnOp) value).opCode == MyOp.Brfalse)) {
3294 return value;
3295 }
3296
3297 // (brtrue (brtrue (x))) => (brtrue (x))
3298 if ((opCode == MyOp.Brtrue) && (value is OTOpndUnOp) && (((OTOpndUnOp) value).opCode == MyOp.Brtrue)) {
3299 return value;
3300 }
3301
3302 // (brfalse (x beq y)) => (x bne y) etc
3303 string brfop;
3304 if ((opCode == MyOp.Brfalse) && (value is OTOpndBinOp) && brfops.TryGetValue (((OTOpndBinOp) value).opCode.name, out brfop)) {
3305 ((OTOpndBinOp) value).opCode = MyOp.GetByName (brfop);
3306 return value;
3307 }
3308
3309 // (brtrue (x beq y)) => (x beq y) etc
3310 if ((opCode == MyOp.Brtrue) && (value is OTOpndBinOp) && brfops.ContainsKey (((OTOpndBinOp) value).opCode.name)) {
3311 return value;
3312 }
3313
3314 // strcmp() can be a special case
3315 if (value is OTOpndStrCmp) {
3316 OTOpnd strcmp = ((OTOpndStrCmp) value).MakeUnOp (opCode);
3317 if (strcmp != null) return strcmp;
3318 }
3319
3320 // nothing special, save opcode and value
3321 OTOpndUnOp it = new OTOpndUnOp ();
3322 it.opCode = opCode;
3323 it.value = value;
3324 return it;
3325 }
3326
3327 private OTOpndUnOp () { }
3328
3329 public override bool HasSideEffects {
3330 get {
3331 return value.HasSideEffects;
3332 }
3333 }
3334
3335 public override void CountRefs (bool writing)
3336 {
3337 value.CountRefs (false);
3338 }
3339
3340 public override OTOpnd ReplaceOperand (OTOpnd oldopnd, OTOpnd newopnd, ref bool rc)
3341 {
3342 if (SameAs (oldopnd)) {
3343 rc = true;
3344 return newopnd;
3345 }
3346 value = value.ReplaceOperand (oldopnd, newopnd, ref rc);
3347 return this;
3348 }
3349
3350 public override bool SameAs (OTOpnd other)
3351 {
3352 if (!(other is OTOpndUnOp)) return false;
3353 OTOpndUnOp otherop = (OTOpndUnOp) other;
3354 return (opCode.ToString () == otherop.opCode.ToString ()) && value.SameAs (otherop.value);
3355 }
3356
3357 public override string PrintableString {
3358 get {
3359 StringBuilder sb = new StringBuilder ();
3360 sb.Append (opCode.source);
3361 sb.Append (' ');
3362 if (value is OTOpndBinOp) sb.Append ('(');
3363 sb.Append (value.PrintableString);
3364 if (value is OTOpndBinOp) sb.Append (')');
3365 return sb.ToString ();
3366 }
3367 }
3368 }
3369
3370 /**
3371 * Vector value.
3372 */
3373 private class OTOpndVec : OTOpnd {
3374 private OTOpnd x, y, z;
3375
3376 public OTOpndVec (OTOpnd x, OTOpnd y, OTOpnd z)
3377 {
3378 this.x = StripFloatCast (x);
3379 this.y = StripFloatCast (y);
3380 this.z = StripFloatCast (z);
3381 }
3382
3383 public override bool HasSideEffects {
3384 get {
3385 return x.HasSideEffects || y.HasSideEffects || z.HasSideEffects;
3386 }
3387 }
3388
3389 public override void CountRefs (bool writing)
3390 {
3391 x.CountRefs (false);
3392 y.CountRefs (false);
3393 z.CountRefs (false);
3394 }
3395
3396 public override OTOpnd ReplaceOperand (OTOpnd oldopnd, OTOpnd newopnd, ref bool rc)
3397 {
3398 if (SameAs (oldopnd)) {
3399 rc = true;
3400 return newopnd;
3401 }
3402 x = x.ReplaceOperand (oldopnd, newopnd, ref rc);
3403 y = y.ReplaceOperand (oldopnd, newopnd, ref rc);
3404 z = z.ReplaceOperand (oldopnd, newopnd, ref rc);
3405 return this;
3406 }
3407
3408 public override bool SameAs (OTOpnd other)
3409 {
3410 if (!(other is OTOpndVec)) return false;
3411 OTOpndVec otherv = (OTOpndVec) other;
3412 return otherv.x.SameAs (x) && otherv.y.SameAs (y) && otherv.z.SameAs (z);
3413 }
3414
3415 public override string PrintableString {
3416 get {
3417 return "<" + x.PrintableString + ", " + y.PrintableString + ", " + z.PrintableString + ">";
3418 }
3419 }
3420 }
3421
3422 /**
3423 * Constants.
3424 */
3425 private class OTOpndDouble : OTOpnd {
3426 public double value;
3427 public OTOpndDouble (double value) { this.value = value; }
3428 public override bool HasSideEffects { get { return false; } }
3429 public override bool SameAs (OTOpnd other)
3430 {
3431 if (!(other is OTOpndDouble)) return false;
3432 return ((OTOpndDouble) other).value == value;
3433 }
3434 public override string PrintableString {
3435 get {
3436 string s = value.ToString ();
3437 long i;
3438 if (long.TryParse (s, out i)) {
3439 s += ".0";
3440 }
3441 return s;
3442 }
3443 }
3444 }
3445 private class OTOpndFloat : OTOpnd {
3446 public float value;
3447 public OTOpndFloat (float value) { this.value = value; }
3448 public override bool HasSideEffects { get { return false; } }
3449 public override bool SameAs (OTOpnd other)
3450 {
3451 if (!(other is OTOpndFloat)) return false;
3452 return ((OTOpndFloat) other).value == value;
3453 }
3454 public override string PrintableString {
3455 get {
3456 string s = value.ToString ();
3457 long i;
3458 if (long.TryParse (s, out i)) {
3459 s += ".0";
3460 }
3461 return s;
3462 }
3463 }
3464 }
3465 private class OTOpndInt : OTOpnd {
3466 public int value;
3467 public OTOpndInt (int value) { this.value = value; }
3468 public override bool HasSideEffects { get { return false; } }
3469 public override bool SameAs (OTOpnd other)
3470 {
3471 if (!(other is OTOpndInt)) return false;
3472 return ((OTOpndInt) other).value == value;
3473 }
3474 public override string PrintableString { get { return value.ToString (); } }
3475 }
3476 private class OTOpndNull : OTOpnd {
3477 public override bool HasSideEffects { get { return false; } }
3478 public override bool SameAs (OTOpnd other)
3479 {
3480 return other is OTOpndNull;
3481 }
3482 public override string PrintableString { get { return "undef"; } }
3483 }
3484 private class OTOpndString : OTOpnd {
3485 public string value;
3486 public OTOpndString (string value) { this.value = value; }
3487 public override bool HasSideEffects { get { return false; } }
3488 public override bool SameAs (OTOpnd other)
3489 {
3490 if (!(other is OTOpndString)) return false;
3491 return ((OTOpndString) other).value == value;
3492 }
3493 public override string PrintableString {
3494 get {
3495 StringBuilder sb = new StringBuilder ();
3496 TokenDeclInline.PrintParamString (sb, value);
3497 return sb.ToString ();
3498 }
3499 }
3500 }
3501
3502 /****************************************\
3503 * Tokens what are in statement list. *
3504 \****************************************/
3505
3506 public abstract class OTStmt {
3507
3508 /**
3509 * Increment reference counts.
3510 */
3511 public abstract void CountRefs ();
3512
3513 /**
3514 * Strip out any of the behind-the-scenes code such as stack capture/restore.
3515 * By default, there is no change.
3516 */
3517 public virtual bool StripStuff (LinkedListNode<OTStmt> link)
3518 {
3519 return false;
3520 }
3521
3522 /**
3523 * Replace the oldopnd operand with the newopnd operand if it is present.
3524 * Return whether or not it was found and replaced.
3525 */
3526 public abstract bool ReplaceOperand (OTOpnd oldopnd, OTOpnd newopnd);
3527
3528 /**
3529 * Detect and modify for do/for/if/while structures.
3530 */
3531 public virtual bool DetectDoForIfWhile (LinkedListNode<OTStmt> link)
3532 {
3533 return false;
3534 }
3535
3536 /**
3537 * If this statement is the old statement, replace it with the given new statement.
3538 * Also search any sub-ordinate statements.
3539 * **NOTE**: minimally implemented to replace a Jump with a Break or Continue
3540 */
3541 public abstract OTStmt ReplaceStatement (OTStmt oldstmt, OTStmt newstmt);
3542
3543 /**
3544 * Print the statement out on the given printer with the given indenting.
3545 * The first line is already indented, subsequent lines must be indented as given.
3546 * This method should leave the printer at the end of the line.
3547 */
3548 public abstract void PrintStmt (TextWriter twout, string indent);
3549
3550 /**
3551 * Strip all statements following this statement
3552 * because this statement jumps somewhere.
3553 */
3554 protected bool StripStuffForTerminal (LinkedListNode<OTStmt> link)
3555 {
3556 // strip all statements following jump until seeing some label
3557 bool rc = false;
3558 if (link != null) {
3559 LinkedListNode<OTStmt> nextlink;
3560 while ((nextlink = link.Next) != null) {
3561 if (nextlink.Value is OTStmtLabel) break;
3562 nextlink.List.Remove (nextlink);
3563 rc = true;
3564 }
3565 }
3566 return rc;
3567 }
3568 }
3569
3570 /**************************\
3571 * Primitive statements *
3572 \**************************/
3573
3574 /**
3575 * Begin catch block (catch).
3576 */
3577 private class OTStmtBegCatBlk : OTStmt {
3578 public OTStmtBegExcBlk tryblock;
3579 public OTStmtBlock catchblock;
3580
3581 private Type excType;
3582
3583 public OTStmtBegCatBlk (Type excType)
3584 {
3585 this.excType = excType;
3586 }
3587
3588 public override void CountRefs ()
3589 {
3590 catchblock.CountRefs ();
3591 }
3592
3593 public override bool StripStuff (LinkedListNode<OTStmt> link)
3594 {
3595 return catchblock.StripStuff (null);
3596 }
3597
3598 public override bool ReplaceOperand (OTOpnd oldopnd, OTOpnd newopnd)
3599 {
3600 return catchblock.ReplaceOperand (oldopnd, newopnd);
3601 }
3602
3603 public override bool DetectDoForIfWhile (LinkedListNode<OTStmt> link)
3604 {
3605 return catchblock.DetectDoForIfWhile (link);
3606 }
3607
3608 public override OTStmt ReplaceStatement (OTStmt oldstmt, OTStmt newstmt)
3609 {
3610 catchblock = (OTStmtBlock) catchblock.ReplaceStatement (oldstmt, newstmt);
3611 return this;
3612 }
3613
3614 /**
3615 * Print out the catch block including its enclosed statements.
3616 */
3617 public override void PrintStmt (TextWriter twout, string indent)
3618 {
3619 twout.Write ("catch (" + excType.Name + ") ");
3620 catchblock.PrintStmt (twout, indent);
3621 }
3622 }
3623
3624 /**
3625 * Begin exception block (try).
3626 */
3627 private class OTStmtBegExcBlk : OTStmt {
3628
3629 // statements within the try { } not including any catch or finally
3630 public OTStmtBlock tryblock;
3631
3632 // list of all catch { } blocks associated with this try { }
3633 public LinkedList<OTStmtBegCatBlk> catches = new LinkedList<OTStmtBegCatBlk> ();
3634
3635 // possible single finally { } associated with this try
3636 public OTStmtBegFinBlk finblock; // might be null
3637
3638 public override void CountRefs ()
3639 {
3640 tryblock.CountRefs ();
3641 foreach (OTStmtBegCatBlk catblock in catches) {
3642 catblock.CountRefs ();
3643 }
3644 if (finblock != null) finblock.CountRefs ();
3645 }
3646
3647 /**
3648 * Strip behind-the-scenes info from all the sub-blocks.
3649 */
3650 public override bool StripStuff (LinkedListNode<OTStmt> link)
3651 {
3652 // strip behind-the-scenes info from all the sub-blocks.
3653 bool rc = tryblock.StripStuff (null);
3654 foreach (OTStmtBegCatBlk catblk in catches) {
3655 rc |= catblk.StripStuff (null);
3656 }
3657 if (finblock != null) rc |= finblock.StripStuff (null);
3658 if (rc) return true;
3659
3660 // change:
3661 // try {
3662 // ...
3663 // }
3664 // to:
3665 // {
3666 // ...
3667 // }
3668 // note that an empty catch () { } has meaning so can't be stripped
3669 // empty finally { } blocks strips itself from the try
3670 if ((catches.Count == 0) && (finblock == null) && (link != null)) {
3671 link.List.AddAfter (link, tryblock);
3672 tryblock = null;
3673 link.List.Remove (link);
3674 return true;
3675 }
3676
3677 return false;
3678 }
3679
3680 public override bool ReplaceOperand (OTOpnd oldopnd, OTOpnd newopnd)
3681 {
3682 bool rc = tryblock.ReplaceOperand (oldopnd, newopnd);
3683 foreach (OTStmtBegCatBlk catblk in catches) {
3684 rc |= catblk.ReplaceOperand (oldopnd, newopnd);
3685 }
3686 if (finblock != null) rc |= finblock.ReplaceOperand (oldopnd, newopnd);
3687 return rc;
3688 }
3689
3690 public override bool DetectDoForIfWhile (LinkedListNode<OTStmt> link)
3691 {
3692 bool rc = tryblock.DetectDoForIfWhile (link);
3693 foreach (OTStmtBegCatBlk catblk in catches) {
3694 rc |= catblk.DetectDoForIfWhile (link);
3695 }
3696 if (finblock != null) rc |= finblock.DetectDoForIfWhile (link);
3697 return rc;
3698 }
3699
3700 /**
3701 * Assume we will never try to replace the try block itself.
3702 * But go through all our sub-ordinates statements.
3703 */
3704 public override OTStmt ReplaceStatement (OTStmt oldstmt, OTStmt newstmt)
3705 {
3706 tryblock = (OTStmtBlock) tryblock.ReplaceStatement (oldstmt, newstmt);
3707 for (LinkedListNode<OTStmtBegCatBlk> catlink = catches.First; catlink != null; catlink = catlink.Next) {
3708 catlink.Value = (OTStmtBegCatBlk) catlink.Value.ReplaceStatement (oldstmt, newstmt);
3709 }
3710 if (finblock != null) finblock = (OTStmtBegFinBlk) finblock.ReplaceStatement (oldstmt, newstmt);
3711 return this;
3712 }
3713
3714 /**
3715 * Print out the try block including its enclosed statements.
3716 * And since the try is the only thing pushed to the outer block,
3717 * we also print out all the catch and finally blocks.
3718 */
3719 public override void PrintStmt (TextWriter twout, string indent)
3720 {
3721 twout.Write ("try ");
3722 tryblock.PrintStmt (twout, indent);
3723 foreach (OTStmtBegCatBlk catblk in catches) {
3724 twout.Write (' ');
3725 catblk.PrintStmt (twout, indent);
3726 }
3727 if (finblock != null) {
3728 twout.Write (' ');
3729 finblock.PrintStmt (twout, indent);
3730 }
3731 }
3732 }
3733
3734 /**
3735 * Begin finally block (finally).
3736 */
3737 private class OTStmtBegFinBlk : OTStmt {
3738 public OTStmtBegExcBlk tryblock;
3739 public OTStmtBlock finblock;
3740
3741 public override void CountRefs ()
3742 {
3743 finblock.CountRefs ();
3744 }
3745
3746 /**
3747 * Strip behind-the-scene parts from the finally block.
3748 */
3749 public override bool StripStuff (LinkedListNode<OTStmt> link)
3750 {
3751 // strip behind-the-scenes parts from finally block itself
3752 if (finblock.StripStuff (null)) return true;
3753
3754 // if finblock is empty, delete the finally from the try
3755 if (finblock.blkstmts.Count == 0) {
3756 tryblock.finblock = null;
3757 return true;
3758 }
3759
3760 return false;
3761 }
3762
3763 public override bool ReplaceOperand (OTOpnd oldopnd, OTOpnd newopnd)
3764 {
3765 return finblock.ReplaceOperand (oldopnd, newopnd);
3766 }
3767
3768 public override bool DetectDoForIfWhile (LinkedListNode<OTStmt> link)
3769 {
3770 return finblock.DetectDoForIfWhile (link);
3771 }
3772
3773 /**
3774 * Assume we will never try to replace the finally block itself.
3775 * But go through all our sub-ordinates statements.
3776 */
3777 public override OTStmt ReplaceStatement (OTStmt oldstmt, OTStmt newstmt)
3778 {
3779 finblock = (OTStmtBlock) finblock.ReplaceStatement (oldstmt, newstmt);
3780 return this;
3781 }
3782
3783 /**
3784 * Print out the finally block including its enclosed statements.
3785 */
3786 public override void PrintStmt (TextWriter twout, string indent)
3787 {
3788 twout.Write ("finally ");
3789 finblock.PrintStmt (twout, indent);
3790 }
3791 }
3792
3793 /**
3794 * Simple if jump/break/continue statement.
3795 */
3796 private class OTStmtCond : OTStmt {
3797 public OTOpnd valu;
3798 public OTStmt stmt; // jump, break, continue only
3799
3800 public OTStmtCond (OTOpnd valu, OTStmt stmt)
3801 {
3802 this.valu = valu;
3803 this.stmt = stmt;
3804 }
3805
3806 public override void CountRefs ()
3807 {
3808 valu.CountRefs (false);
3809 stmt.CountRefs ();
3810 }
3811
3812 public override bool StripStuff (LinkedListNode<OTStmt> link)
3813 {
3814 // we assume that callMode is always CallMode_NORMAL, ie, not doing a stack capture or restore
3815 // so the 'if (arg$0.callMode bne.un 0) ...' is deleted
3816 // and the 'if (arg$0.callMode bne.un 1) ...' becomes unconditional
3817 // it can also be __xmrinst.callMode instead of arg$0
3818 if (valu is OTOpndBinOp) {
3819 OTOpndBinOp binop = (OTOpndBinOp) valu;
3820 if ((binop.left is OTOpndField) && (binop.opCode.ToString () == "bne.un") && (binop.rite is OTOpndInt)) {
3821 OTOpndField leftfield = (OTOpndField) binop.left;
3822 if (leftfield.field.Name == _callMode) {
3823 bool ok = false;
3824 if (leftfield.obj is OTOpndArg) {
3825 ok = ((OTOpndArg) leftfield.obj).index == 0;
3826 }
3827 if (leftfield.obj is OTOpndLocal) {
3828 ok = ((OTOpndLocal) leftfield.obj).local.name.StartsWith (_xmrinstlocal);
3829 }
3830 if (ok) {
3831 OTOpndInt riteint = (OTOpndInt) binop.rite;
3832
3833 // delete 'if ((arg$0).callMode bne.un 0) ...'
3834 if (riteint.value == XMRInstAbstract.CallMode_NORMAL) {
3835 link.List.Remove (link);
3836 return true;
3837 }
3838
3839 // make 'if ((arg$0).callMode bne.un 1) ...' unconditional
3840 if (riteint.value == XMRInstAbstract.CallMode_SAVE) {
3841 link.Value = stmt;
3842 return true;
3843 }
3844 }
3845 }
3846 }
3847 }
3848
3849 // similarly we assume that doGblInit is always 0 to eliminate the code at beginning of default state_entry()
3850 // so the 'if (brfalse __xmrinst.doGblInit) ...' is made unconditional
3851 if (valu is OTOpndUnOp) {
3852 OTOpndUnOp unop = (OTOpndUnOp) valu;
3853 if ((unop.opCode == MyOp.Brfalse) && (unop.value is OTOpndField)) {
3854 OTOpndField valuefield = (OTOpndField) unop.value;
3855 if (valuefield.field.Name == _doGblInit) {
3856 bool ok = false;
3857 if (valuefield.obj is OTOpndLocal) {
3858 ok = ((OTOpndLocal) valuefield.obj).local.name.StartsWith (_xmrinstlocal);
3859 }
3860 if (ok) {
3861
3862 // make 'if (brfalse __xmrinst.doGblInit) ...' unconditional
3863 link.Value = stmt;
3864 return true;
3865 }
3866 }
3867 }
3868 }
3869
3870 return false;
3871 }
3872
3873 public override bool ReplaceOperand (OTOpnd oldopnd, OTOpnd newopnd)
3874 {
3875 bool rc = stmt.ReplaceOperand (oldopnd, newopnd);
3876 valu = valu.ReplaceOperand (oldopnd, newopnd, ref rc);
3877 return rc;
3878 }
3879
3880 /**
3881 * Maybe this simple if statement is part of a script-level if/then/else statement.
3882 */
3883 public override bool DetectDoForIfWhile (LinkedListNode<OTStmt> link)
3884 {
3885 return OTStmtIf.Detect (link);
3886 }
3887
3888 /**
3889 * Assume we won't replace the if statement itself.
3890 * But search all our sub-ordinate statements.
3891 */
3892 public override OTStmt ReplaceStatement (OTStmt oldstmt, OTStmt newstmt)
3893 {
3894 stmt = stmt.ReplaceStatement (oldstmt, newstmt);
3895 return this;
3896 }
3897
3898 public override void PrintStmt (TextWriter twout, string indent)
3899 {
3900 twout.Write ("if (" + StripBrtrue (valu).PrintableString + ") ");
3901 stmt.PrintStmt (twout, indent);
3902 }
3903
3904 /**
3905 * Scan forward for a given label definition.
3906 * Put intervening statements in a statement block.
3907 * @param link = start scanning after this statement
3908 * @param label = look for this label definition
3909 * @param block = where to return intervening statement block
3910 * @returns null: label definition not found
3911 * else: label definition statement
3912 */
3913 private static LinkedListNode<OTStmt> ScanForLabel (LinkedListNode<OTStmt> link,
3914 OTLabel label, out OTStmtBlock block)
3915 {
3916 block = new OTStmtBlock ();
3917 while ((link = link.Next) != null) {
3918 if (link.Value is OTStmtLabel) {
3919 if (((OTStmtLabel) link.Value).label == label) break;
3920 }
3921 block.blkstmts.AddLast (link.Value);
3922 }
3923 return link;
3924 }
3925
3926 /**
3927 * Strip statements after link up to and including donelink.
3928 */
3929 private static void StripInterveningStatements (LinkedListNode<OTStmt> link, LinkedListNode<OTStmt> donelink)
3930 {
3931 LinkedListNode<OTStmt> striplink;
3932 do {
3933 striplink = link.Next;
3934 striplink.List.Remove (striplink);
3935 } while (striplink != donelink);
3936 }
3937 }
3938
3939 /**
3940 * Jump to a label.
3941 */
3942 private class OTStmtJump : OTStmt {
3943 public OTLabel label;
3944
3945 public static OTStmt Make (OTLabel label)
3946 {
3947 // jumps to __retlbl are return statements
3948 // note that is is safe to say it is a valueless return because
3949 // valued returns are done with this construct:
3950 // __retval = ....;
3951 // jump __retlbl;
3952 // and those __retval = statements have been changed to return statements already
3953 if (label.name.StartsWith (_retlbl)) return new OTStmtRet (null);
3954
3955 // other jumps are really jumps
3956 OTStmtJump it = new OTStmtJump ();
3957 it.label = label;
3958 return it;
3959 }
3960
3961 private OTStmtJump () { }
3962
3963 public override void CountRefs ()
3964 {
3965 label.lbljumps ++;
3966 }
3967
3968 public override bool StripStuff (LinkedListNode<OTStmt> link)
3969 {
3970 if (link == null) return false;
3971
3972 // strip statements following unconditional jump until next label
3973 bool rc = StripStuffForTerminal (link);
3974
3975 // if we (now) have:
3976 // jump label;
3977 // @label;
3978 // ... delete this jump
3979 if (link.Next != null) {
3980 OTStmtLabel nextlabel = (OTStmtLabel) link.Next.Value;
3981 if (nextlabel.label == label) {
3982 link.List.Remove (link);
3983 rc = true;
3984 }
3985 }
3986
3987 return rc;
3988 }
3989
3990 public override bool ReplaceOperand (OTOpnd oldopnd, OTOpnd newopnd)
3991 {
3992 return false;
3993 }
3994
3995 /**
3996 * This is actually what ReplaceStatement() is currently used for.
3997 * It replaces a jump with a break or a continue.
3998 */
3999 public override OTStmt ReplaceStatement (OTStmt oldstmt, OTStmt newstmt)
4000 {
4001 if ((oldstmt is OTStmtJump) && (((OTStmtJump) oldstmt).label == label)) return newstmt;
4002 return this;
4003 }
4004
4005 public override void PrintStmt (TextWriter twout, string indent)
4006 {
4007 twout.Write ("jump " + label.PrintableName + ';');
4008 }
4009 }
4010
4011 /**
4012 * Label definition point.
4013 */
4014 private class OTStmtLabel : OTStmt {
4015 public OTLabel label;
4016
4017 private OTDecompile decompile;
4018
4019 public static void AddLast (OTDecompile decompile, OTLabel label)
4020 {
4021 OTStmtLabel it = new OTStmtLabel ();
4022 it.label = label;
4023 it.decompile = decompile;
4024 decompile.AddLastStmt (it);
4025 }
4026
4027 private OTStmtLabel () { }
4028
4029 public override void CountRefs ()
4030 {
4031 // don't increment label.lbljumps
4032 // cuz we don't want the positioning
4033 // to count as a reference, only jumps
4034 // to the label should count
4035 }
4036
4037 public override bool StripStuff (LinkedListNode<OTStmt> link)
4038 {
4039 // if label has nothing jumping to it, remove the label
4040 if (link != null) {
4041 label.lbljumps = 0;
4042 decompile.topBlock.CountRefs ();
4043 if (label.lbljumps == 0) {
4044 link.List.Remove (link);
4045 return true;
4046 }
4047 }
4048
4049 return false;
4050 }
4051
4052 public override bool ReplaceOperand (OTOpnd oldopnd, OTOpnd newopnd)
4053 {
4054 return false;
4055 }
4056
4057 public override bool DetectDoForIfWhile (LinkedListNode<OTStmt> link)
4058 {
4059 if (OTStmtDo.Detect (link)) return true;
4060 if (OTStmtFor.Detect (link, true)) return true;
4061 if (OTStmtFor.Detect (link, false)) return true;
4062 return false;
4063 }
4064
4065 public override OTStmt ReplaceStatement (OTStmt oldstmt, OTStmt newstmt)
4066 {
4067 return this;
4068 }
4069
4070 public override void PrintStmt (TextWriter twout, string indent)
4071 {
4072 twout.Write ("@" + label.PrintableName + ';');
4073 }
4074 }
4075
4076 /**
4077 * Return with or without value.
4078 */
4079 private class OTStmtRet : OTStmt {
4080 public OTOpnd value; // might be null
4081
4082 public OTStmtRet (OTOpnd value)
4083 {
4084 this.value = value;
4085 }
4086
4087 public override void CountRefs ()
4088 {
4089 if (value != null) value.CountRefs (false);
4090 }
4091
4092 public override bool StripStuff (LinkedListNode<OTStmt> link)
4093 {
4094 return StripStuffForTerminal (link);
4095 }
4096
4097 public override bool ReplaceOperand (OTOpnd oldopnd, OTOpnd newopnd)
4098 {
4099 bool rc = false;
4100 if (value != null) value = value.ReplaceOperand (oldopnd, newopnd, ref rc);
4101 return rc;
4102 }
4103
4104 public override OTStmt ReplaceStatement (OTStmt oldstmt, OTStmt newstmt)
4105 {
4106 return this;
4107 }
4108
4109 public override void PrintStmt (TextWriter twout, string indent)
4110 {
4111 if (value == null) {
4112 twout.Write ("return;");
4113 } else {
4114 twout.Write ("return " + value.PrintableString + ';');
4115 }
4116 }
4117 }
4118
4119 /**
4120 * Store value in variable.
4121 */
4122 private class OTStmtStore : OTStmt {
4123 public OTOpnd varwr;
4124 public OTOpnd value;
4125
4126 private OTDecompile decompile;
4127
4128 public static void AddLast (OTDecompile decompile, OTOpnd varwr, OTOpnd value)
4129 {
4130 OTStmtStore it = new OTStmtStore (varwr, value, decompile);
4131 decompile.AddLastStmt (it);
4132 }
4133
4134 public OTStmtStore (OTOpnd varwr, OTOpnd value, OTDecompile decompile)
4135 {
4136 this.varwr = varwr;
4137 this.value = value;
4138 this.decompile = decompile;
4139 }
4140
4141 public override void CountRefs ()
4142 {
4143 varwr.CountRefs (true);
4144 value.CountRefs (false);
4145 }
4146
4147 public override bool StripStuff (LinkedListNode<OTStmt> link)
4148 {
4149 // strip out stores to __mainCallNo
4150 if (varwr is OTOpndLocal) {
4151 OTOpndLocal local = (OTOpndLocal) varwr;
4152 if (local.local.name.StartsWith (_mainCallNo)) {
4153 link.List.Remove (link);
4154 return true;
4155 }
4156 }
4157
4158 // strip out stores to local vars where the var is not read
4159 // but convert the value to an OTStmtVoid in case it is a call
4160 if (varwr is OTOpndLocal) {
4161 OTOpndLocal local = (OTOpndLocal) varwr;
4162 local.local.nlclreads = 0;
4163 decompile.topBlock.CountRefs ();
4164 if (local.local.nlclreads == 0) {
4165 OTStmt voidstmt = OTStmtVoid.Make (value);
4166 if (voidstmt == null) link.List.Remove (link);
4167 else link.Value = voidstmt;
4168 return true;
4169 }
4170 }
4171
4172 // strip out bla = newobj HeapTrackerList (...);
4173 if (value is OTOpndNewobj) {
4174 OTOpndNewobj valueno = (OTOpndNewobj) value;
4175 if (valueno.ctor.DeclaringType == typeof (HeapTrackerList)) {
4176 link.List.Remove (link);
4177 return true;
4178 }
4179 }
4180
4181 // strip out bla = newobj HeapTrackerObject (...);
4182 if (value is OTOpndNewobj) {
4183 OTOpndNewobj valueno = (OTOpndNewobj) value;
4184 if (valueno.ctor.DeclaringType == typeof (HeapTrackerObject)) {
4185 link.List.Remove (link);
4186 return true;
4187 }
4188 }
4189
4190 // strip out bla = newobj HeapTrackerString (...);
4191 if (value is OTOpndNewobj) {
4192 OTOpndNewobj valueno = (OTOpndNewobj) value;
4193 if (valueno.ctor.DeclaringType == typeof (HeapTrackerString)) {
4194 link.List.Remove (link);
4195 return true;
4196 }
4197 }
4198
4199 // convert tmp$n = bla bla;
4200 // .... tmp$n ....;
4201 // to
4202 // .... bla bla ....;
4203 // gets rid of vast majority of temps
4204 if (varwr is OTOpndLocal) {
4205 OTOpndLocal temp = (OTOpndLocal) varwr;
4206 if (temp.local.name.StartsWith ("tmp$")) {
4207 temp.local.nlclreads = 0;
4208 temp.local.nlclwrites = 0;
4209 decompile.topBlock.CountRefs ();
4210 if ((temp.local.nlclreads == 1) && (temp.local.nlclwrites == 1) && (link.Next != null)) {
4211 OTStmt nextstmt = link.Next.Value;
4212 if (!(nextstmt is OTStmtBlock)) {
4213 if (nextstmt.ReplaceOperand (varwr, value)) {
4214 link.List.Remove (link);
4215 return true;
4216 }
4217 }
4218 }
4219
4220 // also try to convert:
4221 // tmp$n = ... asdf ... << we are here (link)
4222 // lcl = tmp$n; << nextstore
4223 // ... qwer tmp$n ...
4224 // ... no further references to tmp$n
4225 // to:
4226 // lcl = ... asdf ...
4227 // ... qwer lcl ...
4228 if ((temp.local.nlclreads == 2) && (temp.local.nlclwrites == 1) &&
4229 (link.Next != null) && (link.Next.Value is OTStmtStore)) {
4230 OTStmtStore nextstore = (OTStmtStore) link.Next.Value;
4231 if ((nextstore.varwr is OTOpndLocal) && (nextstore.value is OTOpndLocal) && (link.Next.Next != null)) {
4232 OTOpndLocal localopnd = (OTOpndLocal) nextstore.varwr;
4233 OTOpndLocal tempopnd = (OTOpndLocal) nextstore.value;
4234 if (tempopnd.local == temp.local) {
4235 OTStmt finalstmt = link.Next.Next.Value;
4236 if (finalstmt.ReplaceOperand (tempopnd, localopnd)) {
4237 nextstore.value = value;
4238 link.List.Remove (link);
4239 return true;
4240 }
4241 }
4242 }
4243 }
4244 }
4245 }
4246
4247 // convert:
4248 // dup$n = ... asdf ... << we are here
4249 // lcl = dup$n;
4250 // ... qwer dup$n ...
4251 // ... no further references to dup$n
4252 // to:
4253 // lcl = ... asdf ...
4254 // ... qwer lcl ...
4255 if ((varwr is OTOpndDup) && (link != null)) {
4256 OTOpndDup vardup = (OTOpndDup) varwr;
4257 LinkedListNode<OTStmt> nextlink = link.Next;
4258 vardup.ndupreads = 0;
4259 decompile.topBlock.CountRefs ();
4260 if ((vardup.ndupreads == 2) && (nextlink != null) && (nextlink.Value is OTStmtStore)) {
4261
4262 // point to the supposed lcl = dup$n statement
4263 OTStmtStore nextstore = (OTStmtStore) nextlink.Value;
4264 LinkedListNode<OTStmt> nextlink2 = nextlink.Next;
4265 if ((nextstore.varwr is OTOpndLocal) && (nextstore.value == vardup) && (nextlink2 != null)) {
4266
4267 // get the local var being written and point to the ... qwer dup$n ... statement
4268 OTOpndLocal varlcl = (OTOpndLocal) nextstore.varwr;
4269 OTStmt nextstmt2 = nextlink2.Value;
4270
4271 // try to replace dup$n in qwer with lcl
4272 if (nextstmt2.ReplaceOperand (vardup, varlcl)) {
4273
4274 // successful, replace dup$n in asdf with lcl
4275 // and delete the lcl = dup$n statement
4276 varwr = varlcl;
4277 nextlink.List.Remove (nextlink);
4278 return true;
4279 }
4280 }
4281 }
4282 }
4283
4284 // convert:
4285 // dup$n = ... asdf ... << we are here
4286 // ... qwer dup$n ...
4287 // ... no further references to dup$n
4288 // to:
4289 // ... qwer ... asdf ... ...
4290 if ((varwr is OTOpndDup) && (link != null)) {
4291 OTOpndDup vardup = (OTOpndDup) varwr;
4292 LinkedListNode<OTStmt> nextlink = link.Next;
4293 vardup.ndupreads = 0;
4294 decompile.topBlock.CountRefs ();
4295 if ((vardup.ndupreads == 1) && (nextlink != null)) {
4296
4297 // point to the ... qwer dup$n ... statement
4298 OTStmt nextstmt = nextlink.Value;
4299
4300 // try to replace dup$n in qwer with ... asdf ...
4301 if (nextstmt.ReplaceOperand (vardup, value)) {
4302
4303 // successful, delete the dup$n = ... asdf ... statement
4304 link.List.Remove (link);
4305 return true;
4306 }
4307 }
4308 }
4309
4310 // look for list initialization [ ... ]
4311 if (OTOpndListIni.Detect (link)) return true;
4312
4313 // __xmrinst = (XMRInstAbstract) arg$0 indicates this is an event handler
4314 // so strip it out and set the flag
4315 if ((varwr is OTOpndLocal) && (value is OTOpndCast)) {
4316 OTOpndLocal lcl = (OTOpndLocal) varwr;
4317 OTOpndCast cast = (OTOpndCast) value;
4318 if (lcl.local.name.StartsWith (_xmrinstlocal) && (cast.value is OTOpndArg)) {
4319 link.List.Remove (link);
4320 return true;
4321 }
4322 }
4323
4324 // local = [ (optional cast) ] __xmrinst.ehArgs[n] is a definition of event handler arg #n
4325 // if found, make it event handler arg list definition
4326 OTOpnd valuenocast = value;
4327 if (valuenocast is OTOpndCast) valuenocast = ((OTOpndCast) value).value;
4328 if ((varwr is OTOpndLocal) && (valuenocast is OTOpndArrayElem)) {
4329 OTOpndArrayElem array = (OTOpndArrayElem) valuenocast;
4330 if ((array.array is OTOpndField) && (array.index is OTOpndInt)) {
4331 OTOpndField arrayfield = (OTOpndField) array.array;
4332 if ((arrayfield.obj is OTOpndLocal) &&
4333 ((OTOpndLocal) arrayfield.obj).local.name.StartsWith (_xmrinstlocal) &&
4334 (arrayfield.field.Name == _ehArgs)) {
4335 int index = ((OTOpndInt) array.index).value;
4336 decompile.eharglist[index] = ((OTOpndLocal) varwr).local;
4337 link.List.Remove (link);
4338 return true;
4339 }
4340 }
4341 }
4342
4343 // __retval$n = ...; => return ...;
4344 if (varwr is OTOpndLocal) {
4345 OTOpndLocal lcl = (OTOpndLocal) varwr;
4346 if (lcl.local.name.StartsWith (_retval)) {
4347 link.Value = new OTStmtRet (value);
4348 return true;
4349 }
4350 }
4351
4352 return false;
4353 }
4354
4355 public override bool ReplaceOperand (OTOpnd oldopnd, OTOpnd newopnd)
4356 {
4357 bool rc = false;
4358 if (value != null) value = value.ReplaceOperand (oldopnd, newopnd, ref rc);
4359 return rc;
4360 }
4361
4362 public override OTStmt ReplaceStatement (OTStmt oldstmt, OTStmt newstmt)
4363 {
4364 return this;
4365 }
4366
4367 public override void PrintStmt (TextWriter twout, string indent)
4368 {
4369 // print x = x + 1 as x += 1, but don't print x = x < 3 as x <= 3
4370 if (value is OTOpndBinOp) {
4371 OTOpndBinOp valuebo = (OTOpndBinOp) value;
4372 if (varwr.SameAs (valuebo.left) && " add and div mul or rem shl shr sub xor ".Contains (' ' + valuebo.opCode.name + ' ')) {
4373 twout.Write (varwr.PrintableString + ' ' + valuebo.opCode.source + "= " + valuebo.rite.PrintableString + ';');
4374 return;
4375 }
4376 }
4377
4378 twout.Write (varwr.PrintableString + " = " + value.PrintableString + ';');
4379 }
4380 }
4381
4382 /**
4383 * Dispatch to a table of labels.
4384 */
4385 private class OTStmtSwitch : OTStmt {
4386 private OTOpnd index;
4387 private OTLabel[] labels;
4388
4389 public OTStmtSwitch (OTOpnd index, OTLabel[] labels)
4390 {
4391 this.index = index;
4392 this.labels = labels;
4393 }
4394
4395 public override void CountRefs ()
4396 {
4397 index.CountRefs (false);
4398 foreach (OTLabel label in labels) {
4399 label.lbljumps ++;
4400 }
4401 }
4402
4403 public override bool ReplaceOperand (OTOpnd oldopnd, OTOpnd newopnd)
4404 {
4405 bool rc = false;
4406 if (index != null) index = index.ReplaceOperand (oldopnd, newopnd, ref rc);
4407 return rc;
4408 }
4409
4410 public override OTStmt ReplaceStatement (OTStmt oldstmt, OTStmt newstmt)
4411 {
4412 return this;
4413 }
4414
4415 public override void PrintStmt (TextWriter twout, string indent)
4416 {
4417 twout.Write ("switch (" + index.PrintableString + ") {\n");
4418 for (int i = 0; i < labels.Length; i ++) {
4419 twout.Write (indent + INDENT + "case " + i + ": jump " + labels[i].name + ";\n");
4420 }
4421 twout.Write (indent + '}');
4422 }
4423 }
4424
4425 /**
4426 * Throw an exception.
4427 */
4428 private class OTStmtThrow : OTStmt {
4429 private OTOpnd value;
4430 private OTDecompile decompile;
4431
4432 public OTStmtThrow (OTOpnd value, OTDecompile decompile)
4433 {
4434 this.value = value;
4435 this.decompile = decompile;
4436 }
4437
4438 public override void CountRefs ()
4439 {
4440 value.CountRefs (false);
4441 }
4442
4443 public override bool StripStuff (LinkedListNode<OTStmt> link)
4444 {
4445 return StripStuffForTerminal (link);
4446 }
4447
4448 public override bool ReplaceOperand (OTOpnd oldopnd, OTOpnd newopnd)
4449 {
4450 bool rc = false;
4451 if (value != null) value = value.ReplaceOperand (oldopnd, newopnd, ref rc);
4452 return rc;
4453 }
4454
4455 public override OTStmt ReplaceStatement (OTStmt oldstmt, OTStmt newstmt)
4456 {
4457 return this;
4458 }
4459
4460 public override void PrintStmt (TextWriter twout, string indent)
4461 {
4462 // throw newobj ScriptUndefinedStateException ("x") => state x
4463 if (value is OTOpndNewobj) {
4464 OTOpndNewobj valueno = (OTOpndNewobj) value;
4465 if ((valueno.ctor.DeclaringType == typeof (ScriptUndefinedStateException)) &&
4466 (valueno.args.Length == 1) && (valueno.args[0] is OTOpndString)) {
4467 OTOpndString arg0 = (OTOpndString) valueno.args[0];
4468 twout.Write ("state " + arg0.value + "; /* throws undefined state exception */");
4469 return;
4470 }
4471 }
4472
4473 // throw newobj ScriptChangeStateException (n) => state n
4474 if (value is OTOpndNewobj) {
4475 OTOpndNewobj valueno = (OTOpndNewobj) value;
4476 if ((valueno.ctor.DeclaringType == typeof (ScriptChangeStateException)) &&
4477 (valueno.args.Length == 1) && (valueno.args[0] is OTOpndInt)) {
4478 OTOpndInt arg0 = (OTOpndInt) valueno.args[0];
4479 twout.Write ("state " + decompile.scriptObjCode.stateNames[arg0.value] + ';');
4480 return;
4481 }
4482 }
4483
4484 // throwing something else, output as is
4485 twout.Write ("throw " + value.PrintableString + ';');
4486 }
4487 }
4488
4489 /**
4490 * Call with void return, or really anything that we discard the value of after computing it.
4491 */
4492 private class OTStmtVoid : OTStmt {
4493 private OTOpnd value;
4494
4495 public static void AddLast (OTDecompile decompile, OTOpnd value)
4496 {
4497 OTStmt it = OTStmtVoid.Make (value);
4498 if (it != null) decompile.AddLastStmt (it);
4499 }
4500
4501 public static OTStmt Make (OTOpnd value)
4502 {
4503 if (!value.HasSideEffects) return null;
4504 OTStmtVoid it = new OTStmtVoid ();
4505 it.value = value;
4506 return it;
4507 }
4508
4509 private OTStmtVoid () { }
4510
4511 public override void CountRefs ()
4512 {
4513 value.CountRefs (false);
4514 }
4515
4516 public override bool ReplaceOperand (OTOpnd oldopnd, OTOpnd newopnd)
4517 {
4518 bool rc = false;
4519 value = value.ReplaceOperand (oldopnd, newopnd, ref rc);
4520 return rc;
4521 }
4522
4523 public override bool StripStuff (LinkedListNode<OTStmt> link)
4524 {
4525 // strip out calls to CheckRunQuick() and CheckRunStack()
4526 if (value is OTOpndCall) {
4527 OTOpndCall call = (OTOpndCall) value;
4528 MethodInfo method = call.method;
4529 if ((method.Name == _checkRunQuick) || (method.Name == _checkRunStack)) {
4530 link.List.Remove (link);
4531 return true;
4532 }
4533 }
4534
4535 return false;
4536 }
4537
4538 public override OTStmt ReplaceStatement (OTStmt oldstmt, OTStmt newstmt)
4539 {
4540 return this;
4541 }
4542
4543 public override void PrintStmt (TextWriter twout, string indent)
4544 {
4545 twout.Write (value.PrintableString + ';');
4546 }
4547 }
4548
4549 /***************************\
4550 * Structured statements *
4551 \***************************/
4552
4553 /**
4554 * Block of statements.
4555 */
4556 private class OTStmtBlock : OTStmt {
4557 public LinkedList<OTStmt> blkstmts = new LinkedList<OTStmt> ();
4558
4559 public override void CountRefs ()
4560 {
4561 foreach (OTStmt stmt in blkstmts) {
4562 stmt.CountRefs ();
4563 }
4564 }
4565
4566 /**
4567 * Scrub out all references to behind-the-scenes parts and simplify.
4568 */
4569 public override bool StripStuff (LinkedListNode<OTStmt> link)
4570 {
4571 // loop through all sub-statements to strip out behind-the-scenes references
4572 bool rc = false;
4573 loop:
4574 for (LinkedListNode<OTStmt> stmtlink = blkstmts.First; stmtlink != null; stmtlink = stmtlink.Next) {
4575 if (stmtlink.Value.StripStuff (stmtlink)) {
4576 rc = true;
4577 goto loop;
4578 }
4579 }
4580 if (rc) return true;
4581
4582 // try to merge this block into outer block
4583 // change:
4584 // {
4585 // ...
4586 // { << link points here
4587 // ...
4588 // }
4589 // ...
4590 // }
4591 // to:
4592 // {
4593 // ...
4594 // ...
4595 // ...
4596 // }
4597 if (link != null) {
4598 LinkedListNode<OTStmt> nextlink;
4599 while ((nextlink = blkstmts.Last) != null) {
4600 nextlink.List.Remove (nextlink);
4601 link.List.AddAfter (link, nextlink);
4602 }
4603 link.List.Remove (link);
4604 return true;
4605 }
4606
4607 return rc;
4608 }
4609
4610 public override bool ReplaceOperand (OTOpnd oldopnd, OTOpnd newopnd)
4611 {
4612 bool rc = false;
4613 foreach (OTStmt stmt in blkstmts) {
4614 rc |= stmt.ReplaceOperand (oldopnd, newopnd);
4615 }
4616 return rc;
4617 }
4618
4619 /**
4620 * Check each statement in the block to see if it starts a do/for/if/while statement.
4621 */
4622 public override bool DetectDoForIfWhile (LinkedListNode<OTStmt> link)
4623 {
4624 bool rc = false;
4625 loop:
4626 for (link = blkstmts.First; link != null; link = link.Next) {
4627 if (link.Value.DetectDoForIfWhile (link)) {
4628 rc = true;
4629 goto loop;
4630 }
4631 }
4632 return rc;
4633 }
4634
4635 /**
4636 * Assume we will never try to replace the block itself.
4637 * But go through all our sub-ordinates statements.
4638 */
4639 public override OTStmt ReplaceStatement (OTStmt oldstmt, OTStmt newstmt)
4640 {
4641 for (LinkedListNode<OTStmt> childlink = blkstmts.First; childlink != null; childlink = childlink.Next) {
4642 childlink.Value = childlink.Value.ReplaceStatement (oldstmt, newstmt);
4643 }
4644 return this;
4645 }
4646
4647 /**
4648 * Print out the block including its enclosed statements.
4649 */
4650 public override void PrintStmt (TextWriter twout, string indent)
4651 {
4652 switch (blkstmts.Count) {
4653 case 0: {
4654 twout.Write ("{ }");
4655 break;
4656 }
4657 ////case 1: {
4658 //// blkstmts.First.Value.PrintStmt (twout, indent);
4659 //// break;
4660 ////}
4661 default: {
4662 twout.Write ('{');
4663 PrintBodyAndEnd (twout, indent);
4664 break;
4665 }
4666 }
4667 }
4668
4669 public void PrintBodyAndEnd (TextWriter twout, string indent)
4670 {
4671 string newindent = indent + INDENT;
4672 foreach (OTStmt stmt in blkstmts) {
4673 twout.Write ('\n' + indent);
4674 if (!(stmt is OTStmtLabel)) twout.Write (INDENT);
4675 else twout.Write (LABELINDENT);
4676 stmt.PrintStmt (twout, newindent);
4677 }
4678 twout.Write ('\n' + indent + '}');
4679 }
4680 }
4681
4682 /**
4683 * 'do' statement.
4684 */
4685 private class OTStmtDo : OTStmt {
4686 private OTOpnd dotest;
4687 private OTStmtBlock dobody;
4688
4689 /**
4690 * See if we have a do loop...
4691 * @doloop_<suffix>; << link points here
4692 * ... <dobody> ...
4693 * [ if (dotest) ] jump doloop_<suffix>;
4694 */
4695 public static bool Detect (LinkedListNode<OTStmt> link)
4696 {
4697 // see if we have label starting with 'doloop_'
4698 OTLabel looplabel = ((OTStmtLabel) link.Value).label;
4699 if (!looplabel.name.StartsWith (_doLoop)) return false;
4700
4701 // good chance we have a do loop
4702 OTStmtDo it = new OTStmtDo ();
4703
4704 // scan ahead looking for the terminating cond/jump loop
4705 // also gather up the statements for the do body block
4706 it.dobody = new OTStmtBlock ();
4707 LinkedListNode<OTStmt> nextlink;
4708 for (nextlink = link.Next; nextlink != null; nextlink = nextlink.Next) {
4709 OTStmt nextstmt = nextlink.Value;
4710
4711 // add statement to do body
4712 it.dobody.blkstmts.AddLast (nextlink.Value);
4713
4714 // check for something what jumps to loop label
4715 // that gives us the end of the loop
4716 OTStmt maybejump = nextstmt;
4717 if (nextstmt is OTStmtCond) {
4718 maybejump = ((OTStmtCond) nextstmt).stmt;
4719 }
4720 if ((maybejump is OTStmtJump) && (((OTStmtJump) maybejump).label == looplabel)) {
4721 break;
4722 }
4723 }
4724
4725 // make sure we found the jump back to the loop label
4726 if (nextlink == null) return false;
4727
4728 // remove all statements from caller's block including the continue label if any
4729 // but leave the break label alone it will be removed later if unreferenced
4730 // and leave the initial loop label intact for now
4731 for (LinkedListNode<OTStmt> remlink = null; (remlink = link.Next) != null;) {
4732 link.List.Remove (remlink);
4733 if (remlink == nextlink) break;
4734 }
4735
4736 // take test condition from last statement of body
4737 // it should be an cond/jump or just a jump to the loop label
4738 LinkedListNode<OTStmt> lastlink = it.dobody.blkstmts.Last;
4739 OTStmt laststmt = lastlink.Value;
4740 if (laststmt is OTStmtCond) {
4741 it.dotest = ((OTStmtCond) laststmt).valu;
4742 } else {
4743 it.dotest = new OTOpndInt (1);
4744 }
4745 lastlink.List.Remove (lastlink);
4746
4747 // finally replace the loop label with the whole do statement
4748 link.Value = it;
4749
4750 // tell caller we made a change
4751 return true;
4752 }
4753
4754 public override void CountRefs ()
4755 {
4756 if (dotest != null) dotest.CountRefs (false);
4757 if (dobody != null) dobody.CountRefs ();
4758 }
4759
4760 public override bool ReplaceOperand (OTOpnd oldopnd, OTOpnd newopnd)
4761 {
4762 return dobody.ReplaceOperand (oldopnd, newopnd);
4763 }
4764
4765 public override bool DetectDoForIfWhile (LinkedListNode<OTStmt> link)
4766 {
4767 return dobody.DetectDoForIfWhile (link);
4768 }
4769
4770 /**
4771 * Assume we won't replace the do statement itself.
4772 * But search all our sub-ordinate statements.
4773 */
4774 public override OTStmt ReplaceStatement (OTStmt oldstmt, OTStmt newstmt)
4775 {
4776 dobody = (OTStmtBlock) dobody.ReplaceStatement (oldstmt, newstmt);
4777 return this;
4778 }
4779
4780 public override void PrintStmt (TextWriter twout, string indent)
4781 {
4782 // output do body
4783 twout.Write ("do ");
4784 dobody.PrintStmt (twout, indent);
4785
4786 // output while part
4787 twout.Write (" while (" + StripBrtrue (dotest).PrintableString + ");");
4788 }
4789 }
4790
4791 /**
4792 * 'for' or 'while' statement.
4793 */
4794 private class OTStmtFor : OTStmt {
4795 private bool iswhile;
4796 private OTOpnd fortest;
4797 private OTStmtBlock forbody;
4798 private OTStmt forinit;
4799 private OTStmt forstep;
4800
4801 /**
4802 * See if we have a for or while loop...
4803 * <forinit>
4804 * @forloop_<suffix>; << link points here
4805 * [ if (<fortest>) jump forbreak_<suffix>; ]
4806 * ... <forbody> ...
4807 * jump forloop_<suffix>;
4808 * [ @forbreak_<suffix>; ]
4809 */
4810 public static bool Detect (LinkedListNode<OTStmt> link, bool iswhile)
4811 {
4812 string loopname = iswhile ? _whileLoop : _forLoop;
4813 string breakname = iswhile ? _whileBreak : _forBreak;
4814
4815 // see if we have label starting with 'forloop_'
4816 OTLabel looplabel = ((OTStmtLabel) link.Value).label;
4817 if (!looplabel.name.StartsWith (loopname)) return false;
4818
4819 // good chance we have a for loop
4820 OTStmtFor it = new OTStmtFor ();
4821 it.iswhile = iswhile;
4822
4823 // all labels end with this suffix
4824 string suffix = looplabel.name.Substring (loopname.Length);
4825
4826 // scan ahead looking for the 'jump forloop_<suffix>;' statement
4827 // also gather up the statements for the for body block
4828 it.forbody = new OTStmtBlock ();
4829 LinkedListNode<OTStmt> lastlink;
4830 for (lastlink = link; (lastlink = lastlink.Next) != null;) {
4831
4832 // check for jump forloop that tells us where loop ends
4833 if (lastlink.Value is OTStmtJump) {
4834 OTStmtJump lastjump = (OTStmtJump) lastlink.Value;
4835 if (lastjump.label == looplabel) break;
4836 }
4837
4838 // add to body block
4839 it.forbody.blkstmts.AddLast (lastlink.Value);
4840 }
4841
4842 // make sure we found the 'jump forloop' where the for loop ends
4843 if (lastlink == null) return false;
4844
4845 // remove all statements from caller's block including final jump
4846 // but leave the loop label in place
4847 for (LinkedListNode<OTStmt> nextlink = null; (nextlink = link.Next) != null;) {
4848 link.List.Remove (nextlink);
4849 if (nextlink == lastlink) break;
4850 }
4851
4852 // if statement before loop label is an assignment, use it for the init statement
4853 if (!iswhile && (link.Previous != null) && (link.Previous.Value is OTStmtStore)) {
4854 it.forinit = link.Previous.Value;
4855 link.List.Remove (link.Previous);
4856 }
4857
4858 // if first statement of for body is 'if (...) jump breaklabel' use it for the test value
4859 if ((it.forbody.blkstmts.First != null) && (it.forbody.blkstmts.First.Value is OTStmtCond)) {
4860 OTStmtCond condstmt = (OTStmtCond) it.forbody.blkstmts.First.Value;
4861 if ((condstmt.stmt is OTStmtJump) && (((OTStmtJump) condstmt.stmt).label.name == breakname + suffix)) {
4862 it.fortest = OTOpndUnOp.Make (MyOp.Brfalse, condstmt.valu);
4863 it.forbody.blkstmts.RemoveFirst ();
4864 }
4865 }
4866
4867 // if last statement of body is an assigment,
4868 // use the assignment as the step statement
4869 if (!iswhile && (it.forbody.blkstmts.Last != null) &&
4870 (it.forbody.blkstmts.Last.Value is OTStmtStore)) {
4871 LinkedListNode<OTStmt> storelink = it.forbody.blkstmts.Last;
4872 storelink.List.Remove (storelink);
4873 it.forstep = storelink.Value;
4874 }
4875
4876 // finally replace the loop label with the whole for statement
4877 link.Value = it;
4878
4879 // tell caller we made a change
4880 return true;
4881 }
4882
4883 public override void CountRefs ()
4884 {
4885 if (fortest != null) fortest.CountRefs (false);
4886 if (forbody != null) forbody.CountRefs ();
4887 if (forinit != null) forinit.CountRefs ();
4888 if (forstep != null) forstep.CountRefs ();
4889 }
4890
4891 public override bool ReplaceOperand (OTOpnd oldopnd, OTOpnd newopnd)
4892 {
4893 return forbody.ReplaceOperand (oldopnd, newopnd) |
4894 ((forinit != null) && forinit.ReplaceOperand (oldopnd, newopnd)) |
4895 ((forstep != null) && forstep.ReplaceOperand (oldopnd, newopnd));
4896 }
4897
4898 public override bool DetectDoForIfWhile (LinkedListNode<OTStmt> link)
4899 {
4900 return forbody.DetectDoForIfWhile (link) |
4901 ((forinit != null) && forinit.DetectDoForIfWhile (link)) |
4902 ((forstep != null) && forstep.DetectDoForIfWhile (link));
4903 }
4904
4905 /**
4906 * Assume we won't replace the for statement itself.
4907 * But search all our sub-ordinate statements.
4908 */
4909 public override OTStmt ReplaceStatement (OTStmt oldstmt, OTStmt newstmt)
4910 {
4911 forbody = (OTStmtBlock) forbody.ReplaceStatement (oldstmt, newstmt);
4912 if (forinit != null) forinit = forinit.ReplaceStatement (oldstmt, newstmt);
4913 if (forstep != null) forstep = forstep.ReplaceStatement (oldstmt, newstmt);
4914 return this;
4915 }
4916
4917 public override void PrintStmt (TextWriter twout, string indent)
4918 {
4919 if (iswhile) {
4920 twout.Write ("while (");
4921 if (fortest == null) {
4922 twout.Write ("TRUE");
4923 } else {
4924 twout.Write (StripBrtrue (fortest).PrintableString);
4925 }
4926 } else {
4927 twout.Write ("for (");
4928 if (forinit != null) {
4929 forinit.PrintStmt (twout, indent + INDENT);
4930 } else {
4931 twout.Write (';');
4932 }
4933 if (fortest != null) {
4934 twout.Write (' ' + StripBrtrue (fortest).PrintableString);
4935 }
4936 twout.Write (';');
4937 if (forstep != null) {
4938 StringWriter sw = new StringWriter ();
4939 sw.Write (' ');
4940 forstep.PrintStmt (sw, indent + INDENT);
4941 StringBuilder sb = sw.GetStringBuilder ();
4942 int sl = sb.Length;
4943 if ((sl > 0) && (sb[sl-1] == ';')) sb.Remove (-- sl, 1);
4944 twout.Write (sb.ToString ());
4945 }
4946 }
4947
4948 twout.Write (") ");
4949 forbody.PrintStmt (twout, indent);
4950 }
4951 }
4952
4953 /**
4954 * if/then/else block.
4955 */
4956 private class OTStmtIf : OTStmt {
4957 private OTOpnd testvalu;
4958 private OTStmt thenstmt;
4959 private OTStmt elsestmt; // might be null
4960
4961 /**
4962 * Try to detect a structured if statement.
4963 *
4964 * if (condition) jump ifdone_<suffix>; << link points here
4965 * ... then body ...
4966 * @ifdone_<suffix>;
4967 *
4968 * if (condition) jump ifelse_<suffix>;
4969 * ... then body ...
4970 * jump ifdone_<suffix>; << optional if true body doesn't fall through
4971 * @ifelse_<suffix>;
4972 * ... else body ...
4973 * @ifdone_<suffix>;
4974 */
4975 public static bool Detect (LinkedListNode<OTStmt> link)
4976 {
4977 OTStmtCond condstmt = (OTStmtCond) link.Value;
4978 if (!(condstmt.stmt is OTStmtJump)) return false;
4979
4980 OTStmtJump jumpstmt = (OTStmtJump) condstmt.stmt;
4981 if (jumpstmt.label.name.StartsWith (_ifDone)) {
4982
4983 // then-only if
4984
4985 // skip forward to find the ifdone_<suffix> label
4986 // also save the intervening statements for the then body
4987 OTStmtBlock thenbody;
4988 LinkedListNode<OTStmt> donelink = ScanForLabel (link, jumpstmt.label, out thenbody);
4989
4990 // make sure we found matching label
4991 if (donelink == null) return false;
4992
4993 // replace the jump ifdone_<suffix> with the <then body>
4994 OTStmtIf it = new OTStmtIf ();
4995 it.thenstmt = thenbody;
4996
4997 // replace the test value with the opposite
4998 it.testvalu = OTOpndUnOp.Make (MyOp.Brfalse, condstmt.valu);
4999 condstmt.valu = null;
5000
5001 // strip out the true body statements from the main code including the ifdone_<suffix> label
5002 StripInterveningStatements (link, donelink);
5003
5004 // replace the simple conditional with the if/then/else block
5005 link.Value = it;
5006
5007 // tell caller we changed something
5008 return true;
5009 }
5010
5011 if (jumpstmt.label.name.StartsWith (_ifElse)) {
5012 string suffix = jumpstmt.label.name.Substring (_ifElse.Length);
5013
5014 // if/then/else
5015 OTStmtIf it = new OTStmtIf ();
5016
5017 // skip forward to find the ifelse_<suffix> label
5018 // also save the intervening statements for the true body
5019 OTStmtBlock thenbody;
5020 LinkedListNode<OTStmt> elselink = ScanForLabel (link, jumpstmt.label, out thenbody);
5021
5022 // make sure we found matching label
5023 if (elselink != null) {
5024
5025 // the last statement of the then body might be a jump ifdone_<suffix>
5026 LinkedListNode<OTStmt> lastthenlink = thenbody.blkstmts.Last;
5027 if ((lastthenlink != null) && (lastthenlink.Value is OTStmtJump)) {
5028 OTStmtJump jumpifdone = (OTStmtJump) lastthenlink.Value;
5029 if (jumpifdone.label.name == _ifDone + suffix) {
5030
5031 lastthenlink.List.Remove (lastthenlink);
5032
5033 // skip forward to find the ifdone_<suffix> label
5034 // also save the intervening statements for the else body
5035 OTStmtBlock elsebody;
5036 LinkedListNode<OTStmt> donelink = ScanForLabel (elselink, jumpifdone.label, out elsebody);
5037 if (donelink != null) {
5038
5039 // replace the jump ifdone_<suffix> with the <true body>
5040 it.thenstmt = thenbody;
5041
5042 // save the else body as well
5043 it.elsestmt = elsebody;
5044
5045 // replace the test value with the opposite
5046 it.testvalu = OTOpndUnOp.Make (MyOp.Brfalse, condstmt.valu);
5047 condstmt.valu = null;
5048
5049 // strip out the true and else body statements from the main code including the ifdone_<suffix> label
5050 StripInterveningStatements (link, donelink);
5051
5052 // replace the simple conditional with the if/then/else block
5053 link.Value = it;
5054
5055 // tell caller we changed something
5056 return true;
5057 }
5058 }
5059 }
5060
5061 // missing the jump _ifDone_<suffix>, so make it a simple if/then
5062 // if (condition) jump ifelse_<suffix>; << link
5063 // ... then body ... << encapsulated in block thenbody
5064 // @ifelse_<suffix>; << elselink
5065 // ... else body ... << still inline and leave it there
5066 // @ifdone_<suffix>; << strip this out
5067
5068 // replace the jump ifelse_<suffix> with the <true body>
5069 it.thenstmt = thenbody;
5070
5071 // replace the test value with the opposite
5072 it.testvalu = OTOpndUnOp.Make (MyOp.Brfalse, condstmt.valu);
5073 condstmt.valu = null;
5074
5075 // strip out the then body statements from the main code including the ifelse_<suffix> label
5076 StripInterveningStatements (link, elselink);
5077
5078 // there's a dangling unused ifdone_<suffix> label ahead that has to be stripped
5079 for (LinkedListNode<OTStmt> donelink = link; (donelink = donelink.Next) != null;) {
5080 if ((donelink.Value is OTStmtLabel) && (((OTStmtLabel) donelink.Value).label.name == _ifDone + suffix)) {
5081 donelink.List.Remove (donelink);
5082 break;
5083 }
5084 }
5085
5086 // replace the simple conditional with the if/then/else block
5087 link.Value = it;
5088
5089 // tell caller we changed something
5090 return true;
5091 }
5092 }
5093
5094 return false;
5095 }
5096
5097 private OTStmtIf () { }
5098
5099 public override void CountRefs ()
5100 {
5101 if (testvalu != null) testvalu.CountRefs (false);
5102 if (thenstmt != null) thenstmt.CountRefs ();
5103 if (elsestmt != null) elsestmt.CountRefs ();
5104 }
5105
5106 public override bool ReplaceOperand (OTOpnd oldopnd, OTOpnd newopnd)
5107 {
5108 bool rc = thenstmt.ReplaceOperand (oldopnd, newopnd);
5109 testvalu = testvalu.ReplaceOperand (oldopnd, newopnd, ref rc);
5110 return rc;
5111 }
5112
5113 public override bool DetectDoForIfWhile (LinkedListNode<OTStmt> link)
5114 {
5115 return ((thenstmt != null) && thenstmt.DetectDoForIfWhile (link)) |
5116 ((elsestmt != null) && elsestmt.DetectDoForIfWhile (link));
5117 }
5118
5119 /**
5120 * Assume we won't replace the if statement itself.
5121 * But search all our sub-ordinate statements.
5122 */
5123 public override OTStmt ReplaceStatement (OTStmt oldstmt, OTStmt newstmt)
5124 {
5125 thenstmt = thenstmt.ReplaceStatement (oldstmt, newstmt);
5126 if (elsestmt != null) elsestmt = elsestmt.ReplaceStatement (oldstmt, newstmt);
5127 return this;
5128 }
5129
5130 public override void PrintStmt (TextWriter twout, string indent)
5131 {
5132 twout.Write ("if (" + StripBrtrue (testvalu).PrintableString + ") ");
5133 OTStmt thenst = ReduceStmtBody (thenstmt, false);
5134 thenst.PrintStmt (twout, indent);
5135 if (elsestmt != null) {
5136 twout.Write ('\n' + indent + "else ");
5137 OTStmt elsest = ReduceStmtBody (elsestmt, true);
5138 elsest.PrintStmt (twout, indent);
5139 }
5140 }
5141
5142 // strip block off a single jump so it prints inline instead of with braces around it
5143 // also, if this is part of else, strip block for ifs to make else if statement
5144 private static OTStmt ReduceStmtBody (OTStmt statement, bool stripif)
5145 {
5146 OTStmt onestmt = statement;
5147 if ((onestmt is OTStmtBlock) && (((OTStmtBlock) onestmt).blkstmts.Count == 1)) {
5148 onestmt = ((OTStmtBlock) onestmt).blkstmts.First.Value;
5149 if ((onestmt is OTStmtJump) || (stripif && (onestmt is OTStmtIf))) {
5150 return onestmt;
5151 }
5152 }
5153 return statement;
5154 }
5155
5156 /**
5157 * Scan forward for a given label definition.
5158 * Put intervening statements in a statement block.
5159 * @param link = start scanning after this statement
5160 * @param label = look for this label definition
5161 * @param block = where to return intervening statement block
5162 * @returns null: label definition not found
5163 * else: label definition statement
5164 */
5165 private static LinkedListNode<OTStmt> ScanForLabel (LinkedListNode<OTStmt> link,
5166 OTLabel label, out OTStmtBlock block)
5167 {
5168 block = new OTStmtBlock ();
5169 while ((link = link.Next) != null) {
5170 if (link.Value is OTStmtLabel) {
5171 if (((OTStmtLabel) link.Value).label == label) break;
5172 }
5173 block.blkstmts.AddLast (link.Value);
5174 }
5175 return link;
5176 }
5177
5178 /**
5179 * Strip statements after link up to and including donelink.
5180 */
5181 private static void StripInterveningStatements (LinkedListNode<OTStmt> link, LinkedListNode<OTStmt> donelink)
5182 {
5183 LinkedListNode<OTStmt> striplink;
5184 do {
5185 striplink = link.Next;
5186 striplink.List.Remove (striplink);
5187 } while (striplink != donelink);
5188 }
5189 }
5190
5191 private class MyOp {
5192 public int index;
5193 public OpCode sysop;
5194 public string name;
5195 public string source;
5196
5197 private static Dictionary<string,MyOp> myopsbyname = new Dictionary<string,MyOp> ();
5198 private static int nextindex = 0;
5199
5200 public MyOp (OpCode sysop)
5201 {
5202 this.index = nextindex ++;
5203 this.sysop = sysop;
5204 this.name = sysop.Name;
5205 myopsbyname.Add (name, this);
5206 }
5207
5208 public MyOp (OpCode sysop, string source)
5209 {
5210 this.index = nextindex ++;
5211 this.sysop = sysop;
5212 this.name = sysop.Name;
5213 this.source = source;
5214 myopsbyname.Add (name, this);
5215 }
5216
5217 public MyOp (string name)
5218 {
5219 this.index = nextindex ++;
5220 this.name = name;
5221 myopsbyname.Add (name, this);
5222 }
5223
5224 public MyOp (string name, string source)
5225 {
5226 this.index = nextindex ++;
5227 this.name = name;
5228 this.source = source;
5229 myopsbyname.Add (name, this);
5230 }
5231
5232 public static MyOp GetByName (string name)
5233 {
5234 return myopsbyname[name];
5235 }
5236
5237 public override string ToString ()
5238 {
5239 return name;
5240 }
5241
5242 // these copied from OpCodes.cs
5243 public static readonly MyOp Nop = new MyOp (OpCodes.Nop);
5244 public static readonly MyOp Break = new MyOp (OpCodes.Break);
5245 public static readonly MyOp Ldarg_0 = new MyOp (OpCodes.Ldarg_0);
5246 public static readonly MyOp Ldarg_1 = new MyOp (OpCodes.Ldarg_1);
5247 public static readonly MyOp Ldarg_2 = new MyOp (OpCodes.Ldarg_2);
5248 public static readonly MyOp Ldarg_3 = new MyOp (OpCodes.Ldarg_3);
5249 public static readonly MyOp Ldloc_0 = new MyOp (OpCodes.Ldloc_0);
5250 public static readonly MyOp Ldloc_1 = new MyOp (OpCodes.Ldloc_1);
5251 public static readonly MyOp Ldloc_2 = new MyOp (OpCodes.Ldloc_2);
5252 public static readonly MyOp Ldloc_3 = new MyOp (OpCodes.Ldloc_3);
5253 public static readonly MyOp Stloc_0 = new MyOp (OpCodes.Stloc_0);
5254 public static readonly MyOp Stloc_1 = new MyOp (OpCodes.Stloc_1);
5255 public static readonly MyOp Stloc_2 = new MyOp (OpCodes.Stloc_2);
5256 public static readonly MyOp Stloc_3 = new MyOp (OpCodes.Stloc_3);
5257 public static readonly MyOp Ldarg_S = new MyOp (OpCodes.Ldarg_S);
5258 public static readonly MyOp Ldarga_S = new MyOp (OpCodes.Ldarga_S);
5259 public static readonly MyOp Starg_S = new MyOp (OpCodes.Starg_S);
5260 public static readonly MyOp Ldloc_S = new MyOp (OpCodes.Ldloc_S);
5261 public static readonly MyOp Ldloca_S = new MyOp (OpCodes.Ldloca_S);
5262 public static readonly MyOp Stloc_S = new MyOp (OpCodes.Stloc_S);
5263 public static readonly MyOp Ldnull = new MyOp (OpCodes.Ldnull);
5264 public static readonly MyOp Ldc_I4_M1 = new MyOp (OpCodes.Ldc_I4_M1);
5265 public static readonly MyOp Ldc_I4_0 = new MyOp (OpCodes.Ldc_I4_0);
5266 public static readonly MyOp Ldc_I4_1 = new MyOp (OpCodes.Ldc_I4_1);
5267 public static readonly MyOp Ldc_I4_2 = new MyOp (OpCodes.Ldc_I4_2);
5268 public static readonly MyOp Ldc_I4_3 = new MyOp (OpCodes.Ldc_I4_3);
5269 public static readonly MyOp Ldc_I4_4 = new MyOp (OpCodes.Ldc_I4_4);
5270 public static readonly MyOp Ldc_I4_5 = new MyOp (OpCodes.Ldc_I4_5);
5271 public static readonly MyOp Ldc_I4_6 = new MyOp (OpCodes.Ldc_I4_6);
5272 public static readonly MyOp Ldc_I4_7 = new MyOp (OpCodes.Ldc_I4_7);
5273 public static readonly MyOp Ldc_I4_8 = new MyOp (OpCodes.Ldc_I4_8);
5274 public static readonly MyOp Ldc_I4_S = new MyOp (OpCodes.Ldc_I4_S);
5275 public static readonly MyOp Ldc_I4 = new MyOp (OpCodes.Ldc_I4);
5276 public static readonly MyOp Ldc_I8 = new MyOp (OpCodes.Ldc_I8);
5277 public static readonly MyOp Ldc_R4 = new MyOp (OpCodes.Ldc_R4);
5278 public static readonly MyOp Ldc_R8 = new MyOp (OpCodes.Ldc_R8);
5279 public static readonly MyOp Dup = new MyOp (OpCodes.Dup);
5280 public static readonly MyOp Pop = new MyOp (OpCodes.Pop);
5281 public static readonly MyOp Jmp = new MyOp (OpCodes.Jmp);
5282 public static readonly MyOp Call = new MyOp (OpCodes.Call);
5283 public static readonly MyOp Calli = new MyOp (OpCodes.Calli);
5284 public static readonly MyOp Ret = new MyOp (OpCodes.Ret);
5285 public static readonly MyOp Br_S = new MyOp (OpCodes.Br_S);
5286 public static readonly MyOp Brfalse_S = new MyOp (OpCodes.Brfalse_S);
5287 public static readonly MyOp Brtrue_S = new MyOp (OpCodes.Brtrue_S);
5288 public static readonly MyOp Beq_S = new MyOp (OpCodes.Beq_S, "==");
5289 public static readonly MyOp Bge_S = new MyOp (OpCodes.Bge_S, ">=");
5290 public static readonly MyOp Bgt_S = new MyOp (OpCodes.Bgt_S, ">");
5291 public static readonly MyOp Ble_S = new MyOp (OpCodes.Ble_S, "<=");
5292 public static readonly MyOp Blt_S = new MyOp (OpCodes.Blt_S, "<");
5293 public static readonly MyOp Bne_Un_S = new MyOp (OpCodes.Bne_Un_S, "!=");
5294 public static readonly MyOp Bge_Un_S = new MyOp (OpCodes.Bge_Un_S);
5295 public static readonly MyOp Bgt_Un_S = new MyOp (OpCodes.Bgt_Un_S);
5296 public static readonly MyOp Ble_Un_S = new MyOp (OpCodes.Ble_Un_S);
5297 public static readonly MyOp Blt_Un_S = new MyOp (OpCodes.Blt_Un_S);
5298 public static readonly MyOp Br = new MyOp (OpCodes.Br);
5299 public static readonly MyOp Brfalse = new MyOp (OpCodes.Brfalse, "!");
5300 public static readonly MyOp Brtrue = new MyOp (OpCodes.Brtrue, "!!");
5301 public static readonly MyOp Beq = new MyOp (OpCodes.Beq, "==");
5302 public static readonly MyOp Bge = new MyOp (OpCodes.Bge, ">=");
5303 public static readonly MyOp Bgt = new MyOp (OpCodes.Bgt, ">");
5304 public static readonly MyOp Ble = new MyOp (OpCodes.Ble, "<=");
5305 public static readonly MyOp Blt = new MyOp (OpCodes.Blt, "<");
5306 public static readonly MyOp Bne_Un = new MyOp (OpCodes.Bne_Un, "!=");
5307 public static readonly MyOp Bge_Un = new MyOp (OpCodes.Bge_Un);
5308 public static readonly MyOp Bgt_Un = new MyOp (OpCodes.Bgt_Un);
5309 public static readonly MyOp Ble_Un = new MyOp (OpCodes.Ble_Un);
5310 public static readonly MyOp Blt_Un = new MyOp (OpCodes.Blt_Un);
5311 public static readonly MyOp Switch = new MyOp (OpCodes.Switch);
5312 public static readonly MyOp Ldind_I1 = new MyOp (OpCodes.Ldind_I1);
5313 public static readonly MyOp Ldind_U1 = new MyOp (OpCodes.Ldind_U1);
5314 public static readonly MyOp Ldind_I2 = new MyOp (OpCodes.Ldind_I2);
5315 public static readonly MyOp Ldind_U2 = new MyOp (OpCodes.Ldind_U2);
5316 public static readonly MyOp Ldind_I4 = new MyOp (OpCodes.Ldind_I4);
5317 public static readonly MyOp Ldind_U4 = new MyOp (OpCodes.Ldind_U4);
5318 public static readonly MyOp Ldind_I8 = new MyOp (OpCodes.Ldind_I8);
5319 public static readonly MyOp Ldind_I = new MyOp (OpCodes.Ldind_I);
5320 public static readonly MyOp Ldind_R4 = new MyOp (OpCodes.Ldind_R4);
5321 public static readonly MyOp Ldind_R8 = new MyOp (OpCodes.Ldind_R8);
5322 public static readonly MyOp Ldind_Ref = new MyOp (OpCodes.Ldind_Ref);
5323 public static readonly MyOp Stind_Ref = new MyOp (OpCodes.Stind_Ref);
5324 public static readonly MyOp Stind_I1 = new MyOp (OpCodes.Stind_I1);
5325 public static readonly MyOp Stind_I2 = new MyOp (OpCodes.Stind_I2);
5326 public static readonly MyOp Stind_I4 = new MyOp (OpCodes.Stind_I4);
5327 public static readonly MyOp Stind_I8 = new MyOp (OpCodes.Stind_I8);
5328 public static readonly MyOp Stind_R4 = new MyOp (OpCodes.Stind_R4);
5329 public static readonly MyOp Stind_R8 = new MyOp (OpCodes.Stind_R8);
5330 public static readonly MyOp Add = new MyOp (OpCodes.Add, "+");
5331 public static readonly MyOp Sub = new MyOp (OpCodes.Sub, "-");
5332 public static readonly MyOp Mul = new MyOp (OpCodes.Mul, "*");
5333 public static readonly MyOp Div = new MyOp (OpCodes.Div, "/");
5334 public static readonly MyOp Div_Un = new MyOp (OpCodes.Div_Un);
5335 public static readonly MyOp Rem = new MyOp (OpCodes.Rem, "%");
5336 public static readonly MyOp Rem_Un = new MyOp (OpCodes.Rem_Un);
5337 public static readonly MyOp And = new MyOp (OpCodes.And, "&");
5338 public static readonly MyOp Or = new MyOp (OpCodes.Or, "|");
5339 public static readonly MyOp Xor = new MyOp (OpCodes.Xor, "^");
5340 public static readonly MyOp Shl = new MyOp (OpCodes.Shl, "<<");
5341 public static readonly MyOp Shr = new MyOp (OpCodes.Shr, ">>");
5342 public static readonly MyOp Shr_Un = new MyOp (OpCodes.Shr_Un);
5343 public static readonly MyOp Neg = new MyOp (OpCodes.Neg, "-");
5344 public static readonly MyOp Not = new MyOp (OpCodes.Not, "~");
5345 public static readonly MyOp Conv_I1 = new MyOp (OpCodes.Conv_I1);
5346 public static readonly MyOp Conv_I2 = new MyOp (OpCodes.Conv_I2);
5347 public static readonly MyOp Conv_I4 = new MyOp (OpCodes.Conv_I4);
5348 public static readonly MyOp Conv_I8 = new MyOp (OpCodes.Conv_I8);
5349 public static readonly MyOp Conv_R4 = new MyOp (OpCodes.Conv_R4);
5350 public static readonly MyOp Conv_R8 = new MyOp (OpCodes.Conv_R8);
5351 public static readonly MyOp Conv_U4 = new MyOp (OpCodes.Conv_U4);
5352 public static readonly MyOp Conv_U8 = new MyOp (OpCodes.Conv_U8);
5353 public static readonly MyOp Callvirt = new MyOp (OpCodes.Callvirt);
5354 public static readonly MyOp Cpobj = new MyOp (OpCodes.Cpobj);
5355 public static readonly MyOp Ldobj = new MyOp (OpCodes.Ldobj);
5356 public static readonly MyOp Ldstr = new MyOp (OpCodes.Ldstr);
5357 public static readonly MyOp Newobj = new MyOp (OpCodes.Newobj);
5358 public static readonly MyOp Castclass = new MyOp (OpCodes.Castclass);
5359 public static readonly MyOp Isinst = new MyOp (OpCodes.Isinst);
5360 public static readonly MyOp Conv_R_Un = new MyOp (OpCodes.Conv_R_Un);
5361 public static readonly MyOp Unbox = new MyOp (OpCodes.Unbox);
5362 public static readonly MyOp Throw = new MyOp (OpCodes.Throw);
5363 public static readonly MyOp Ldfld = new MyOp (OpCodes.Ldfld);
5364 public static readonly MyOp Ldflda = new MyOp (OpCodes.Ldflda);
5365 public static readonly MyOp Stfld = new MyOp (OpCodes.Stfld);
5366 public static readonly MyOp Ldsfld = new MyOp (OpCodes.Ldsfld);
5367 public static readonly MyOp Ldsflda = new MyOp (OpCodes.Ldsflda);
5368 public static readonly MyOp Stsfld = new MyOp (OpCodes.Stsfld);
5369 public static readonly MyOp Stobj = new MyOp (OpCodes.Stobj);
5370 public static readonly MyOp Conv_Ovf_I1_Un = new MyOp (OpCodes.Conv_Ovf_I1_Un);
5371 public static readonly MyOp Conv_Ovf_I2_Un = new MyOp (OpCodes.Conv_Ovf_I2_Un);
5372 public static readonly MyOp Conv_Ovf_I4_Un = new MyOp (OpCodes.Conv_Ovf_I4_Un);
5373 public static readonly MyOp Conv_Ovf_I8_Un = new MyOp (OpCodes.Conv_Ovf_I8_Un);
5374 public static readonly MyOp Conv_Ovf_U1_Un = new MyOp (OpCodes.Conv_Ovf_U1_Un);
5375 public static readonly MyOp Conv_Ovf_U2_Un = new MyOp (OpCodes.Conv_Ovf_U2_Un);
5376 public static readonly MyOp Conv_Ovf_U4_Un = new MyOp (OpCodes.Conv_Ovf_U4_Un);
5377 public static readonly MyOp Conv_Ovf_U8_Un = new MyOp (OpCodes.Conv_Ovf_U8_Un);
5378 public static readonly MyOp Conv_Ovf_I_Un = new MyOp (OpCodes.Conv_Ovf_I_Un);
5379 public static readonly MyOp Conv_Ovf_U_Un = new MyOp (OpCodes.Conv_Ovf_U_Un);
5380 public static readonly MyOp Box = new MyOp (OpCodes.Box);
5381 public static readonly MyOp Newarr = new MyOp (OpCodes.Newarr);
5382 public static readonly MyOp Ldlen = new MyOp (OpCodes.Ldlen);
5383 public static readonly MyOp Ldelema = new MyOp (OpCodes.Ldelema);
5384 public static readonly MyOp Ldelem_I1 = new MyOp (OpCodes.Ldelem_I1);
5385 public static readonly MyOp Ldelem_U1 = new MyOp (OpCodes.Ldelem_U1);
5386 public static readonly MyOp Ldelem_I2 = new MyOp (OpCodes.Ldelem_I2);
5387 public static readonly MyOp Ldelem_U2 = new MyOp (OpCodes.Ldelem_U2);
5388 public static readonly MyOp Ldelem_I4 = new MyOp (OpCodes.Ldelem_I4);
5389 public static readonly MyOp Ldelem_U4 = new MyOp (OpCodes.Ldelem_U4);
5390 public static readonly MyOp Ldelem_I8 = new MyOp (OpCodes.Ldelem_I8);
5391 public static readonly MyOp Ldelem_I = new MyOp (OpCodes.Ldelem_I);
5392 public static readonly MyOp Ldelem_R4 = new MyOp (OpCodes.Ldelem_R4);
5393 public static readonly MyOp Ldelem_R8 = new MyOp (OpCodes.Ldelem_R8);
5394 public static readonly MyOp Ldelem_Ref = new MyOp (OpCodes.Ldelem_Ref);
5395 public static readonly MyOp Stelem_I = new MyOp (OpCodes.Stelem_I);
5396 public static readonly MyOp Stelem_I1 = new MyOp (OpCodes.Stelem_I1);
5397 public static readonly MyOp Stelem_I2 = new MyOp (OpCodes.Stelem_I2);
5398 public static readonly MyOp Stelem_I4 = new MyOp (OpCodes.Stelem_I4);
5399 public static readonly MyOp Stelem_I8 = new MyOp (OpCodes.Stelem_I8);
5400 public static readonly MyOp Stelem_R4 = new MyOp (OpCodes.Stelem_R4);
5401 public static readonly MyOp Stelem_R8 = new MyOp (OpCodes.Stelem_R8);
5402 public static readonly MyOp Stelem_Ref = new MyOp (OpCodes.Stelem_Ref);
5403 public static readonly MyOp Ldelem = new MyOp (OpCodes.Ldelem);
5404 public static readonly MyOp Stelem = new MyOp (OpCodes.Stelem);
5405 public static readonly MyOp Unbox_Any = new MyOp (OpCodes.Unbox_Any);
5406 public static readonly MyOp Conv_Ovf_I1 = new MyOp (OpCodes.Conv_Ovf_I1);
5407 public static readonly MyOp Conv_Ovf_U1 = new MyOp (OpCodes.Conv_Ovf_U1);
5408 public static readonly MyOp Conv_Ovf_I2 = new MyOp (OpCodes.Conv_Ovf_I2);
5409 public static readonly MyOp Conv_Ovf_U2 = new MyOp (OpCodes.Conv_Ovf_U2);
5410 public static readonly MyOp Conv_Ovf_I4 = new MyOp (OpCodes.Conv_Ovf_I4);
5411 public static readonly MyOp Conv_Ovf_U4 = new MyOp (OpCodes.Conv_Ovf_U4);
5412 public static readonly MyOp Conv_Ovf_I8 = new MyOp (OpCodes.Conv_Ovf_I8);
5413 public static readonly MyOp Conv_Ovf_U8 = new MyOp (OpCodes.Conv_Ovf_U8);
5414 public static readonly MyOp Refanyval = new MyOp (OpCodes.Refanyval);
5415 public static readonly MyOp Ckfinite = new MyOp (OpCodes.Ckfinite);
5416 public static readonly MyOp Mkrefany = new MyOp (OpCodes.Mkrefany);
5417 public static readonly MyOp Ldtoken = new MyOp (OpCodes.Ldtoken);
5418 public static readonly MyOp Conv_U2 = new MyOp (OpCodes.Conv_U2);
5419 public static readonly MyOp Conv_U1 = new MyOp (OpCodes.Conv_U1);
5420 public static readonly MyOp Conv_I = new MyOp (OpCodes.Conv_I);
5421 public static readonly MyOp Conv_Ovf_I = new MyOp (OpCodes.Conv_Ovf_I);
5422 public static readonly MyOp Conv_Ovf_U = new MyOp (OpCodes.Conv_Ovf_U);
5423 public static readonly MyOp Add_Ovf = new MyOp (OpCodes.Add_Ovf);
5424 public static readonly MyOp Add_Ovf_Un = new MyOp (OpCodes.Add_Ovf_Un);
5425 public static readonly MyOp Mul_Ovf = new MyOp (OpCodes.Mul_Ovf);
5426 public static readonly MyOp Mul_Ovf_Un = new MyOp (OpCodes.Mul_Ovf_Un);
5427 public static readonly MyOp Sub_Ovf = new MyOp (OpCodes.Sub_Ovf);
5428 public static readonly MyOp Sub_Ovf_Un = new MyOp (OpCodes.Sub_Ovf_Un);
5429 public static readonly MyOp Endfinally = new MyOp (OpCodes.Endfinally);
5430 public static readonly MyOp Leave = new MyOp (OpCodes.Leave);
5431 public static readonly MyOp Leave_S = new MyOp (OpCodes.Leave_S);
5432 public static readonly MyOp Stind_I = new MyOp (OpCodes.Stind_I);
5433 public static readonly MyOp Conv_U = new MyOp (OpCodes.Conv_U);
5434 public static readonly MyOp Prefix7 = new MyOp (OpCodes.Prefix7);
5435 public static readonly MyOp Prefix6 = new MyOp (OpCodes.Prefix6);
5436 public static readonly MyOp Prefix5 = new MyOp (OpCodes.Prefix5);
5437 public static readonly MyOp Prefix4 = new MyOp (OpCodes.Prefix4);
5438 public static readonly MyOp Prefix3 = new MyOp (OpCodes.Prefix3);
5439 public static readonly MyOp Prefix2 = new MyOp (OpCodes.Prefix2);
5440 public static readonly MyOp Prefix1 = new MyOp (OpCodes.Prefix1);
5441 public static readonly MyOp Prefixref = new MyOp (OpCodes.Prefixref);
5442 public static readonly MyOp Arglist = new MyOp (OpCodes.Arglist);
5443 public static readonly MyOp Ceq = new MyOp (OpCodes.Ceq, "==");
5444 public static readonly MyOp Cgt = new MyOp (OpCodes.Cgt, ">");
5445 public static readonly MyOp Cgt_Un = new MyOp (OpCodes.Cgt_Un);
5446 public static readonly MyOp Clt = new MyOp (OpCodes.Clt, "<");
5447 public static readonly MyOp Clt_Un = new MyOp (OpCodes.Clt_Un);
5448 public static readonly MyOp Ldftn = new MyOp (OpCodes.Ldftn);
5449 public static readonly MyOp Ldvirtftn = new MyOp (OpCodes.Ldvirtftn);
5450 public static readonly MyOp Ldarg = new MyOp (OpCodes.Ldarg);
5451 public static readonly MyOp Ldarga = new MyOp (OpCodes.Ldarga);
5452 public static readonly MyOp Starg = new MyOp (OpCodes.Starg);
5453 public static readonly MyOp Ldloc = new MyOp (OpCodes.Ldloc);
5454 public static readonly MyOp Ldloca = new MyOp (OpCodes.Ldloca);
5455 public static readonly MyOp Stloc = new MyOp (OpCodes.Stloc);
5456 public static readonly MyOp Localloc = new MyOp (OpCodes.Localloc);
5457 public static readonly MyOp Endfilter = new MyOp (OpCodes.Endfilter);
5458 public static readonly MyOp Unaligned = new MyOp (OpCodes.Unaligned);
5459 public static readonly MyOp Volatile = new MyOp (OpCodes.Volatile);
5460 public static readonly MyOp Tailcall = new MyOp (OpCodes.Tailcall);
5461 public static readonly MyOp Initobj = new MyOp (OpCodes.Initobj);
5462 public static readonly MyOp Constrained = new MyOp (OpCodes.Constrained);
5463 public static readonly MyOp Cpblk = new MyOp (OpCodes.Cpblk);
5464 public static readonly MyOp Initblk = new MyOp (OpCodes.Initblk);
5465 public static readonly MyOp Rethrow = new MyOp (OpCodes.Rethrow);
5466 public static readonly MyOp Sizeof = new MyOp (OpCodes.Sizeof);
5467 public static readonly MyOp Refanytype = new MyOp (OpCodes.Refanytype);
5468 public static readonly MyOp Readonly = new MyOp (OpCodes.Readonly);
5469
5470 // used internally
5471 public static readonly MyOp Cge = new MyOp ("cge", ">=");
5472 public static readonly MyOp Cle = new MyOp ("cle", "<=");
5473 public static readonly MyOp Cne = new MyOp ("cne", "!=");
5474 }
5475 }
5476}