X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fgmcs%2Fcodegen.cs;h=fedc652b551bc3cba80107b32f37c59cd9e6f9b8;hb=b0eff411fcc55fa6a7bbc5ee97bb592fe3204309;hp=a06373e464308b8279c95347f2a78107ffab5bc9;hpb=3763abdafb2c1e5f9594b015fe4bf3acb553a25a;p=mono.git
diff --git a/mcs/gmcs/codegen.cs b/mcs/gmcs/codegen.cs
old mode 100755
new mode 100644
index a06373e4643..fedc652b551
--- a/mcs/gmcs/codegen.cs
+++ b/mcs/gmcs/codegen.cs
@@ -4,16 +4,20 @@
// Author:
// Miguel de Icaza (miguel@ximian.com)
//
-// (C) 2001 Ximian, Inc.
+// (C) 2001, 2002, 2003 Ximian, Inc.
+// (C) 2004 Novell, Inc.
//
-
+//#define PRODUCTION
using System;
using System.IO;
using System.Collections;
+using System.Collections.Specialized;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.InteropServices;
+using System.Security;
using System.Security.Cryptography;
+using System.Security.Permissions;
using Mono.Security.Cryptography;
@@ -30,6 +34,11 @@ namespace Mono.CSharp {
public static ModuleClass Module;
static CodeGen ()
+ {
+ Reset ();
+ }
+
+ public static void Reset ()
{
Assembly = new AssemblyClass ();
Module = new ModuleClass (RootContext.Unsafe);
@@ -63,28 +72,21 @@ namespace Mono.CSharp {
return ".";
}
- static string TrimExt (string name)
- {
- int pos = name.LastIndexOf ('.');
-
- return name.Substring (0, pos);
- }
-
static public string FileName;
//
// Initializes the symbol writer
//
- static void InitializeSymbolWriter ()
+ static void InitializeSymbolWriter (string filename)
{
- SymbolWriter = SymbolWriter.GetSymbolWriter (Module.Builder);
+ SymbolWriter = SymbolWriter.GetSymbolWriter (Module.Builder, filename);
//
// If we got an ISymbolWriter instance, initialize it.
//
if (SymbolWriter == null) {
Report.Warning (
- -18, "Could not find the symbol writer assembly (Mono.CSharp.Debugger.dll). This is normally an installation problem. Please make sure to compile and install the mcs/class/Mono.CSharp.Debugger directory.");
+ -18, "Could not find the symbol writer assembly (Mono.CompilerServices.SymbolWriter.dll). This is normally an installation problem. Please make sure to compile and install the mcs/class/Mono.CompilerServices.SymbolWriter directory.");
return;
}
}
@@ -92,10 +94,28 @@ namespace Mono.CSharp {
//
// Initializes the code generator variables
//
- static public void Init (string name, string output, bool want_debugging_support)
+ static public bool Init (string name, string output, bool want_debugging_support)
{
FileName = output;
AssemblyName an = Assembly.GetAssemblyName (name, output);
+ if (an == null)
+ return false;
+
+ if (an.KeyPair != null) {
+ // If we are going to strong name our assembly make
+ // sure all its refs are strong named
+ foreach (Assembly a in TypeManager.GetAssemblies ()) {
+ AssemblyName ref_name = a.GetName ();
+ byte [] b = ref_name.GetPublicKeyToken ();
+ if (b == null || b.Length == 0) {
+ Report.Warning (1577, "Assembly generation failed " +
+ "-- Referenced assembly '" +
+ ref_name.Name +
+ "' does not have a strong name.");
+ //Environment.Exit (1);
+ }
+ }
+ }
current_domain = AppDomain.CurrentDomain;
@@ -110,14 +130,14 @@ namespace Mono.CSharp {
RootContext.StrongNameKeyContainer + "'.");
Environment.Exit (1);
}
- throw;
+ return false;
}
catch (CryptographicException) {
if ((RootContext.StrongNameKeyContainer != null) || (RootContext.StrongNameKeyFile != null)) {
Report.Error (1548, "Could not use the specified key to strongname the assembly.");
Environment.Exit (1);
}
- throw;
+ return false;
}
//
@@ -129,10 +149,12 @@ namespace Mono.CSharp {
// load the default symbol writer.
//
Module.Builder = Assembly.Builder.DefineDynamicModule (
- Basename (name), Basename (output), want_debugging_support);
+ Basename (name), Basename (output), false);
if (want_debugging_support)
- InitializeSymbolWriter ();
+ InitializeSymbolWriter (output);
+
+ return true;
}
static public void Save (string name)
@@ -152,82 +174,15 @@ namespace Mono.CSharp {
catch (System.IO.IOException io) {
Report.Error (16, "Could not write to file `"+name+"', cause: " + io.Message);
}
- }
- }
-
- //
- // Provides "local" store across code that can yield: locals
- // or fields, notice that this should not be used by anonymous
- // methods to create local storage, those only require
- // variable mapping.
- //
- public class VariableStorage {
- ILGenerator ig;
- FieldBuilder fb;
- LocalBuilder local;
-
- static int count;
-
- public VariableStorage (EmitContext ec, Type t)
- {
- count++;
- if (ec.InIterator)
- fb = IteratorHandler.Current.MapVariable ("s_", count.ToString (), t);
- else
- local = ec.ig.DeclareLocal (t);
- ig = ec.ig;
- }
-
- public void EmitThis ()
- {
- if (fb != null)
- ig.Emit (OpCodes.Ldarg_0);
- }
-
- public void EmitStore ()
- {
- if (fb == null)
- ig.Emit (OpCodes.Stloc, local);
- else
- ig.Emit (OpCodes.Stfld, fb);
- }
-
- public void EmitLoad ()
- {
- if (fb == null)
- ig.Emit (OpCodes.Ldloc, local);
- else
- ig.Emit (OpCodes.Ldfld, fb);
- }
-
- public void EmitCall (MethodInfo mi)
- {
- // FIXME : we should handle a call like tostring
- // here, where boxing is needed. However, we will
- // never encounter that with the current usage.
-
- bool value_type_call;
- EmitThis ();
- if (fb == null) {
- value_type_call = local.LocalType.IsValueType;
-
- if (value_type_call)
- ig.Emit (OpCodes.Ldloca, local);
- else
- ig.Emit (OpCodes.Ldloc, local);
- } else {
- value_type_call = fb.FieldType.IsValueType;
-
- if (value_type_call)
- ig.Emit (OpCodes.Ldflda, fb);
- else
- ig.Emit (OpCodes.Ldfld, fb);
+ catch (System.UnauthorizedAccessException ua) {
+ Report.Error (16, "Could not write to file `"+name+"', cause: " + ua.Message);
}
-
- ig.Emit (value_type_call ? OpCodes.Call : OpCodes.Callvirt, mi);
+
+ if (SymbolWriter != null)
+ SymbolWriter.WriteSymbolFile ();
}
}
-
+
///
/// An Emit Context is created for each body of code (from methods,
/// properties bodies, indexer bodies or constructor bodies)
@@ -262,11 +217,26 @@ namespace Mono.CSharp {
///
public bool IsStatic;
+ ///
+ /// Whether the actual created method is static or instance method.
+ /// Althoug the method might be declared as `static', if an anonymous
+ /// method is involved, we might turn this into an instance method.
+ ///
+ /// So this reflects the low-level staticness of the method, while
+ /// IsStatic represents the semantic, high-level staticness.
+ ///
+ public bool MethodIsStatic;
+
///
/// Whether we are emitting a field initializer
///
public bool IsFieldInitializer;
+ ///
+ /// We are resolving a class'es base class and interfaces.
+ ///
+ public bool ResolvingTypeTree;
+
///
/// The value that is allowed to be returned or NULL if there is no
/// return type.
@@ -288,7 +258,7 @@ namespace Mono.CSharp {
/// Whether we're control flow analysis enabled
///
public bool DoFlowAnalysis;
-
+
///
/// Keeps track of the Type to LocalBuilder temporary storage created
/// to store structures (used to compute the address of the structure
@@ -323,12 +293,6 @@ namespace Mono.CSharp {
public bool IsLastStatement;
- ///
- /// Whether remapping of locals, parameters and fields is turned on.
- /// Used by iterators and anonymous methods.
- ///
- public bool RemapToProxy;
-
///
/// Whether we are inside an unsafe block
///
@@ -339,23 +303,21 @@ namespace Mono.CSharp {
///
public bool InFixedInitializer;
+ public bool InRefOutArgumentResolving;
+
+ public bool InCatch;
+ public bool InFinally;
+
///
/// Whether we are inside an anonymous method.
///
- public bool InAnonymousMethod;
+ public AnonymousContainer CurrentAnonymousMethod;
///
/// Location for this EmitContext
///
public Location loc;
- ///
- /// Used to flag that it is ok to define types recursively, as the
- /// expressions are being evaluated as part of the type lookup
- /// during the type resolution process
- ///
- public bool ResolvingTypeTree;
-
///
/// Inside an enum definition, we do not resolve enumeration values
/// to their enumerations, but rather to the underlying type/value
@@ -366,7 +328,44 @@ namespace Mono.CSharp {
///
public bool InEnumContext;
+ ///
+ /// Anonymous methods can capture local variables and fields,
+ /// this object tracks it. It is copied from the TopLevelBlock
+ /// field.
+ ///
+ public CaptureContext capture_context;
+
+ ///
+ /// Trace when method is called and is obsolete then this member suppress message
+ /// when call is inside next [Obsolete] method or type.
+ ///
+ public bool TestObsoleteMethodUsage = true;
+
+ ///
+ /// The current iterator
+ ///
+ public Iterator CurrentIterator;
+
+ ///
+ /// Whether we are in the resolving stage or not
+ ///
+ enum Phase {
+ Created,
+ Resolving,
+ Emitting
+ }
+
+ Phase current_phase;
FlowBranching current_flow_branching;
+
+ static int next_id = 0;
+ int id = ++next_id;
+
+ public override string ToString ()
+ {
+ return String.Format ("EmitContext ({0}:{1}:{2})", id,
+ CurrentIterator, capture_context, loc);
+ }
public EmitContext (DeclSpace parent, DeclSpace ds, Location l, ILGenerator ig,
Type return_type, int code_flags, bool is_constructor)
@@ -377,14 +376,18 @@ namespace Mono.CSharp {
DeclSpace = ds;
CheckState = RootContext.Checked;
ConstantCheckState = true;
+
+ if ((return_type is TypeBuilder) && return_type.IsGenericTypeDefinition)
+ throw new InternalErrorException ();
IsStatic = (code_flags & Modifiers.STATIC) != 0;
+ MethodIsStatic = IsStatic;
InIterator = (code_flags & Modifiers.METHOD_YIELDS) != 0;
- RemapToProxy = InIterator;
ReturnType = return_type;
IsConstructor = is_constructor;
CurrentBlock = null;
CurrentFile = 0;
+ current_phase = Phase.Created;
if (parent != null){
// Can only be null for the ResolveType contexts.
@@ -418,6 +421,12 @@ namespace Mono.CSharp {
}
}
+ public bool HaveCaptureInfo {
+ get {
+ return capture_context != null;
+ }
+ }
+
//
// Starts a new code branching. This inherits the state of all local
// variables and parameters from the current branching.
@@ -435,15 +444,27 @@ namespace Mono.CSharp {
{
FlowBranching.BranchingType type;
- if (CurrentBranching.Type == FlowBranching.BranchingType.Switch)
+ if ((CurrentBranching != null) &&
+ (CurrentBranching.Type == FlowBranching.BranchingType.Switch))
type = FlowBranching.BranchingType.SwitchSection;
else
type = FlowBranching.BranchingType.Block;
- current_flow_branching = FlowBranching.CreateBranching (CurrentBranching, type, block, block.StartLocation);
+ DoFlowAnalysis = true;
+
+ current_flow_branching = FlowBranching.CreateBranching (
+ CurrentBranching, type, block, block.StartLocation);
return current_flow_branching;
}
+ public FlowBranchingException StartFlowBranching (ExceptionStatement stmt)
+ {
+ FlowBranchingException branching = new FlowBranchingException (
+ CurrentBranching, stmt);
+ current_flow_branching = branching;
+ return branching;
+ }
+
//
// Ends a code branching. Merges the state of locals and parameters
// from all the children of the ending branching.
@@ -476,46 +497,160 @@ namespace Mono.CSharp {
current_flow_branching = current_flow_branching.Parent;
}
- public void EmitTopBlock (Block block, InternalParameters ip, Location loc)
+ public void CaptureVariable (LocalInfo li)
{
- bool unreachable = false;
+ capture_context.AddLocal (CurrentAnonymousMethod, li);
+ li.IsCaptured = true;
+ }
+
+ public void CaptureParameter (string name, Type t, int idx)
+ {
+ capture_context.AddParameter (this, CurrentAnonymousMethod, name, t, idx);
+ }
+
+ public void CaptureThis ()
+ {
+ capture_context.CaptureThis ();
+ }
+
+
+ //
+ // Use to register a field as captured
+ //
+ public void CaptureField (FieldExpr fe)
+ {
+ capture_context.AddField (fe);
+ }
+
+ //
+ // Whether anonymous methods have captured variables
+ //
+ public bool HaveCapturedVariables ()
+ {
+ if (capture_context != null)
+ return capture_context.HaveCapturedVariables;
+ return false;
+ }
+
+ //
+ // Whether anonymous methods have captured fields or this.
+ //
+ public bool HaveCapturedFields ()
+ {
+ if (capture_context != null)
+ return capture_context.HaveCapturedFields;
+ return false;
+ }
+
+ //
+ // Emits the instance pointer for the host method
+ //
+ public void EmitMethodHostInstance (EmitContext target, AnonymousMethod am)
+ {
+ if (capture_context != null)
+ capture_context.EmitMethodHostInstance (target, am);
+ else if (IsStatic)
+ target.ig.Emit (OpCodes.Ldnull);
+ else
+ target.ig.Emit (OpCodes.Ldarg_0);
+ }
+
+ //
+ // Returns whether the `local' variable has been captured by an anonymous
+ // method
+ //
+ public bool IsCaptured (LocalInfo local)
+ {
+ return capture_context.IsCaptured (local);
+ }
+
+ public bool IsParameterCaptured (string name)
+ {
+ if (capture_context != null)
+ return capture_context.IsParameterCaptured (name);
+ return false;
+ }
+
+ public void EmitMeta (ToplevelBlock b, InternalParameters ip)
+ {
+ if (capture_context != null)
+ capture_context.EmitAnonymousHelperClasses (this);
+ b.EmitMeta (this);
+
+ if (HasReturnLabel)
+ ReturnLabel = ig.DefineLabel ();
+ }
+
+ //
+ // Here until we can fix the problem with Mono.CSharp.Switch, which
+ // currently can not cope with ig == null during resolve (which must
+ // be fixed for switch statements to work on anonymous methods).
+ //
+ public void EmitTopBlock (ToplevelBlock block, InternalParameters ip, Location loc)
+ {
+ if (block == null)
+ return;
+
+ bool unreachable;
+
+ if (ResolveTopBlock (null, block, ip, loc, out unreachable)){
+ EmitMeta (block, ip);
+
+ current_phase = Phase.Emitting;
+ EmitResolvedTopBlock (block, unreachable);
+ }
+ }
+
+ bool resolved;
+
+ public bool ResolveTopBlock (EmitContext anonymous_method_host, ToplevelBlock block,
+ InternalParameters ip, Location loc, out bool unreachable)
+ {
+ current_phase = Phase.Resolving;
+
+ unreachable = false;
+
+ if (resolved)
+ return true;
+
+ capture_context = block.CaptureContext;
if (!Location.IsNull (loc))
CurrentFile = loc.File;
- if (block != null){
- try {
- int errors = Report.Errors;
-
- block.EmitMeta (this, ip);
+#if PRODUCTION
+ try {
+#endif
+ if (!block.ResolveMeta (this, ip))
+ return false;
- if (Report.Errors == errors){
- bool old_do_flow_analysis = DoFlowAnalysis;
- DoFlowAnalysis = true;
+ bool old_do_flow_analysis = DoFlowAnalysis;
+ DoFlowAnalysis = true;
+ if (anonymous_method_host != null)
current_flow_branching = FlowBranching.CreateBranching (
- null, FlowBranching.BranchingType.Block, block, loc);
+ anonymous_method_host.CurrentBranching,
+ FlowBranching.BranchingType.Block, block, loc);
+ else
+ current_flow_branching = block.TopLevelBranching;
- if (!block.Resolve (this)) {
- current_flow_branching = null;
- DoFlowAnalysis = old_do_flow_analysis;
- return;
- }
-
- FlowBranching.Reachability reachability = current_flow_branching.MergeTopBlock ();
+ if (!block.Resolve (this)) {
current_flow_branching = null;
-
DoFlowAnalysis = old_do_flow_analysis;
+ return false;
+ }
- block.Emit (this);
+ FlowBranching.Reachability reachability = current_flow_branching.MergeTopBlock ();
+ current_flow_branching = null;
- if (reachability.AlwaysReturns ||
- reachability.AlwaysThrows ||
- reachability.IsUnreachable)
- unreachable = true;
- }
-#if FIXME
- } catch (Exception e) {
+ DoFlowAnalysis = old_do_flow_analysis;
+
+ if (reachability.AlwaysReturns ||
+ reachability.AlwaysThrows ||
+ reachability.IsUnreachable)
+ unreachable = true;
+#if PRODUCTION
+ } catch (Exception e) {
Console.WriteLine ("Exception caught by the compiler while compiling:");
Console.WriteLine (" Block that caused the problem begin at: " + loc);
@@ -524,24 +659,36 @@ namespace Mono.CSharp {
CurrentBlock.StartLocation, CurrentBlock.EndLocation);
}
Console.WriteLine (e.GetType ().FullName + ": " + e.Message);
- Console.WriteLine (Report.FriendlyStackTrace (e));
-
- Environment.Exit (1);
-#else
- } finally {
-#endif
- }
+ throw;
}
+#endif
- if (ReturnType != null && !unreachable){
- if (!InIterator){
+ if (ReturnType != null && !unreachable) {
+ if (CurrentAnonymousMethod == null) {
Report.Error (161, loc, "Not all code paths return a value");
- return;
+ return false;
+ } else if (!CurrentAnonymousMethod.IsIterator) {
+ Report.Error (
+ 1643, loc, "Not all code paths return a " +
+ "value in anonymous method of type `{0}'",
+ CurrentAnonymousMethod.Type);
+ return false;
}
}
+ block.CompleteContexts ();
+ resolved = true;
+ return true;
+ }
+
+ public void EmitResolvedTopBlock (ToplevelBlock block, bool unreachable)
+ {
+ if (block != null)
+ block.Emit (this);
+
if (HasReturnLabel)
ig.MarkLabel (ReturnLabel);
+
if (return_value != null){
ig.Emit (OpCodes.Ldloc, return_value);
ig.Emit (OpCodes.Ret);
@@ -559,14 +706,23 @@ namespace Mono.CSharp {
// this case.
//
+ bool in_iterator = (CurrentAnonymousMethod != null) &&
+ CurrentAnonymousMethod.IsIterator && InIterator;
+
if ((block != null) && block.IsDestructor) {
// Nothing to do; S.R.E automatically emits a leave.
- } else if (HasReturnLabel || (!unreachable && !InIterator)) {
+ } else if (HasReturnLabel || (!unreachable && !in_iterator)) {
if (ReturnType != null)
ig.Emit (OpCodes.Ldloc, TemporaryReturn ());
ig.Emit (OpCodes.Ret);
}
}
+
+ //
+ // Close pending helper classes if we are the toplevel
+ //
+ if (capture_context != null && capture_context.ParentToplevel == null)
+ capture_context.CloseAnonymousHelperClasses ();
}
///
@@ -581,7 +737,31 @@ namespace Mono.CSharp {
if (check_file && (CurrentFile != loc.File))
return;
- ig.MarkSequencePoint (null, loc.Row, 0, 0, 0);
+ CodeGen.SymbolWriter.MarkSequencePoint (ig, loc.Row, 0);
+ }
+
+ public void DefineLocalVariable (string name, LocalBuilder builder)
+ {
+ if (CodeGen.SymbolWriter == null)
+ return;
+
+ CodeGen.SymbolWriter.DefineLocalVariable (name, builder);
+ }
+
+ public void BeginScope ()
+ {
+ ig.BeginScope();
+
+ if (CodeGen.SymbolWriter != null)
+ CodeGen.SymbolWriter.OpenScope(ig);
+ }
+
+ public void EndScope ()
+ {
+ ig.EndScope();
+
+ if (CodeGen.SymbolWriter != null)
+ CodeGen.SymbolWriter.CloseScope(ig);
}
///
@@ -665,84 +845,90 @@ namespace Mono.CSharp {
/// return value from the function. By default this is not
/// used. This is only required when returns are found inside
/// Try or Catch statements.
+ ///
+ /// This method is typically invoked from the Emit phase, so
+ /// we allow the creation of a return label if it was not
+ /// requested during the resolution phase. Could be cleaned
+ /// up, but it would replicate a lot of logic in the Emit phase
+ /// of the code that uses it.
///
public LocalBuilder TemporaryReturn ()
{
if (return_value == null){
return_value = ig.DeclareLocal (ReturnType);
+ if (!HasReturnLabel){
ReturnLabel = ig.DefineLabel ();
HasReturnLabel = true;
}
+ }
return return_value;
}
+ ///
+ /// This method is used during the Resolution phase to flag the
+ /// need to define the ReturnLabel
+ ///
public void NeedReturnLabel ()
{
- if (!HasReturnLabel) {
- ReturnLabel = ig.DefineLabel ();
- HasReturnLabel = true;
+ if (current_phase != Phase.Resolving){
+ //
+ // The reason is that the `ReturnLabel' is declared between
+ // resolution and emission
+ //
+ throw new Exception ("NeedReturnLabel called from Emit phase, should only be called during Resolve");
}
+
+ if (!InIterator && !HasReturnLabel)
+ HasReturnLabel = true;
}
//
- // Creates a field `name' with the type `t' on the proxy class
+ // Emits the proper object to address fields on a remapped
+ // variable/parameter to field in anonymous-method/iterator proxy classes.
//
- public FieldBuilder MapVariable (string name, Type t)
+ public void EmitThis ()
{
- if (InIterator){
- return IteratorHandler.Current.MapVariable ("v_", name, t);
- }
-
- throw new Exception ("MapVariable for an unknown state");
+ ig.Emit (OpCodes.Ldarg_0);
+ if (capture_context != null && CurrentAnonymousMethod != null){
+ ScopeInfo si = CurrentAnonymousMethod.Scope;
+ while (si != null){
+ if (si.ParentLink != null)
+ ig.Emit (OpCodes.Ldfld, si.ParentLink);
+ if (si.THIS != null){
+ ig.Emit (OpCodes.Ldfld, si.THIS);
+ break;
+ }
+ si = si.ParentScope;
+ }
+ }
}
//
- // Invoke this routine to remap a VariableInfo into the
- // proper MemberAccess expression
+ // Emits the code necessary to load the instance required
+ // to access the captured LocalInfo
//
- public Expression RemapLocal (LocalInfo local_info)
+ public void EmitCapturedVariableInstance (LocalInfo li)
{
- FieldExpr fe = new FieldExpr (local_info.FieldBuilder, loc);
- fe.InstanceExpression = new ProxyInstance ();
- return fe.DoResolve (this);
+ if (capture_context == null)
+ throw new Exception ("Calling EmitCapturedContext when there is no capture_context");
+
+ capture_context.EmitCapturedVariableInstance (this, li, CurrentAnonymousMethod);
}
- public Expression RemapLocalLValue (LocalInfo local_info, Expression right_side)
+ public void EmitParameter (string name)
{
- FieldExpr fe = new FieldExpr (local_info.FieldBuilder, loc);
- fe.InstanceExpression = new ProxyInstance ();
- return fe.DoResolveLValue (this, right_side);
+ capture_context.EmitParameter (this, name);
}
- public Expression RemapParameter (int idx)
+ public void EmitAssignParameter (string name, Expression source, bool leave_copy, bool prepare_for_load)
{
- FieldExpr fe = new FieldExprNoAddress (IteratorHandler.Current.parameter_fields [idx], loc);
- fe.InstanceExpression = new ProxyInstance ();
- return fe.DoResolve (this);
+ capture_context.EmitAssignParameter (this, name, source, leave_copy, prepare_for_load);
}
- public Expression RemapParameterLValue (int idx, Expression right_side)
+ public void EmitAddressOfParameter (string name)
{
- FieldExpr fe = new FieldExprNoAddress (IteratorHandler.Current.parameter_fields [idx], loc);
- fe.InstanceExpression = new ProxyInstance ();
- return fe.DoResolveLValue (this, right_side);
- }
-
- //
- // Emits the proper object to address fields on a remapped
- // variable/parameter to field in anonymous-method/iterator proxy classes.
- //
- public void EmitThis ()
- {
- ig.Emit (OpCodes.Ldarg_0);
-
- if (!IsStatic){
- if (InIterator)
- ig.Emit (OpCodes.Ldfld, IteratorHandler.Current.this_field);
- else
- throw new Exception ("EmitThis for an unknown state");
- }
+ capture_context.EmitAddressOfParameter (this, name);
}
public Expression GetThis (Location loc)
@@ -761,87 +947,58 @@ namespace Mono.CSharp {
}
- public abstract class CommonAssemblyModulClass: IAttributeSupport {
- protected Hashtable m_attributes;
-
- protected CommonAssemblyModulClass ()
+ public abstract class CommonAssemblyModulClass: Attributable {
+ protected CommonAssemblyModulClass ():
+ base (null)
{
- m_attributes = new Hashtable ();
}
- //
- // Adds a global attribute that was declared in `container',
- // the attribute is in `attr', and it was defined at `loc'
- //
- public void AddAttribute (TypeContainer container, AttributeSection attr)
+ public void AddAttributes (ArrayList attrs)
{
- NamespaceEntry ns = container.NamespaceEntry;
- Attributes a = (Attributes) m_attributes [ns];
-
- if (a == null) {
- m_attributes [ns] = new Attributes (attr);
+ if (OptAttributes == null) {
+ OptAttributes = new Attributes (attrs);
return;
}
-
- a.AddAttributeSection (attr);
+ OptAttributes.AddAttributes (attrs);
}
- public virtual void Emit ()
+ public virtual void Emit (TypeContainer tc)
{
- if (m_attributes.Count < 1)
+ if (OptAttributes == null)
return;
- TypeContainer dummy = new TypeContainer ();
- EmitContext temp_ec = new EmitContext (dummy, Mono.CSharp.Location.Null, null, null, 0, false);
-
- foreach (DictionaryEntry de in m_attributes)
- {
- NamespaceEntry ns = (NamespaceEntry) de.Key;
- Attributes attrs = (Attributes) de.Value;
-
- dummy.NamespaceEntry = ns;
- Attribute.ApplyAttributes (temp_ec, null, this, attrs);
- }
+ EmitContext ec = new EmitContext (tc, Mono.CSharp.Location.Null, null, null, 0, false);
+ OptAttributes.Emit (ec, this);
}
-
- protected Attribute GetClsCompliantAttribute ()
+
+ protected Attribute ResolveAttribute (Type a_type)
{
- if (m_attributes.Count < 1)
+ if (OptAttributes == null)
return null;
- EmitContext temp_ec = new EmitContext (new TypeContainer (), Mono.CSharp.Location.Null, null, null, 0, false);
-
- foreach (DictionaryEntry de in m_attributes) {
-
- NamespaceEntry ns = (NamespaceEntry) de.Key;
- Attributes attrs = (Attributes) de.Value;
- temp_ec.TypeContainer.NamespaceEntry = ns;
-
- foreach (AttributeSection attr_section in attrs.AttributeSections) {
- foreach (Attribute a in attr_section.Attributes) {
- TypeExpr attributeType = RootContext.LookupType (temp_ec.DeclSpace, Attributes.GetAttributeFullName (a.Name), true, Location.Null);
- if (attributeType != null && attributeType.Type == TypeManager.cls_compliant_attribute_type) {
- a.Resolve (temp_ec);
- return a;
- }
- }
- }
+ // Ensure that we only have GlobalAttributes, since the Search below isn't safe with other types.
+ if (!OptAttributes.CheckTargets (this))
+ return null;
+
+ EmitContext temp_ec = new EmitContext (RootContext.Tree.Types, Mono.CSharp.Location.Null, null, null, 0, false);
+ Attribute a = OptAttributes.Search (a_type, temp_ec);
+ if (a != null) {
+ a.Resolve (temp_ec);
}
- return null;
+ return a;
}
-
- #region IAttributeSupport Members
- public abstract void SetCustomAttribute(CustomAttributeBuilder customBuilder);
- #endregion
-
}
-
public class AssemblyClass: CommonAssemblyModulClass {
// TODO: make it private and move all builder based methods here
public AssemblyBuilder Builder;
bool is_cls_compliant;
+ public Attribute ClsCompliantAttribute;
+
+ ListDictionary declarative_security;
+
+ static string[] attribute_targets = new string [] { "assembly" };
public AssemblyClass (): base ()
{
@@ -854,31 +1011,76 @@ namespace Mono.CSharp {
}
}
+ public override AttributeTargets AttributeTargets {
+ get {
+ return AttributeTargets.Assembly;
+ }
+ }
+
+ public override bool IsClsComplianceRequired(DeclSpace ds)
+ {
+ return is_cls_compliant;
+ }
+
public void ResolveClsCompliance ()
{
- Attribute a = GetClsCompliantAttribute ();
- if (a == null)
+ ClsCompliantAttribute = ResolveAttribute (TypeManager.cls_compliant_attribute_type);
+ if (ClsCompliantAttribute == null)
return;
- is_cls_compliant = a.GetClsCompliantAttributeValue (null);
+ is_cls_compliant = ClsCompliantAttribute.GetClsCompliantAttributeValue (null);
}
+ // fix bug #56621
+ private void SetPublicKey (AssemblyName an, byte[] strongNameBlob)
+ {
+ try {
+ // check for possible ECMA key
+ if (strongNameBlob.Length == 16) {
+ // will be rejected if not "the" ECMA key
+ an.SetPublicKey (strongNameBlob);
+ }
+ else {
+ // take it, with or without, a private key
+ RSA rsa = CryptoConvert.FromCapiKeyBlob (strongNameBlob);
+ // and make sure we only feed the public part to Sys.Ref
+ byte[] publickey = CryptoConvert.ToCapiPublicKeyBlob (rsa);
+
+ // AssemblyName.SetPublicKey requires an additional header
+ byte[] publicKeyHeader = new byte [12] { 0x00, 0x24, 0x00, 0x00, 0x04, 0x80, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00 };
+
+ byte[] encodedPublicKey = new byte [12 + publickey.Length];
+ Buffer.BlockCopy (publicKeyHeader, 0, encodedPublicKey, 0, 12);
+ Buffer.BlockCopy (publickey, 0, encodedPublicKey, 12, publickey.Length);
+ an.SetPublicKey (encodedPublicKey);
+ }
+ }
+ catch (Exception) {
+ Report.Error (1548, "Could not strongname the assembly. File `" +
+ RootContext.StrongNameKeyFile + "' incorrectly encoded.");
+ Environment.Exit (1);
+ }
+ }
+
+ // TODO: rewrite this code (to kill N bugs and make it faster) and use standard ApplyAttribute way.
public AssemblyName GetAssemblyName (string name, string output)
{
- // scan assembly attributes for strongname related attr
- foreach (DictionaryEntry nsattr in m_attributes) {
- ArrayList list = ((Attributes)nsattr.Value).AttributeSections;
- for (int i=0; i < list.Count; i++) {
- AttributeSection asect = (AttributeSection) list [i];
- if (asect.Target != "assembly")
- continue;
- // strongname attributes don't support AllowMultiple
- Attribute a = (Attribute) asect.Attributes [0];
+ if (OptAttributes != null) {
+ foreach (Attribute a in OptAttributes.Attrs) {
+ // cannot rely on any resolve-based members before you call Resolve
+ if (a.ExplicitTarget == null || a.ExplicitTarget != "assembly")
+ continue;
+
+ // TODO: This code is buggy: comparing Attribute name without resolving it is wrong.
+ // However, this is invoked by CodeGen.Init, at which time none of the namespaces
+ // are loaded yet.
switch (a.Name) {
case "AssemblyKeyFile":
+ case "AssemblyKeyFileAttribute":
+ case "System.Reflection.AssemblyKeyFileAttribute":
if (RootContext.StrongNameKeyFile != null) {
- Report.Warning (1616, "Compiler option -keyfile overrides " +
- "AssemblyKeyFileAttribute");
+ Report.SymbolRelatedToPreviousError (a.Location, a.Name);
+ Report.Warning (1616, "Compiler option '{0}' overrides '{1}' given in source", "keyfile", "System.Reflection.AssemblyKeyFileAttribute");
}
else {
string value = a.GetString ();
@@ -887,9 +1089,11 @@ namespace Mono.CSharp {
}
break;
case "AssemblyKeyName":
+ case "AssemblyKeyNameAttribute":
+ case "System.Reflection.AssemblyKeyNameAttribute":
if (RootContext.StrongNameKeyContainer != null) {
- Report.Warning (1616, "Compiler option -keycontainer overrides " +
- "AssemblyKeyNameAttribute");
+ Report.SymbolRelatedToPreviousError (a.Location, a.Name);
+ Report.Warning (1616, "keycontainer", "Compiler option '{0}' overrides '{1}' given in source", "System.Reflection.AssemblyKeyNameAttribute");
}
else {
string value = a.GetString ();
@@ -898,6 +1102,8 @@ namespace Mono.CSharp {
}
break;
case "AssemblyDelaySign":
+ case "AssemblyDelaySignAttribute":
+ case "System.Reflection.AssemblyDelaySignAttribute":
RootContext.StrongNameDelaySign = a.GetBoolean ();
break;
}
@@ -939,25 +1145,7 @@ namespace Mono.CSharp {
if (RootContext.StrongNameDelaySign) {
// delayed signing - DO NOT include private key
- try {
- // check for possible ECMA key
- if (snkeypair.Length == 16) {
- // will be rejected if not "the" ECMA key
- an.KeyPair = new StrongNameKeyPair (snkeypair);
- }
- else {
- // take it, with or without, a private key
- RSA rsa = CryptoConvert.FromCapiKeyBlob (snkeypair);
- // and make sure we only feed the public part to Sys.Ref
- byte[] publickey = CryptoConvert.ToCapiPublicKeyBlob (rsa);
- an.KeyPair = new StrongNameKeyPair (publickey);
- }
- }
- catch (Exception) {
- Report.Error (1548, "Could not strongname the assembly. File `" +
- RootContext.StrongNameKeyFile + "' incorrectly encoded.");
- Environment.Exit (1);
- }
+ SetPublicKey (an, snkeypair);
}
else {
// no delay so we make sure we have the private key
@@ -976,7 +1164,7 @@ namespace Mono.CSharp {
RootContext.StrongNameKeyFile +
"' doesn't have a private key.");
}
- Environment.Exit (1);
+ return null;
}
}
}
@@ -984,37 +1172,91 @@ namespace Mono.CSharp {
else {
Report.Error (1548, "Could not strongname the assembly. File `" +
RootContext.StrongNameKeyFile + "' not found.");
- Environment.Exit (1);
+ return null;
}
return an;
}
- public override void SetCustomAttribute(CustomAttributeBuilder customBuilder)
+ public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder customBuilder)
{
+ if (a.Type.IsSubclassOf (TypeManager.security_attr_type) && a.CheckSecurityActionValidity (true)) {
+ if (declarative_security == null)
+ declarative_security = new ListDictionary ();
+
+ a.ExtractSecurityPermissionSet (declarative_security);
+ return;
+ }
+
Builder.SetCustomAttribute (customBuilder);
}
+
+ public override void Emit (TypeContainer tc)
+ {
+ base.Emit (tc);
+
+ if (declarative_security != null) {
+
+ MethodInfo add_permission = typeof (AssemblyBuilder).GetMethod ("AddPermissionRequests", BindingFlags.Instance | BindingFlags.NonPublic);
+ object builder_instance = Builder;
+
+ try {
+ // Microsoft runtime hacking
+ if (add_permission == null) {
+ Type assembly_builder = typeof (AssemblyBuilder).Assembly.GetType ("System.Reflection.Emit.AssemblyBuilderData");
+ add_permission = assembly_builder.GetMethod ("AddPermissionRequests", BindingFlags.Instance | BindingFlags.NonPublic);
+
+ FieldInfo fi = typeof (AssemblyBuilder).GetField ("m_assemblyData", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.GetField);
+ builder_instance = fi.GetValue (Builder);
+ }
+
+ object[] args = new object [] { declarative_security [SecurityAction.RequestMinimum],
+ declarative_security [SecurityAction.RequestOptional],
+ declarative_security [SecurityAction.RequestRefuse] };
+ add_permission.Invoke (builder_instance, args);
+ }
+ catch {
+ Report.RuntimeMissingSupport (Location.Null, "assembly permission setting");
+ }
+ }
+ }
+
+ public override string[] ValidAttributeTargets {
+ get {
+ return attribute_targets;
+ }
+ }
}
public class ModuleClass: CommonAssemblyModulClass {
// TODO: make it private and move all builder based methods here
public ModuleBuilder Builder;
-
bool m_module_is_unsafe;
+ public CharSet DefaultCharSet = CharSet.Ansi;
+ public TypeAttributes DefaultCharSetType = TypeAttributes.AnsiClass;
+
+ static string[] attribute_targets = new string [] { "module" };
+
public ModuleClass (bool is_unsafe)
{
m_module_is_unsafe = is_unsafe;
}
- public override void Emit ()
- {
- base.Emit ();
+ public override AttributeTargets AttributeTargets {
+ get {
+ return AttributeTargets.Module;
+ }
+ }
- Attribute a = GetClsCompliantAttribute ();
- if (a != null) {
- Report.Warning (3012, a.Location);
+ public override bool IsClsComplianceRequired(DeclSpace ds)
+ {
+ return CodeGen.Assembly.IsClsCompliant;
}
+ public override void Emit (TypeContainer tc)
+ {
+ base.Emit (tc);
+
if (!m_module_is_unsafe)
return;
@@ -1023,13 +1265,54 @@ namespace Mono.CSharp {
return;
}
- SetCustomAttribute (new CustomAttributeBuilder (TypeManager.unverifiable_code_ctor, new object [0]));
+ Builder.SetCustomAttribute (new CustomAttributeBuilder (TypeManager.unverifiable_code_ctor, new object [0]));
}
- public override void SetCustomAttribute(CustomAttributeBuilder customBuilder)
+ public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder customBuilder)
{
+ if (a.Type == TypeManager.cls_compliant_attribute_type) {
+ if (CodeGen.Assembly.ClsCompliantAttribute == null) {
+ Report.Warning (3012, a.Location, "You must specify the CLSCompliant attribute on the assembly, not the module, to enable CLS compliance checking");
+ }
+ else if (CodeGen.Assembly.IsClsCompliant != a.GetBoolean ()) {
+ Report.SymbolRelatedToPreviousError (CodeGen.Assembly.ClsCompliantAttribute.Location, CodeGen.Assembly.ClsCompliantAttribute.Name);
+ Report.Error (3017, a.Location, "You cannot specify the CLSCompliant attribute on a module that differs from the CLSCompliant attribute on the assembly");
+ return;
+ }
+ }
+
Builder.SetCustomAttribute (customBuilder);
}
- }
+ ///
+ /// It is called very early therefore can resolve only predefined attributes
+ ///
+ public void ResolveAttributes ()
+ {
+ Attribute a = ResolveAttribute (TypeManager.default_charset_type);
+ if (a != null) {
+ DefaultCharSet = a.GetCharSetValue ();
+ switch (DefaultCharSet) {
+ case CharSet.Ansi:
+ case CharSet.None:
+ break;
+ case CharSet.Auto:
+ DefaultCharSetType = TypeAttributes.AutoClass;
+ break;
+ case CharSet.Unicode:
+ DefaultCharSetType = TypeAttributes.UnicodeClass;
+ break;
+ default:
+ Report.Error (1724, a.Location, "Value specified for the argument to 'System.Runtime.InteropServices.DefaultCharSetAttribute' is not valid");
+ break;
+ }
+ }
+ }
+
+ public override string[] ValidAttributeTargets {
+ get {
+ return attribute_targets;
+ }
+ }
+ }
}