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