using System.Reflection;
using System.Runtime.CompilerServices;
-[assembly: AssemblyVersion("0.28")]
+[assembly: AssemblyVersion("0.29.99")]
[assembly: AssemblyTitle ("Mono C# Compiler")]
[assembly: AssemblyDescription ("Mono C# Compiler with Generics")]
[assembly: AssemblyCopyright ("2001, 2002, 2003 Ximian, Inc.")]
+2003-12-31 Ben Maurer <bmaurer@users.sourceforge.net>
+
+ * report.cs, codegen.cs: Give the real stack trace to
+ the error when an exception is thrown.
+
+2003-12-31 Ben Maurer <bmaurer@users.sourceforge.net>
+
+ * decl.cs: only allocate hashtables for ifaces if
+ it is an iface!
+
+2003-12-31 Ben Maurer <bmaurer@users.sourceforge.net>
+
+ * expression.cs: fix the error from cs0121-2.cs
+ (a parent interface has two child interfaces that
+ have a function with the same name and 0 params
+ and the function is called through the parent).
+
+2003-12-30 Ben Maurer <bmaurer@users.sourceforge.net>
+
+ * class.cs, rootcontext.cs, typmanager.cs: do not
+ leak pointers.
+
+2003-12-28 Ben Maurer <bmaurer@users.sourceforge.net>
+
+ * codegen.cs: remove stack for the ec flow branching.
+ It is already a linked list, so no need.
+
+2003-12-27 Ben Maurer <bmaurer@users.sourceforge.net>
+
+ * Makefile: Allow custom profiler here.
+
+2003-12-26 Ben Maurer <bmaurer@users.sourceforge.net>
+
+ * typemanager.cs (LookupType):
+ - Use a static char [], because split takes
+ a param array for args, so it was allocating
+ every time.
+ - Do not store true in a hashtable, it boxes.
+
+2003-12-26 Ben Maurer <bmaurer@users.sourceforge.net>
+
+ * flowanalysis.cs: bytify common enums.
+
+2003-12-25 Ben Maurer <bmaurer@users.sourceforge.net>
+
+ * modifiers.cs: Add a new set of flags for the
+ flags allowed on explicit interface impls.
+ * cs-parser.jay: catch the use of modifiers in
+ interfaces correctly.
+ * class.cs: catch private void IFoo.Blah ().
+
+ All related to bug #50572.
+
+2003-12-25 Ben Maurer <bmaurer@users.sourceforge.net>
+
+ * decl.cs: Rewrite the consistant accessability checking.
+ Accessability is not linear, it must be implemented in
+ a tableish way. Fixes #49704.
+
+2003-12-25 Ben Maurer <bmaurer@users.sourceforge.net>
+
+ * expression.cs: Handle negation in a checked context.
+ We must use subtraction from zero. Fixes #38674.
+
+2003-12-23 Ben Maurer <bmaurer@users.sourceforge.net>
+
+ * class.cs: Ignore static void main in DLLs.
+ * rootcontext.cs: Handle the target type here,
+ since we are have to access it from class.cs
+ * driver.cs: account for the above.
+
+2003-12-23 Ben Maurer <bmaurer@users.sourceforge.net>
+
+ * report.cs: Give line numbers and files if available.
+
+2003-12-20 Zoltan Varga <vargaz@freemail.hu>
+
+ * driver.cs: Implement /addmodule.
+
+ * typemanager.cs: Change 'modules' field so it now contains Modules not
+ ModuleBuilders.
+
+2003-12-20 Martin Baulig <martin@ximian.com>
+
+ * class.cs (TypeContainer.DefineMembers): Don't do the CS0649 check here.
+ (FieldBase.IsAssigned): Removed this field.
+ (FieldBase.SetAssigned): New public method.
+ (TypeContainer.Emit): Make the CS0169/CS0649 checks actually work.
+
+2003-12-20 Martin Baulig <martin@ximian.com>
+
+ * expression.cs (LocalVariableReference.DoResolve): Don't set
+ `vi.Used' if we're called from DoResolveLValue().
+
+ * statement.cs (Block.DoResolve): `ec.DoEndFlowBranching()' now
+ returns the usage vector it just merged into the current one -
+ pass this one to UsageWarning().
+ (Block.UsageWarning): Take the `FlowBranching.UsageVector' instead
+ of the `EmitContext', don't call this recursively on our children.
+
+2003-12-19 Zoltan Varga <vargaz@freemail.hu>
+
+ * driver.cs: Implement /target:module.
+
+2003-12-18 Zoltan Varga <vargaz@freemail.hu>
+
+ * support.cs (CharArrayHashtable): New helper class.
+
+ * cs-tokenizer.cs: Store keywords in a hashtable indexed by
+ char arrays, not strings, so we can avoid creating a string in
+ consume_identifier if the identifier is a keyword.
+
+2003-12-16 Martin Baulig <martin@ximian.com>
+
+ * statement.cs (LocalInfo.Assigned): Removed this property.
+ (LocalInfo.Flags): Removed `Assigned'.
+ (LocalInfo.IsAssigned): New public method; takes the EmitContext
+ and uses flow analysis.
+ (Block.UsageWarning): Made this method private.
+ (Block.Resolve): Call UsageWarning() if appropriate.
+
+ * expression.cs (LocalVariableReference.DoResolve): Always set
+ LocalInfo.Used here.
+
+2003-12-13 Martin Baulig <martin@ximian.com>
+
+ * statement.cs (Statement.DoEmit, Statement.Emit): Don't return
+ any value here; we're now using flow analysis to figure out
+ whether a statement/block returns a value.
+
+2003-12-13 Martin Baulig <martin@ximian.com>
+
+ * flowanalysis.cs (UsageVector.MergeFinallyOrigins): Made this
+ working again.
+ (FlowBranching.MergeFinally): Don't call
+ `branching.CheckOutParameters()' here, this is called in
+ MergeTopBlock().
+ (FlowBranchingException.AddSibling): Call MergeFinallyOrigins()
+ when adding the `finally' vector.
+
+2003-12-13 Martin Baulig <martin@ximian.com>
+
+ * flowanalysis.cs
+ (UsageVector.MergeJumpOrigins, FlowBranching.Label): Make this
+ actually work and also fix #48962.
+
+2003-12-12 Ben Maurer <bmaurer@users.sourceforge.net>
+
+ * decl.cs: Do not check System.Object for nested types,
+ since we know it does not have any. Big bang for buck:
+
+ BEFORE:
+ Run 1: 8.35 seconds
+ Run 2: 8.32 seconds
+ corlib: 17.99 seconds
+ AFTER:
+ Run 1: 8.17 seconds
+ Run 2: 8.17 seconds
+ corlib: 17.39 seconds
+
+2003-12-11 Ben Maurer <bmaurer@users.sourceforge.net>
+
+ * class.cs (FindMembers): Allocate arraylists on demand. Most of the
+ time we are returning 0 members, so we save alot here.
+
+2003-12-11 Martin Baulig <martin@ximian.com>
+
+ * flowanalysis.cs (UsageVector.MergeResult): Renamed this back to
+ `MergeChild()', also just take the `FlowBranching' as argument;
+ call Merge() on it and return the result.
+ (FlowBranching.Merge): We don't need to do anything if we just
+ have one sibling.
+
+2003-12-11 Martin Baulig <martin@ximian.com>
+
+ * flowanalysis.cs: Use a list of `UsageVector's instead of storing
+ them in an `ArrayList' to reduce memory usage. Thanks to Ben
+ Maurer for this idea.
+
+2003-12-11 Martin Baulig <martin@ximian.com>
+
+ * flowanalysis.cs (MergeResult): This class is now gone; we now
+ use the `UsageVector' for this. The reason for this is that if a
+ branching just has one sibling, we don't need to "merge" them at
+ all - that's the next step to do.
+ (FlowBranching.Merge): We now return a `UsageVector' instead of a
+ `MergeResult'.
+
+2003-12-11 Martin Baulig <martin@ximian.com>
+
+ Reworked flow analyis and made it more precise and bug-free. The
+ most important change is that we're now using a special `Reachability'
+ class instead of having "magic" meanings of `FlowReturns'. I'll
+ do some more cleanups and optimizations and also add some more
+ documentation this week.
+
+ * flowanalysis.cs (Reachability): Added `Throws' and `Barrier';
+ largely reworked this class.
+ (FlowReturns): Removed `Unreachable' and `Exception'; we now use
+ the new `Reachability' class instead of having "magic" values here.
+ (FlowBranching): We're now using an instance of `Reachability'
+ instead of having separate `Returns', `Breaks' etc. fields.
+
+ * codegen.cs (EmitContext.EmitTopBlock): Set `has_ret' solely
+ based on flow analysis; ignore the return value of block.Emit ().
+
+2003-12-10 Zoltan Varga <vargaz@freemail.hu>
+
+ * driver.cs typemanager.cs: Find the mono extensions to corlib even
+ if they are private.
+
+2003-12-09 Martin Baulig <martin@ximian.com>
+
+ * flowanalyis.cs (FlowBranching.Return, Goto, Throw): Removed;
+ call them directly on the UsageVector.
+
+2003-12-09 Martin Baulig <martin@ximian.com>
+
+ * flowanalysis.cs (FlowBranching.MergeChild, MergeTopBlock):
+ Changed return type from `FlowReturns' to `Reachability'.
+
+2003-12-09 Martin Baulig <martin@ximian.com>
+
+ * flowanalysis.cs (FlowBranching.Reachability): New sealed class.
+ (FlowBranching.MergeResult): Replaced the `Returns', `Breaks' and
+ `Reachable' fields with a single `Reachability' one.
+
+2003-12-08 Ben Maurer <bmaurer@users.sourceforge.net>
+
+ * class.cs (FindMembers): Remove foreach's.
+
+ Bootstrap times:
+
+ BEFORE
+ Run 1: 8.74 seconds
+ Run 2: 8.71 seconds
+
+ AFTER
+ Run 1: 8.64 seconds
+ Run 2: 8.58 seconds
+
+
+2003-12-08 Ben Maurer <bmaurer@users.sourceforge.net>
+
+ * cs-parser.jay:
+ * gen-treedump.cs:
+ * statement.cs:
+ This patch does a few things:
+ 1. EmptyStatement is now a singleton, so it is never reallocated.
+ 2. All blah is EmptyStatement constructs have been changed to
+ blah == EmptyStatement.Value, which is much faster and valid
+ now that EmptyStatement is a singleton.
+ 3. When resolving a block, rather than allocating a new array for
+ the non-empty statements, empty statements are replaced with
+ EmptyStatement.Value
+ 4. Some recursive functions have been made non-recursive.
+ Mainly the performance impact is from (3), however (1) and (2) are needed for
+ this to work. (4) does not make a big difference in normal situations, however
+ it makes the profile look saner.
+
+ Bootstrap times:
+
+ BEFORE
+ 9.25user 0.23system 0:10.28elapsed 92%CPU (0avgtext+0avgdata 0maxresident)k
+ 9.34user 0.13system 0:10.23elapsed 92%CPU (0avgtext+0avgdata 0maxresident)k
+ Total memory allocated: 56397 KB
+
+ AFTER
+ 9.13user 0.09system 0:09.64elapsed 95%CPU (0avgtext+0avgdata 0maxresident)k
+ 8.96user 0.24system 0:10.13elapsed 90%CPU (0avgtext+0avgdata 0maxresident)k
+ Total memory allocated: 55666 KB
+
+2003-12-08 Ben Maurer <bmaurer@users.sourceforge.net>
+
+ * support.cs: Rewrite DoubleHash to use its own impl. Is faster
+ than the hashtable in a hashtable version
+
+ * decl.cs: Right now, whenever we try to lookup a type inside a namespace,
+ we always end up concating a string. This results in a huge perf
+ loss, because many strings have to be tracked by the GC. In this
+ patch, we first use a hashtable that works with two keys, so that
+ the strings do not need to be concat'ed.
+
+ Bootstrap times:
+ BEFORE
+ Run 1: 8.74 seconds
+ Run 2: 8.71 seconds
+
+ AFTER
+ Run 1: 8.65 seconds
+ Run 2: 8.56 seconds
+
+2003-12-08 Ben Maurer <bmaurer@users.sourceforge.net>
+
+ * Makefile: Add a new target `do-time' that does a quick and simple
+ profile, leaving easy to parse output.
+
+2003-12-08 Zoltan Varga <vargaz@freemail.hu>
+
+ * codegen.cs (Init): Create the dynamic assembly with
+ AssemblyBuilderAccess.Save, to enable some optimizations in the runtime.
+
+2003-12-02 Ben Maurer <bmaurer@users.sourceforge.net>
+
+ * support.cs: Make the PtrHashtable use only one
+ instance of its comparer.
+
2003-11-30 Zoltan Varga <vargaz@freemail.hu>
* typemanager.cs: Fix lookup of GetNamespaces.
-rm mcs2.exe mcs3.exe
make btest USE_MCS_FLAGS=
+# we need this because bash tries to use its own crappy timer
+FRIENDLY_TIME = $(shell which time) -f'%U seconds'
+
+do-time : mcs.exe
+ @ echo -n "Run 1: "
+ @ $(FRIENDLY_TIME) $(RUNTIME) ./mcs.exe $(USE_MCS_FLAGS) /target:exe /out:mcs2.exe $(all_sources) > /dev/null || (echo FAILED; exit 1)
+ @ echo -n "Run 2: "
+ @ $(FRIENDLY_TIME) $(RUNTIME) ./mcs2.exe $(USE_MCS_FLAGS) /target:exe /out:mcs3.exe $(all_sources) > /dev/null || (echo FAILED; exit 1)
+ @ echo -n "corlib: "
+ @ rm -f ../class/lib/mscorlib.dll
+ @ (cd ../class/corlib ; make BOOTSTRAP_MCS="$(FRIENDLY_TIME) mono ../../mcs/mcs.exe" > /dev/null ) || (echo FAILED; exit 1)
+
+PROFILER=default
+
+profile : mcs.exe
+ $(RUNTIME) --profile=$(PROFILER) ./mcs.exe $(USE_MCS_FLAGS) /target:exe /out:mcs2.exe $(all_sources)
+
response:
echo $(all_sources) > res
CallingConvention cc = CallingConvention.Winapi;\r
CharSet charset = CharSet.Ansi;\r
bool preserve_sig = true;\r
+#if FIXME\r
bool exact_spelling = false;\r
+#endif\r
bool set_last_err = false;\r
string entry_point = null;\r
\r
entry_point = (string) c.GetValue ();\r
else if (member_name == "SetLastError")\r
set_last_err = (bool) c.GetValue ();\r
+#if FIXME\r
else if (member_name == "ExactSpelling")\r
exact_spelling = (bool) c.GetValue ();\r
+#endif\r
else if (member_name == "PreserveSig")\r
preserve_sig = (bool) c.GetValue ();\r
} else { \r
// converted to type ulong. or an error ocurrs if the other
// operand is of type sbyte, short, int or long
//
+#if WRONG
Constant match, other;
+#endif
if (left is ULongConstant){
+#if WRONG
other = right;
match = left;
+#endif
if (!(right is ULongConstant))
right = right.ToULong (loc);
} else {
+#if WRONG
other = left;
match = right;
+#endif
left = left.ToULong (loc);
}
public TypeContainer (NamespaceEntry ns, TypeContainer parent, string name, Location l)
: base (ns, parent, name, l)
{
- string n;
types = new ArrayList ();
- if (parent == null)
- n = "";
- else
- n = parent.Name;
-
base_class_name = null;
-
- //Console.WriteLine ("New class " + name + " inside " + n);
}
public AdditionResult AddConstant (Const constant)
public bool EmitFieldInitializers (EmitContext ec)
{
ArrayList fields;
- ILGenerator ig = ec.ig;
Expression instance_expr;
if (ec.IsStatic){
if (fields != null)
DefineMembers (fields, defined_names);
- if ((RootContext.WarningLevel >= 4) && (fields != null)) {
- foreach (Field f in fields) {
- if (((f.ModFlags & Modifiers.READONLY) != 0) && !f.IsAssigned)
- Report.Warning (649, "Field `" + MakeFQN (Name, f.Name) + "; is never " +
- "assigned and will ever have its default value");
- }
- }
-
if (this is Class){
if (instance_constructors == null){
if (default_constructor == null)
public override MemberList FindMembers (MemberTypes mt, BindingFlags bf,
MemberFilter filter, object criteria)
{
- ArrayList members = new ArrayList ();
+ ArrayList members = null;
int modflags = 0;
if ((bf & BindingFlags.Public) != 0)
if ((mt & MemberTypes.Field) != 0) {
if (fields != null) {
- foreach (Field f in fields) {
+ int len = fields.Count;
+ for (int i = 0; i < len; i++) {
+ Field f = (Field) fields [i];
+
if ((f.ModFlags & modflags) == 0)
continue;
if ((f.ModFlags & static_mask) != static_flags)
continue;
FieldBuilder fb = f.FieldBuilder;
- if (fb != null && filter (fb, criteria) == true)
+ if (fb != null && filter (fb, criteria) == true) {
+ if (members == null)
+ members = new ArrayList ();
+
members.Add (fb);
}
}
+ }
if (constants != null) {
- foreach (Const con in constants) {
+ int len = constants.Count;
+ for (int i = 0; i < len; i++) {
+ Const con = (Const) constants [i];
+
if ((con.ModFlags & modflags) == 0)
continue;
if ((con.ModFlags & static_mask) != static_flags)
continue;
FieldBuilder fb = con.FieldBuilder;
- if (fb != null && filter (fb, criteria) == true)
+ if (fb != null && filter (fb, criteria) == true) {
+ if (members == null)
+ members = new ArrayList ();
+
members.Add (fb);
}
}
}
+ }
if ((mt & MemberTypes.Method) != 0) {
if (methods != null) {
- foreach (Method m in methods) {
+ int len = methods.Count;
+ for (int i = 0; i < len; i++) {
+ Method m = (Method) methods [i];
+
if ((m.ModFlags & modflags) == 0)
continue;
if ((m.ModFlags & static_mask) != static_flags)
MethodBuilder mb = m.MethodBuilder;
- if (mb != null && filter (mb, criteria) == true)
+ if (mb != null && filter (mb, criteria) == true) {
+ if (members == null)
+ members = new ArrayList ();
+
members.Add (mb);
}
}
+ }
+
+ if (operators != null) {
+ int len = operators.Count;
+ for (int i = 0; i < len; i++) {
+ Operator o = (Operator) operators [i];
- if (operators != null){
- foreach (Operator o in operators) {
if ((o.ModFlags & modflags) == 0)
continue;
if ((o.ModFlags & static_mask) != static_flags)
continue;
MethodBuilder ob = o.OperatorMethodBuilder;
- if (ob != null && filter (ob, criteria) == true)
+ if (ob != null && filter (ob, criteria) == true) {
+ if (members == null)
+ members = new ArrayList ();
+
members.Add (ob);
}
}
+ }
+
+ if (properties != null) {
+ int len = properties.Count;
+ for (int i = 0; i < len; i++) {
+ Property p = (Property) properties [i];
- if (properties != null){
- foreach (Property p in properties){
if ((p.ModFlags & modflags) == 0)
continue;
if ((p.ModFlags & static_mask) != static_flags)
MethodBuilder b;
b = p.GetBuilder;
- if (b != null && filter (b, criteria) == true)
+ if (b != null && filter (b, criteria) == true) {
+ if (members == null)
+ members = new ArrayList ();
+
members.Add (b);
+ }
b = p.SetBuilder;
- if (b != null && filter (b, criteria) == true)
+ if (b != null && filter (b, criteria) == true) {
+ if (members == null)
+ members = new ArrayList ();
+
members.Add (b);
}
}
+ }
+
+ if (indexers != null) {
+ int len = indexers.Count;
+ for (int i = 0; i < len; i++) {
+ Indexer ix = (Indexer) indexers [i];
- if (indexers != null){
- foreach (Indexer ix in indexers){
if ((ix.ModFlags & modflags) == 0)
continue;
if ((ix.ModFlags & static_mask) != static_flags)
MethodBuilder b;
b = ix.GetBuilder;
- if (b != null && filter (b, criteria) == true)
+ if (b != null && filter (b, criteria) == true) {
+ if (members == null)
+ members = new ArrayList ();
+
members.Add (b);
+ }
b = ix.SetBuilder;
- if (b != null && filter (b, criteria) == true)
+ if (b != null && filter (b, criteria) == true) {
+ if (members == null)
+ members = new ArrayList ();
+
members.Add (b);
}
}
}
+ }
if ((mt & MemberTypes.Event) != 0) {
- if (events != null)
- foreach (Event e in events) {
+ if (events != null) {
+ int len = events.Count;
+ for (int i = 0; i < len; i++) {
+ Event e = (Event) events [i];
+
if ((e.ModFlags & modflags) == 0)
continue;
if ((e.ModFlags & static_mask) != static_flags)
continue;
MemberInfo eb = e.EventBuilder;
- if (eb != null && filter (eb, criteria) == true)
+ if (eb != null && filter (eb, criteria) == true) {
+ if (members == null)
+ members = new ArrayList ();
+
members.Add (e.EventBuilder);
}
}
+ }
+ }
if ((mt & MemberTypes.Property) != 0){
- if (properties != null)
- foreach (Property p in properties) {
+ if (properties != null) {
+ int len = properties.Count;
+ for (int i = 0; i < len; i++) {
+ Property p = (Property) properties [i];
+
if ((p.ModFlags & modflags) == 0)
continue;
if ((p.ModFlags & static_mask) != static_flags)
MemberInfo pb = p.PropertyBuilder;
if (pb != null && filter (pb, criteria) == true) {
+ if (members == null)
+ members = new ArrayList ();
+
members.Add (p.PropertyBuilder);
}
}
+ }
+
+ if (indexers != null) {
+ int len = indexers.Count;
+ for (int i = 0; i < len; i++) {
+ Indexer ix = (Indexer) indexers [i];
- if (indexers != null)
- foreach (Indexer ix in indexers) {
if ((ix.ModFlags & modflags) == 0)
continue;
if ((ix.ModFlags & static_mask) != static_flags)
MemberInfo ib = ix.PropertyBuilder;
if (ib != null && filter (ib, criteria) == true) {
+ if (members == null)
+ members = new ArrayList ();
+
members.Add (ix.PropertyBuilder);
}
}
}
+ }
if ((mt & MemberTypes.NestedType) != 0) {
- if (types != null){
- foreach (TypeContainer t in types) {
+ if (types != null) {
+ int len = types.Count;
+ for (int i = 0; i < len; i++) {
+ TypeContainer t = (TypeContainer) types [i];
+
if ((t.ModFlags & modflags) == 0)
continue;
TypeBuilder tb = t.TypeBuilder;
- if (tb != null && (filter (tb, criteria) == true))
+ if (tb != null && (filter (tb, criteria) == true)) {
+ if (members == null)
+ members = new ArrayList ();
+
members.Add (tb);
}
}
+ }
+
+ if (enums != null) {
+ int len = enums.Count;
+ for (int i = 0; i < len; i++) {
+ Enum en = (Enum) enums [i];
- if (enums != null){
- foreach (Enum en in enums){
if ((en.ModFlags & modflags) == 0)
continue;
TypeBuilder tb = en.TypeBuilder;
- if (tb != null && (filter (tb, criteria) == true))
+ if (tb != null && (filter (tb, criteria) == true)) {
+ if (members == null)
+ members = new ArrayList ();
+
members.Add (tb);
}
}
+ }
+
+ if (delegates != null) {
+ int len = delegates.Count;
+ for (int i = 0; i < len; i++) {
+ Delegate d = (Delegate) delegates [i];
- if (delegates != null){
- foreach (Delegate d in delegates){
if ((d.ModFlags & modflags) == 0)
continue;
TypeBuilder tb = d.TypeBuilder;
- if (tb != null && (filter (tb, criteria) == true))
+ if (tb != null && (filter (tb, criteria) == true)) {
+ if (members == null)
+ members = new ArrayList ();
+
members.Add (tb);
}
}
+ }
+
+ if (interfaces != null) {
+ int len = interfaces.Count;
+ for (int i = 0; i < len; i++) {
+ Interface iface = (Interface) interfaces [i];
- if (interfaces != null){
- foreach (Interface iface in interfaces){
if ((iface.ModFlags & modflags) == 0)
continue;
TypeBuilder tb = iface.TypeBuilder;
- if (tb != null && (filter (tb, criteria) == true))
+ if (tb != null && (filter (tb, criteria) == true)) {
+ if (members == null)
+ members = new ArrayList ();
+
members.Add (tb);
}
}
}
+ }
if ((mt & MemberTypes.Constructor) != 0){
if (((bf & BindingFlags.Instance) != 0) && (instance_constructors != null)){
- foreach (Constructor c in instance_constructors){
+ int len = instance_constructors.Count;
+ for (int i = 0; i < len; i++) {
+ Constructor c = (Constructor) instance_constructors [i];
+
ConstructorBuilder cb = c.ConstructorBuilder;
- if (cb != null)
- if (filter (cb, criteria) == true)
+ if (cb != null && filter (cb, criteria) == true) {
+ if (members == null)
+ members = new ArrayList ();
+
members.Add (cb);
}
}
+ }
if (((bf & BindingFlags.Static) != 0) && (default_static_constructor != null)){
ConstructorBuilder cb =
default_static_constructor.ConstructorBuilder;
- if (cb != null)
- if (filter (cb, criteria) == true)
+ if (cb != null && filter (cb, criteria) == true) {
+ if (members == null)
+ members = new ArrayList ();
+
members.Add (cb);
}
}
+ }
//
// Lookup members in parent if requested.
//
if (((bf & BindingFlags.DeclaredOnly) == 0) && (TypeBuilder.BaseType != null)) {
MemberList list = FindMembers (TypeBuilder.BaseType, mt, bf, filter, criteria);
+ if (list.Count > 0) {
+ if (members == null)
+ members = new ArrayList ();
+
members.AddRange (list);
}
+ }
Timer.StopTimer (TimerType.TcFindMembers);
+ if (members == null)
+ return MemberList.Empty;
+ else
return new MemberList (members);
}
if (RootContext.WarningLevel >= 3) {
if (fields != null){
foreach (Field f in fields) {
- if ((f.ModFlags & Modifiers.PUBLIC) != 0)
+ if ((f.ModFlags & Modifiers.Accessibility) != Modifiers.PRIVATE)
continue;
- if (f.status == 0){
+ if ((f.status & Field.Status.USED) == 0){
Report.Warning (
169, f.Location, "Private field " +
MakeName (f.Name) + " is never used");
public override void CloseType ()
{
+ if (Created)
+ return;
+
try {
- if (!Created){
Created = true;
TypeBuilder.CreateType ();
- }
} catch (TypeLoadException){
//
// This is fine, the code still created the type
if (Delegates != null)
foreach (Delegate d in Delegates)
d.CloseType ();
+
+ types = null;
+ properties = null;
+ enums = null;
+ delegates = null;
+ fields = null;
+ initialized_fields = null;
+ initialized_static_fields = null;
+ constants = null;
+ interfaces = null;
+ interface_order = null;
+ methods = null;
+ events = null;
+ indexers = null;
+ operators = null;
+ ec = null;
+ default_constructor = null;
+ default_static_constructor = null;
+ type_bases = null;
+ attributes = null;
+ ifaces = null;
+ parent_container = null;
+ member_cache = null;
}
public string MakeName (string n)
// This is used to track the Entry Point,
//
if (Name == "Main" &&
- ((ModFlags & Modifiers.STATIC) != 0) &&
+ ((ModFlags & Modifiers.STATIC) != 0) && RootContext.NeedsEntryPoint &&
(RootContext.MainClass == null ||
RootContext.MainClass == container.TypeBuilder.FullName)){
if (IsEntryPoint (MethodBuilder, ParameterInfo)) {
{
MethodData.Emit (container, Block, this);
Block = null;
+ MethodData = null;
}
void IIteratorContainer.SetYields ()
protected MethodAttributes flags;
+ protected readonly int explicit_mod_flags;
+
//
// The "short" name of this property / indexer / event. This is the
// name without the explicit interface.
Attributes attrs, Location loc)
: base (name, loc)
{
+ explicit_mod_flags = mod;
Type = type;
ModFlags = Modifiers.Check (allowed_mod, mod, def_mod, loc);
OptAttributes = attrs;
if (!container.VerifyImplements (InterfaceType, ShortName, Name, Location))
return false;
+ Modifiers.Check (Modifiers.AllowedExplicitImplFlags, explicit_mod_flags, 0, Location);
+
IsExplicitImpl = true;
} else
IsExplicitImpl = false;
}
}
- public bool IsAssigned;
-
protected readonly Object init;
// Private.
Expression init_expr;
return init_expr;
}
+
+ public void SetAssigned ()
+ {
+ status |= Status.ASSIGNED;
+ }
}
//
//
// Are we implementing an interface ?
//
- bool IsImplementing = false;
-
public Indexer (DeclSpace ds, Expression type, string int_type, int flags,
Parameters parameters, Accessor get_block, Accessor set_block,
Attributes attrs, Location loc)
}
}
- if (GetData != null)
- IsImplementing = GetData.IsImplementing;
- else if (SetData != null)
- IsImplementing = SetData.IsImplementing;
-
//
// Define the PropertyBuilder if one of the following conditions are met:
// a) we're not implementing an interface indexer.
current_domain = AppDomain.CurrentDomain;
AssemblyBuilder = current_domain.DefineDynamicAssembly (
- an, AssemblyBuilderAccess.RunAndSave, Dirname (name));
+ an, AssemblyBuilderAccess.Save, Dirname (name));
//
// Pass a path-less name to DefineDynamicModule. Wonder how
/// </summary>
public bool InEnumContext;
- protected Stack FlowStack;
+ FlowBranching current_flow_branching;
public EmitContext (DeclSpace parent, DeclSpace ds, Location l, ILGenerator ig,
Type return_type, int code_flags, bool is_constructor)
}
loc = l;
- FlowStack = new Stack ();
-
if (ReturnType == TypeManager.void_type)
ReturnType = null;
}
public FlowBranching CurrentBranching {
get {
- return (FlowBranching) FlowStack.Peek ();
+ return current_flow_branching;
}
}
// </summary>
public FlowBranching StartFlowBranching (FlowBranching.BranchingType type, Location loc)
{
- FlowBranching cfb = FlowBranching.CreateBranching (CurrentBranching, type, null, loc);
-
- FlowStack.Push (cfb);
-
- return cfb;
+ current_flow_branching = FlowBranching.CreateBranching (CurrentBranching, type, null, loc);
+ return current_flow_branching;
}
// <summary>
// </summary>
public FlowBranching StartFlowBranching (Block block)
{
- FlowBranching cfb;
FlowBranching.BranchingType type;
if (CurrentBranching.Type == FlowBranching.BranchingType.Switch)
else
type = FlowBranching.BranchingType.Block;
- cfb = FlowBranching.CreateBranching (CurrentBranching, type, block, block.StartLocation);
+ current_flow_branching = FlowBranching.CreateBranching (CurrentBranching, type, block, block.StartLocation);
+ return current_flow_branching;
+ }
- FlowStack.Push (cfb);
+ // <summary>
+ // Ends a code branching. Merges the state of locals and parameters
+ // from all the children of the ending branching.
+ // </summary>
+ public FlowBranching.UsageVector DoEndFlowBranching ()
+ {
+ FlowBranching old = current_flow_branching;
+ current_flow_branching = current_flow_branching.Parent;
- return cfb;
+ return current_flow_branching.MergeChild (old);
}
// <summary>
// Ends a code branching. Merges the state of locals and parameters
// from all the children of the ending branching.
// </summary>
- public FlowBranching.FlowReturns EndFlowBranching ()
+ public FlowBranching.Reachability EndFlowBranching ()
{
- FlowBranching cfb = (FlowBranching) FlowStack.Pop ();
+ FlowBranching.UsageVector vector = DoEndFlowBranching ();
- return CurrentBranching.MergeChild (cfb);
+ return vector.Reachability;
}
// <summary>
// </summary>
public void KillFlowBranching ()
{
- FlowBranching cfb = (FlowBranching) FlowStack.Pop ();
+ current_flow_branching = current_flow_branching.Parent;
}
public void EmitTopBlock (Block block, InternalParameters ip, Location loc)
bool old_do_flow_analysis = DoFlowAnalysis;
DoFlowAnalysis = true;
- FlowBranching cfb = FlowBranching.CreateBranching (
+ current_flow_branching = FlowBranching.CreateBranching (
null, FlowBranching.BranchingType.Block, block, loc);
- FlowStack.Push (cfb);
if (!block.Resolve (this)) {
- FlowStack.Pop ();
+ current_flow_branching = null;
DoFlowAnalysis = old_do_flow_analysis;
return;
}
- cfb = (FlowBranching) FlowStack.Pop ();
- FlowBranching.FlowReturns returns = cfb.MergeTopBlock ();
+ FlowBranching.Reachability reachability = current_flow_branching.MergeTopBlock ();
+ current_flow_branching = null;
DoFlowAnalysis = old_do_flow_analysis;
- has_ret = block.Emit (this);
+ block.Emit (this);
- if ((returns == FlowBranching.FlowReturns.Always) ||
- (returns == FlowBranching.FlowReturns.Exception) ||
- (returns == FlowBranching.FlowReturns.Unreachable))
+ if ((reachability.Returns == FlowBranching.FlowReturns.Always) ||
+ (reachability.Throws == FlowBranching.FlowReturns.Always) ||
+ (reachability.Reachable == FlowBranching.FlowReturns.Never))
has_ret = true;
-
- if (Report.Errors == errors){
- if (RootContext.WarningLevel >= 3)
- block.UsageWarning ();
}
- }
- } catch {
+ } catch (Exception e) {
Console.WriteLine ("Exception caught by the compiler while compiling:");
Console.WriteLine (" Block that caused the problem begin at: " + loc);
Console.WriteLine (" Block being compiled: [{0},{1}]",
CurrentBlock.StartLocation, CurrentBlock.EndLocation);
}
- throw;
+
+ Console.WriteLine (e.GetType ().FullName + ": " + e.Message);
+ Console.WriteLine (Report.FriendlyStackTrace (e));
+
+ Environment.Exit (1);
}
}
static public Expression ImplicitConversion (EmitContext ec, Expression expr,
Type target_type, Location loc)
{
- Type expr_type = expr.Type;
Expression e;
if (target_type == null)
;
opt_new
- : /* empty */ { $$ = false; }
- | NEW { $$ = true; }
+ : opt_modifiers
+ {
+ int val = (int) $1;
+
+ val = Modifiers.Check (Modifiers.NEW, val, 0, lexer.Location);
+ $$ = (bool) (val != 0);
+ }
;
interface_method_declaration
//\r
// Class variables\r
// \r
- static Hashtable keywords;\r
+ static CharArrayHashtable[] keywords;\r
static NumberStyles styles;\r
static NumberFormatInfo csharp_format_info;\r
\r
}\r
}\r
\r
+ static void AddKeyword (string kw, int token) {\r
+ if (keywords [kw.Length] == null) {\r
+ keywords [kw.Length] = new CharArrayHashtable (kw.Length);\r
+ }\r
+ keywords [kw.Length] [kw.ToCharArray ()] = token;\r
+ }\r
+\r
static void InitTokens ()\r
{\r
- keywords = new Hashtable ();\r
-\r
- keywords.Add ("abstract", Token.ABSTRACT);\r
- keywords.Add ("as", Token.AS);\r
- keywords.Add ("add", Token.ADD);\r
- keywords.Add ("assembly", Token.ASSEMBLY);\r
- keywords.Add ("base", Token.BASE);\r
- keywords.Add ("bool", Token.BOOL);\r
- keywords.Add ("break", Token.BREAK);\r
- keywords.Add ("byte", Token.BYTE);\r
- keywords.Add ("case", Token.CASE);\r
- keywords.Add ("catch", Token.CATCH);\r
- keywords.Add ("char", Token.CHAR);\r
- keywords.Add ("checked", Token.CHECKED);\r
- keywords.Add ("class", Token.CLASS);\r
- keywords.Add ("const", Token.CONST);\r
- keywords.Add ("continue", Token.CONTINUE);\r
- keywords.Add ("decimal", Token.DECIMAL);\r
- keywords.Add ("default", Token.DEFAULT);\r
- keywords.Add ("delegate", Token.DELEGATE);\r
- keywords.Add ("do", Token.DO);\r
- keywords.Add ("double", Token.DOUBLE);\r
- keywords.Add ("else", Token.ELSE);\r
- keywords.Add ("enum", Token.ENUM);\r
- keywords.Add ("event", Token.EVENT);\r
- keywords.Add ("explicit", Token.EXPLICIT);\r
- keywords.Add ("extern", Token.EXTERN);\r
- keywords.Add ("false", Token.FALSE);\r
- keywords.Add ("finally", Token.FINALLY);\r
- keywords.Add ("fixed", Token.FIXED);\r
- keywords.Add ("float", Token.FLOAT);\r
- keywords.Add ("for", Token.FOR);\r
- keywords.Add ("foreach", Token.FOREACH);\r
- keywords.Add ("goto", Token.GOTO);\r
- keywords.Add ("get", Token.GET);\r
- keywords.Add ("if", Token.IF);\r
- keywords.Add ("implicit", Token.IMPLICIT);\r
- keywords.Add ("in", Token.IN);\r
- keywords.Add ("int", Token.INT);\r
- keywords.Add ("interface", Token.INTERFACE);\r
- keywords.Add ("internal", Token.INTERNAL);\r
- keywords.Add ("is", Token.IS);\r
- keywords.Add ("lock", Token.LOCK);\r
- keywords.Add ("long", Token.LONG);\r
- keywords.Add ("namespace", Token.NAMESPACE);\r
- keywords.Add ("new", Token.NEW);\r
- keywords.Add ("null", Token.NULL);\r
- keywords.Add ("object", Token.OBJECT);\r
- keywords.Add ("operator", Token.OPERATOR);\r
- keywords.Add ("out", Token.OUT);\r
- keywords.Add ("override", Token.OVERRIDE);\r
- keywords.Add ("params", Token.PARAMS);\r
- keywords.Add ("private", Token.PRIVATE);\r
- keywords.Add ("protected", Token.PROTECTED);\r
- keywords.Add ("public", Token.PUBLIC);\r
- keywords.Add ("readonly", Token.READONLY);\r
- keywords.Add ("ref", Token.REF);\r
- keywords.Add ("remove", Token.REMOVE);\r
- keywords.Add ("return", Token.RETURN);\r
- keywords.Add ("sbyte", Token.SBYTE);\r
- keywords.Add ("sealed", Token.SEALED);\r
- keywords.Add ("set", Token.SET);\r
- keywords.Add ("short", Token.SHORT);\r
- keywords.Add ("sizeof", Token.SIZEOF);\r
- keywords.Add ("stackalloc", Token.STACKALLOC);\r
- keywords.Add ("static", Token.STATIC);\r
- keywords.Add ("string", Token.STRING);\r
- keywords.Add ("struct", Token.STRUCT);\r
- keywords.Add ("switch", Token.SWITCH);\r
- keywords.Add ("this", Token.THIS);\r
- keywords.Add ("throw", Token.THROW);\r
- keywords.Add ("true", Token.TRUE);\r
- keywords.Add ("try", Token.TRY);\r
- keywords.Add ("typeof", Token.TYPEOF);\r
- keywords.Add ("uint", Token.UINT);\r
- keywords.Add ("ulong", Token.ULONG);\r
- keywords.Add ("unchecked", Token.UNCHECKED);\r
- keywords.Add ("unsafe", Token.UNSAFE);\r
- keywords.Add ("ushort", Token.USHORT);\r
- keywords.Add ("using", Token.USING);\r
- keywords.Add ("virtual", Token.VIRTUAL);\r
- keywords.Add ("void", Token.VOID);\r
- keywords.Add ("volatile", Token.VOLATILE);\r
- keywords.Add ("where", Token.WHERE);\r
- keywords.Add ("while", Token.WHILE);\r
+ keywords = new CharArrayHashtable [64];\r
+\r
+ AddKeyword ("abstract", Token.ABSTRACT);\r
+ AddKeyword ("as", Token.AS);\r
+ AddKeyword ("add", Token.ADD);\r
+ AddKeyword ("assembly", Token.ASSEMBLY);\r
+ AddKeyword ("base", Token.BASE);\r
+ AddKeyword ("bool", Token.BOOL);\r
+ AddKeyword ("break", Token.BREAK);\r
+ AddKeyword ("byte", Token.BYTE);\r
+ AddKeyword ("case", Token.CASE);\r
+ AddKeyword ("catch", Token.CATCH);\r
+ AddKeyword ("char", Token.CHAR);\r
+ AddKeyword ("checked", Token.CHECKED);\r
+ AddKeyword ("class", Token.CLASS);\r
+ AddKeyword ("const", Token.CONST);\r
+ AddKeyword ("continue", Token.CONTINUE);\r
+ AddKeyword ("decimal", Token.DECIMAL);\r
+ AddKeyword ("default", Token.DEFAULT);\r
+ AddKeyword ("delegate", Token.DELEGATE);\r
+ AddKeyword ("do", Token.DO);\r
+ AddKeyword ("double", Token.DOUBLE);\r
+ AddKeyword ("else", Token.ELSE);\r
+ AddKeyword ("enum", Token.ENUM);\r
+ AddKeyword ("event", Token.EVENT);\r
+ AddKeyword ("explicit", Token.EXPLICIT);\r
+ AddKeyword ("extern", Token.EXTERN);\r
+ AddKeyword ("false", Token.FALSE);\r
+ AddKeyword ("finally", Token.FINALLY);\r
+ AddKeyword ("fixed", Token.FIXED);\r
+ AddKeyword ("float", Token.FLOAT);\r
+ AddKeyword ("for", Token.FOR);\r
+ AddKeyword ("foreach", Token.FOREACH);\r
+ AddKeyword ("goto", Token.GOTO);\r
+ AddKeyword ("get", Token.GET);\r
+ AddKeyword ("if", Token.IF);\r
+ AddKeyword ("implicit", Token.IMPLICIT);\r
+ AddKeyword ("in", Token.IN);\r
+ AddKeyword ("int", Token.INT);\r
+ AddKeyword ("interface", Token.INTERFACE);\r
+ AddKeyword ("internal", Token.INTERNAL);\r
+ AddKeyword ("is", Token.IS);\r
+ AddKeyword ("lock", Token.LOCK);\r
+ AddKeyword ("long", Token.LONG);\r
+ AddKeyword ("namespace", Token.NAMESPACE);\r
+ AddKeyword ("new", Token.NEW);\r
+ AddKeyword ("null", Token.NULL);\r
+ AddKeyword ("object", Token.OBJECT);\r
+ AddKeyword ("operator", Token.OPERATOR);\r
+ AddKeyword ("out", Token.OUT);\r
+ AddKeyword ("override", Token.OVERRIDE);\r
+ AddKeyword ("params", Token.PARAMS);\r
+ AddKeyword ("private", Token.PRIVATE);\r
+ AddKeyword ("protected", Token.PROTECTED);\r
+ AddKeyword ("public", Token.PUBLIC);\r
+ AddKeyword ("readonly", Token.READONLY);\r
+ AddKeyword ("ref", Token.REF);\r
+ AddKeyword ("remove", Token.REMOVE);\r
+ AddKeyword ("return", Token.RETURN);\r
+ AddKeyword ("sbyte", Token.SBYTE);\r
+ AddKeyword ("sealed", Token.SEALED);\r
+ AddKeyword ("set", Token.SET);\r
+ AddKeyword ("short", Token.SHORT);\r
+ AddKeyword ("sizeof", Token.SIZEOF);\r
+ AddKeyword ("stackalloc", Token.STACKALLOC);\r
+ AddKeyword ("static", Token.STATIC);\r
+ AddKeyword ("string", Token.STRING);\r
+ AddKeyword ("struct", Token.STRUCT);\r
+ AddKeyword ("switch", Token.SWITCH);\r
+ AddKeyword ("this", Token.THIS);\r
+ AddKeyword ("throw", Token.THROW);\r
+ AddKeyword ("true", Token.TRUE);\r
+ AddKeyword ("try", Token.TRY);\r
+ AddKeyword ("typeof", Token.TYPEOF);\r
+ AddKeyword ("uint", Token.UINT);\r
+ AddKeyword ("ulong", Token.ULONG);\r
+ AddKeyword ("unchecked", Token.UNCHECKED);\r
+ AddKeyword ("unsafe", Token.UNSAFE);\r
+ AddKeyword ("ushort", Token.USHORT);\r
+ AddKeyword ("using", Token.USING);\r
+ AddKeyword ("virtual", Token.VIRTUAL);\r
+ AddKeyword ("void", Token.VOID);\r
+ AddKeyword ("volatile", Token.VOLATILE);\r
+ AddKeyword ("where", Token.WHERE);\r
+ AddKeyword ("while", Token.WHILE);\r
\r
if (RootContext.V2){\r
- keywords.Add ("__yield", Token.YIELD);\r
- keywords.Add ("yield", Token.YIELD);\r
+ AddKeyword ("__yield", Token.YIELD);\r
+ AddKeyword ("yield", Token.YIELD);\r
}\r
}\r
\r
string_builder = new System.Text.StringBuilder ();\r
}\r
\r
- int GetKeyword (string name)\r
+ int GetKeyword (char[] id, int id_len)\r
{\r
- object o = keywords [name];\r
+ /*\r
+ * Keywords are stored in an array of hashtables grouped by their\r
+ * length.\r
+ */\r
+\r
+ if ((id_len >= keywords.Length) || (keywords [id_len] == null))\r
+ return -1;\r
+ object o = keywords [id_len] [id];\r
\r
if (o == null)\r
return -1;\r
//\r
int getHex (int count, out bool error)\r
{\r
- int [] buffer = new int [8];\r
int i;\r
int total = 0;\r
int c;\r
//\r
bool handle_preprocessing_directive (bool caller_is_taking)\r
{\r
- char [] blank = { ' ', '\t' };\r
string cmd, arg;\r
bool region_directive = false;\r
\r
}\r
}\r
\r
- string ids = new String (id_builder, 0, pos);\r
-\r
//\r
// Optimization: avoids doing the keyword lookup\r
// on uppercase letters and _\r
//\r
if (s >= 'a'){\r
- int keyword = GetKeyword (ids);\r
- if (keyword == -1 || quoted){\r
- val = ids;\r
- return Token.IDENTIFIER;\r
- }\r
+ int keyword = GetKeyword (id_builder, pos);\r
+ if (keyword != -1 && !quoted)\r
return keyword;\r
}\r
- val = ids;\r
+\r
+ val = new String (id_builder, 0, pos);\r
+\r
return Token.IDENTIFIER;\r
}\r
\r
return true;
string check_type_name = check_type.FullName;
- string type_name = TypeBuilder.FullName;
int cio = check_type_name.LastIndexOf ('+');
string container = check_type_name.Substring (0, cio);
}
// Access level of a type.
- enum AccessLevel {
- Public = 0,
- ProtectedInternal = 1,
- Internal = 2,
- Protected = 3,
- Private = 4
+ const int X = 1;
+ enum AccessLevel { // Each column represents `is this scope larger or equal to Blah scope'
+ // Public Assembly Protected
+ Protected = (0 << 0) | (0 << 1) | (X << 2),
+ Public = (X << 0) | (X << 1) | (X << 2),
+ Private = (0 << 0) | (0 << 1) | (0 << 2),
+ Internal = (0 << 0) | (X << 1) | (0 << 2),
+ ProtectedOrInternal = (0 << 0) | (X << 1) | (X << 2),
}
- // Check whether `flags' denotes a more restricted access than `level'
- // and return the new level.
- static AccessLevel CheckAccessLevel (AccessLevel level, int flags)
+ static AccessLevel GetAccessLevelFromModifiers (int flags)
{
- AccessLevel old_level = level;
-
if ((flags & Modifiers.INTERNAL) != 0) {
- if ((flags & Modifiers.PROTECTED) != 0) {
- if ((int) level < (int) AccessLevel.ProtectedInternal)
- level = AccessLevel.ProtectedInternal;
- } else {
- if ((int) level < (int) AccessLevel.Internal)
- level = AccessLevel.Internal;
- }
- } else if ((flags & Modifiers.PROTECTED) != 0) {
- if ((int) level < (int) AccessLevel.Protected)
- level = AccessLevel.Protected;
- } else if ((flags & Modifiers.PRIVATE) != 0)
- level = AccessLevel.Private;
- return level;
- }
+ if ((flags & Modifiers.PROTECTED) != 0)
+ return AccessLevel.ProtectedOrInternal;
+ else
+ return AccessLevel.Internal;
- // Return the access level for a new member which is defined in the current
- // TypeContainer with access modifiers `flags'.
- AccessLevel GetAccessLevel (int flags)
- {
- if ((flags & Modifiers.PRIVATE) != 0)
+ } else if ((flags & Modifiers.PROTECTED) != 0)
+ return AccessLevel.Protected;
+ else if ((flags & Modifiers.PRIVATE) != 0)
return AccessLevel.Private;
-
- AccessLevel level;
- if (!IsTopLevel && (Parent != null))
- level = Parent.GetAccessLevel (flags);
else
- level = AccessLevel.Public;
+ return AccessLevel.Public;
+ }
- return CheckAccessLevel (CheckAccessLevel (level, flags), ModFlags);
+ // What is the effective access level of this?
+ // TODO: Cache this?
+ AccessLevel EffectiveAccessLevel {
+ get {
+ AccessLevel myAccess = GetAccessLevelFromModifiers (ModFlags);
+ if (!IsTopLevel && (Parent != null))
+ return myAccess & Parent.EffectiveAccessLevel;
+ return myAccess;
+ }
}
- // Return the access level for type `t', but don't give more access than `flags'.
- static AccessLevel GetAccessLevel (Type t, int flags)
+ // Return the access level for type `t'
+ static AccessLevel TypeEffectiveAccessLevel (Type t)
{
- if (((flags & Modifiers.PRIVATE) != 0) || t.IsNestedPrivate)
- return AccessLevel.Private;
-
- AccessLevel level;
- if (TypeManager.IsBuiltinType (t))
+ if (t.IsPublic)
return AccessLevel.Public;
- else if ((t.DeclaringType != null) && (t != t.DeclaringType))
- level = GetAccessLevel (t.DeclaringType, flags);
- else {
- level = CheckAccessLevel (AccessLevel.Public, flags);
- }
+ if (t.IsNestedPrivate)
+ return AccessLevel.Private;
+ if (t.IsNotPublic)
+ return AccessLevel.Internal;
- if (t.IsNestedPublic)
- return level;
+ // By now, it must be nested
+ AccessLevel parentLevel = TypeEffectiveAccessLevel (t.DeclaringType);
- if (t.IsNestedAssembly || t.IsNotPublic) {
- if ((int) level < (int) AccessLevel.Internal)
- level = AccessLevel.Internal;
- }
+ if (t.IsNestedPublic)
+ return parentLevel;
+ if (t.IsNestedAssembly)
+ return parentLevel & AccessLevel.Internal;
+ if (t.IsNestedFamily)
+ return parentLevel & AccessLevel.Protected;
+ if (t.IsNestedFamORAssem)
+ return parentLevel & AccessLevel.ProtectedOrInternal;
+ if (t.IsNestedFamANDAssem)
+ throw new NotImplementedException ("NestedFamANDAssem not implemented, cant make this kind of type from c# anyways");
- if (t.IsNestedFamily) {
- if ((int) level < (int) AccessLevel.Protected)
- level = AccessLevel.Protected;
- }
+ // nested private is taken care of
- if (t.IsNestedFamORAssem) {
- if ((int) level < (int) AccessLevel.ProtectedInternal)
- level = AccessLevel.ProtectedInternal;
- }
-
- return level;
+ throw new Exception ("I give up, what are you?");
}
//
- // Returns true if `parent' is as accessible as the flags `flags'
- // given for this member.
+ // This answers `is the type P, as accessible as a member M which has the
+ // accessability @flags which is declared as a nested member of the type T, this declspace'
//
- public bool AsAccessible (Type parent, int flags)
+ public bool AsAccessible (Type p, int flags)
{
- while (parent.IsArray || parent.IsPointer || parent.IsByRef)
- parent = TypeManager.GetElementType (parent);
-
- if (parent.IsGenericParameter)
+ if (p.IsGenericParameter)
return true; // FIXME
- AccessLevel level = GetAccessLevel (flags);
- AccessLevel level2 = GetAccessLevel (parent, flags);
+ //
+ // 1) if M is private, its accessability is the same as this declspace.
+ // we already know that P is accessible to T before this method, so we
+ // may return true.
+ //
- return (int) level >= (int) level2;
+ if ((flags & Modifiers.PRIVATE) != 0)
+ return true;
+
+ while (p.IsArray || p.IsPointer || p.IsByRef)
+ p = TypeManager.GetElementType (p);
+
+ AccessLevel pAccess = TypeEffectiveAccessLevel (p);
+ AccessLevel mAccess = this.EffectiveAccessLevel &
+ GetAccessLevelFromModifiers (flags);
+
+ // for every place from which we can access M, we must
+ // be able to access P as well. So, we want
+ // For every bit in M and P, M_i -> P_1 == true
+ // or, ~ (M -> P) == 0 <-> ~ ( ~M | P) == 0
+
+ return ~ (~ mAccess | pAccess) == 0;
}
- static DoubleHash dh = new DoubleHash ();
+ static DoubleHash dh = new DoubleHash (1000);
Type LookupInterfaceOrClass (string ns, string name, out bool error)
{
error = false;
if (dh.Lookup (ns, name, out r))
- t = (Type) r;
+ return (Type) r;
else {
if (ns != ""){
if (Namespace.IsNamespace (ns)){
t = TypeManager.LookupType (name);
}
- if (t != null)
+ if (t != null) {
+ dh.Insert (ns, name, t);
return t;
+ }
//
// In case we are fed a composite name, normalize it.
}
parent = RootContext.Tree.LookupByNamespace (ns, name);
- if (parent == null)
+ if (parent == null) {
+ dh.Insert (ns, name, null);
return null;
+ }
t = parent.DefineType ();
- dh.Insert (ns, name, t);
if (t == null){
error = true;
return null;
}
+
+ dh.Insert (ns, name, t);
return t;
}
Type container_type = containing_ds.TypeBuilder;
Type current_type = container_type;
- while (current_type != null) {
+ while (current_type != null && current_type != TypeManager.object_type) {
string pre = current_type.FullName;
t = LookupInterfaceOrClass (pre, name, out error);
public readonly IMemberContainer Container;
protected Hashtable member_hash;
protected Hashtable method_hash;
- protected Hashtable interface_hash;
+
+ Hashtable interface_hash;
/// <summary>
/// Create a new MemberCache for the given IMemberContainer `container'.
Timer.IncrementCounter (CounterType.MemberCache);
Timer.StartTimer (TimerType.CacheInit);
- interface_hash = new Hashtable ();
+
// If we have a parent class (we have a parent class unless we're
// TypeManager.object_type), we deep-copy its MemberCache here.
if (Container.IsInterface) {
MemberCache parent;
+ interface_hash = new Hashtable ();
+
if (Container.Parent != null)
parent = Container.Parent.MemberCache;
else
return hash;
}
- void AddInterfaces (MemberCache parent)
- {
- foreach (Type iface in parent.interface_hash.Keys) {
- if (!interface_hash.Contains (iface))
- interface_hash.Add (iface, true);
- }
- }
/// <summary>
/// Add the contents of `new_hash' to `hash'.
if (interface_hash.Contains (itype))
continue;
- interface_hash.Add (itype, true);
+
+ interface_hash [itype] = null;
IMemberContainer iface_container =
TypeManager.LookupMemberContainer (itype);
MemberCache iface_cache = iface_container.MemberCache;
AddHashtable (hash, iface_cache.member_hash);
- AddInterfaces (iface_cache);
+
+ if (iface_cache.interface_hash == null)
+ continue;
+
+ foreach (Type parent_contains in iface_cache.interface_hash.Keys)
+ interface_hash [parent_contains] = null;
}
return hash;
void AddMembers (MemberTypes mt, BindingFlags bf, IMemberContainer container)
{
MemberList members = container.GetMembers (mt, bf);
- BindingFlags new_bf = (container == Container) ?
- bf | BindingFlags.DeclaredOnly : bf;
foreach (MemberInfo member in members) {
string name = member.Name;
\r
public override void Emit (EmitContext ec)\r
{\r
- Delegate del = TypeManager.LookupDelegate (InstanceExpr.Type);\r
-\r
//\r
// Invocation on delegates call the virtual Invoke member\r
// so we are always `instance' calls\r
using System.Text;
using System.Globalization;
- enum Target {
+ public enum Target {
Library, Exe, Module, WinExe
};
//
static ArrayList soft_references;
+ //
+ // Modules to be linked
+ //
+ static ArrayList modules;
+
// Lookup paths
static ArrayList link_paths;
static string first_source;
- static Target target = Target.Exe;
- static string target_ext = ".exe";
-
static bool want_debugging_support = false;
static bool parse_only = false;
int token, tokens = 0, errors = 0;
while ((token = lexer.token ()) != Token.EOF){
- Location l = lexer.Location;
tokens++;
if (token == Token.ERROR)
errors++;
}
}
+ static public void LoadModule (MethodInfo adder_method, string module)
+ {
+ Module m;
+ string total_log = "";
+
+ try {
+ try {
+ m = (Module)adder_method.Invoke (CodeGen.AssemblyBuilder, new object [] { module });
+ }
+ catch (TargetInvocationException ex) {
+ throw ex.InnerException;
+ }
+ TypeManager.AddModule (m);
+
+ }
+ catch (FileNotFoundException){
+ foreach (string dir in link_paths){
+ string full_path = Path.Combine (dir, module);
+ if (!module.EndsWith (".netmodule"))
+ full_path += ".netmodule";
+
+ try {
+ try {
+ m = (Module)adder_method.Invoke (CodeGen.AssemblyBuilder, new object [] { full_path });
+ }
+ catch (TargetInvocationException ex) {
+ throw ex.InnerException;
+ }
+ TypeManager.AddModule (m);
+ return;
+ } catch (FileNotFoundException ff) {
+ total_log += ff.FusionLog;
+ continue;
+ }
+ }
+ Report.Error (6, "Cannot find module `" + module + "'" );
+ Console.WriteLine ("Log: \n" + total_log);
+ } catch (BadImageFormatException f) {
+ Report.Error(6, "Cannot load module (bad file format)" + f.FusionLog);
+ } catch (FileLoadException f){
+ Report.Error(6, "Cannot load module " + f.FusionLog);
+ } catch (ArgumentNullException){
+ Report.Error(6, "Cannot load module (null argument)");
+ }
+ }
+
/// <summary>
/// Loads all assemblies referenced on the command line
/// </summary>
string type = args [++i];
switch (type){
case "library":
- target = Target.Library;
- target_ext = ".dll";
+ RootContext.Target = Target.Library;
+ RootContext.TargetExt = ".dll";
break;
case "exe":
- target = Target.Exe;
+ RootContext.Target = Target.Exe;
break;
case "winexe":
- target = Target.WinExe;
+ RootContext.Target = Target.WinExe;
break;
case "module":
- target = Target.Module;
- target_ext = ".dll";
+ RootContext.Target = Target.Module;
+ RootContext.TargetExt = ".dll";
break;
default:
TargetUsage ();
case "/target":
switch (value){
case "exe":
- target = Target.Exe;
+ RootContext.Target = Target.Exe;
break;
case "winexe":
- target = Target.WinExe;
+ RootContext.Target = Target.WinExe;
break;
case "library":
- target = Target.Library;
- target_ext = ".dll";
+ RootContext.Target = Target.Library;
+ RootContext.TargetExt = ".dll";
break;
case "module":
- target = Target.Module;
- target_ext = ".netmodule";
+ RootContext.Target = Target.Module;
+ RootContext.TargetExt = ".netmodule";
break;
default:
}
return true;
}
+ case "/addmodule": {
+ if (value == ""){
+ Report.Error (5, arg + " requires an argument");
+ Environment.Exit (1);
+ }
+
+ string [] refs = value.Split (new char [] { ';', ',' });
+ foreach (string r in refs){
+ modules.Add (r);
+ }
+ return true;
+ }
case "/doc": {
if (value == ""){
Report.Error (5, arg + " requires an argument");
references = new ArrayList ();
soft_references = new ArrayList ();
+ modules = new ArrayList ();
link_paths = new ArrayList ();
SetupDefaultDefines ();
int pos = first_source.LastIndexOf ('.');
if (pos > 0)
- output_file = first_source.Substring (0, pos) + target_ext;
+ output_file = first_source.Substring (0, pos) + RootContext.TargetExt;
else
- output_file = first_source + target_ext;
+ output_file = first_source + RootContext.TargetExt;
}
CodeGen.Init (output_file, output_file, want_debugging_support);
+ if (RootContext.Target == Target.Module) {
+ PropertyInfo module_only = typeof (AssemblyBuilder).GetProperty ("IsModuleOnly", BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic);
+ if (module_only == null) {
+ Report.Error (0, new Location (-1), "Cannot use /target:module on this runtime: try the Mono runtime instead.");
+ Environment.Exit (1);
+ }
+
+ module_only.SetValue (CodeGen.AssemblyBuilder, true, null);
+ }
+
TypeManager.AddModule (CodeGen.ModuleBuilder);
- DateTime start = DateTime.Now;
+ if (modules.Count > 0) {
+ MethodInfo adder_method = typeof (AssemblyBuilder).GetMethod ("AddModule", BindingFlags.Instance|BindingFlags.NonPublic);
+ if (adder_method == null) {
+ Report.Error (0, new Location (-1), "Cannot use /addmodule on this runtime: Try the Mono runtime instead.");
+ Environment.Exit (1);
+ }
+
+ foreach (string module in modules)
+ LoadModule (adder_method, module);
+ }
+
TypeManager.ComputeNamespaces ();
- DateTime end = DateTime.Now;
//
// Before emitting, we need to get the core
PEFileKinds k = PEFileKinds.ConsoleApplication;
- if (target == Target.Library || target == Target.Module){
- k = PEFileKinds.Dll;
-
- if (RootContext.MainClass != null)
- Report.Error (2017, "Can not specify -main: when building module or library");
- } else if (target == Target.Exe)
- k = PEFileKinds.ConsoleApplication;
- else if (target == Target.WinExe)
- k = PEFileKinds.WindowApplication;
+ switch (RootContext.Target) {
+ case Target.Library:
+ case Target.Module:
+ k = PEFileKinds.Dll; break;
+ case Target.Exe:
+ k = PEFileKinds.ConsoleApplication; break;
+ case Target.WinExe:
+ k = PEFileKinds.WindowApplication; break;
+ }
- if (target == Target.Exe || target == Target.WinExe){
+ if (RootContext.NeedsEntryPoint) {
MethodInfo ep = RootContext.EntryPoint;
- if (ep == null){
+ if (ep == null) {
if (Report.Errors == 0)
Report.Error (5001, "Program " + output_file +
" does not have an entry point defined");
}
CodeGen.AssemblyBuilder.SetEntryPoint (ep, k);
+ } else if (RootContext.MainClass != null) {
+ Report.Error (2017, "Can not specify -main: when building module or library");
}
//
object[] margs = new object [2];
Type[] argst = new Type [2];
argst [0] = argst [1] = typeof (string);
- MethodInfo embed_res = typeof (AssemblyBuilder).GetMethod ("EmbedResourceFile", argst);
+
+ MethodInfo embed_res = typeof (AssemblyBuilder).GetMethod ("EmbedResourceFile", BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic, null, CallingConventions.Any, argst, null);
if (embed_res == null) {
Report.Warning (0, new Location (-1), "Cannot embed resources on this runtime: try the Mono runtime instead.");
} else {
FieldBase fb = TypeManager.GetField (FieldInfo);
if (fb != null)
- fb.IsAssigned = true;
+ fb.SetAssigned ();
//
// InitOnly fields can only be assigned in constructors
public override void Emit (EmitContext ec)
{
ILGenerator ig = ec.ig;
- Type expr_type = Expr.Type;
switch (Oper) {
case Operator.UnaryPlus:
throw new Exception ("This should be caught by Resolve");
case Operator.UnaryNegation:
+ if (ec.CheckState) {
+ ig.Emit (OpCodes.Ldc_I4_0);
+ if (type == TypeManager.int64_type)
+ ig.Emit (OpCodes.Conv_U8);
+ Expr.Emit (ec);
+ ig.Emit (OpCodes.Sub_Ovf);
+ } else {
Expr.Emit (ec);
ig.Emit (OpCodes.Neg);
+ }
+
break;
case Operator.LogicalNot:
if (expr == null)
return null;
- int errors = Report.Errors;
-
type = ec.DeclSpace.ResolveType (target_type, false, Location);
if (type == null)
Expression CheckShiftArguments (EmitContext ec)
{
Expression e;
- Type l = left.Type;
- Type r = right.Type;
e = ForceConversion (ec, right, TypeManager.int32_type);
if (e == null){
{
ILGenerator ig = ec.ig;
Type l = left.Type;
- Type r = right.Type;
OpCode opcode;
//
right.Emit (ec);
bool isUnsigned = is_unsigned (left.Type);
- IntConstant ic;
switch (oper){
case Operator.Multiply:
#endif
}
- public override Expression DoResolve (EmitContext ec)
+ protected Expression DoResolve (EmitContext ec, bool is_lvalue)
{
- DoResolveBase (ec);
-
Expression e = Block.GetConstantExpression (Name);
if (e != null) {
local_info.Used = true;
if ((variable_info != null) && !variable_info.IsAssigned (ec, loc))
return null;
+ if (!is_lvalue)
+ local_info.Used = true;
+
if (local_info.LocalBuilder == null)
return ec.RemapLocal (local_info);
return this;
}
+ public override Expression DoResolve (EmitContext ec)
+ {
+ DoResolveBase (ec);
+
+ return DoResolve (ec, false);
+ }
+
override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
{
DoResolveBase (ec);
if (variable_info != null)
variable_info.SetAssigned (ec);
- Expression e = DoResolve (ec);
+ Expression e = DoResolve (ec, true);
if (e == null)
return null;
{
ILGenerator ig = ec.ig;
- local_info.Assigned = true;
-
source.Emit (ec);
ig.Emit (OpCodes.Stloc, local_info.LocalBuilder);
}
int cand_count = candidate_pd.Count;
+ //
+ // If there is no best method, than this one
+ // is better, however, if we already found a
+ // best method, we cant tell. This happens
+ // if we have:
+ //
+ //
+ // interface IFoo {
+ // void DoIt ();
+ // }
+ //
+ // interface IBar {
+ // void DoIt ();
+ // }
+ //
+ // interface IFooBar : IFoo, IBar {}
+ //
+ // We cant tell if IFoo.DoIt is better than IBar.DoIt
+ //
+ // However, we have to consider that
+ // Trim (); is better than Trim (params char[] chars);
if (cand_count == 0 && argument_count == 0)
- return 1;
+ return best == null || best_params ? 1 : 0;
if (candidate_pd.ParameterModifier (cand_count - 1) != Parameter.Modifier.PARAMS)
if (cand_count != argument_count)
ParameterData pd = GetParameterData (candidate);
- int pd_count = pd.Count;
-
if (arg_count != pd.Count)
return false;
Parameter.Modifier pm = pd.ParameterModifier (j);
if (pm == Parameter.Modifier.PARAMS){
- Parameter.Modifier am = a.GetParameterModifier ();
-
if ((pm & ~Parameter.Modifier.PARAMS) != a.GetParameterModifier ()) {
if (!Location.IsNull (loc))
Error_InvalidArguments (
if (expr is BaseAccess)
is_base = true;
- Expression old = expr;
-
expr = expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
if (expr == null)
return null;
// it will fail to find any members at all
//
- int errors = Report.Errors;
-
Type expr_type = expr.Type;
if (expr is TypeExpr){
if (!ec.DeclSpace.CheckAccessLevel (expr_type)){
public override Expression DoResolve (EmitContext ec)
{
+#if false
ExprClass eclass = ea.Expr.eclass;
-#if false
// As long as the type is valid
if (!(eclass == ExprClass.Variable || eclass == ExprClass.PropertyAccess ||
eclass == ExprClass.Value)) {
if (!CommonResolve (ec))
return null;
- Type right_type = right_side.Type;
-
bool found_any = false, found_any_setters = false;
Indexers ilist = Indexers.GetIndexersForType (current_type, indexer_type, loc);
// <summary>
// The type of a FlowBranching.
// </summary>
- public enum BranchingType {
+ public enum BranchingType : byte {
// Normal (conditional or toplevel) block.
Block,
+ // Conditional.
+ Conditional,
+
// A loop block.
LoopBlock,
// <summary>
// The type of one sibling of a branching.
// </summary>
- public enum SiblingType {
+ public enum SiblingType : byte {
+ Block,
Conditional,
SwitchSection,
Try,
// current code block may return to its enclosing block before reaching
// its end.
// </summary>
- public enum FlowReturns {
+ public enum FlowReturns : byte {
Undefined = 0,
// It can never return.
// The code always returns, ie. there's an unconditional return / break
// statement in it.
- Always,
+ Always
+ }
- // The code always throws an exception.
- Exception,
+ public sealed class Reachability
+ {
+ FlowReturns returns, breaks, throws, barrier, reachable;
+
+ public FlowReturns Returns {
+ get { return returns; }
+ }
+ public FlowReturns Breaks {
+ get { return breaks; }
+ }
+ public FlowReturns Throws {
+ get { return throws; }
+ }
+ public FlowReturns Barrier {
+ get { return barrier; }
+ }
+ public FlowReturns Reachable {
+ get { return reachable; }
+ }
+
+ public Reachability (FlowReturns returns, FlowReturns breaks,
+ FlowReturns throws, FlowReturns barrier)
+ {
+ this.returns = returns;
+ this.breaks = breaks;
+ this.throws = throws;
+ this.barrier = barrier;
+
+ update ();
+ }
+
+ public Reachability Clone ()
+ {
+ Reachability cloned = new Reachability (returns, breaks, throws, barrier);
+ cloned.reachable = reachable;
+ return cloned;
+ }
+
+ public static void And (ref Reachability a, Reachability b, bool do_break)
+ {
+ if (a == null) {
+ a = b.Clone ();
+ return;
+ }
+
+ //
+ // `break' does not "break" in a Switch or a LoopBlock
+ //
+ bool a_breaks = do_break && a.AlwaysBreaks;
+ bool b_breaks = do_break && b.AlwaysBreaks;
+
+ bool a_has_barrier, b_has_barrier;
+ if (do_break) {
+ //
+ // This is the normal case: the code following a barrier
+ // cannot be reached.
+ //
+ a_has_barrier = a.AlwaysHasBarrier;
+ b_has_barrier = b.AlwaysHasBarrier;
+ } else {
+ //
+ // Special case for Switch and LoopBlocks: we can reach the
+ // code after the barrier via the `break'.
+ //
+ a_has_barrier = !a.AlwaysBreaks && a.AlwaysHasBarrier;
+ b_has_barrier = !b.AlwaysBreaks && b.AlwaysHasBarrier;
+ }
+
+ bool a_unreachable = a_breaks || a.AlwaysThrows || a_has_barrier;
+ bool b_unreachable = b_breaks || b.AlwaysThrows || b_has_barrier;
+
+ //
+ // Do all code paths always return ?
+ //
+ if (a.AlwaysReturns) {
+ if (b.AlwaysReturns || b_unreachable)
+ a.returns = FlowReturns.Always;
+ else
+ a.returns = FlowReturns.Sometimes;
+ } else if (b.AlwaysReturns) {
+ if (a.AlwaysReturns || a_unreachable)
+ a.returns = FlowReturns.Always;
+ else
+ a.returns = FlowReturns.Sometimes;
+ } else if (!a.MayReturn) {
+ if (b.MayReturn)
+ a.returns = FlowReturns.Sometimes;
+ else
+ a.returns = FlowReturns.Never;
+ } else if (!b.MayReturn) {
+ if (a.MayReturn)
+ a.returns = FlowReturns.Sometimes;
+ else
+ a.returns = FlowReturns.Never;
+ }
+
+ a.breaks = AndFlowReturns (a.breaks, b.breaks);
+ a.throws = AndFlowReturns (a.throws, b.throws);
+ a.barrier = AndFlowReturns (a.barrier, b.barrier);
+
+ a.reachable = AndFlowReturns (a.reachable, b.reachable);
+ }
+
+ public static Reachability Never ()
+ {
+ return new Reachability (
+ FlowReturns.Never, FlowReturns.Never,
+ FlowReturns.Never, FlowReturns.Never);
+ }
+
+ void update ()
+ {
+ if ((returns == FlowReturns.Always) || (breaks == FlowReturns.Always) ||
+ (throws == FlowReturns.Always) || (barrier == FlowReturns.Always))
+ reachable = FlowReturns.Never;
+ else if ((returns == FlowReturns.Never) && (breaks == FlowReturns.Never) &&
+ (throws == FlowReturns.Never) && (barrier == FlowReturns.Never))
+ reachable = FlowReturns.Always;
+ else
+ reachable = FlowReturns.Sometimes;
+ }
+
+ public bool AlwaysBreaks {
+ get { return breaks == FlowReturns.Always; }
+ }
+
+ public bool MayBreak {
+ get { return breaks != FlowReturns.Never; }
+ }
+
+ public bool AlwaysReturns {
+ get { return returns == FlowReturns.Always; }
+ }
+
+ public bool MayReturn {
+ get { return returns != FlowReturns.Never; }
+ }
+
+ public bool AlwaysThrows {
+ get { return throws == FlowReturns.Always; }
+ }
+
+ public bool MayThrow {
+ get { return throws != FlowReturns.Never; }
+ }
+
+ public bool AlwaysHasBarrier {
+ get { return barrier == FlowReturns.Always; }
+ }
+
+ public bool MayHaveBarrier {
+ get { return barrier != FlowReturns.Never; }
+ }
+
+ public bool IsUnreachable {
+ get { return reachable == FlowReturns.Never; }
+ }
+
+ public void SetReturns ()
+ {
+ returns = FlowReturns.Always;
+ update ();
+ }
+
+ public void SetReturnsSometimes ()
+ {
+ returns = FlowReturns.Sometimes;
+ update ();
+ }
+
+ public void SetBreaks ()
+ {
+ breaks = FlowReturns.Always;
+ update ();
+ }
- // The current code block is unreachable. This happens if it's immediately
- // following a FlowReturns.Always block.
- Unreachable
+ public void ResetBreaks ()
+ {
+ breaks = FlowReturns.Never;
+ update ();
+ }
+
+ public void SetThrows ()
+ {
+ throws = FlowReturns.Always;
+ update ();
+ }
+
+ public void SetBarrier ()
+ {
+ barrier = FlowReturns.Always;
+ update ();
+ }
+
+ static string ShortName (FlowReturns returns)
+ {
+ switch (returns) {
+ case FlowReturns.Never:
+ return "N";
+ case FlowReturns.Sometimes:
+ return "S";
+ default:
+ return "A";
+ }
+ }
+
+ public override string ToString ()
+ {
+ return String.Format ("[{0}:{1}:{2}:{3}:{4}]",
+ ShortName (returns), ShortName (breaks),
+ ShortName (throws), ShortName (barrier),
+ ShortName (reachable));
+ }
}
public static FlowBranching CreateBranching (FlowBranching parent, BranchingType type, Block block, Location loc)
case BranchingType.Switch:
return new FlowBranchingBlock (parent, type, SiblingType.SwitchSection, block, loc);
+ case BranchingType.SwitchSection:
+ return new FlowBranchingBlock (parent, type, SiblingType.Block, block, loc);
+
+ case BranchingType.Block:
+ return new FlowBranchingBlock (parent, type, SiblingType.Block, block, loc);
+
default:
return new FlowBranchingBlock (parent, type, SiblingType.Conditional, block, loc);
}
// </summary>
public bool Infinite;
- // <summary>
- // If we may leave the current loop.
- // </summary>
- public bool MayLeaveLoop;
-
//
// Private
//
{
if (a == FlowReturns.Undefined)
return b;
- if (b == FlowReturns.Unreachable)
- return a;
switch (a) {
case FlowReturns.Never:
return FlowReturns.Sometimes;
case FlowReturns.Always:
- if ((b == FlowReturns.Always) || (b == FlowReturns.Exception))
+ if (b == FlowReturns.Always)
return FlowReturns.Always;
else
return FlowReturns.Sometimes;
- case FlowReturns.Exception:
- if (b == FlowReturns.Exception)
- return FlowReturns.Exception;
- else if (b == FlowReturns.Always)
- return FlowReturns.Always;
- else
- return FlowReturns.Sometimes;
+ default:
+ throw new ArgumentException ();
}
-
- return b;
}
// <summary>
// </summary>
public readonly UsageVector InheritsFrom;
+ // <summary>
+ // This is used to construct a list of UsageVector's.
+ // </summary>
+ public UsageVector Next;
+
//
// Private.
//
MyBitVector locals, parameters;
- FlowReturns RealReturns, RealBreaks, RealReachable;
- bool is_finally;
+ Reachability reachability;
static int next_id = 0;
int id;
this.InheritsFrom = parent;
this.CountParameters = num_params;
this.CountLocals = num_locals;
- this.RealReturns = FlowReturns.Never;
- this.RealBreaks = FlowReturns.Never;
- this.RealReachable = FlowReturns.Always;
if (parent != null) {
locals = new MyBitVector (parent.locals, CountLocals);
if (num_params > 0)
parameters = new MyBitVector (parent.parameters, num_params);
- RealReturns = parent.Returns;
- RealBreaks = parent.Breaks;
+
+ reachability = parent.Reachability.Clone ();
} else {
locals = new MyBitVector (null, CountLocals);
if (num_params > 0)
parameters = new MyBitVector (null, num_params);
+
+ reachability = Reachability.Never ();
}
id = ++next_id;
: this (type, parent, loc, parent.CountParameters, parent.CountLocals)
{ }
+ public UsageVector (MyBitVector parameters, MyBitVector locals,
+ Reachability reachability, Location loc)
+ {
+ this.Type = SiblingType.Block;
+ this.Location = loc;
+
+ this.reachability = reachability;
+ this.parameters = parameters;
+ this.locals = locals;
+
+ id = ++next_id;
+ }
+
// <summary>
// This does a deep copy of the usage vector.
// </summary>
retval.locals = locals.Clone ();
if (parameters != null)
retval.parameters = parameters.Clone ();
- retval.RealReturns = RealReturns;
- retval.RealBreaks = RealBreaks;
- retval.RealReachable = RealReachable;
+ retval.reachability = reachability.Clone ();
return retval;
}
public bool IsAssigned (VariableInfo var)
{
- if (!var.IsParameter && AlwaysBreaks)
+ if (!var.IsParameter && Reachability.AlwaysBreaks)
return true;
return var.IsAssigned (var.IsParameter ? parameters : locals);
public void SetAssigned (VariableInfo var)
{
- if (!var.IsParameter && AlwaysBreaks)
+ if (!var.IsParameter && Reachability.AlwaysBreaks)
return;
+ IsDirty = true;
var.SetAssigned (var.IsParameter ? parameters : locals);
}
public bool IsFieldAssigned (VariableInfo var, string name)
{
- if (!var.IsParameter && AlwaysBreaks)
+ if (!var.IsParameter && Reachability.AlwaysBreaks)
return true;
return var.IsFieldAssigned (var.IsParameter ? parameters : locals, name);
public void SetFieldAssigned (VariableInfo var, string name)
{
- if (!var.IsParameter && AlwaysBreaks)
+ if (!var.IsParameter && Reachability.AlwaysBreaks)
return;
+ IsDirty = true;
var.SetFieldAssigned (var.IsParameter ? parameters : locals, name);
}
- // <summary>
- // Specifies when the current block returns.
- // If this is FlowReturns.Unreachable, then control can never reach the
- // end of the method (so that we don't need to emit a return statement).
- // The same applies for FlowReturns.Exception, but in this case the return
- // value will never be used.
- // </summary>
- public FlowReturns Returns {
+ public Reachability Reachability {
get {
- return RealReturns;
+ return reachability;
}
}
- // <summary>
- // Specifies whether control may return to our containing block
- // before reaching the end of this block. This happens if there
- // is a break/continue/goto/return in it.
- // This can also be used to find out whether the statement immediately
- // following the current block may be reached or not.
- // </summary>
- public FlowReturns Breaks {
- get {
- return RealBreaks;
- }
- }
-
- public FlowReturns Reachable {
- get {
- return RealReachable;
- }
- }
-
- public bool AlwaysBreaks {
- get {
- return (Breaks == FlowReturns.Always) ||
- (Breaks == FlowReturns.Exception) ||
- (Breaks == FlowReturns.Unreachable);
+ public void Return ()
+ {
+ if (!reachability.IsUnreachable) {
+ IsDirty = true;
+ reachability.SetReturns ();
}
}
- public bool MayBreak {
- get {
- return Breaks != FlowReturns.Never;
+ public void Break ()
+ {
+ if (!reachability.IsUnreachable) {
+ IsDirty = true;
+ reachability.SetBreaks ();
}
}
- public bool AlwaysReturns {
- get {
- return (Returns == FlowReturns.Always) ||
- (Returns == FlowReturns.Exception);
+ public void Throw ()
+ {
+ if (!reachability.IsUnreachable) {
+ IsDirty = true;
+ reachability.SetThrows ();
}
}
- public bool MayReturn {
- get {
- return (Returns == FlowReturns.Sometimes) ||
- (Returns == FlowReturns.Always);
+ public void Goto ()
+ {
+ if (!reachability.IsUnreachable) {
+ IsDirty = true;
+ reachability.SetBarrier ();
}
}
- public void Break ()
+ // <summary>
+ // Merges a child branching.
+ // </summary>
+ public UsageVector MergeChild (FlowBranching branching)
{
- RealBreaks = FlowReturns.Always;
- }
+ UsageVector result = branching.Merge ();
- public void Return ()
- {
- RealReturns = FlowReturns.Always;
- }
+ Report.Debug (2, " MERGING CHILD", this, IsDirty,
+ result.ParameterVector, result.LocalVector,
+ result.Reachability, Type);
- public bool IsUnreachable {
- get {
- return (Reachable == FlowReturns.Exception) ||
- (Reachable == FlowReturns.Unreachable);
- }
- }
+ reachability = result.Reachability;
- public void Unreachable ()
- {
- // If we're already unreachable, don't modify the reason why.
- if (!IsUnreachable)
- RealReachable = FlowReturns.Unreachable;
- }
+ if (branching.Type == BranchingType.LoopBlock) {
+ bool may_leave_loop = reachability.MayBreak;
+ reachability.ResetBreaks ();
- public void NeverReachable ()
- {
- // If we're already unreachable, don't modify the reason why.
- if (!IsUnreachable)
- RealReachable = FlowReturns.Never;
+ if (branching.Infinite && !may_leave_loop) {
+ if (reachability.Returns == FlowReturns.Sometimes) {
+ // If we're an infinite loop and do not break,
+ // the code after the loop can never be reached.
+ // However, if we may return from the loop,
+ // then we do always return (or stay in the
+ // loop forever).
+ reachability.SetReturns ();
}
- public void Throw ()
- {
- // If we're already unreachable, don't modify the reason why.
- if (!IsUnreachable)
- RealReachable = FlowReturns.Exception;
+ reachability.SetBarrier ();
+ } else {
+ if (reachability.Returns == FlowReturns.Always) {
+ // We're either finite or we may leave the loop.
+ reachability.SetReturnsSometimes ();
}
-
- // <summary>
- // Merges a child branching.
- // </summary>
- public FlowReturns MergeChild (MyBitVector new_params, MyBitVector new_locals,
- FlowReturns new_returns, FlowReturns new_breaks,
- FlowReturns new_reachable)
- {
- Report.Debug (2, "MERGING CHILD", this, new_params, new_locals, new_returns, new_breaks,
- new_reachable);
-
- RealReturns = new_returns;
- RealBreaks = new_breaks;
- RealReachable = new_reachable;
+ }
+ } else if (branching.Type == BranchingType.Switch)
+ reachability.ResetBreaks ();
//
// We've now either reached the point after the branching or we will
// we need to look at (see above).
//
- Report.Debug (2, "MERGING CHILD #1", this, Returns, Breaks, Reachable, new_locals, new_params);
-
- if ((Reachable == FlowReturns.Always) || (Reachable == FlowReturns.Sometimes) ||
- (Reachable == FlowReturns.Never)) {
- if ((Returns == FlowReturns.Always) || (Breaks == FlowReturns.Always))
- RealReachable = FlowReturns.Never;
- if ((Type == SiblingType.SwitchSection) && (Reachable != FlowReturns.Never)) {
- Report.Error (163, Location, "Control cannot fall through from one " +
+ if ((Type == SiblingType.SwitchSection) && !reachability.IsUnreachable) {
+ Report.Error (163, Location,
+ "Control cannot fall through from one " +
"case label to another");
+ return result;
}
- if (new_locals != null)
- locals.Or (new_locals);
+ if (result.LocalVector != null)
+ locals.Or (result.LocalVector);
+
+ if (result.ParameterVector != null)
+ parameters.Or (result.ParameterVector);
+
+ Report.Debug (2, " MERGING CHILD DONE", this, result);
+
+ IsDirty = true;
- if (new_params != null)
- parameters.Or (new_params);
+ return result;
}
- Report.Debug (2, "MERGING CHILD DONE", this);
+ protected void MergeFinally (FlowBranching branching, UsageVector f_origins,
+ MyBitVector f_params)
+ {
+ for (UsageVector vector = f_origins; vector != null; vector = vector.Next) {
+ MyBitVector temp_params = f_params.Clone ();
+ temp_params.Or (vector.Parameters);
+ }
+ }
+
+ public void MergeFinally (FlowBranching branching, UsageVector f_vector,
+ UsageVector f_origins)
+ {
+ if (parameters != null) {
+ if (f_vector != null) {
+ MergeFinally (branching, f_origins, f_vector.Parameters);
+ MyBitVector.Or (ref parameters, f_vector.ParameterVector);
+ } else
+ MergeFinally (branching, f_origins, parameters);
+ }
- return Returns;
+ if (f_vector != null)
+ MyBitVector.Or (ref locals, f_vector.LocalVector);
}
// <summary>
// </summary>
public void MergeJumpOrigins (ICollection origin_vectors)
{
- Report.Debug (1, "MERGING JUMP ORIGIN", this);
+ Report.Debug (1, " MERGING JUMP ORIGINS", this);
- RealBreaks = FlowReturns.Never;
- RealReturns = FlowReturns.Never;
- if (Reachable != FlowReturns.Always)
- RealReachable = FlowReturns.Always;
+ reachability = Reachability.Never ();
if (origin_vectors == null)
return;
+ bool first = true;
+
foreach (UsageVector vector in origin_vectors) {
Report.Debug (1, " MERGING JUMP ORIGIN", vector);
+ if (first) {
+ locals.Or (vector.locals);
+ if (parameters != null)
+ parameters.Or (vector.parameters);
+ first = false;
+ } else {
locals.And (vector.locals);
if (parameters != null)
parameters.And (vector.parameters);
- RealBreaks = AndFlowReturns (RealBreaks, vector.Breaks);
- RealReturns = AndFlowReturns (RealReturns, vector.Returns);
- RealReachable = AndFlowReturns (RealReachable, vector.Reachable);
}
- Report.Debug (1, "MERGING JUMP ORIGIN DONE", this);
+ Reachability.And (ref reachability, vector.Reachability, true);
+ }
+
+ Report.Debug (1, " MERGING JUMP ORIGINS DONE", this);
}
// <summary>
// This is used at the beginning of a finally block if there were
// any return statements in the try block or one of the catch blocks.
// </summary>
- public void MergeFinallyOrigins (ICollection finally_vectors)
+ public void MergeFinallyOrigins (UsageVector f_origins)
{
- Report.Debug (1, "MERGING FINALLY ORIGIN", this);
+ Report.Debug (1, " MERGING FINALLY ORIGIN", this);
- RealBreaks = FlowReturns.Never;
+ reachability = Reachability.Never ();
- foreach (UsageVector vector in finally_vectors) {
+ for (UsageVector vector = f_origins; vector != null; vector = vector.Next) {
Report.Debug (1, " MERGING FINALLY ORIGIN", vector);
if (parameters != null)
parameters.And (vector.parameters);
- RealBreaks = AndFlowReturns (Breaks, vector.Breaks);
- }
- is_finally = true;
+ Reachability.And (ref reachability, vector.Reachability, true);
+ }
- Report.Debug (1, "MERGING FINALLY ORIGIN DONE", this);
+ Report.Debug (1, " MERGING FINALLY ORIGIN DONE", this);
}
public void CheckOutParameters (FlowBranching branching)
// </summary>
public void Or (UsageVector new_vector)
{
+ IsDirty = true;
locals.Or (new_vector.locals);
if (parameters != null)
parameters.Or (new_vector.parameters);
// </summary>
public void AndLocals (UsageVector new_vector)
{
+ IsDirty = true;
locals.And (new_vector.locals);
}
sb.Append ("Vector (");
sb.Append (id);
sb.Append (",");
- sb.Append (Returns);
+ sb.Append (IsDirty);
sb.Append (",");
- sb.Append (Breaks);
- sb.Append (",");
- sb.Append (Reachable);
+ sb.Append (reachability);
if (parameters != null) {
sb.Append (" - ");
sb.Append (parameters);
{
AddSibling (new UsageVector (type, Parent.CurrentUsageVector, Location));
- Report.Debug (1, "CREATED SIBLING", CurrentUsageVector);
+ Report.Debug (1, " CREATED SIBLING", CurrentUsageVector);
}
protected abstract void AddSibling (UsageVector uv);
- public abstract void Break ();
- public abstract void Return ();
- public abstract void Goto ();
- public abstract void Throw ();
public abstract void Label (ArrayList origin_vectors);
// <summary>
}
}
- protected class MergeResult
- {
- public MyBitVector Parameters;
- public MyBitVector Locals;
- public FlowReturns Returns;
- public FlowReturns Breaks;
- public FlowReturns Reachable;
- public bool MayLeaveLoop;
-
- public MergeResult (MyBitVector parameters, MyBitVector locals, FlowReturns returns, FlowReturns breaks,
- FlowReturns reachable, bool may_leave_loop)
+ protected UsageVector Merge (UsageVector sibling_list)
{
- this.Parameters = parameters;
- this.Locals = locals;
- this.Returns = returns;
- this.Breaks = breaks;
- this.Reachable = reachable;
- this.MayLeaveLoop = may_leave_loop;
- }
- }
+ if (sibling_list.Next == null)
+ return sibling_list;
- protected MergeResult Merge (ArrayList children)
- {
MyBitVector locals = null;
MyBitVector parameters = null;
- FlowReturns returns = FlowReturns.Undefined;
- FlowReturns breaks = FlowReturns.Undefined;
- FlowReturns reachable = FlowReturns.Undefined;
+ Reachability reachability = null;
- Report.Debug (2, "MERGING CHILDREN", this, Type, children.Count);
+ Report.Debug (2, " MERGING SIBLINGS", this, Name);
- int children_count = children.Count;
- for (int ix = 0; ix < children_count; ix++){
- UsageVector child = (UsageVector) children [ix];
+ for (UsageVector child = sibling_list; child != null; child = child.Next) {
+ bool do_break = (Type != BranchingType.Switch) &&
+ (Type != BranchingType.LoopBlock);
- Report.Debug (2, " MERGING CHILD", child, child.AlwaysBreaks, child.AlwaysReturns,
- child.IsUnreachable, child.Locals, child.Parameters,
- child.Returns, child.Breaks, child.Reachable);
-
- reachable = AndFlowReturns (reachable, child.Reachable);
-
- // Ignore unreachable children.
- if (child.IsUnreachable)
- continue;
+ Report.Debug (2, " MERGING SIBLING ", child,
+ child.Parameters, child.Locals,
+ reachability, child.Reachability, do_break);
- returns = AndFlowReturns (returns, child.Returns);
- breaks = AndFlowReturns (breaks, child.Breaks);
+ Reachability.And (ref reachability, child.Reachability, do_break);
// A local variable is initialized after a flow branching if it
// has been initialized in all its branches which do neither
// Here, `a' is initialized in line 3 and we must not look at
// line 5 since it always returns.
//
- if (!child.AlwaysReturns && !child.AlwaysBreaks)
+ bool do_break_2 = (child.Type != SiblingType.Block) &&
+ (child.Type != SiblingType.SwitchSection);
+ bool unreachable = (do_break_2 && child.Reachability.AlwaysBreaks) ||
+ child.Reachability.AlwaysThrows ||
+ child.Reachability.AlwaysReturns ||
+ child.Reachability.AlwaysHasBarrier;
+
+ Report.Debug (2, " MERGING SIBLING #1", reachability,
+ Type, child.Type, child.Reachability.IsUnreachable,
+ do_break_2, unreachable);
+
+ if (!unreachable)
MyBitVector.And (ref locals, child.LocalVector);
// An `out' parameter must be assigned in all branches which do
// not always throw an exception.
- if ((child.Type != SiblingType.Catch) &&
- (child.ParameterVector != null) && (child.Breaks != FlowReturns.Exception))
+ if ((child.ParameterVector != null) && !child.Reachability.AlwaysThrows)
MyBitVector.And (ref parameters, child.ParameterVector);
- }
-
- Report.Debug (2, "MERGING CHILDREN DONE", Type, parameters, locals, returns, breaks, reachable,
- Infinite, MayLeaveLoop, this);
- if (Infinite && !MayLeaveLoop) {
- Report.Debug (1, "INFINITE", returns, breaks, this);
-
- if (returns == FlowReturns.Never) {
- // We're actually infinite.
- breaks = FlowReturns.Unreachable;
- returns = FlowReturns.Unreachable;
- } else if ((returns == FlowReturns.Sometimes) || (returns == FlowReturns.Always)) {
- // If we're an infinite loop and do not break, the code after
- // the loop can never be reached. However, if we may return
- // from the loop, then we do always return (or stay in the loop
- // forever).
- returns = FlowReturns.Always;
- }
+ Report.Debug (2, " MERGING SIBLING #2", parameters, locals);
}
- if (returns == FlowReturns.Undefined)
- returns = FlowReturns.Never;
- if (breaks == FlowReturns.Undefined)
- breaks = FlowReturns.Never;
+ if (reachability == null)
+ reachability = Reachability.Never ();
+
+ Report.Debug (2, " MERGING SIBLINGS DONE", parameters, locals,
+ reachability, Infinite);
- return new MergeResult (parameters, locals, returns, breaks, reachable, MayLeaveLoop);
+ return new UsageVector (parameters, locals, reachability, Location);
}
- protected abstract MergeResult Merge ();
+ protected abstract UsageVector Merge ();
// <summary>
// Merge a child branching.
// </summary>
- public FlowReturns MergeChild (FlowBranching child)
+ public UsageVector MergeChild (FlowBranching child)
{
- MergeResult result = child.Merge ();
-
- CurrentUsageVector.MergeChild (
- result.Parameters, result.Locals, result.Returns, result.Breaks, result.Reachable);
-
- if ((child.Type != BranchingType.LoopBlock) && (child.Type != BranchingType.SwitchSection))
- MayLeaveLoop |= child.MayLeaveLoop;
-
- if (result.Reachable == FlowReturns.Exception)
- return FlowReturns.Exception;
- else
- return result.Returns;
+ return CurrentUsageVector.MergeChild (child);
}
// <summary>
// Does the toplevel merging.
// </summary>
- public FlowReturns MergeTopBlock ()
+ public Reachability MergeTopBlock ()
{
if ((Type != BranchingType.Block) || (Block == null))
throw new NotSupportedException ();
UsageVector vector = new UsageVector (
SiblingType.Conditional, null, Location, param_map.Length, local_map.Length);
- MergeResult result = Merge ();
- vector.MergeChild (result.Parameters, result.Locals, result.Returns, result.Breaks, result.Reachable);
+ UsageVector result = vector.MergeChild (this);
- if (vector.Reachable != FlowReturns.Exception)
+ Report.Debug (4, "MERGE TOP BLOCK", Location, vector, result.Reachability);
+
+ if (vector.Reachability.Throws != FlowReturns.Always)
CheckOutParameters (vector.Parameters, Location);
- else
- return FlowReturns.Exception;
- return result.Returns;
+ return result.Reachability;
}
public virtual bool InTryBlock ()
sb.Append (")");
return sb.ToString ();
}
+
+ public string Name {
+ get {
+ return String.Format ("{0} ({1}:{2}:{3})",
+ GetType (), id, Type, Location);
+ }
+ }
}
public class FlowBranchingBlock : FlowBranching
{
- UsageVector current_vector;
- ArrayList siblings = new ArrayList ();
+ UsageVector sibling_list = null;
public FlowBranchingBlock (FlowBranching parent, BranchingType type, SiblingType stype,
Block block, Location loc)
{ }
public override UsageVector CurrentUsageVector {
- get { return current_vector; }
+ get { return sibling_list; }
}
protected override void AddSibling (UsageVector sibling)
{
- siblings.Add (sibling);
- current_vector = sibling;
- }
-
- public override void Break ()
- {
- if (Type == BranchingType.SwitchSection)
- CurrentUsageVector.NeverReachable ();
- else {
- if (Type == BranchingType.LoopBlock)
- MayLeaveLoop = true;
- CurrentUsageVector.Break ();
- }
- }
-
- public override void Return ()
- {
- CurrentUsageVector.Return ();
- }
-
- public override void Goto ()
- {
- CurrentUsageVector.Unreachable ();
+ sibling.Next = sibling_list;
+ sibling_list = sibling;
}
- public override void Throw ()
+ public override void Label (ArrayList origin_vectors)
{
- CurrentUsageVector.Throw ();
+ if (!CurrentUsageVector.Reachability.IsUnreachable) {
+ if (origin_vectors == null)
+ origin_vectors = new ArrayList (1);
+ origin_vectors.Add (CurrentUsageVector.Clone ());
}
- public override void Label (ArrayList origin_vectors)
- {
CurrentUsageVector.MergeJumpOrigins (origin_vectors);
}
- protected override MergeResult Merge ()
+ protected override UsageVector Merge ()
{
- MergeResult result = Merge (siblings);
- if (Type == BranchingType.LoopBlock)
- result.MayLeaveLoop = false;
- return result;
+ return Merge (sibling_list);
}
}
public class FlowBranchingException : FlowBranching
{
- ArrayList finally_vectors;
-
- bool has_params;
UsageVector current_vector;
- UsageVector try_vector;
- ArrayList catch_vectors = new ArrayList ();
+ UsageVector catch_vectors;
UsageVector finally_vector;
+ UsageVector finally_origins;
public FlowBranchingException (FlowBranching parent, BranchingType type, Block block, Location loc)
: base (parent, type, SiblingType.Try, block, loc)
- {
- finally_vectors = new ArrayList ();
- has_params = current_vector.HasParameters;
- }
+ { }
protected override void AddSibling (UsageVector sibling)
{
if (sibling.Type == SiblingType.Try) {
- try_vector = sibling;
- catch_vectors.Add (sibling);
- } else if (sibling.Type == SiblingType.Catch)
- catch_vectors.Add (sibling);
- else if (sibling.Type == SiblingType.Finally) {
- // sibling.MergeFinallyOrigins (finally_vectors);
+ sibling.Next = catch_vectors;
+ catch_vectors = sibling;
+ } else if (sibling.Type == SiblingType.Catch) {
+ sibling.Next = catch_vectors;
+ catch_vectors = sibling;
+ } else if (sibling.Type == SiblingType.Finally) {
+ sibling.MergeFinallyOrigins (finally_origins);
finally_vector = sibling;
} else
throw new InvalidOperationException ();
public override void AddFinallyVector (UsageVector vector)
{
- finally_vectors.Add (vector.Clone ());
- }
-
- public override void Break ()
- {
- CurrentUsageVector.Break ();
- }
-
- public override void Return ()
- {
- CurrentUsageVector.Return ();
- }
-
- public override void Goto ()
- {
- CurrentUsageVector.Unreachable ();
- }
-
- public override void Throw ()
- {
- CurrentUsageVector.Throw ();
+ vector = vector.Clone ();
+ vector.Next = finally_origins;
+ finally_origins = vector;
}
public override void Label (ArrayList origin_vectors)
CurrentUsageVector.MergeJumpOrigins (origin_vectors);
}
- protected void MergeFinally (MyBitVector f_params, ref MergeResult result)
- {
- foreach (UsageVector vector in finally_vectors) {
- MyBitVector temp_params = f_params.Clone ();
- temp_params.Or (vector.Parameters);
-
- CheckOutParameters (temp_params, Location);
- }
- }
-
- protected override MergeResult Merge ()
+ protected override UsageVector Merge ()
{
- MergeResult result = Merge (catch_vectors);
-
- if (has_params) {
- if (finally_vector != null) {
- MergeFinally (finally_vector.Parameters, ref result);
- MyBitVector.Or (ref result.Parameters, finally_vector.ParameterVector);
- } else
- MergeFinally (result.Parameters, ref result);
- }
+ UsageVector vector = Merge (catch_vectors);
- if (finally_vector != null)
- MyBitVector.Or (ref result.Locals, finally_vector.LocalVector);
+ vector.MergeFinally (this, finally_vector, finally_origins);
- return result;
+ return vector;
}
}
public override string ToString ()
{
- StringBuilder sb = new StringBuilder ("MyBitVector (");
+ StringBuilder sb = new StringBuilder ("{");
BitArray vector = Vector;
- sb.Append (Count);
- sb.Append (",");
if (!IsDirty)
- sb.Append ("INHERITED - ");
+ sb.Append ("=");
for (int i = 0; i < vector.Count; i++) {
- if (i > 0)
- sb.Append (",");
- sb.Append (vector [i]);
+ sb.Append (vector [i] ? "1" : "0");
}
- sb.Append (")");
+ sb.Append ("}");
return sb.ToString ();
}
}
void GenerateFor (For s)
{
output ("for (");
- if (! (s.InitStatement is EmptyStatement))
+ if (! (s.InitStatement == EmptyStatement.Value))
GenerateStatement (s.InitStatement, true, true, true);
output ("; ");
output (GetExpression (s.Test, 0));
output ("; ");
- if (! (s.Increment is EmptyStatement))
+ if (! (s.Increment == EmptyStatement.Value))
GenerateStatement (s.Increment, true, true, true);
output (") ");
GenerateStatement (s.Statement, true, true, false);
output_newline ("break;");
else if (s is Continue)
output_newline ("continue;");
- else if (s is EmptyStatement)
+ else if (s == EmptyStatement.Value)
output_newline ("/* empty statement */;");
else if (s is Block)
GenerateBlock ((Block) s, doPlacement, embedded);
Type [] arg_types = im.ParameterTypes (this);
MethodBuilder mb;
- Parameter [] p;
- int i;
if (return_type == null)
return;
return true;
}
- protected override bool DoEmit (EmitContext ec)
+ protected override void DoEmit (EmitContext ec)
{
IteratorHandler.Current.MarkYield (ec, expr);
-
- return false;
}
}
if (!Yield.CheckContext (ec, loc))
return false;
- ec.CurrentBranching.Goto ();
+ ec.CurrentBranching.CurrentUsageVector.Goto ();
return true;
}
- protected override bool DoEmit (EmitContext ec)
+ protected override void DoEmit (EmitContext ec)
{
IteratorHandler.Current.EmitYieldBreak (ec.ig, true);
- return false;
}
}
static int source_bits;
static int source_mask;
static int source_count;
- static int module_base;
static int current_source;
public readonly static Location Null;
source_files = new Hashtable ();
source_list = new ArrayList ();
current_source = 0;
- module_base = 0;
Null.token = 0;
}
static public void Push (SourceFile file)
{
current_source = file.Index;
- module_base = current_source << source_bits;
}
// <remarks>
public const int Accessibility =
PUBLIC | PROTECTED | INTERNAL | PRIVATE;
+ public const int AllowedExplicitImplFlags =
+ UNSAFE | EXTERN;
static public string Name (int i)
{
static Hashtable namespaces_map = new Hashtable ();
Namespace parent;
- string name, fullname;
+ string fullname;
ArrayList entries;
Hashtable namespaces;
Hashtable defined_names;
/// </summary>
public Namespace (Namespace parent, string name)
{
- this.name = name;
this.parent = parent;
string pname = parent != null ? parent.Name : "";
using System.Text;
using System.Collections;
using System.Diagnostics;
+using System.Reflection;
namespace Mono.CSharp {
}
}
+ public static string FriendlyStackTrace (Exception e)
+ {
+ return FriendlyStackTrace (new StackTrace (e, true));
+ }
+
+ static string FriendlyStackTrace (StackTrace t)
+ {
+ StringBuilder sb = new StringBuilder ();
+
+ bool foundUserCode = false;
+
+ for (int i = 0; i < t.FrameCount; i++) {
+ StackFrame f = t.GetFrame (i);
+ MethodBase mb = f.GetMethod ();
+
+ if (!foundUserCode && mb.ReflectedType == typeof (Report))
+ continue;
+
+ foundUserCode = true;
+
+ sb.Append ("\tin ");
+
+ if (f.GetFileLineNumber () > 0)
+ sb.AppendFormat ("(at {0}:{1}) ", f.GetFileName (), f.GetFileLineNumber ());
+
+ sb.AppendFormat ("{0}.{1} (", mb.ReflectedType.Name, mb.Name);
+
+ bool first = true;
+ foreach (ParameterInfo pi in mb.GetParameters ()) {
+ if (!first)
+ sb.Append (", ");
+ first = false;
+
+ sb.Append (TypeManager.CSharpName (pi.ParameterType));
+ }
+ sb.Append (")\n");
+ }
+
+ return sb.ToString ();
+ }
+
static public void RealError (string msg)
{
Errors++;
Console.WriteLine (msg);
if (Stacktrace)
- Console.WriteLine (new StackTrace ().ToString ());
+ Console.WriteLine (FriendlyStackTrace (new StackTrace (true)));
+
if (Fatal)
throw new Exception (msg);
}
public static int WarningLevel = 2;
+ public static Target Target = Target.Exe;
+ public static string TargetExt = ".exe";
+
//
// If set, enable C# version 2 features
//
type_container_resolve_order = new ArrayList ();
}
+ public static bool NeedsEntryPoint {
+ get {
+ return RootContext.Target == Target.Exe || RootContext.Target == Target.WinExe;
+ }
+ }
+
static public Tree Tree {
get {
return tree;
{
TypeContainer root = Tree.Types;
- ArrayList ifaces = root.Interfaces;
-
if (root.Enums != null)
foreach (Enum en in root.Enums)
en.CloseType ();
foreach (TypeBuilder type_builder in helper_classes)
type_builder.CreateType ();
}
+
+ attribute_types = null;
+ interface_resolve_order = null;
+ type_container_resolve_order = null;
+ helper_classes = null;
+ tree = null;
+ TypeManager.CleanUp ();
}
/// <summary>
static Type NamespaceLookup (DeclSpace ds, string name, Location loc)
{
- Type t;
-
//
// Try in the current namespace and all its implicit parents
//
static public FieldBuilder MakeStaticData (byte [] data)
{
FieldBuilder fb;
- int size = data.Length;
if (impl_details_class == null){
impl_details_class = CodeGen.ModuleBuilder.DefineType (
/// <summary>
/// Return value indicates whether all code paths emitted return.
/// </summary>
- protected abstract bool DoEmit (EmitContext ec);
+ protected abstract void DoEmit (EmitContext ec);
/// <summary>
/// Return value indicates whether all code paths emitted return.
/// </summary>
- public virtual bool Emit (EmitContext ec)
+ public virtual void Emit (EmitContext ec)
{
ec.Mark (loc, true);
- return DoEmit (ec);
+ DoEmit (ec);
}
/// <remarks>
return true;
}
- protected override bool DoEmit (EmitContext ec)
+ protected override void DoEmit (EmitContext ec)
{
- return true;
}
}
public Statement TrueStatement;
public Statement FalseStatement;
+ bool is_true_ret;
+
public If (Expression expr, Statement trueStatement, Location l)
{
this.expr = expr;
return false;
}
- ec.StartFlowBranching (FlowBranching.BranchingType.Block, loc);
+ ec.StartFlowBranching (FlowBranching.BranchingType.Conditional, loc);
if (!TrueStatement.Resolve (ec)) {
ec.KillFlowBranching ();
return false;
}
+ is_true_ret = ec.CurrentBranching.CurrentUsageVector.Reachability.IsUnreachable;
+
ec.CurrentBranching.CreateSibling (FlowBranching.SiblingType.Conditional);
if ((FalseStatement != null) && !FalseStatement.Resolve (ec)) {
return true;
}
- protected override bool DoEmit (EmitContext ec)
+ protected override void DoEmit (EmitContext ec)
{
ILGenerator ig = ec.ig;
Label false_target = ig.DefineLabel ();
Label end;
- bool is_true_ret, is_false_ret;
//
// Dead code elimination
if (FalseStatement != null){
Warning_DeadCodeFound (FalseStatement.loc);
}
- return TrueStatement.Emit (ec);
+ TrueStatement.Emit (ec);
+ return;
} else {
Warning_DeadCodeFound (TrueStatement.loc);
- if (FalseStatement != null)
- return FalseStatement.Emit (ec);
+ if (FalseStatement != null) {
+ FalseStatement.Emit (ec);
+ return;
+ }
}
}
EmitBoolExpression (ec, expr, false_target, false);
- is_true_ret = TrueStatement.Emit (ec);
- is_false_ret = is_true_ret;
+ TrueStatement.Emit (ec);
if (FalseStatement != null){
bool branch_emitted = false;
}
ig.MarkLabel (false_target);
- is_false_ret = FalseStatement.Emit (ec);
+ FalseStatement.Emit (ec);
if (branch_emitted)
ig.MarkLabel (end);
} else {
ig.MarkLabel (false_target);
- is_false_ret = false;
}
-
- return is_true_ret && is_false_ret;
}
}
public class Do : Statement {
public Expression expr;
public readonly Statement EmbeddedStatement;
- bool infinite, may_return;
+ bool infinite;
public Do (Statement statement, Expression boolExpr, Location l)
{
}
ec.CurrentBranching.Infinite = infinite;
- FlowBranching.FlowReturns returns = ec.EndFlowBranching ();
- may_return = returns != FlowBranching.FlowReturns.Never;
+ ec.EndFlowBranching ();
return ok;
}
- protected override bool DoEmit (EmitContext ec)
+ protected override void DoEmit (EmitContext ec)
{
ILGenerator ig = ec.ig;
Label loop = ig.DefineLabel ();
ec.LoopBegin = old_begin;
ec.LoopEnd = old_end;
ec.InLoop = old_inloop;
-
- if (infinite)
- return may_return == false;
- else
- return false;
}
}
public class While : Statement {
public Expression expr;
public readonly Statement Statement;
- bool may_return, empty, infinite;
+ bool empty, infinite;
public While (Expression boolExpr, Statement statement, Location l)
{
ec.KillFlowBranching ();
else {
ec.CurrentBranching.Infinite = infinite;
- FlowBranching.FlowReturns returns = ec.EndFlowBranching ();
- may_return = returns != FlowBranching.FlowReturns.Never;
+ ec.EndFlowBranching ();
}
return ok;
}
- protected override bool DoEmit (EmitContext ec)
+ protected override void DoEmit (EmitContext ec)
{
if (empty)
- return false;
+ return;
ILGenerator ig = ec.ig;
Label old_begin = ec.LoopBegin;
Label old_end = ec.LoopEnd;
bool old_inloop = ec.InLoop;
int old_loop_begin_try_catch_level = ec.LoopBeginTryCatchLevel;
- bool ret;
ec.LoopBegin = ig.DefineLabel ();
ec.LoopEnd = ig.DefineLabel ();
// Inform whether we are infinite or not
//
if (expr is BoolConstant){
- BoolConstant bc = (BoolConstant) expr;
-
ig.MarkLabel (ec.LoopBegin);
Statement.Emit (ec);
ig.Emit (OpCodes.Br, ec.LoopBegin);
// Inform that we are infinite (ie, `we return'), only
// if we do not `break' inside the code.
//
- ret = may_return == false;
ig.MarkLabel (ec.LoopEnd);
} else {
Label while_loop = ig.DefineLabel ();
EmitBoolExpression (ec, expr, while_loop, true);
ig.MarkLabel (ec.LoopEnd);
-
- ret = false;
}
ec.LoopBegin = old_begin;
ec.LoopEnd = old_end;
ec.InLoop = old_inloop;
ec.LoopBeginTryCatchLevel = old_loop_begin_try_catch_level;
-
- return ret;
}
}
readonly Statement InitStatement;
readonly Statement Increment;
readonly Statement Statement;
- bool may_return, infinite, empty;
+ bool infinite, empty;
public For (Statement initStatement,
Expression test,
ec.KillFlowBranching ();
else {
ec.CurrentBranching.Infinite = infinite;
- FlowBranching.FlowReturns returns = ec.EndFlowBranching ();
- may_return = returns != FlowBranching.FlowReturns.Never;
+ ec.EndFlowBranching ();
}
return ok;
}
- protected override bool DoEmit (EmitContext ec)
+ protected override void DoEmit (EmitContext ec)
{
if (empty)
- return false;
+ return;
ILGenerator ig = ec.ig;
Label old_begin = ec.LoopBegin;
Label loop = ig.DefineLabel ();
Label test = ig.DefineLabel ();
- if (InitStatement != null)
- if (! (InitStatement is EmptyStatement))
+ if (InitStatement != null && InitStatement != EmptyStatement.Value)
InitStatement.Emit (ec);
ec.LoopBegin = ig.DefineLabel ();
Statement.Emit (ec);
ig.MarkLabel (ec.LoopBegin);
- if (!(Increment is EmptyStatement))
+ if (Increment != EmptyStatement.Value)
Increment.Emit (ec);
ig.MarkLabel (test);
ec.LoopEnd = old_end;
ec.InLoop = old_inloop;
ec.LoopBeginTryCatchLevel = old_loop_begin_try_catch_level;
-
- //
- // Inform whether we are infinite or not
- //
- if (Test != null){
- if (Test is BoolConstant){
- BoolConstant bc = (BoolConstant) Test;
-
- if (bc.Value)
- return may_return == false;
- }
- return false;
- } else
- return may_return == false;
}
}
return expr != null;
}
- protected override bool DoEmit (EmitContext ec)
+ protected override void DoEmit (EmitContext ec)
{
- ILGenerator ig = ec.ig;
-
expr.EmitStatement (ec);
-
- return false;
}
public override string ToString ()
else
vector.CheckOutParameters (ec.CurrentBranching);
- ec.CurrentBranching.Return ();
+ ec.CurrentBranching.CurrentUsageVector.Return ();
return true;
}
- protected override bool DoEmit (EmitContext ec)
+ protected override void DoEmit (EmitContext ec)
{
if (ec.InFinally){
Report.Error (157, loc, "Control can not leave the body of the finally block");
- return false;
+ return;
}
if (ec.ReturnType == null){
if (Expr != null){
Report.Error (127, loc, "Return with a value not allowed here");
- return true;
+ return;
}
} else {
if (Expr == null){
Report.Error (126, loc, "An object of type `" +
TypeManager.CSharpName (ec.ReturnType) + "' is " +
"expected for the return statement");
- return true;
+ return;
}
if (Expr.Type != ec.ReturnType)
ec, Expr, ec.ReturnType, loc);
if (Expr == null)
- return true;
+ return;
Expr.Emit (ec);
ec.ig.Emit (OpCodes.Ret);
ec.NeedExplicitReturn = false;
}
-
- return true;
}
}
if (!label.IsDefined)
label.AddUsageVector (ec.CurrentBranching.CurrentUsageVector);
- ec.CurrentBranching.Goto ();
+ ec.CurrentBranching.CurrentUsageVector.Goto ();
return true;
}
}
}
- protected override bool DoEmit (EmitContext ec)
+ protected override void DoEmit (EmitContext ec)
{
Label l = label.LabelTarget (ec);
ec.ig.Emit (OpCodes.Br, l);
-
- return false;
}
}
public class LabeledStatement : Statement {
public readonly Location Location;
- string label_name;
bool defined;
bool referenced;
Label label;
public LabeledStatement (string label_name, Location l)
{
- this.label_name = label_name;
this.Location = l;
}
return true;
}
- protected override bool DoEmit (EmitContext ec)
+ protected override void DoEmit (EmitContext ec)
{
LabelTarget (ec);
ec.ig.MarkLabel (label);
-
- return false;
}
}
public override bool Resolve (EmitContext ec)
{
- ec.CurrentBranching.Goto ();
+ ec.CurrentBranching.CurrentUsageVector.Goto ();
return true;
}
- protected override bool DoEmit (EmitContext ec)
+ protected override void DoEmit (EmitContext ec)
{
if (ec.Switch == null){
Report.Error (153, loc, "goto default is only valid in a switch statement");
- return false;
+ return;
}
if (!ec.Switch.GotDefault){
Report.Error (159, loc, "No default target on switch statement");
- return false;
+ return;
}
ec.ig.Emit (OpCodes.Br, ec.Switch.DefaultTarget);
- return false;
}
}
label = sl.ILLabelCode;
- ec.CurrentBranching.Goto ();
+ ec.CurrentBranching.CurrentUsageVector.Goto ();
return true;
}
- protected override bool DoEmit (EmitContext ec)
+ protected override void DoEmit (EmitContext ec)
{
ec.ig.Emit (OpCodes.Br, label);
- return true;
}
}
}
}
- ec.CurrentBranching.Throw ();
+ ec.CurrentBranching.CurrentUsageVector.Throw ();
return true;
}
- protected override bool DoEmit (EmitContext ec)
+ protected override void DoEmit (EmitContext ec)
{
if (expr == null){
if (ec.InCatch)
"A throw statement with no argument is only " +
"allowed in a catch clause");
}
- return false;
+ return;
}
expr.Emit (ec);
ec.ig.Emit (OpCodes.Throw);
-
- return true;
}
}
public override bool Resolve (EmitContext ec)
{
- ec.CurrentBranching.MayLeaveLoop = true;
- ec.CurrentBranching.Break ();
+ ec.CurrentBranching.CurrentUsageVector.Break ();
return true;
}
- protected override bool DoEmit (EmitContext ec)
+ protected override void DoEmit (EmitContext ec)
{
ILGenerator ig = ec.ig;
if (ec.InLoop == false && ec.Switch == null){
Report.Error (139, loc, "No enclosing loop or switch to continue to");
- return false;
+ return;
}
if (ec.InTry || ec.InCatch)
ig.Emit (OpCodes.Leave, ec.LoopEnd);
else
ig.Emit (OpCodes.Br, ec.LoopEnd);
-
- return false;
}
}
public override bool Resolve (EmitContext ec)
{
- ec.CurrentBranching.Goto ();
+ ec.CurrentBranching.CurrentUsageVector.Goto ();
return true;
}
- protected override bool DoEmit (EmitContext ec)
+ protected override void DoEmit (EmitContext ec)
{
Label begin = ec.LoopBegin;
if (!ec.InLoop){
Report.Error (139, loc, "No enclosing loop to continue to");
- return false;
+ return;
}
//
throw new Exception ("Should never happen");
else
ec.ig.Emit (OpCodes.Br, begin);
- return false;
}
}
enum Flags : byte {
Used = 1,
- Assigned = 2,
- ReadOnly = 4,
- Fixed = 8
+ ReadOnly = 2,
+ Fixed = 4
}
Flags flags;
return VariableInfo.TypeInfo.IsFullyInitialized (ec.CurrentBranching, VariableInfo, loc);
}
+ public bool IsAssigned (EmitContext ec)
+ {
+ if (VariableInfo == null)
+ throw new Exception ();
+
+ return !ec.DoFlowAnalysis || ec.CurrentBranching.IsAssigned (VariableInfo);
+ }
+
public bool Resolve (DeclSpace decl)
{
if (VariableType == null)
}
}
- public bool Assigned {
- get {
- return (flags & Flags.Assigned) != 0;
- }
- set {
- flags = value ? (flags | Flags.Assigned) : (flags & ~Flags.Assigned);
- }
- }
-
public bool ReadOnly {
get {
return (flags & Flags.ReadOnly) != 0;
variables = new Hashtable ();
this_variable = new LocalInfo (tc, this, l);
+ this_variable.Used = true;
variables.Add ("this", this_variable);
}
if (pars != null) {
- int idx = 0;
+ int idx;
Parameter p = pars.GetParameterByName (name, out idx);
if (p != null) {
Report.Error (136, l, "A local variable named `" + name + "' " +
public LocalInfo GetLocalInfo (string name)
{
- if (variables != null) {
- object temp;
- temp = variables [name];
-
- if (temp != null){
- return (LocalInfo) temp;
+ for (Block b = this; b != null; b = b.Parent) {
+ if (b.variables != null) {
+ LocalInfo ret = b.variables [name] as LocalInfo;
+ if (ret != null)
+ return ret;
}
}
-
- if (Parent != null)
- return Parent.GetLocalInfo (name);
-
return null;
}
public Expression GetConstantExpression (string name)
{
- if (constants != null) {
- object temp;
- temp = constants [name];
-
- if (temp != null)
- return (Expression) temp;
+ for (Block b = this; b != null; b = b.Parent) {
+ if (b.constants != null) {
+ Expression ret = b.constants [name] as Expression;
+ if (ret != null)
+ return ret;
+ }
}
-
- if (Parent != null)
- return Parent.GetConstantExpression (name);
-
return null;
}
Parameters parameters = null;
public Parameters Parameters {
get {
- if (Parent != null)
- return Parent.Parameters;
-
- return parameters;
+ Block b = this;
+ while (b.Parent != null)
+ b = b.Parent;
+ return b.parameters;
}
}
flags |= Flags.BlockUsed;
}
+ public bool HasRet {
+ get {
+ return (flags & Flags.HasRet) != 0;
+ }
+ }
+
VariableMap param_map, local_map;
public VariableMap ParameterMap {
/// </remarks>
public void EmitMeta (EmitContext ec, InternalParameters ip)
{
- DeclSpace ds = ec.DeclSpace;
ILGenerator ig = ec.ig;
//
}
}
- public void UsageWarning ()
+ void UsageWarning (FlowBranching.UsageVector vector)
{
string name;
name = (string) de.Key;
- if (vi.Assigned){
+ if (vector.IsAssigned (vi.VariableInfo)){
Report.Warning (
219, vi.Location, "The variable `" + name +
"' is assigned but its value is never used");
}
}
}
-
- if (children != null)
- foreach (Block b in children)
- b.UsageWarning ();
}
public override bool Resolve (EmitContext ec)
Block prev_block = ec.CurrentBlock;
bool ok = true;
+ int errors = Report.Errors;
+
ec.CurrentBlock = this;
ec.StartFlowBranching (this);
- Report.Debug (1, "RESOLVE BLOCK", StartLocation, ec.CurrentBranching);
+ Report.Debug (4, "RESOLVE BLOCK", StartLocation, ec.CurrentBranching);
- ArrayList new_statements = new ArrayList ();
bool unreachable = false, warning_shown = false;
int statement_count = statements.Count;
Statement s = (Statement) statements [ix];
if (unreachable && !(s is LabeledStatement)) {
- if (!warning_shown && !(s is EmptyStatement)) {
+ if (!warning_shown && s != EmptyStatement.Value) {
warning_shown = true;
Warning_DeadCodeFound (s.loc);
}
+ statements [ix] = EmptyStatement.Value;
continue;
}
if (s.Resolve (ec) == false) {
ok = false;
+ statements [ix] = EmptyStatement.Value;
continue;
}
if (s is LabeledStatement)
unreachable = false;
else
- unreachable = ec.CurrentBranching.CurrentUsageVector.IsUnreachable;
-
- new_statements.Add (s);
+ unreachable = ec.CurrentBranching.CurrentUsageVector.Reachability.IsUnreachable;
}
- statements = new_statements;
+ Report.Debug (4, "RESOLVE BLOCK DONE", StartLocation, ec.CurrentBranching);
+
- Report.Debug (1, "RESOLVE BLOCK DONE", StartLocation, ec.CurrentBranching);
+ FlowBranching.UsageVector vector = ec.DoEndFlowBranching ();
- FlowBranching.FlowReturns returns = ec.EndFlowBranching ();
ec.CurrentBlock = prev_block;
// If we're a non-static `struct' constructor which doesn't have an
// initializer, then we must initialize all of the struct's fields.
- if ((this_variable != null) && (returns != FlowBranching.FlowReturns.Exception) &&
+ if ((this_variable != null) &&
+ (vector.Reachability.Throws != FlowBranching.FlowReturns.Always) &&
!this_variable.IsThisAssigned (ec, loc))
ok = false;
"This label has not been referenced");
}
- Report.Debug (1, "RESOLVE BLOCK DONE #2", StartLocation, returns);
+ Report.Debug (4, "RESOLVE BLOCK DONE #2", StartLocation, vector);
- if ((returns == FlowBranching.FlowReturns.Always) ||
- (returns == FlowBranching.FlowReturns.Exception) ||
- (returns == FlowBranching.FlowReturns.Unreachable))
+ if ((vector.Reachability.Returns == FlowBranching.FlowReturns.Always) ||
+ (vector.Reachability.Throws == FlowBranching.FlowReturns.Always) ||
+ (vector.Reachability.Reachable == FlowBranching.FlowReturns.Never))
flags |= Flags.HasRet;
+ if (ok && (errors == Report.Errors)) {
+ if (RootContext.WarningLevel >= 3)
+ UsageWarning (vector);
+ }
+
return ok;
}
- protected override bool DoEmit (EmitContext ec)
+ protected override void DoEmit (EmitContext ec)
{
int statement_count = statements.Count;
for (int ix = 0; ix < statement_count; ix++){
Statement s = (Statement) statements [ix];
s.Emit (ec);
}
-
- return (flags & Flags.HasRet) != 0;
}
- public override bool Emit (EmitContext ec)
+ public override void Emit (EmitContext ec)
{
Block prev_block = ec.CurrentBlock;
}
ec.Mark (StartLocation, true);
- bool retval = DoEmit (ec);
+ DoEmit (ec);
ec.Mark (EndLocation, true);
if (emit_debug_info && is_lexical_block)
ec.ig.EndScope ();
ec.CurrentBlock = prev_block;
-
- return retval;
}
}
/// <param name="ec"></param>
/// <param name="val"></param>
/// <returns></returns>
- bool TableSwitchEmit (EmitContext ec, LocalBuilder val)
+ void TableSwitchEmit (EmitContext ec, LocalBuilder val)
{
int cElements = Elements.Count;
object [] rgKeys = new object [cElements];
// now emit the code for the sections
bool fFoundDefault = false;
- bool fAllReturn = true;
foreach (SwitchSection ss in Sections)
{
foreach (SwitchLabel sl in ss.Labels)
fFoundDefault = true;
}
}
- bool returns = ss.Block.Emit (ec);
- fAllReturn &= returns;
+ ss.Block.Emit (ec);
//ig.Emit (OpCodes.Br, lblEnd);
}
if (!fFoundDefault) {
ig.MarkLabel (lblDefault);
- fAllReturn = false;
}
ig.MarkLabel (lblEnd);
-
- return fAllReturn;
}
//
// This simple emit switch works, but does not take advantage of the
// TODO: remove non-string logic from here
// TODO: binary search strings?
//
- bool SimpleSwitchEmit (EmitContext ec, LocalBuilder val)
+ void SimpleSwitchEmit (EmitContext ec, LocalBuilder val)
{
ILGenerator ig = ec.ig;
Label end_of_switch = ig.DefineLabel ();
bool default_found = false;
bool first_test = true;
bool pending_goto_end = false;
- bool all_return = true;
bool null_found;
ig.Emit (OpCodes.Ldloc, val);
foreach (SwitchLabel sl in ss.Labels)
ig.MarkLabel (sl.ILLabelCode);
- bool returns = ss.Block.Emit (ec);
- if (returns)
- pending_goto_end = false;
- else {
- all_return = false;
- pending_goto_end = true;
- }
+ ss.Block.Emit (ec);
+ pending_goto_end = !ss.Block.HasRet;
first_test = false;
}
if (!default_found){
ig.MarkLabel (default_target);
- all_return = false;
}
ig.MarkLabel (next_test);
ig.MarkLabel (end_of_switch);
-
- return all_return;
}
public override bool Resolve (EmitContext ec)
return true;
}
- protected override bool DoEmit (EmitContext ec)
+ protected override void DoEmit (EmitContext ec)
{
// Store variable for comparission purposes
LocalBuilder value = ec.ig.DeclareLocal (SwitchType);
ec.Switch = this;
// Emit Code.
- bool all_return;
if (SwitchType == TypeManager.string_type)
- all_return = SimpleSwitchEmit (ec, value);
+ SimpleSwitchEmit (ec, value);
else
- all_return = TableSwitchEmit (ec, value);
+ TableSwitchEmit (ec, value);
// Restore context state.
ig.MarkLabel (ec.LoopEnd);
//
ec.LoopEnd = old_end;
ec.Switch = old_switch;
-
- return all_return;
}
}
return Statement.Resolve (ec) && expr != null;
}
- protected override bool DoEmit (EmitContext ec)
+ protected override void DoEmit (EmitContext ec)
{
Type type = expr.Type;
- bool val;
if (type.IsValueType){
Report.Error (185, loc, "lock statement requires the expression to be " +
" a reference type (type is: `" +
TypeManager.CSharpName (type) + "'");
- return false;
+ return;
}
ILGenerator ig = ec.ig;
ig.Emit (OpCodes.Call, TypeManager.void_monitor_enter_object);
// try
- Label end = ig.BeginExceptionBlock ();
+ ig.BeginExceptionBlock ();
bool old_in_try = ec.InTry;
ec.InTry = true;
Label finish = ig.DefineLabel ();
- val = Statement.Emit (ec);
+ Statement.Emit (ec);
ec.InTry = old_in_try;
// ig.Emit (OpCodes.Leave, finish);
ig.Emit (OpCodes.Ldloc, temp);
ig.Emit (OpCodes.Call, TypeManager.void_monitor_exit_object);
ig.EndExceptionBlock ();
-
- return val;
}
}
return ret;
}
- protected override bool DoEmit (EmitContext ec)
+ protected override void DoEmit (EmitContext ec)
{
bool previous_state = ec.CheckState;
bool previous_state_const = ec.ConstantCheckState;
- bool val;
ec.CheckState = false;
ec.ConstantCheckState = false;
- val = Block.Emit (ec);
+ Block.Emit (ec);
ec.CheckState = previous_state;
ec.ConstantCheckState = previous_state_const;
-
- return val;
}
}
return ret;
}
- protected override bool DoEmit (EmitContext ec)
+ protected override void DoEmit (EmitContext ec)
{
bool previous_state = ec.CheckState;
bool previous_state_const = ec.ConstantCheckState;
- bool val;
ec.CheckState = true;
ec.ConstantCheckState = true;
- val = Block.Emit (ec);
+ Block.Emit (ec);
ec.CheckState = previous_state;
ec.ConstantCheckState = previous_state_const;
-
- return val;
}
}
return val;
}
- protected override bool DoEmit (EmitContext ec)
+ protected override void DoEmit (EmitContext ec)
{
bool previous_state = ec.InUnsafe;
- bool val;
ec.InUnsafe = true;
- val = Block.Emit (ec);
+ Block.Emit (ec);
ec.InUnsafe = previous_state;
-
- return val;
}
}
Statement statement;
Type expr_type;
FixedData[] data;
+ bool has_ret;
struct FixedData {
public bool is_object;
}
}
- return statement.Resolve (ec);
+ ec.StartFlowBranching (FlowBranching.BranchingType.Conditional, loc);
+
+ if (!statement.Resolve (ec)) {
+ ec.KillFlowBranching ();
+ return false;
+ }
+
+ FlowBranching.Reachability reachability = ec.EndFlowBranching ();
+ has_ret = reachability.IsUnreachable;
+
+ return true;
}
- protected override bool DoEmit (EmitContext ec)
+ protected override void DoEmit (EmitContext ec)
{
ILGenerator ig = ec.ig;
- bool is_ret = false;
LocalBuilder [] clear_list = new LocalBuilder [data.Length];
for (int i = 0; i < data.Length; i++) {
}
}
- is_ret = statement.Emit (ec);
+ statement.Emit (ec);
+
+ if (has_ret)
+ return;
- if (is_ret)
- return is_ret;
//
// Clear the pinned variable
//
for (int i = 0; i < data.Length; i++) {
- LocalInfo vi = data [i].vi;
-
if (data [i].is_object || data [i].expr.Type.IsArray) {
ig.Emit (OpCodes.Ldc_I4_0);
ig.Emit (OpCodes.Conv_U);
ig.Emit (OpCodes.Stloc, clear_list [i]);
}
}
-
- return is_ret;
}
}
ec.InFinally = old_in_finally;
}
- FlowBranching.FlowReturns returns = ec.EndFlowBranching ();
+ FlowBranching.Reachability reachability = ec.EndFlowBranching ();
FlowBranching.UsageVector f_vector = ec.CurrentBranching.CurrentUsageVector;
- Report.Debug (1, "END OF TRY", ec.CurrentBranching, returns, vector, f_vector);
+ Report.Debug (1, "END OF TRY", ec.CurrentBranching, reachability, vector, f_vector);
- if (returns != FlowBranching.FlowReturns.Always) {
+ if (reachability.Returns != FlowBranching.FlowReturns.Always) {
// Unfortunately, System.Reflection.Emit automatically emits a leave
// to the end of the finally block. This is a problem if `returns'
// is true since we may jump to a point after the end of the method.
return ok;
}
- protected override bool DoEmit (EmitContext ec)
+ protected override void DoEmit (EmitContext ec)
{
ILGenerator ig = ec.ig;
- Label end;
Label finish = ig.DefineLabel ();;
- bool returns;
ec.TryCatchLevel++;
- end = ig.BeginExceptionBlock ();
+ ig.BeginExceptionBlock ();
bool old_in_try = ec.InTry;
ec.InTry = true;
- returns = Block.Emit (ec);
+ Block.Emit (ec);
ec.InTry = old_in_try;
//
bool old_in_catch = ec.InCatch;
ec.InCatch = true;
- DeclSpace ds = ec.DeclSpace;
foreach (Catch c in Specific){
LocalInfo vi;
} else
ig.Emit (OpCodes.Pop);
- if (!c.Block.Emit (ec))
- returns = false;
+ c.Block.Emit (ec);
}
if (General != null){
ig.BeginCatchBlock (TypeManager.object_type);
ig.Emit (OpCodes.Pop);
- if (!General.Block.Emit (ec))
- returns = false;
+ General.Block.Emit (ec);
}
ec.InCatch = old_in_catch;
ig.EndExceptionBlock ();
ec.TryCatchLevel--;
-
- return returns;
}
}
return false;
}
- FlowBranching.FlowReturns returns = ec.EndFlowBranching ();
+ FlowBranching.Reachability reachability = ec.EndFlowBranching ();
- if (returns != FlowBranching.FlowReturns.Always) {
+ if (reachability.Returns != FlowBranching.FlowReturns.Always) {
// Unfortunately, System.Reflection.Emit automatically emits a leave
// to the end of the finally block. This is a problem if `returns'
// is true since we may jump to a point after the end of the method.
return true;
}
- protected override bool DoEmit (EmitContext ec)
+ protected override void DoEmit (EmitContext ec)
{
if (expression_or_block is DictionaryEntry)
- return EmitLocalVariableDecls (ec);
+ EmitLocalVariableDecls (ec);
else if (expression_or_block is Expression)
- return EmitExpression (ec);
-
- return false;
+ EmitExpression (ec);
}
}
if (!statement.Resolve (ec))
return false;
- FlowBranching.FlowReturns returns = ec.EndFlowBranching ();
+ ec.EndFlowBranching ();
return true;
}
// Protect the code in a try/finalize block, so that
// if the beast implement IDisposable, we get rid of it
//
- Label l;
bool old_in_try = ec.InTry;
if (hm.is_disposable) {
- l = ig.BeginExceptionBlock ();
+ ig.BeginExceptionBlock ();
ec.InTry = true;
}
return false;
}
- protected override bool DoEmit (EmitContext ec)
+ protected override void DoEmit (EmitContext ec)
{
- bool ret_val;
-
ILGenerator ig = ec.ig;
Label old_begin = ec.LoopBegin, old_end = ec.LoopEnd;
ec.LoopBeginTryCatchLevel = ec.TryCatchLevel;
if (hm != null)
- ret_val = EmitCollectionForeach (ec);
+ EmitCollectionForeach (ec);
else
- ret_val = EmitArrayForeach (ec);
+ EmitArrayForeach (ec);
ec.LoopBegin = old_begin;
ec.LoopEnd = old_end;
ec.InLoop = old_inloop;
ec.LoopBeginTryCatchLevel = old_loop_begin_try_catch_level;
-
- return ret_val;
}
}
}
}
class PtrHashtable : Hashtable {
- class PtrComparer : IComparer {
+ sealed class PtrComparer : IComparer {
+ private PtrComparer () {}
+
+ public static PtrComparer Instance = new PtrComparer ();
+
public int Compare (object x, object y)
{
if (x == y)
public PtrHashtable ()
{
- comparer = new PtrComparer ();
+ comparer = PtrComparer.Instance;
+ }
+ }
+
+ /*
+ * Hashtable whose keys are character arrays with the same length
+ */
+ class CharArrayHashtable : Hashtable {
+ sealed class ArrComparer : IComparer {
+ private int len;
+
+ public ArrComparer (int len) {
+ this.len = len;
+ }
+
+ public int Compare (object x, object y)
+ {
+ char[] a = (char[])x;
+ char[] b = (char[])y;
+
+ for (int i = 0; i < len; ++i)
+ if (a [i] != b [i])
+ return 1;
+ return 0;
+ }
+ }
+
+ private int len;
+
+ protected override int GetHash (Object key)
+ {
+ char[] arr = (char[])key;
+ int h = 0;
+
+ for (int i = 0; i < len; ++i)
+ h = (h << 5) - h + arr [i];
+
+ return h;
+ }
+
+ public CharArrayHashtable (int len)
+ {
+ this.len = len;
+ comparer = new ArrComparer (len);
}
}
}
public class DoubleHash {
- Hashtable l = new Hashtable ();
+ const int DEFAULT_INITIAL_BUCKETS = 100;
- public DoubleHash ()
+ public DoubleHash () : this (DEFAULT_INITIAL_BUCKETS) {}
+
+ public DoubleHash (int size)
{
+ count = size;
+ buckets = new Entry [size];
+ }
+
+ int count;
+ Entry [] buckets;
+ int size = 0;
+
+ class Entry {
+ public object key1;
+ public object key2;
+ public int hash;
+ public object value;
+ public Entry next;
+
+ public Entry (object key1, object key2, int hash, object value, Entry next)
+ {
+ this.key1 = key1;
+ this.key2 = key2;
+ this.hash = hash;
+ this.next = next;
+ this.value = value;
+ }
}
public bool Lookup (object a, object b, out object res)
{
- object r = l [a];
- if (r == null){
- res = null;
- return false;
+ int h = (a.GetHashCode () ^ b.GetHashCode ()) & 0x7FFFFFFF;
+
+ for (Entry e = buckets [h % count]; e != null; e = e.next) {
+ if (e.hash == h && e.key1.Equals (a) && e.key2.Equals (b)) {
+ res = e.value;
+ return true;
}
- Hashtable ht = (Hashtable) r;
- if (ht.Contains (b)){
- res = ht [b];
- return true;
}
res = null;
return false;
public void Insert (object a, object b, object value)
{
- Hashtable ht;
- object r = l [a];
- if (r == null){
- ht = new Hashtable ();
- l [a] = ht;
- ht [b] = value;
- return;
+ // Is it an existing one?
+
+ int h = (a.GetHashCode () ^ b.GetHashCode ()) & 0x7FFFFFFF;
+
+ for (Entry e = buckets [h % count]; e != null; e = e.next) {
+ if (e.hash == h && e.key1.Equals (a) && e.key2.Equals (b))
+ e.value = value;
+ }
+
+ int bucket = h % count;
+ buckets [bucket] = new Entry (a, b, h, value, buckets [bucket]);
+
+ // Grow whenever we double in size
+ if (size++ == count) {
+ count <<= 1;
+ count ++;
+
+ Entry [] newBuckets = new Entry [count];
+ foreach (Entry root in buckets) {
+ Entry e = root;
+ while (e != null) {
+ int newLoc = e.hash % count;
+ Entry n = e.next;
+ e.next = newBuckets [newLoc];
+ newBuckets [newLoc] = e;
+ e = n;
+ }
+ }
+
+ buckets = newBuckets;
}
- ht = (Hashtable) r;
- ht [b] = value;
}
}
}
static Assembly [] assemblies;
// <remarks>
- // Keeps a list of module builders. We used this to do lookups
- // on the modulebuilder using GetType -- needed for arrays
+ // Keeps a list of modules. We used this to do lookups
+ // on the module using GetType -- needed for arrays
// </remarks>
- static ModuleBuilder [] modules;
+ static Module [] modules;
// <remarks>
// This is the type_cache from the assemblies to avoid
public Type [] args;
}
+ public static void CleanUp ()
+ {
+ // Lets get everything clean so that we can collect before generating code
+ assemblies = null;
+ modules = null;
+ types = null;
+ typecontainers = null;
+ user_types = null;
+ builder_to_declspace = null;
+ builder_to_ifaces = null;
+ method_arguments = null;
+ indexer_arguments = null;
+ method_internal_params = null;
+ builder_to_attr = null;
+ builder_to_method = null;
+
+ fields = null;
+ references = null;
+ negative_hits = null;
+ attr_to_allowmult = null;
+ builder_to_constant = null;
+ fieldbuilders_to_fields = null;
+ events = null;
+ priv_fields_events = null;
+ properties = null;
+
+ TypeHandle.CleanUp ();
+ }
+
/// <summary>
/// A filter for Findmembers that uses the Signature object to
/// extract objects
return;
}
- Location l;
tc = builder_to_declspace [t] as TypeContainer;
if (tc != null){
Report.Warning (
/// <summary>
/// Registers a module builder to lookup types from
/// </summary>
- public static void AddModule (ModuleBuilder mb)
+ public static void AddModule (Module mb)
{
int top = modules != null ? modules.Length : 0;
- ModuleBuilder [] n = new ModuleBuilder [top + 1];
+ Module [] n = new Module [top + 1];
if (modules != null)
modules.CopyTo (n, 0);
} while (t != null);
}
- foreach (ModuleBuilder mb in modules) {
+ foreach (Module mb in modules) {
t = mb.GetType (name);
if (t != null)
return t;
return t;
}
+ static readonly char [] dot_array = { '.' };
+
/// <summary>
/// Returns the Type associated with @name, takes care of the fact that
/// reflection expects nested types to be separated from the main type
if (negative_hits.Contains (name))
return null;
- string [] elements = name.Split ('.');
+ // Sadly, split takes a param array, so this ends up allocating *EVERY TIME*
+ string [] elements = name.Split (dot_array);
int count = elements.Length;
for (int n = 1; n <= count; n++){
if (t == null){
t = LookupTypeReflection (top_level_type);
if (t == null){
- negative_hits [top_level_type] = true;
+ negative_hits [top_level_type] = null;
continue;
}
}
//Console.WriteLine ("Looking up: " + newt + " " + name);
t = LookupTypeReflection (newt);
if (t == null)
- negative_hits [name] = true;
+ negative_hits [name] = null;
else
types [name] = t;
return t;
}
- negative_hits [name] = true;
+ negative_hits [name] = null;
return null;
}
//
if (assembly_get_namespaces != null){
int count = assemblies.Length;
- int total;
for (int i = 0; i < count; i++){
Assembly a = assemblies [i];
/// Returns the MethodInfo for a method named `name' defined
/// in type `t' which takes arguments of types `args'
/// </summary>
- static MethodInfo GetMethod (Type t, string name, Type [] args, bool report_errors)
+ static MethodInfo GetMethod (Type t, string name, Type [] args, bool is_private, bool report_errors)
{
MemberList list;
Signature sig;
+ BindingFlags flags = instance_and_static | BindingFlags.Public;
sig.name = name;
sig.args = args;
- list = FindMembers (t, MemberTypes.Method, instance_and_static | BindingFlags.Public,
- signature_filter, sig);
+ if (is_private)
+ flags |= BindingFlags.NonPublic;
+
+ list = FindMembers (t, MemberTypes.Method, flags, signature_filter, sig);
if (list.Count == 0) {
if (report_errors)
Report.Error (-19, "Can not find the core function `" + name + "'");
return mi;
}
+ static MethodInfo GetMethod (Type t, string name, Type [] args, bool report_errors)
+ {
+ return GetMethod (t, name, args, false, report_errors);
+ }
+
static MethodInfo GetMethod (Type t, string name, Type [] args)
{
return GetMethod (t, name, args, true);
MethodInfo set_corlib_type_builders = GetMethod (
system_assemblybuilder_type, "SetCorlibTypeBuilders",
- system_4_type_arg, false);
+ system_4_type_arg, true, false);
if (set_corlib_type_builders != null) {
object[] args = new object [4];
// Compatibility for an older version of the class libs.
set_corlib_type_builders = GetMethod (
system_assemblybuilder_type, "SetCorlibTypeBuilders",
- system_3_type_arg, true);
+ system_3_type_arg, true, true);
if (set_corlib_type_builders == null) {
Report.Error (-26, "Corlib compilation is not supported in Microsoft.NET due to bugs in it");
const BindingFlags instance_and_static = BindingFlags.Static | BindingFlags.Instance;
- static Hashtable type_hash = new Hashtable ();
-
/// <remarks>
/// This is the "old", non-cache based FindMembers() function. We cannot use
/// the cache here because there is no member name argument.
private static MemberList MemberLookup_FindMembers (Type t, MemberTypes mt, BindingFlags bf,
string name, out bool used_cache)
{
- bool not_loaded_corlib = (t.Assembly == CodeGen.AssemblyBuilder);
-
//
// We have to take care of arrays specially, because GetType on
// a TypeBuilder array will return a Type, not a TypeBuilder,
#region MemberLookup implementation
- //
- // Name of the member
- //
- static string closure_name;
-
//
// Whether we allow private members in the result (since FindMembers
// uses NonPublic for both protected and private), we need to distinguish.
// Who is invoking us and which type is being queried currently.
//
static Type closure_invocation_type;
- static Type closure_queried_type;
static Type closure_qualifier_type;
//
bool skip_iface_check = true, used_cache = false;
bool always_ok_flag = false;
- closure_name = name;
closure_invocation_type = invocation_type;
closure_invocation_assembly = invocation_type != null ? invocation_type.Assembly : null;
closure_qualifier_type = qualifier_type;
bf = original_bf;
closure_private_ok = (original_bf & BindingFlags.NonPublic) != 0;
- closure_queried_type = current_type;
Timer.StopTimer (TimerType.MemberLookup);
type_hash.Add (t, handle);
return handle;
}
+
+ public static void CleanUp ()
+ {
+ type_hash = null;
+ }
/// <summary>
/// Returns the TypeHandle for TypeManager.object_type.