123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236 |
- /*
- * Copyright (c) Contributors, http://opensimulator.org/
- * See CONTRIBUTORS.TXT for a full list of copyright holders.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * * Neither the name of the OpenSimulator Project nor the
- * names of its contributors may be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
- using OpenSim.Region.ScriptEngine.Yengine;
- using System;
- using System.Collections.Generic;
- using System.IO;
- using System.Reflection;
- using System.Reflection.Emit;
- namespace OpenSim.Region.ScriptEngine.Yengine
- {
- public delegate void ScriptEventHandler(XMRInstAbstract instance);
- /*
- * This object represents the output of the compilation.
- * Once the compilation is complete, its contents should be
- * considered 'read-only', so it can be shared among multiple
- * instances of the script.
- *
- * It gets created by ScriptCodeGen.
- * It gets used by XMRInstance to create script instances.
- */
- public class ScriptObjCode
- {
- public string sourceHash; // source text hash code
- public XMRInstArSizes glblSizes = new XMRInstArSizes();
- // number of global variables of various types
- public string[] stateNames; // convert state number to corresponding string
- public ScriptEventHandler[,] scriptEventHandlerTable;
- // entrypoints to all event handler functions
- // 1st subscript = state code number (0=default)
- // 2nd subscript = event code number
- // null entry means no handler defined for that state,event
- public Dictionary<string, TokenDeclSDType> sdObjTypesName;
- // all script-defined types by name
- public TokenDeclSDType[] sdObjTypesIndx;
- // all script-defined types by sdTypeIndex
- public Dictionary<Type, string> sdDelTypes;
- // all script-defined delegates (including anonymous)
- public Dictionary<string, DynamicMethod> dynamicMethods;
- // all dyanmic methods
- public Dictionary<string, KeyValuePair<int, ScriptSrcLoc>[]> scriptSrcLocss;
- // method,iloffset -> source file,line,posn
- public int refCount; // used by engine to keep track of number of
- // instances that are using this object code
- public Dictionary<string, Dictionary<int, string>> globalVarNames = new Dictionary<string, Dictionary<int, string>>();
- /**
- * @brief Fill in ScriptObjCode from an YEngine object file.
- * 'objFileReader' is a serialized form of the CIL code we generated
- * 'asmFileWriter' is where we write the disassembly to (or null if not wanted)
- * 'srcFileWriter' is where we write the decompilation to (or null if not wanted)
- * Throws an exception if there is any error (theoretically).
- */
- public ScriptObjCode(BinaryReader objFileReader, TextWriter asmFileWriter, TextWriter srcFileWriter)
- {
- // Check version number to make sure we know how to process file contents.
- char[] ocm = objFileReader.ReadChars(ScriptCodeGen.OBJECT_CODE_MAGIC.Length);
- if(new String(ocm) != ScriptCodeGen.OBJECT_CODE_MAGIC)
- throw new CVVMismatchException("Not an Yengine object file (bad magic)");
- int cvv = objFileReader.ReadInt32();
- if(cvv != ScriptCodeGen.COMPILED_VERSION_VALUE)
- throw new CVVMismatchException(
- "Object version is " + cvv.ToString() + " but accept only " + ScriptCodeGen.COMPILED_VERSION_VALUE.ToString());
- // Fill in simple parts of scriptObjCode object.
- sourceHash = objFileReader.ReadString();
- glblSizes.ReadFromFile(objFileReader);
- int nStates = objFileReader.ReadInt32();
- stateNames = new string[nStates];
- for(int i = 0; i < nStates; i++)
- {
- stateNames[i] = objFileReader.ReadString();
- if(asmFileWriter != null)
- asmFileWriter.WriteLine(" state[{0}] = {1}", i, stateNames[i]);
- }
- if(asmFileWriter != null)
- glblSizes.WriteAsmFile(asmFileWriter, "numGbl");
- string gblName;
- while((gblName = objFileReader.ReadString()) != "")
- {
- string gblType = objFileReader.ReadString();
- int gblIndex = objFileReader.ReadInt32();
- Dictionary<int, string> names;
- if(!globalVarNames.TryGetValue(gblType, out names))
- {
- names = new Dictionary<int, string>();
- globalVarNames.Add(gblType, names);
- }
- names.Add(gblIndex, gblName);
- if(asmFileWriter != null)
- asmFileWriter.WriteLine(" {0} = {1}[{2}]", gblName, gblType, gblIndex);
- }
- // Read in script-defined types.
- sdObjTypesName = new Dictionary<string, TokenDeclSDType>();
- sdDelTypes = new Dictionary<Type, string>();
- int maxIndex = -1;
- while((gblName = objFileReader.ReadString()) != "")
- {
- TokenDeclSDType sdt = TokenDeclSDType.ReadFromFile(sdObjTypesName,
- gblName, objFileReader, asmFileWriter);
- sdObjTypesName.Add(gblName, sdt);
- if(maxIndex < sdt.sdTypeIndex)
- maxIndex = sdt.sdTypeIndex;
- if(sdt is TokenDeclSDTypeDelegate)
- sdDelTypes.Add(sdt.GetSysType(), gblName);
- }
- sdObjTypesIndx = new TokenDeclSDType[maxIndex + 1];
- foreach(TokenDeclSDType sdt in sdObjTypesName.Values)
- sdObjTypesIndx[sdt.sdTypeIndex] = sdt;
- // Now fill in the methods (the hard part).
- scriptEventHandlerTable = new ScriptEventHandler[nStates, (int)ScriptEventCode.Size];
- dynamicMethods = new Dictionary<string, DynamicMethod>();
- scriptSrcLocss = new Dictionary<string, KeyValuePair<int, ScriptSrcLoc>[]>();
- ObjectTokens objectTokens = null;
- if(asmFileWriter != null)
- objectTokens = new OTDisassemble(this, asmFileWriter);
- else if(srcFileWriter != null)
- objectTokens = new OTDecompile(this, srcFileWriter);
- try
- {
- ScriptObjWriter.CreateObjCode(sdObjTypesName, objFileReader, this, objectTokens);
- }
- finally
- {
- objectTokens?.Close();
- }
- // We enter all script event handler methods in the ScriptEventHandler table.
- // They are named: <statename> <eventname>
- foreach(KeyValuePair<string, DynamicMethod> kvp in dynamicMethods)
- {
- string methName = kvp.Key;
- int i = methName.IndexOf(' ');
- if(i < 0)
- continue;
- string stateName = methName.Substring(0, i);
- string eventName = methName.Substring(++i);
- int stateCode;
- for(stateCode = stateNames.Length; --stateCode >= 0;)
- if(stateNames[stateCode] == stateName)
- break;
- int eventCode = (int)Enum.Parse(typeof(ScriptEventCode), eventName);
- scriptEventHandlerTable[stateCode, eventCode] =
- (ScriptEventHandler)kvp.Value.CreateDelegate(typeof(ScriptEventHandler));
- }
- // Fill in all script-defined class vtables.
- foreach(TokenDeclSDType sdt in sdObjTypesIndx)
- {
- if((sdt != null) && (sdt is TokenDeclSDTypeClass))
- {
- TokenDeclSDTypeClass sdtc = (TokenDeclSDTypeClass)sdt;
- sdtc.FillVTables(this);
- }
- }
- }
- /**
- * @brief Called once for every method found in objFileReader file.
- * It enters the method in the ScriptObjCode object table so it can be called.
- */
- public void EndMethod(DynamicMethod method, Dictionary<int, ScriptSrcLoc> srcLocs)
- {
- // Save method object code pointer.
- dynamicMethods.Add(method.Name, method);
- // Build and sort iloffset -> source code location array.
- int n = srcLocs.Count;
- KeyValuePair<int, ScriptSrcLoc>[] srcLocArray = new KeyValuePair<int, ScriptSrcLoc>[n];
- n = 0;
- foreach(KeyValuePair<int, ScriptSrcLoc> kvp in srcLocs)
- srcLocArray[n++] = kvp;
- Array.Sort(srcLocArray, endMethodWrapper);
- // Save sorted array.
- scriptSrcLocss.Add(method.Name, srcLocArray);
- }
- /**
- * @brief Called once for every method found in objFileReader file.
- * It enters the method in the ScriptObjCode object table so it can be called.
- */
- private static EndMethodWrapper endMethodWrapper = new EndMethodWrapper();
- private class EndMethodWrapper: System.Collections.IComparer
- {
- public int Compare(object x, object y)
- {
- KeyValuePair<int, ScriptSrcLoc> kvpx = (KeyValuePair<int, ScriptSrcLoc>)x;
- KeyValuePair<int, ScriptSrcLoc> kvpy = (KeyValuePair<int, ScriptSrcLoc>)y;
- return kvpx.Key - kvpy.Key;
- }
- }
- }
- }
|