CompiledMethod CompileBlock (Class host, Undo undo, Report Report) { #if STATIC throw new NotSupportedException (); #else string current_debug_name = "eval-" + count + ".dll"; ++count; AssemblyDefinitionDynamic assembly; AssemblyBuilderAccess access; if (Environment.GetEnvironmentVariable ("SAVE") != null) { access = AssemblyBuilderAccess.RunAndSave; assembly = new AssemblyDefinitionDynamic (module, current_debug_name, current_debug_name); assembly.Importer = importer; } else { #if NET_4_0 access = AssemblyBuilderAccess.RunAndCollect; #else access = AssemblyBuilderAccess.Run; #endif assembly = new AssemblyDefinitionDynamic (module, current_debug_name); } assembly.Create (AppDomain.CurrentDomain, access); Method expression_method; if (host != null) { var base_class_imported = importer.ImportType (base_class); var baseclass_list = new List<FullNamedExpression> (1) { new TypeExpression (base_class_imported, host.Location) }; host.SetBaseTypes (baseclass_list); expression_method = (Method) host.Members[0]; if ((expression_method.ModFlags & Modifiers.ASYNC) != 0) { // // Host method is async. When WaitOnTask is set we wrap it with wait // // void AsyncWait (ref object $retval) { // $retval = Host(); // ((Task)$retval).Wait(); // When WaitOnTask is set // } // var p = new ParametersCompiled ( new Parameter (new TypeExpression (module.Compiler.BuiltinTypes.Object, Location.Null), "$retval", Parameter.Modifier.REF, null, Location.Null) ); var method = new Method(host, new TypeExpression(module.Compiler.BuiltinTypes.Void, Location.Null), Modifiers.PUBLIC | Modifiers.STATIC, new MemberName("AsyncWait"), p, null); method.Block = new ToplevelBlock(method.Compiler, p, Location.Null); method.Block.AddStatement(new StatementExpression (new SimpleAssign( new SimpleName(p [0].Name, Location.Null), new Invocation(new SimpleName(expression_method.MemberName.Name, Location.Null), new Arguments(0)), Location.Null), Location.Null)); if (WaitOnTask) { var task = new Cast (expression_method.TypeExpression, new SimpleName (p [0].Name, Location.Null), Location.Null); method.Block.AddStatement (new StatementExpression (new Invocation ( new MemberAccess (task, "Wait", Location.Null), new Arguments (0)), Location.Null)); } host.AddMember(method); expression_method = method; } host.CreateContainer(); host.DefineContainer(); host.Define(); } else { expression_method = null; } module.CreateContainer (); // Disable module and source file re-definition checks module.EnableRedefinition (); source_file.EnableRedefinition (); module.Define (); if (Report.Errors != 0){ if (undo != null) undo.ExecuteUndo (); return null; } if (host != null){ host.PrepareEmit (); host.EmitContainer (); } module.EmitContainer (); if (Report.Errors != 0){ if (undo != null) undo.ExecuteUndo (); return null; } module.CloseContainer (); if (host != null) host.CloseContainer (); if (access == AssemblyBuilderAccess.RunAndSave) assembly.Save (); if (host == null) return null; // // Unlike Mono, .NET requires that the MethodInfo is fetched, it cant // work from MethodBuilders. Retarded, I know. // var tt = assembly.Builder.GetType (host.TypeBuilder.Name); var mi = tt.GetMethod (expression_method.MemberName.Name); // // We need to then go from FieldBuilder to FieldInfo // or reflection gets confused (it basically gets confused, and variables override each // other). // foreach (var member in host.Members) { var field = member as Field; if (field == null) continue; var fi = tt.GetField (field.Name); Tuple<FieldSpec, FieldInfo> old; // If a previous value was set, nullify it, so that we do // not leak memory if (fields.TryGetValue (field.Name, out old)) { if (old.Item1.MemberType.IsStruct) { // // TODO: Clear fields for structs // } else { try { old.Item2.SetValue (null, null); } catch { } } } fields[field.Name] = Tuple.Create (field.Spec, fi); } return (CompiledMethod) System.Delegate.CreateDelegate (typeof (CompiledMethod), mi); #endif }
public override Assembly LoadAssemblyFile (string fileName, bool isImplicitReference) { bool? has_extension = null; foreach (var path in paths) { var file = Path.Combine (path, fileName); if (compiler.Settings.DebugFlags > 0) Console.WriteLine ("Probing assembly location `{0}'", file); if (!File.Exists (file)) { if (!has_extension.HasValue) has_extension = fileName.EndsWith (".dll", StringComparison.Ordinal) || fileName.EndsWith (".exe", StringComparison.Ordinal); if (has_extension.Value) continue; file += ".dll"; if (!File.Exists (file)) continue; } try { using (RawModule module = domain.OpenRawModule (file)) { if (!module.IsManifestModule) { Error_AssemblyIsModule (fileName); return null; } // // check whether the assembly can be actually imported without // collision // var an = module.GetAssemblyName (); foreach (var entry in loaded_names) { var loaded_name = entry.Item1; if (an.Name != loaded_name.Name) continue; if (module.ModuleVersionId == entry.Item3.ManifestModule.ModuleVersionId) return entry.Item3; if (((an.Flags | loaded_name.Flags) & AssemblyNameFlags.PublicKey) == 0) { compiler.Report.SymbolRelatedToPreviousError (entry.Item2); compiler.Report.SymbolRelatedToPreviousError (fileName); compiler.Report.Error (1704, "An assembly with the same name `{0}' has already been imported. Consider removing one of the references or sign the assembly", an.Name); return null; } if ((an.Flags & AssemblyNameFlags.PublicKey) == (loaded_name.Flags & AssemblyNameFlags.PublicKey) && an.Version.Equals (loaded_name.Version)) { compiler.Report.SymbolRelatedToPreviousError (entry.Item2); compiler.Report.SymbolRelatedToPreviousError (fileName); compiler.Report.Error (1703, "An assembly with the same identity `{0}' has already been imported. Consider removing one of the references", an.FullName); return null; } } if (compiler.Settings.DebugFlags > 0) Console.WriteLine ("Loading assembly `{0}'", fileName); var assembly = domain.LoadAssembly (module); if (assembly != null) loaded_names.Add (Tuple.Create (an, fileName, assembly)); return assembly; } } catch { if (!isImplicitReference) Error_FileCorrupted (file); return null; } } if (!isImplicitReference) Error_FileNotFound (fileName); return null; }