aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ScriptEngine/XMREngine/MMRScriptObjWriter.cs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--OpenSim/Region/ScriptEngine/XMREngine/MMRScriptObjWriter.cs947
1 files changed, 947 insertions, 0 deletions
diff --git a/OpenSim/Region/ScriptEngine/XMREngine/MMRScriptObjWriter.cs b/OpenSim/Region/ScriptEngine/XMREngine/MMRScriptObjWriter.cs
new file mode 100644
index 0000000..e4e0ac8
--- /dev/null
+++ b/OpenSim/Region/ScriptEngine/XMREngine/MMRScriptObjWriter.cs
@@ -0,0 +1,947 @@
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 * @brief Wrapper class for ILGenerator.
46 * It writes the object code to a file and can then make real ILGenerator calls
47 * based on the file's contents.
48 */
49namespace OpenSim.Region.ScriptEngine.XMREngine
50{
51 public enum ScriptObjWriterCode : byte {
52 BegMethod, EndMethod, TheEnd,
53 DclLabel, DclLocal, DclMethod, MarkLabel,
54 EmitNull, EmitField, EmitLocal, EmitType, EmitLabel, EmitMethodExt,
55 EmitMethodInt, EmitCtor, EmitDouble, EmitFloat, EmitInteger, EmitString,
56 EmitLabels,
57 BegExcBlk, BegCatBlk, BegFinBlk, EndExcBlk
58 }
59
60 public class ScriptObjWriter : ScriptMyILGen
61 {
62 private static Dictionary<short, OpCode> opCodes = PopulateOpCodes ();
63 private static Dictionary<string, Type> string2Type = PopulateS2T ();
64 private static Dictionary<Type, string> type2String = PopulateT2S ();
65
66 private static MethodInfo monoGetCurrentOffset = typeof (ILGenerator).GetMethod ("Mono_GetCurrentOffset",
67 BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null,
68 new Type[] { typeof (ILGenerator) }, null);
69
70 private static readonly OpCode[] opCodesLdcI4M1P8 = new OpCode[] {
71 OpCodes.Ldc_I4_M1, OpCodes.Ldc_I4_0, OpCodes.Ldc_I4_1, OpCodes.Ldc_I4_2, OpCodes.Ldc_I4_3,
72 OpCodes.Ldc_I4_4, OpCodes.Ldc_I4_5, OpCodes.Ldc_I4_6, OpCodes.Ldc_I4_7, OpCodes.Ldc_I4_8
73 };
74
75 private BinaryWriter objFileWriter;
76 private string lastErrorAtFile = "";
77 private int lastErrorAtLine = 0;
78 private int lastErrorAtPosn = 0;
79
80 private Dictionary<Type, string> sdTypesRev = new Dictionary<Type, string> ();
81 public int labelNumber = 0;
82 public int localNumber = 0;
83
84 private string _methName;
85 public string methName { get { return _methName; } }
86
87 public Type retType;
88 public Type[] argTypes;
89
90 /**
91 * @brief Begin function declaration
92 * @param sdTypes = script-defined types
93 * @param methName = name of the method being declared, eg, "Verify(array,list,string)"
94 * @param retType = its return value type
95 * @param argTypes[] = its argument types
96 * @param objFileWriter = file to write its object code to
97 *
98 * After calling this function, the following functions should be called:
99 * this.BegMethod ();
100 * this.<as required> ();
101 * this.EndMethod ();
102 *
103 * The design of this object is such that many constructors may be called,
104 * but once a BegMethod() is called for one of the objects, no method may
105 * called for any of the other objects until EndMethod() is called (or it
106 * would break up the object stream for that method). But we need to have
107 * many constructors possible so we get function headers at the beginning
108 * of the object file in case there are forward references to the functions.
109 */
110 public ScriptObjWriter (TokenScript tokenScript, string methName, Type retType, Type[] argTypes, string[] argNames, BinaryWriter objFileWriter)
111 {
112 this._methName = methName;
113 this.retType = retType;
114 this.argTypes = argTypes;
115 this.objFileWriter = objFileWriter;
116
117 /*
118 * Build list that translates system-defined types to script defined types.
119 */
120 foreach (TokenDeclSDType sdt in tokenScript.sdSrcTypesValues) {
121 Type sys = sdt.GetSysType();
122 if (sys != null) sdTypesRev[sys] = sdt.longName.val;
123 }
124
125 /*
126 * This tells the reader to call 'new DynamicMethod()' to create
127 * the function header. Then any forward reference calls to this
128 * method will have a MethodInfo struct to call.
129 */
130 objFileWriter.Write ((byte)ScriptObjWriterCode.DclMethod);
131 objFileWriter.Write (methName);
132 objFileWriter.Write (GetStrFromType (retType));
133
134 int nArgs = argTypes.Length;
135 objFileWriter.Write (nArgs);
136 for (int i = 0; i < nArgs; i ++) {
137 objFileWriter.Write (GetStrFromType (argTypes[i]));
138 objFileWriter.Write (argNames[i]);
139 }
140 }
141
142 /**
143 * @brief Begin outputting object code for the function
144 */
145 public void BegMethod ()
146 {
147 /*
148 * This tells the reader to call methodInfo.GetILGenerator()
149 * so it can start writing CIL code for the method.
150 */
151 objFileWriter.Write ((byte)ScriptObjWriterCode.BegMethod);
152 objFileWriter.Write (methName);
153 }
154
155 /**
156 * @brief End of object code for the function
157 */
158 public void EndMethod ()
159 {
160 /*
161 * This tells the reader that all code for the method has
162 * been written and so it will typically call CreateDelegate()
163 * to finalize the method and create an entrypoint.
164 */
165 objFileWriter.Write ((byte)ScriptObjWriterCode.EndMethod);
166
167 objFileWriter = null;
168 }
169
170 /**
171 * @brief Declare a local variable for use by the function
172 */
173 public ScriptMyLocal DeclareLocal (Type type, string name)
174 {
175 ScriptMyLocal myLocal = new ScriptMyLocal ();
176 myLocal.type = type;
177 myLocal.name = name;
178 myLocal.number = localNumber ++;
179 myLocal.isReferenced = true; // so ScriptCollector won't optimize references away
180 return DeclareLocal (myLocal);
181 }
182 public ScriptMyLocal DeclareLocal (ScriptMyLocal myLocal)
183 {
184 objFileWriter.Write ((byte)ScriptObjWriterCode.DclLocal);
185 objFileWriter.Write (myLocal.number);
186 objFileWriter.Write (myLocal.name);
187 objFileWriter.Write (GetStrFromType (myLocal.type));
188 return myLocal;
189 }
190
191 /**
192 * @brief Define a label for use by the function
193 */
194 public ScriptMyLabel DefineLabel (string name)
195 {
196 ScriptMyLabel myLabel = new ScriptMyLabel ();
197 myLabel.name = name;
198 myLabel.number = labelNumber ++;
199 return DefineLabel (myLabel);
200 }
201 public ScriptMyLabel DefineLabel (ScriptMyLabel myLabel)
202 {
203 objFileWriter.Write ((byte)ScriptObjWriterCode.DclLabel);
204 objFileWriter.Write (myLabel.number);
205 objFileWriter.Write (myLabel.name);
206 return myLabel;
207 }
208
209 /**
210 * @brief try/catch blocks.
211 */
212 public void BeginExceptionBlock ()
213 {
214 objFileWriter.Write ((byte)ScriptObjWriterCode.BegExcBlk);
215 }
216
217 public void BeginCatchBlock (Type excType)
218 {
219 objFileWriter.Write ((byte)ScriptObjWriterCode.BegCatBlk);
220 objFileWriter.Write (GetStrFromType (excType));
221 }
222
223 public void BeginFinallyBlock ()
224 {
225 objFileWriter.Write ((byte)ScriptObjWriterCode.BegFinBlk);
226 }
227
228 public void EndExceptionBlock ()
229 {
230 objFileWriter.Write ((byte)ScriptObjWriterCode.EndExcBlk);
231 }
232
233 public void Emit (Token errorAt, OpCode opcode)
234 {
235 objFileWriter.Write ((byte)ScriptObjWriterCode.EmitNull);
236 WriteOpCode (errorAt, opcode);
237 }
238
239 public void Emit (Token errorAt, OpCode opcode, FieldInfo field)
240 {
241 objFileWriter.Write ((byte)ScriptObjWriterCode.EmitField);
242 WriteOpCode (errorAt, opcode);
243 objFileWriter.Write (GetStrFromType (field.ReflectedType));
244 objFileWriter.Write (field.Name);
245 }
246
247 public void Emit (Token errorAt, OpCode opcode, ScriptMyLocal myLocal)
248 {
249 objFileWriter.Write ((byte)ScriptObjWriterCode.EmitLocal);
250 WriteOpCode (errorAt, opcode);
251 objFileWriter.Write (myLocal.number);
252 }
253
254 public void Emit (Token errorAt, OpCode opcode, Type type)
255 {
256 objFileWriter.Write ((byte)ScriptObjWriterCode.EmitType);
257 WriteOpCode (errorAt, opcode);
258 objFileWriter.Write (GetStrFromType (type));
259 }
260
261 public void Emit (Token errorAt, OpCode opcode, ScriptMyLabel myLabel)
262 {
263 objFileWriter.Write ((byte)ScriptObjWriterCode.EmitLabel);
264 WriteOpCode (errorAt, opcode);
265 objFileWriter.Write (myLabel.number);
266 }
267
268 public void Emit (Token errorAt, OpCode opcode, ScriptMyLabel[] myLabels)
269 {
270 objFileWriter.Write ((byte)ScriptObjWriterCode.EmitLabels);
271 WriteOpCode (errorAt, opcode);
272 int nLabels = myLabels.Length;
273 objFileWriter.Write (nLabels);
274 for (int i = 0; i < nLabels; i ++) {
275 objFileWriter.Write (myLabels[i].number);
276 }
277 }
278
279 public void Emit (Token errorAt, OpCode opcode, ScriptObjWriter method)
280 {
281 if (method == null) throw new ArgumentNullException ("method");
282 objFileWriter.Write ((byte)ScriptObjWriterCode.EmitMethodInt);
283 WriteOpCode (errorAt, opcode);
284 objFileWriter.Write (method.methName);
285 }
286
287 public void Emit (Token errorAt, OpCode opcode, MethodInfo method)
288 {
289 objFileWriter.Write ((byte)ScriptObjWriterCode.EmitMethodExt);
290 WriteOpCode (errorAt, opcode);
291 objFileWriter.Write (method.Name);
292 objFileWriter.Write (GetStrFromType (method.ReflectedType));
293 ParameterInfo[] parms = method.GetParameters ();
294 int nArgs = parms.Length;
295 objFileWriter.Write (nArgs);
296 for (int i = 0; i < nArgs; i ++) {
297 objFileWriter.Write (GetStrFromType (parms[i].ParameterType));
298 }
299 }
300
301 public void Emit (Token errorAt, OpCode opcode, ConstructorInfo ctor)
302 {
303 objFileWriter.Write ((byte)ScriptObjWriterCode.EmitCtor);
304 WriteOpCode (errorAt, opcode);
305 objFileWriter.Write (GetStrFromType (ctor.ReflectedType));
306 ParameterInfo[] parms = ctor.GetParameters ();
307 int nArgs = parms.Length;
308 objFileWriter.Write (nArgs);
309 for (int i = 0; i < nArgs; i ++) {
310 objFileWriter.Write (GetStrFromType (parms[i].ParameterType));
311 }
312 }
313
314 public void Emit (Token errorAt, OpCode opcode, double value)
315 {
316 if (opcode != OpCodes.Ldc_R8) {
317 throw new Exception ("bad opcode " + opcode.ToString ());
318 }
319 objFileWriter.Write ((byte)ScriptObjWriterCode.EmitDouble);
320 WriteOpCode (errorAt, opcode);
321 objFileWriter.Write (value);
322 }
323
324 public void Emit (Token errorAt, OpCode opcode, float value)
325 {
326 if (opcode != OpCodes.Ldc_R4) {
327 throw new Exception ("bad opcode " + opcode.ToString ());
328 }
329 objFileWriter.Write ((byte)ScriptObjWriterCode.EmitFloat);
330 WriteOpCode (errorAt, opcode);
331 objFileWriter.Write (value);
332 }
333
334 public void Emit (Token errorAt, OpCode opcode, int value)
335 {
336 objFileWriter.Write ((byte)ScriptObjWriterCode.EmitInteger);
337 WriteOpCode (errorAt, opcode);
338 objFileWriter.Write (value);
339 }
340
341 public void Emit (Token errorAt, OpCode opcode, string value)
342 {
343 objFileWriter.Write ((byte)ScriptObjWriterCode.EmitString);
344 WriteOpCode (errorAt, opcode);
345 objFileWriter.Write (value);
346 }
347
348 /**
349 * @brief Declare that the target of a label is the next instruction.
350 */
351 public void MarkLabel (ScriptMyLabel myLabel)
352 {
353 objFileWriter.Write ((byte)ScriptObjWriterCode.MarkLabel);
354 objFileWriter.Write (myLabel.number);
355 }
356
357 /**
358 * @brief Write end-of-file marker to binary file.
359 */
360 public static void TheEnd (BinaryWriter objFileWriter)
361 {
362 objFileWriter.Write ((byte)ScriptObjWriterCode.TheEnd);
363 }
364
365 /**
366 * @brief Take an object file created by ScriptObjWriter() and convert it to a series of dynamic methods.
367 * @param sdTypes = script-defined types
368 * @param objReader = where to read object file from (as written by ScriptObjWriter above).
369 * @param scriptObjCode.EndMethod = called for each method defined at the end of the methods definition
370 * @param objectTokens = write disassemble/decompile data (or null if not wanted)
371 */
372 public static void CreateObjCode (Dictionary<string, TokenDeclSDType> sdTypes, BinaryReader objReader,
373 ScriptObjCode scriptObjCode, ObjectTokens objectTokens)
374 {
375 Dictionary<string, DynamicMethod> methods = new Dictionary<string, DynamicMethod> ();
376 DynamicMethod method = null;
377 ILGenerator ilGen = null;
378 Dictionary<int, Label> labels = new Dictionary<int, Label> ();
379 Dictionary<int, LocalBuilder> locals = new Dictionary<int, LocalBuilder> ();
380 Dictionary<int, string> labelNames = new Dictionary<int, string> ();
381 Dictionary<int, string> localNames = new Dictionary<int, string> ();
382 object[] ilGenArg = new object[1];
383 int offset = 0;
384 Dictionary<int, ScriptSrcLoc> srcLocs = null;
385 string srcFile = "";
386 int srcLine = 0;
387 int srcPosn = 0;
388
389 while (true) {
390
391 /*
392 * Get IL instruction offset at beginning of instruction.
393 */
394 offset = 0;
395 if ((ilGen != null) && (monoGetCurrentOffset != null)) {
396 offset = (int)monoGetCurrentOffset.Invoke (null, ilGenArg);
397 }
398
399 /*
400 * Read and decode next internal format code from input file (.xmrobj file).
401 */
402 ScriptObjWriterCode code = (ScriptObjWriterCode)objReader.ReadByte ();
403 switch (code) {
404
405 /*
406 * Reached end-of-file so we are all done.
407 */
408 case ScriptObjWriterCode.TheEnd: {
409 return;
410 }
411
412 /*
413 * Beginning of method's contents.
414 * Method must have already been declared via DclMethod
415 * so all we need is its name to retrieve from methods[].
416 */
417 case ScriptObjWriterCode.BegMethod: {
418 string methName = objReader.ReadString ();
419
420 method = methods[methName];
421 ilGen = method.GetILGenerator ();
422 ilGenArg[0] = ilGen;
423
424 labels.Clear ();
425 locals.Clear ();
426 labelNames.Clear ();
427 localNames.Clear ();
428
429 srcLocs = new Dictionary<int, ScriptSrcLoc> ();
430 if (objectTokens != null) objectTokens.BegMethod (method);
431 break;
432 }
433
434 /*
435 * End of method's contents (ie, an OpCodes.Ret was probably just output).
436 * Call the callback to tell it the method is complete, and it can do whatever
437 * it wants with the method.
438 */
439 case ScriptObjWriterCode.EndMethod: {
440 ilGen = null;
441 ilGenArg[0] = null;
442 scriptObjCode.EndMethod (method, srcLocs);
443 srcLocs = null;
444 if (objectTokens != null) objectTokens.EndMethod ();
445 break;
446 }
447
448 /*
449 * Declare a label for branching to.
450 */
451 case ScriptObjWriterCode.DclLabel: {
452 int number = objReader.ReadInt32 ();
453 string name = objReader.ReadString ();
454
455 labels.Add (number, ilGen.DefineLabel ());
456 labelNames.Add (number, name + "_" + number.ToString ());
457 if (objectTokens != null) objectTokens.DefineLabel (number, name);
458 break;
459 }
460
461 /*
462 * Declare a local variable to store into.
463 */
464 case ScriptObjWriterCode.DclLocal: {
465 int number = objReader.ReadInt32 ();
466 string name = objReader.ReadString ();
467 string type = objReader.ReadString ();
468 Type syType = GetTypeFromStr (sdTypes, type);
469
470 locals.Add (number, ilGen.DeclareLocal (syType));
471 localNames.Add (number, name + "_" + number.ToString ());
472 if (objectTokens != null) objectTokens.DefineLocal (number, name, type, syType);
473 break;
474 }
475
476 /*
477 * Declare a method that will subsequently be defined.
478 * We create the DynamicMethod object at this point in case there
479 * are forward references from other method bodies.
480 */
481 case ScriptObjWriterCode.DclMethod: {
482 string methName = objReader.ReadString ();
483 Type retType = GetTypeFromStr (sdTypes, objReader.ReadString ());
484 int nArgs = objReader.ReadInt32 ();
485
486 Type[] argTypes = new Type[nArgs];
487 string[] argNames = new string[nArgs];
488 for (int i = 0; i < nArgs; i ++) {
489 argTypes[i] = GetTypeFromStr (sdTypes, objReader.ReadString ());
490 argNames[i] = objReader.ReadString ();
491 }
492 methods.Add (methName, new DynamicMethod (methName, retType, argTypes));
493 if (objectTokens != null) objectTokens.DefineMethod (methName, retType, argTypes, argNames);
494 break;
495 }
496
497 /*
498 * Mark a previously declared label at this spot.
499 */
500 case ScriptObjWriterCode.MarkLabel: {
501 int number = objReader.ReadInt32 ();
502
503 ilGen.MarkLabel (labels[number]);
504
505 if (objectTokens != null) objectTokens.MarkLabel (offset, number);
506 break;
507 }
508
509 /*
510 * Try/Catch blocks.
511 */
512 case ScriptObjWriterCode.BegExcBlk: {
513 ilGen.BeginExceptionBlock ();
514 if (objectTokens != null) objectTokens.BegExcBlk (offset);
515 break;
516 }
517
518 case ScriptObjWriterCode.BegCatBlk: {
519 Type excType = GetTypeFromStr (sdTypes, objReader.ReadString ());
520 ilGen.BeginCatchBlock (excType);
521 if (objectTokens != null) objectTokens.BegCatBlk (offset, excType);
522 break;
523 }
524
525 case ScriptObjWriterCode.BegFinBlk: {
526 ilGen.BeginFinallyBlock ();
527 if (objectTokens != null) objectTokens.BegFinBlk (offset);
528 break;
529 }
530
531 case ScriptObjWriterCode.EndExcBlk: {
532 ilGen.EndExceptionBlock ();
533 if (objectTokens != null) objectTokens.EndExcBlk (offset);
534 break;
535 }
536
537 /*
538 * Emit an opcode with no operand.
539 */
540 case ScriptObjWriterCode.EmitNull: {
541 OpCode opCode = ReadOpCode (objReader, ref srcFile, ref srcLine, ref srcPosn);
542
543 SaveSrcLoc (srcLocs, offset, srcFile, srcLine, srcPosn);
544 ilGen.Emit (opCode);
545
546 if (objectTokens != null) objectTokens.EmitNull (offset, opCode);
547 break;
548 }
549
550 /*
551 * Emit an opcode with a FieldInfo operand.
552 */
553 case ScriptObjWriterCode.EmitField: {
554 OpCode opCode = ReadOpCode (objReader, ref srcFile, ref srcLine, ref srcPosn);
555 Type reflectedType = GetTypeFromStr (sdTypes, objReader.ReadString ());
556 string fieldName = objReader.ReadString ();
557
558 FieldInfo field = reflectedType.GetField (fieldName);
559 SaveSrcLoc (srcLocs, offset, srcFile, srcLine, srcPosn);
560 ilGen.Emit (opCode, field);
561
562 if (objectTokens != null) objectTokens.EmitField (offset, opCode, field);
563 break;
564 }
565
566 /*
567 * Emit an opcode with a LocalBuilder operand.
568 */
569 case ScriptObjWriterCode.EmitLocal: {
570 OpCode opCode = ReadOpCode (objReader, ref srcFile, ref srcLine, ref srcPosn);
571 int number = objReader.ReadInt32 ();
572 SaveSrcLoc (srcLocs, offset, srcFile, srcLine, srcPosn);
573 ilGen.Emit (opCode, locals[number]);
574
575 if (objectTokens != null) objectTokens.EmitLocal (offset, opCode, number);
576 break;
577 }
578
579 /*
580 * Emit an opcode with a Type operand.
581 */
582 case ScriptObjWriterCode.EmitType: {
583 OpCode opCode = ReadOpCode (objReader, ref srcFile, ref srcLine, ref srcPosn);
584 string name = objReader.ReadString ();
585 Type type = GetTypeFromStr (sdTypes, name);
586
587 SaveSrcLoc (srcLocs, offset, srcFile, srcLine, srcPosn);
588 ilGen.Emit (opCode, type);
589
590 if (objectTokens != null) objectTokens.EmitType (offset, opCode, type);
591 break;
592 }
593
594 /*
595 * Emit an opcode with a Label operand.
596 */
597 case ScriptObjWriterCode.EmitLabel: {
598 OpCode opCode = ReadOpCode (objReader, ref srcFile, ref srcLine, ref srcPosn);
599 int number = objReader.ReadInt32 ();
600
601 SaveSrcLoc (srcLocs, offset, srcFile, srcLine, srcPosn);
602 ilGen.Emit (opCode, labels[number]);
603
604 if (objectTokens != null) objectTokens.EmitLabel (offset, opCode, number);
605 break;
606 }
607
608 /*
609 * Emit an opcode with a Label array operand.
610 */
611 case ScriptObjWriterCode.EmitLabels: {
612 OpCode opCode = ReadOpCode (objReader, ref srcFile, ref srcLine, ref srcPosn);
613 int nLabels = objReader.ReadInt32 ();
614 Label[] lbls = new Label[nLabels];
615 int[] nums = new int[nLabels];
616 for (int i = 0; i < nLabels; i ++) {
617 nums[i] = objReader.ReadInt32 ();
618 lbls[i] = labels[nums[i]];
619 }
620
621 SaveSrcLoc (srcLocs, offset, srcFile, srcLine, srcPosn);
622 ilGen.Emit (opCode, lbls);
623
624 if (objectTokens != null) objectTokens.EmitLabels (offset, opCode, nums);
625 break;
626 }
627
628 /*
629 * Emit an opcode with a MethodInfo operand (such as a call) of an external function.
630 */
631 case ScriptObjWriterCode.EmitMethodExt: {
632 OpCode opCode = ReadOpCode (objReader, ref srcFile, ref srcLine, ref srcPosn);
633 string methName = objReader.ReadString ();
634 Type methType = GetTypeFromStr (sdTypes, objReader.ReadString ());
635 int nArgs = objReader.ReadInt32 ();
636
637 Type[] argTypes = new Type[nArgs];
638 for (int i = 0; i < nArgs; i ++) {
639 argTypes[i] = GetTypeFromStr (sdTypes, objReader.ReadString ());
640 }
641 MethodInfo methInfo = methType.GetMethod (methName, argTypes);
642 SaveSrcLoc (srcLocs, offset, srcFile, srcLine, srcPosn);
643 ilGen.Emit (opCode, methInfo);
644
645 if (objectTokens != null) objectTokens.EmitMethod (offset, opCode, methInfo);
646 break;
647 }
648
649 /*
650 * Emit an opcode with a MethodInfo operand of an internal function
651 * (previously declared via DclMethod).
652 */
653 case ScriptObjWriterCode.EmitMethodInt: {
654 OpCode opCode = ReadOpCode (objReader, ref srcFile, ref srcLine, ref srcPosn);
655 string methName = objReader.ReadString ();
656
657 MethodInfo methInfo = methods[methName];
658 SaveSrcLoc (srcLocs, offset, srcFile, srcLine, srcPosn);
659 ilGen.Emit (opCode, methInfo);
660
661 if (objectTokens != null) objectTokens.EmitMethod (offset, opCode, methInfo);
662 break;
663 }
664
665 /*
666 * Emit an opcode with a ConstructorInfo operand.
667 */
668 case ScriptObjWriterCode.EmitCtor: {
669 OpCode opCode = ReadOpCode (objReader, ref srcFile, ref srcLine, ref srcPosn);
670 Type ctorType = GetTypeFromStr (sdTypes, objReader.ReadString ());
671 int nArgs = objReader.ReadInt32 ();
672 Type[] argTypes = new Type[nArgs];
673 for (int i = 0; i < nArgs; i ++) {
674 argTypes[i] = GetTypeFromStr (sdTypes, objReader.ReadString ());
675 }
676
677 ConstructorInfo ctorInfo = ctorType.GetConstructor (argTypes);
678 SaveSrcLoc (srcLocs, offset, srcFile, srcLine, srcPosn);
679 ilGen.Emit (opCode, ctorInfo);
680
681 if (objectTokens != null) objectTokens.EmitCtor (offset, opCode, ctorInfo);
682 break;
683 }
684
685 /*
686 * Emit an opcode with a constant operand of various types.
687 */
688 case ScriptObjWriterCode.EmitDouble: {
689 OpCode opCode = ReadOpCode (objReader, ref srcFile, ref srcLine, ref srcPosn);
690 double value = objReader.ReadDouble ();
691
692 if (opCode != OpCodes.Ldc_R8) {
693 throw new Exception ("bad opcode " + opCode.ToString ());
694 }
695 SaveSrcLoc (srcLocs, offset, srcFile, srcLine, srcPosn);
696 ilGen.Emit (opCode, value);
697
698 if (objectTokens != null) objectTokens.EmitDouble (offset, opCode, value);
699 break;
700 }
701
702 case ScriptObjWriterCode.EmitFloat: {
703 OpCode opCode = ReadOpCode (objReader, ref srcFile, ref srcLine, ref srcPosn);
704 float value = objReader.ReadSingle ();
705
706 if (opCode != OpCodes.Ldc_R4) {
707 throw new Exception ("bad opcode " + opCode.ToString ());
708 }
709 SaveSrcLoc (srcLocs, offset, srcFile, srcLine, srcPosn);
710 ilGen.Emit (opCode, value);
711
712 if (objectTokens != null) objectTokens.EmitFloat (offset, opCode, value);
713 break;
714 }
715
716 case ScriptObjWriterCode.EmitInteger: {
717 OpCode opCode = ReadOpCode (objReader, ref srcFile, ref srcLine, ref srcPosn);
718 int value = objReader.ReadInt32 ();
719
720 SaveSrcLoc (srcLocs, offset, srcFile, srcLine, srcPosn);
721
722 if (opCode == OpCodes.Ldc_I4) {
723 if ((value >= -1) && (value <= 8)) {
724 opCode = opCodesLdcI4M1P8[value+1];
725 ilGen.Emit (opCode);
726 if (objectTokens != null) objectTokens.EmitNull (offset, opCode);
727 break;
728 }
729 if ((value >= 0) && (value <= 127)) {
730 opCode = OpCodes.Ldc_I4_S;
731 ilGen.Emit (OpCodes.Ldc_I4_S, (sbyte)value);
732 goto pemitint;
733 }
734 }
735
736 ilGen.Emit (opCode, value);
737 pemitint:
738 if (objectTokens != null) objectTokens.EmitInteger (offset, opCode, value);
739 break;
740 }
741
742 case ScriptObjWriterCode.EmitString: {
743 OpCode opCode = ReadOpCode (objReader, ref srcFile, ref srcLine, ref srcPosn);
744 string value = objReader.ReadString ();
745
746 SaveSrcLoc (srcLocs, offset, srcFile, srcLine, srcPosn);
747 ilGen.Emit (opCode, value);
748
749 if (objectTokens != null) objectTokens.EmitString (offset, opCode, value);
750 break;
751 }
752
753 /*
754 * Who knows what?
755 */
756 default: throw new Exception ("bad ScriptObjWriterCode " + ((byte)code).ToString ());
757 }
758 }
759 }
760
761 /**
762 * @brief Generate array to quickly translate OpCode.Value to full OpCode struct.
763 */
764 private static Dictionary<short, OpCode> PopulateOpCodes ()
765 {
766 Dictionary<short, OpCode> opCodeDict = new Dictionary<short, OpCode> ();
767 FieldInfo[] fields = typeof (OpCodes).GetFields ();
768 for (int i = 0; i < fields.Length; i ++) {
769 OpCode opcode = (OpCode)fields[i].GetValue (null);
770 opCodeDict.Add (opcode.Value, opcode);
771 }
772 return opCodeDict;
773 }
774
775 /**
776 * @brief Write opcode out to file.
777 */
778 private void WriteOpCode (Token errorAt, OpCode opcode)
779 {
780 if (errorAt == null) {
781 objFileWriter.Write ("");
782 objFileWriter.Write (lastErrorAtLine);
783 objFileWriter.Write (lastErrorAtPosn);
784 } else {
785 if (errorAt.file != lastErrorAtFile) {
786 objFileWriter.Write (errorAt.file);
787 lastErrorAtFile = errorAt.file;
788 } else {
789 objFileWriter.Write ("");
790 }
791 objFileWriter.Write (errorAt.line);
792 objFileWriter.Write (errorAt.posn);
793 lastErrorAtLine = errorAt.line;
794 lastErrorAtPosn = errorAt.posn;
795 }
796 objFileWriter.Write (opcode.Value);
797 }
798
799 /**
800 * @brief Read opcode in from file.
801 */
802 private static OpCode ReadOpCode (BinaryReader objReader, ref string srcFile, ref int srcLine, ref int srcPosn)
803 {
804 string f = objReader.ReadString ();
805 if (f != "") srcFile = f;
806 srcLine = objReader.ReadInt32 ();
807 srcPosn = objReader.ReadInt32 ();
808
809 short value = objReader.ReadInt16 ();
810 return opCodes[value];
811 }
812
813 /**
814 * @brief Save an IL_offset -> source location translation entry
815 * @param srcLocs = saved entries for the current function
816 * @param offset = offset in IL object code for next instruction
817 * @param src{File,Line,Posn} = location in source file corresponding to opcode
818 * @returns with entry added to srcLocs
819 */
820 private static void SaveSrcLoc (Dictionary<int, ScriptSrcLoc> srcLocs, int offset, string srcFile, int srcLine, int srcPosn)
821 {
822 ScriptSrcLoc srcLoc = new ScriptSrcLoc ();
823 srcLoc.file = srcFile;
824 srcLoc.line = srcLine;
825 srcLoc.posn = srcPosn;
826 srcLocs[offset] = srcLoc;
827 }
828
829 /**
830 * @brief Create type<->string conversions.
831 * Using Type.AssemblyQualifiedName is horribly inefficient
832 * and all our types should be known.
833 */
834 private static Dictionary<string, Type> PopulateS2T ()
835 {
836 Dictionary<string, Type> s2t = new Dictionary<string, Type> ();
837
838 s2t.Add ("badcallx", typeof (ScriptBadCallNoException));
839 s2t.Add ("binopstr", typeof (BinOpStr));
840 s2t.Add ("bool", typeof (bool));
841 s2t.Add ("char", typeof (char));
842 s2t.Add ("delegate", typeof (Delegate));
843 s2t.Add ("delarr[]", typeof (Delegate[]));
844 s2t.Add ("double", typeof (double));
845 s2t.Add ("exceptn", typeof (Exception));
846 s2t.Add ("float", typeof (float));
847 s2t.Add ("htlist", typeof (HeapTrackerList));
848 s2t.Add ("htobject", typeof (HeapTrackerObject));
849 s2t.Add ("htstring", typeof (HeapTrackerString));
850 s2t.Add ("inlfunc", typeof (CompValuInline));
851 s2t.Add ("int", typeof (int));
852 s2t.Add ("int*", typeof (int).MakeByRefType ());
853 s2t.Add ("intrlokd", typeof (System.Threading.Interlocked));
854 s2t.Add ("lslfloat", typeof (LSL_Float));
855 s2t.Add ("lslint", typeof (LSL_Integer));
856 s2t.Add ("lsllist", typeof (LSL_List));
857 s2t.Add ("lslrot", typeof (LSL_Rotation));
858 s2t.Add ("lslstr", typeof (LSL_String));
859 s2t.Add ("lslvec", typeof (LSL_Vector));
860 s2t.Add ("math", typeof (Math));
861 s2t.Add ("midround", typeof (MidpointRounding));
862 s2t.Add ("object", typeof (object));
863 s2t.Add ("object*", typeof (object).MakeByRefType ());
864 s2t.Add ("object[]", typeof (object[]));
865 s2t.Add ("scrbase", typeof (ScriptBaseClass));
866 s2t.Add ("scrcode", typeof (ScriptCodeGen));
867 s2t.Add ("sdtclobj", typeof (XMRSDTypeClObj));
868 s2t.Add ("string", typeof (string));
869 s2t.Add ("typecast", typeof (TypeCast));
870 s2t.Add ("undstatx", typeof (ScriptUndefinedStateException));
871 s2t.Add ("void", typeof (void));
872 s2t.Add ("xmrarray", typeof (XMR_Array));
873 s2t.Add ("xmrinst", typeof (XMRInstAbstract));
874
875 return s2t;
876 }
877
878 private static Dictionary<Type, string> PopulateT2S ()
879 {
880 Dictionary<string, Type> s2t = PopulateS2T ();
881 Dictionary<Type, string> t2s = new Dictionary<Type, string> ();
882 foreach (KeyValuePair<string, Type> kvp in s2t) {
883 t2s.Add (kvp.Value, kvp.Key);
884 }
885 return t2s;
886 }
887
888 /**
889 * @brief Add to list of internally recognized types.
890 */
891 public static void DefineInternalType (string name, Type type)
892 {
893 if (!string2Type.ContainsKey(name))
894 {
895 string2Type.Add (name, type);
896 type2String.Add (type, name);
897 }
898 }
899
900 private string GetStrFromType (Type t)
901 {
902 string s = GetStrFromTypeWork (t);
903 return s;
904 }
905 private string GetStrFromTypeWork (Type t)
906 {
907 string s;
908
909 // internal fixed types like int and xmrarray etc
910 if (type2String.TryGetValue (t, out s)) return s;
911
912 // script-defined types
913 if (sdTypesRev.TryGetValue (t, out s)) return "sdt$" + s;
914
915 // inline function types
916 s = TokenDeclSDTypeDelegate.TryGetInlineName (t);
917 if (s != null) return s;
918
919 // last resort
920 return t.AssemblyQualifiedName;
921 }
922
923 private static Type GetTypeFromStr (Dictionary<string, TokenDeclSDType> sdTypes, string s)
924 {
925 Type t;
926
927 // internal fixed types like int and xmrarray etc
928 if (string2Type.TryGetValue (s, out t)) return t;
929
930 // script-defined types
931 if (s.StartsWith ("sdt$")) return sdTypes[s.Substring(4)].GetSysType ();
932
933 // inline function types
934 t = TokenDeclSDTypeDelegate.TryGetInlineSysType (s);
935 if (t != null) return t;
936
937 // last resort
938 return Type.GetType (s, true);
939 }
940 }
941
942 public class ScriptSrcLoc {
943 public string file;
944 public int line;
945 public int posn;
946 }
947}