private void VerifyGeneratedCode() { #if false if (this.EnableDebugging == false) { return; } var filePath = System.IO.Path.Combine(System.IO.Path.GetTempPath(), "JurassicDebug.dll"); // set the entry point for the application and save it this.ReflectionEmitInfo.AssemblyBuilder.Save(System.IO.Path.GetFileName(filePath)); // Copy this DLL there as well. var assemblyPath = System.Reflection.Assembly.GetExecutingAssembly().Location; System.IO.File.Copy(assemblyPath, System.IO.Path.Combine(System.IO.Path.GetDirectoryName(filePath), System.IO.Path.GetFileName(assemblyPath)), true); var startInfo = new System.Diagnostics.ProcessStartInfo(); startInfo.FileName = @"C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin\NETFX 4.0 Tools\x64\PEVerify.exe"; startInfo.Arguments = string.Format("\"{0}\" /nologo /verbose /unique", filePath); startInfo.CreateNoWindow = true; startInfo.RedirectStandardOutput = true; startInfo.UseShellExecute = false; var verifyProcess = System.Diagnostics.Process.Start(startInfo); string output = verifyProcess.StandardOutput.ReadToEnd(); if (verifyProcess.ExitCode != 0) { throw new InvalidOperationException(output); } //else //{ // System.Diagnostics.Process.Start(@"C:\Program Files\Reflector\Reflector.exe", string.Format("\"{0}\" /select:JavaScriptClass", filePath)); // Environment.Exit(0); //} // The assembly can no longer be modified - so don't use it again. this.ReflectionEmitInfo = null; #endif }
internal Prototype(ScriptEngine engine, string name, Prototype baseProto, bool isStatic) { Engine = engine; BasePrototype = baseProto; IsStatic = isStatic; ReflectionEmitModuleInfo moduleInfo = engine.ReflectionEmitInfo; if (name == null) { name = "__proto__" + moduleInfo.TypeCount; moduleInfo.TypeCount++; } Name = name; Type baseType; if (baseProto == null) { baseType = typeof(object); } else { baseType = baseProto.Type; } // Define the type now; note that methods are not declared on these (JS defined methods are always static): Builder = moduleInfo.ModuleBuilder.DefineType(name, System.Reflection.TypeAttributes.Public | System.Reflection.TypeAttributes.Class, baseType ); if (!isStatic) { // Define the default ctr and obtain it: AddConstructor(Builder.DefineDefaultConstructor(System.Reflection.MethodAttributes.Public)); } }
/// <summary> /// Generates IL for the script. /// </summary> public void GenerateCode() { // Generate the abstract syntax tree if it hasn't already been generated. if (this.AbstractSyntaxTree == null) { Parse(); Optimize(); } // Initialize global code-gen information. var optimizationInfo = new OptimizationInfo(); optimizationInfo.AbstractSyntaxTree = this.AbstractSyntaxTree; optimizationInfo.StrictMode = this.StrictMode; optimizationInfo.MethodOptimizationHints = this.MethodOptimizationHints; optimizationInfo.FunctionName = this.GetStackName(); optimizationInfo.Source = this.Source; ILGenerator generator; if (this.Options.EnableDebugging == false) { // DynamicMethod requires full trust because of generator.LoadMethodPointer in the // FunctionExpression class. // Create a new dynamic method. System.Reflection.Emit.DynamicMethod dynamicMethod = new System.Reflection.Emit.DynamicMethod( GetMethodName(), // Name of the generated method. typeof(object), // Return type of the generated method. GetParameterTypes(), // Parameter types of the generated method. typeof(MethodGenerator), // Owner type. true); // Skip visibility checks. #if USE_DYNAMIC_IL_INFO generator = new DynamicILGenerator(dynamicMethod); #else generator = new ReflectionEmitILGenerator(dynamicMethod.GetILGenerator(), emitDebugInfo: false); #endif if (this.Options.EnableILAnalysis == true) { // Replace the generator with one that logs. generator = new LoggingILGenerator(generator); } // Initialization code will appear to come from line 1. optimizationInfo.MarkSequencePoint(generator, new SourceCodeSpan(1, 1, 1, 1)); // Generate the IL. GenerateCode(generator, optimizationInfo); generator.Complete(); // Create a delegate from the method. this.GeneratedMethod = new GeneratedMethod(dynamicMethod.CreateDelegate(GetDelegate()), optimizationInfo.NestedFunctions); } else { #if ENABLE_DEBUGGING // Debugging or low trust path. ReflectionEmitModuleInfo reflectionEmitInfo; System.Reflection.Emit.TypeBuilder typeBuilder; lock (reflectionEmitInfoLock) { reflectionEmitInfo = ReflectionEmitInfo; if (reflectionEmitInfo == null) { reflectionEmitInfo = new ReflectionEmitModuleInfo(); // Create a dynamic assembly and module. reflectionEmitInfo.AssemblyBuilder = System.Threading.Thread.GetDomain().DefineDynamicAssembly( new System.Reflection.AssemblyName("Jurassic Dynamic Assembly"), System.Reflection.Emit.AssemblyBuilderAccess.Run); // Mark the assembly as debuggable. This must be done before the module is created. var debuggableAttributeConstructor = typeof(System.Diagnostics.DebuggableAttribute).GetConstructor( new Type[] { typeof(System.Diagnostics.DebuggableAttribute.DebuggingModes) }); reflectionEmitInfo.AssemblyBuilder.SetCustomAttribute( new System.Reflection.Emit.CustomAttributeBuilder(debuggableAttributeConstructor, new object[] { System.Diagnostics.DebuggableAttribute.DebuggingModes.DisableOptimizations | System.Diagnostics.DebuggableAttribute.DebuggingModes.Default })); // Create a dynamic module. reflectionEmitInfo.ModuleBuilder = reflectionEmitInfo.AssemblyBuilder.DefineDynamicModule("Module", this.Options.EnableDebugging); ReflectionEmitInfo = reflectionEmitInfo; } // Create a new type to hold our method. typeBuilder = reflectionEmitInfo.ModuleBuilder.DefineType("JavaScriptClass" + reflectionEmitInfo.TypeCount.ToString(), System.Reflection.TypeAttributes.Public | System.Reflection.TypeAttributes.Class); reflectionEmitInfo.TypeCount++; } // Create a method. var methodBuilder = typeBuilder.DefineMethod(this.GetMethodName(), System.Reflection.MethodAttributes.HideBySig | System.Reflection.MethodAttributes.Static | System.Reflection.MethodAttributes.Public, typeof(object), GetParameterTypes()); // Generate the IL for the method. generator = new ReflectionEmitILGenerator(methodBuilder.GetILGenerator(), emitDebugInfo: true); if (this.Options.EnableILAnalysis == true) { // Replace the generator with one that logs. generator = new LoggingILGenerator(generator); } if (this.Source.Path != null && this.Options.EnableDebugging == true) { // Initialize the debugging information. optimizationInfo.DebugDocument = reflectionEmitInfo.ModuleBuilder.DefineDocument(this.Source.Path, LanguageType, LanguageVendor, DocumentType); var parameterNames = GetParameterNames(); for (var i = 0; i < parameterNames.Length; i++) { methodBuilder.DefineParameter(i + 1, System.Reflection.ParameterAttributes.In, parameterNames[i]); } } optimizationInfo.MarkSequencePoint(generator, new SourceCodeSpan(1, 1, 1, 1)); GenerateCode(generator, optimizationInfo); generator.Complete(); // Bake it. var type = typeBuilder.CreateType(); var methodInfo = type.GetMethod(this.GetMethodName()); this.GeneratedMethod = new GeneratedMethod(Delegate.CreateDelegate(GetDelegate(), methodInfo), optimizationInfo.NestedFunctions); #else throw new NotImplementedException(); #endif // ENABLE_DEBUGGING } if (this.Options.EnableILAnalysis == true) { // Store the disassembled IL so it can be retrieved for analysis purposes. this.GeneratedMethod.DisassembledIL = generator.ToString(); } }
/// <summary> /// Generates IL for a specific variant of the method. Arguments MUST include 'this' keyword. /// </summary> public UserDefinedFunction GenerateCode(ArgVariable[] arguments, OptimizationInfo optimizationInfo) { // Generate the abstract syntax tree if it hasn't already been generated. if (this.AbstractSyntaxTree == null) { Parse(optimizationInfo); Dependencies = optimizationInfo.NestedFunctions; } // Create the param types, which is the args (as they already include 'this'): int argCount = arguments == null?0 : arguments.Length; Type[] parameters = new Type[argCount]; for (int i = 0; i < argCount; i++) { // Transfer the type over: parameters[i] = arguments[i].Type; } string name = GetMethodName(); // Initialize global code-gen information. optimizationInfo.AbstractSyntaxTree = this.AbstractSyntaxTree; optimizationInfo.StrictMode = this.StrictMode; optimizationInfo.MethodOptimizationHints = this.MethodOptimizationHints; optimizationInfo.FunctionName = this.GetStackName(); optimizationInfo.Source = this.Source; ILGenerator generator; // Create the UDF now (must be before we generate the code as it would go recursive for recursive functions otherwise): UserDefinedFunction mtd = new UserDefinedFunction(name, arguments, this as FunctionMethodGenerator, StrictMode); // Add to created set: GeneratedMethods.Add(mtd); // Clear locals: if (InitialScope != null) { InitialScope.Reset(); } // Resolve variables now: AbstractSyntaxTree.ResolveVariables(optimizationInfo); // Low trust path. ReflectionEmitModuleInfo reflectionEmitInfo = this.Engine.ReflectionEmitInfo; var typeBuilder = reflectionEmitInfo.MainType; // Create the method builder now: var methodBuilder = typeBuilder.DefineMethod(name, System.Reflection.MethodAttributes.HideBySig | System.Reflection.MethodAttributes.Static | System.Reflection.MethodAttributes.Public, optimizationInfo.ReturnType, parameters); mtd.body = methodBuilder; // Generate the IL for the method. generator = new ReflectionEmitILGenerator(Engine, methodBuilder); if (ScriptEngine.EnableILAnalysis) { // Replace the generator with one that logs. generator = new LoggingILGenerator(generator); } // optimizationInfo.MarkSequencePoint(generator, new SourceCodeSpan(1, 1, 1, 1)); GenerateCode(arguments, generator, optimizationInfo); generator.Complete(); if (ScriptEngine.EnableILAnalysis) { // Store the disassembled IL so it can be retrieved for analysis purposes. mtd.DisassembledIL = generator.ToString(); string args = ""; if (arguments != null) { for (int i = 0; i < arguments.Length; i++) { if (i != 0) { args += ","; } args += parameters[i] + " " + arguments[i].Name.ToString(); } } Engine.Log("-IL " + GetMethodName() + "(" + args + ") : " + methodBuilder.ReturnType + "-"); Engine.Log(mtd.DisassembledIL); } return(mtd); }