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