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