diff --git a/src/DNA/.gitignore b/src/DNA/.gitignore deleted file mode 100644 index f6400b5d..00000000 --- a/src/DNA/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -Debug -native/Debug -native/x64 diff --git a/src/DNA/corlib/System.Collections.Generic/Comparer.cs b/src/DNA/corlib/System.Collections.Generic/Comparer.cs index c46cf680..6d403872 100644 --- a/src/DNA/corlib/System.Collections.Generic/Comparer.cs +++ b/src/DNA/corlib/System.Collections.Generic/Comparer.cs @@ -24,7 +24,7 @@ using System.Collections; namespace System.Collections.Generic { - public abstract class Comparer : IComparer,IComparer { + public abstract class Comparer : IComparer, IComparer { private sealed class DefaultComparer : Comparer { @@ -45,7 +45,6 @@ public override int Compare(T x, T y) { } throw new ArgumentException("Does not implement IComparable"); } - } private sealed class DefaultComparerValueType : Comparer { @@ -61,7 +60,21 @@ public override int Compare(T x, T y) { } throw new ArgumentException("Does not implement IComparable"); } + } + + private sealed class ComparisonComparer : Comparer { + private readonly Comparison comparison; + public ComparisonComparer(Comparison comparison) { + this.comparison = comparison; + } + public override int Compare(T x, T y) { + return comparison(x, y); + } + } + public static Comparer Create(Comparison comparison) { + if (comparison == null) throw new ArgumentNullException("comparison"); + return new ComparisonComparer(comparison); } static Comparer() { diff --git a/src/DNA/corlib/System.Collections.Generic/IReadOnlyCollection.cs b/src/DNA/corlib/System.Collections.Generic/IReadOnlyCollection.cs new file mode 100644 index 00000000..83cda666 --- /dev/null +++ b/src/DNA/corlib/System.Collections.Generic/IReadOnlyCollection.cs @@ -0,0 +1,33 @@ +// +// IReadOnlyCollection.cs +// +// Authors: +// Marek Safar +// +// Copyright (C) 2012 Xamarin, Inc (http://www.xamarin.com) +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +namespace System.Collections.Generic { + public interface IReadOnlyCollection : IEnumerable { + int Count { get; } + } +} diff --git a/src/DNA/corlib/System.Collections.Generic/List.cs b/src/DNA/corlib/System.Collections.Generic/List.cs index 359e25df..7e8148d7 100644 --- a/src/DNA/corlib/System.Collections.Generic/List.cs +++ b/src/DNA/corlib/System.Collections.Generic/List.cs @@ -27,7 +27,7 @@ namespace System_.Collections.Generic { #else namespace System.Collections.Generic { #endif - public class List : IList, ICollection, IEnumerable, IList, ICollection, IEnumerable { + public class List : IList, ICollection, IEnumerable, IList, ICollection, IEnumerable, IReadOnlyCollection { public struct Enumerator : IEnumerator, IDisposable { @@ -95,6 +95,10 @@ public List(IEnumerable collection) { } } + public void TrimExcess() { + // does nothing + } + private void EnsureSpace(int space) { if (this.size + space > this.items.Length) { Array.Resize(ref this.items, Math.Max(this.items.Length << 1, 4)); @@ -128,6 +132,19 @@ public void Add(T item) { this.items[this.size++] = item; } + public void AddRange(IEnumerable collection) { + ICollection iCol = collection as ICollection; + if (iCol != null) { + this.EnsureSpace(iCol.Count); + iCol.CopyTo(this.items, this.size); + this.size += iCol.Count; + } else { + foreach (T t in collection) { + Add (t); + } + } + } + public int Count { get { return this.size; @@ -158,6 +175,16 @@ public T this[int index] { } } + public List FindAll(Predicate match) { + List results = new List(); + for (int i = 0; i < this.size; i++) { + if (match(this.items[i])) { + results.Add(this.items[i]); + } + } + return results; + } + public Enumerator GetEnumerator() { return new Enumerator(this); } @@ -184,6 +211,22 @@ public void InsertRange(int index, IEnumerable collection) { } } + // public void Sort() { + // Array.Sort(this.items, 0, this.size); + // } + + public void Sort(Comparison comparison) { + Array.Sort(this.items, 0, this.size, comparison); + } + + public void Sort(IComparer comparer) { + Array.Sort(this.items, 0, this.size, comparer); + } + + public void Sort(int index, int count, IComparer comparer) { + Array.Sort(this.items, index, count, comparer); + } + public T[] ToArray() { T[] array = new T[this.size]; Array.Copy(this.items, array, this.size); diff --git a/src/DNA/corlib/System.Collections.Generic/Queue.cs b/src/DNA/corlib/System.Collections.Generic/Queue.cs new file mode 100644 index 00000000..a753fa8c --- /dev/null +++ b/src/DNA/corlib/System.Collections.Generic/Queue.cs @@ -0,0 +1,245 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace System.Collections.Generic { + public class Queue : IEnumerable, ICollection, IEnumerable { + T[] _array; + int _head; + int _tail; + int _size; + int _version; + + private const int INITIAL_SIZE = 16; + + public Queue() { + } + + public Queue(int count) { + if (count < 0) + throw new ArgumentOutOfRangeException("count"); + + _array = new T[count]; + } + + public Queue(IEnumerable collection) { + if (collection == null) + throw new ArgumentNullException("collection"); + + foreach (T t in collection) + Enqueue(t); + } + + public void Clear() { + if (_array != null) + Array.Clear(_array, 0, _array.Length); + + _head = _tail = _size = 0; + _version++; + } + + public bool Contains(T item) { + if (item == null) { + foreach (T t in this) + if (t == null) + return true; + } else { + foreach (T t in this) + if (item.Equals(t)) + return true; + } + + return false; + } + + public void CopyTo(T[] array, int idx) { + if (array == null) + throw new ArgumentNullException(); + + if ((uint)idx > (uint)array.Length) + throw new ArgumentOutOfRangeException(); + + if (array.Length - idx < _size) + throw new ArgumentOutOfRangeException(); + + if (_size == 0) + return; + + int contents_length = _array.Length; + int length_from_head = contents_length - _head; + + Array.Copy(_array, _head, array, idx, Math.Min(_size, length_from_head)); + if (_size > length_from_head) + Array.Copy(_array, 0, array, + idx + length_from_head, + _size - length_from_head); + + } + + void ICollection.CopyTo(Array array, int idx) { + if (array == null) + throw new ArgumentNullException(); + + if ((uint)idx < (uint)array.Length) + throw new ArgumentOutOfRangeException(); + + if (array.Length - idx < _size) + throw new ArgumentOutOfRangeException(); + + if (_size == 0) + return; + + try { + int contents_length = _array.Length; + int length_from_head = contents_length - _head; + + Array.Copy(_array, _head, array, idx, Math.Min(_size, length_from_head)); + if (_size > length_from_head) + Array.Copy(_array, 0, array, + idx + length_from_head, + _size - length_from_head); + } catch (ArrayTypeMismatchException) { + throw new ArgumentException(); + } + } + + public T Dequeue() { + T ret = Peek(); + + // clear stuff out to make the GC happy + _array[_head] = default(T); + + if (++_head == _array.Length) + _head = 0; + _size--; + _version++; + + return ret; + } + + public T Peek() { + if (_size == 0) + throw new InvalidOperationException(); + + return _array[_head]; + } + + public void Enqueue(T item) { + if (_array == null || _size == _array.Length) + SetCapacity(Math.Max(_size * 2, 4)); + + _array[_tail] = item; + + if (++_tail == _array.Length) + _tail = 0; + + _size++; + _version++; + } + + public T[] ToArray() { + T[] t = new T[_size]; + CopyTo(t, 0); + return t; + } + + public void TrimExcess() { + if (_array != null && (_size < _array.Length * 0.9)) + SetCapacity(_size); + } + + void SetCapacity(int new_size) { + if (_array != null && new_size == _array.Length) + return; + + if (new_size < _size) + throw new InvalidOperationException("shouldnt happen"); + + T[] new_data = new T[new_size]; + if (_size > 0) + CopyTo(new_data, 0); + + _array = new_data; + _tail = _size; + _head = 0; + _version++; + } + + public int Count { + get { return _size; } + } + + bool ICollection.IsSynchronized { + get { return false; } + } + + object ICollection.SyncRoot { + get { return this; } + } + + public Enumerator GetEnumerator() { + return new Enumerator(this); + } + + IEnumerator IEnumerable.GetEnumerator() { + return GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() { + return GetEnumerator(); + } + + public struct Enumerator : IEnumerator, IEnumerator, IDisposable { + const int NOT_STARTED = -2; + + // this MUST be -1, because we depend on it in move next. + // we just decr the _size, so, 0 - 1 == FINISHED + const int FINISHED = -1; + + Queue q; + int idx; + int ver; + + internal Enumerator(Queue q) { + this.q = q; + idx = NOT_STARTED; + ver = q._version; + } + + public void Dispose() { + idx = NOT_STARTED; + } + + public bool MoveNext() { + if (ver != q._version) + throw new InvalidOperationException(); + + if (idx == NOT_STARTED) + idx = q._size; + + return idx != FINISHED && --idx != FINISHED; + } + + public T Current { + get { + if (idx < 0) + throw new InvalidOperationException(); + + return q._array[(q._size - 1 - idx + q._head) % q._array.Length]; + } + } + + void IEnumerator.Reset() { + if (ver != q._version) + throw new InvalidOperationException(); + + idx = NOT_STARTED; + } + + object IEnumerator.Current { + get { return Current; } + } + + } + } +} diff --git a/src/DNA/corlib/System.Collections.Generic/Stack.cs b/src/DNA/corlib/System.Collections.Generic/Stack.cs new file mode 100644 index 00000000..ec9f4915 --- /dev/null +++ b/src/DNA/corlib/System.Collections.Generic/Stack.cs @@ -0,0 +1,239 @@ +// +// System.Collections.Generic.Stack +// +// Authors: +// Martin Baulig (martin@ximian.com) +// Ben Maurer (bmaurer@ximian.com) +// +// (C) 2003, 2004 Novell, Inc. +// + +// +// Copyright (C) 2004 Novell, Inc (http://www.novell.com) +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +//using System.Runtime.InteropServices; + +namespace System.Collections.Generic +{ + public class Stack : IEnumerable , ICollection, IEnumerable + { + T [] _array; + int _size; + int _version; + + private const int INITIAL_SIZE = 16; + + public Stack () + { + } + + public Stack (int count) + { + if (count < 0) + throw new ArgumentOutOfRangeException ("count"); + + _array = new T [count]; + } + + public Stack (IEnumerable collection) + { + if (collection == null) + throw new ArgumentNullException ("collection"); + + ICollection col = collection as ICollection ; + + if (col != null) { + _size = col.Count; + _array = new T [_size]; + col.CopyTo (_array, 0); + } else { + foreach (T t in collection) + Push (t); + } + } + + public void Clear () + { + if (_array != null) + Array.Clear (_array, 0, _array.Length); + + _size = 0; + _version ++; + } + + public bool Contains (T t) + { + return _array != null && Array.IndexOf (_array, t, 0, _size) != -1; + } + + public void CopyTo (T [] dest, int idx) + { + // this gets copied in the order that it is poped + if (_array != null) { + Array.Copy (_array, 0, dest, idx, _size); + Array.Reverse (dest, idx, _size); + } + } + + public T Peek () + { + if (_size == 0) + throw new InvalidOperationException (); + + return _array [_size - 1]; + } + + public T Pop () + { + if (_size == 0) + throw new InvalidOperationException (); + + _version ++; + T popped = _array [--_size]; + // clear stuff out to make the GC happy + _array [_size] = default(T); + return popped; + } + + public void Push (T t) + { + if (_size == 0 || _size == _array.Length) + Array.Resize (ref _array, _size == 0 ? INITIAL_SIZE : 2 * _size); + + _version ++; + + _array [_size++] = t; + } + + public T [] ToArray () + { + T [] copy = new T [_size]; + CopyTo (copy, 0); + return copy; + } + + public void TrimExcess () + { + if (_array != null && (_size < _array.Length * 0.9)) + Array.Resize (ref _array, _size); + _version ++; + } + + public int Count { + get { return _size; } + } + + bool ICollection.IsSynchronized { + get { return false; } + } + + object ICollection.SyncRoot { + get { return this; } + } + + void ICollection.CopyTo (Array dest, int idx) + { + try { + if (_array != null) { + _array.CopyTo (dest, idx); + Array.Reverse (dest, idx, _size); + } + } catch (ArrayTypeMismatchException) { + throw new ArgumentException (); + } + } + + public Enumerator GetEnumerator () + { + return new Enumerator (this); + } + + IEnumerator IEnumerable.GetEnumerator () + { + return GetEnumerator (); + } + + IEnumerator IEnumerable.GetEnumerator () + { + return GetEnumerator (); + } + + public struct Enumerator : IEnumerator , IEnumerator, IDisposable { + const int NOT_STARTED = -2; + + // this MUST be -1, because we depend on it in move next. + // we just decr the _size, so, 0 - 1 == FINISHED + const int FINISHED = -1; + + Stack parent; + int idx; + int _version; + + internal Enumerator (Stack t) + { + parent = t; + idx = NOT_STARTED; + _version = t._version; + } + + public void Dispose () + { + idx = NOT_STARTED; + } + + public bool MoveNext () + { + if (_version != parent._version) + throw new InvalidOperationException (); + + if (idx == -2) + idx = parent._size; + + return idx != FINISHED && -- idx != FINISHED; + } + + public T Current { + get { + if (idx < 0) + throw new InvalidOperationException (); + + return parent._array [idx]; + } + } + + void IEnumerator.Reset () + { + if (_version != parent._version) + throw new InvalidOperationException (); + + idx = NOT_STARTED; + } + + object IEnumerator.Current { + get { return Current; } + } + + } + } +} diff --git a/src/DNA/corlib/System.Collections/IStructuralComparable.cs b/src/DNA/corlib/System.Collections/IStructuralComparable.cs new file mode 100644 index 00000000..42a38dc6 --- /dev/null +++ b/src/DNA/corlib/System.Collections/IStructuralComparable.cs @@ -0,0 +1,10 @@ +// source: https://bitbucket.org/danipen/mono/src/master/mcs/class/corlib/System.Collections/IStructuralComparable.cs +// Copyright (C) 2009 Novell + +using System; + +namespace System.Collections { + public interface IStructuralComparable { + int CompareTo(object other, IComparer comparer); + } +} \ No newline at end of file diff --git a/src/DNA/corlib/System.Collections/IStructuralEquatable.cs b/src/DNA/corlib/System.Collections/IStructuralEquatable.cs new file mode 100644 index 00000000..50f1561e --- /dev/null +++ b/src/DNA/corlib/System.Collections/IStructuralEquatable.cs @@ -0,0 +1,13 @@ +// source: https://bitbucket.org/danipen/mono/src/master/mcs/class/corlib/System.Collections/IStructuralEquatable.cs +// Copyright (C) 2009 Novell + +using System; + +namespace System.Collections +{ + public interface IStructuralEquatable { + bool Equals (object other, IEqualityComparer comparer); + + int GetHashCode (IEqualityComparer comparer); + } +} \ No newline at end of file diff --git a/src/DNA/corlib/System.Diagnostics/Debug.cs b/src/DNA/corlib/System.Diagnostics/Debug.cs new file mode 100644 index 00000000..3606a113 --- /dev/null +++ b/src/DNA/corlib/System.Diagnostics/Debug.cs @@ -0,0 +1,22 @@ + +namespace System.Diagnostics { + public static class Debug { + + public static void Assert(bool condition) { +#if DEBUG + if (!condition) { + throw new Exception(string.Empty); + } +#endif + } + + public static void Assert(bool condition, string message) { +#if DEBUG + if (!condition) { + throw new Exception(message); + } +#endif + } + + } +} diff --git a/src/DNA/corlib/System.Diagnostics/Debugger.cs b/src/DNA/corlib/System.Diagnostics/Debugger.cs index 39acce7a..8543dad0 100644 --- a/src/DNA/corlib/System.Diagnostics/Debugger.cs +++ b/src/DNA/corlib/System.Diagnostics/Debugger.cs @@ -27,10 +27,12 @@ public sealed class Debugger { [MethodImpl(MethodImplOptions.InternalCall)] extern public static void Break(); - [MethodImpl(MethodImplOptions.InternalCall)] - extern private static void Internal_BreakPoint(int method, int offset); + public static bool Launch() { Break(); return false; } - } + [MethodImpl(MethodImplOptions.InternalCall)] + extern private static void Internal_BreakPoint(int method, int offset); + + } } #endif diff --git a/src/DNA/corlib/System.Diagnostics/DebuggerAttributes.cs b/src/DNA/corlib/System.Diagnostics/DebuggerAttributes.cs new file mode 100644 index 00000000..7998111c --- /dev/null +++ b/src/DNA/corlib/System.Diagnostics/DebuggerAttributes.cs @@ -0,0 +1,364 @@ +// From https://github.com/Microsoft/referencesource +// See copyright and license details in that repo + +namespace System.Diagnostics { + using System; + using System.Runtime.InteropServices; + // using System.Diagnostics.Contracts; + + [Serializable] + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Constructor, Inherited = false)] + // [ComVisible(true)] + public sealed class DebuggerStepThroughAttribute : Attribute + { + public DebuggerStepThroughAttribute () {} + } + + [Serializable] + [AttributeUsage(AttributeTargets.Method | AttributeTargets.Constructor, Inherited = false)] + // [ComVisible(true)] + public sealed class DebuggerStepperBoundaryAttribute : Attribute + { + public DebuggerStepperBoundaryAttribute () {} + } + + [Serializable] + [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Constructor, Inherited = false)] + // [ComVisible(true)] + public sealed class DebuggerHiddenAttribute : Attribute + { + public DebuggerHiddenAttribute () {} + } + + [Serializable] + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Constructor |AttributeTargets.Struct, Inherited = false)] + // [ComVisible(true)] + public sealed class DebuggerNonUserCodeAttribute : Attribute + { + public DebuggerNonUserCodeAttribute () {} + } + + // Attribute class used by the compiler to mark modules. + // If present, then debugging information for everything in the + // assembly was generated by the compiler, and will be preserved + // by the Runtime so that the debugger can provide full functionality + // in the case of JIT attach. If not present, then the compiler may + // or may not have included debugging information, and the Runtime + // won't preserve the debugging info, which will make debugging after + // a JIT attach difficult. + [AttributeUsage(AttributeTargets.Assembly|AttributeTargets.Module, AllowMultiple = false)] + // [ComVisible(true)] + public sealed class DebuggableAttribute : Attribute + { + [Flags] + // [ComVisible(true)] + public enum DebuggingModes + { + None = 0x0, + Default = 0x1, + DisableOptimizations = 0x100, + IgnoreSymbolStoreSequencePoints = 0x2, + EnableEditAndContinue = 0x4 + } + + private DebuggingModes m_debuggingModes; + + public DebuggableAttribute(bool isJITTrackingEnabled, + bool isJITOptimizerDisabled) + { + m_debuggingModes = 0; + + if (isJITTrackingEnabled) + { + m_debuggingModes |= DebuggingModes.Default; + } + + if (isJITOptimizerDisabled) + { + m_debuggingModes |= DebuggingModes.DisableOptimizations; + } + } + + public DebuggableAttribute(DebuggingModes modes) + { + m_debuggingModes = modes; + } + + public bool IsJITTrackingEnabled + { + get { return ((m_debuggingModes & DebuggingModes.Default) != 0); } + } + + public bool IsJITOptimizerDisabled + { + get { return ((m_debuggingModes & DebuggingModes.DisableOptimizations) != 0); } + } + + public DebuggingModes DebuggingFlags + { + get { return m_debuggingModes; } + } + } + + // DebuggerBrowsableState states are defined as follows: + // Never never show this element + // Expanded expansion of the class is done, so that all visible internal members are shown + // Collapsed expansion of the class is not performed. Internal visible members are hidden + // RootHidden The target element itself should not be shown, but should instead be + // automatically expanded to have its members displayed. + // Default value is collapsed + + // Please also change the code which validates DebuggerBrowsableState variable (in this file) + // if you change this enum. + // [ComVisible(true)] + public enum DebuggerBrowsableState + { + Never = 0, + //Expanded is not supported in this release + //Expanded = 1, + Collapsed = 2, + RootHidden = 3 + } + + + // the one currently supported with the csee.dat + // (mcee.dat, autoexp.dat) file. + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false)] + // [ComVisible(true)] + public sealed class DebuggerBrowsableAttribute: Attribute + { + private DebuggerBrowsableState state; + public DebuggerBrowsableAttribute(DebuggerBrowsableState state) + { + if( state < DebuggerBrowsableState.Never || state > DebuggerBrowsableState.RootHidden) + throw new ArgumentOutOfRangeException("state"); + // Contract.EndContractBlock(); + + this.state = state; + } + public DebuggerBrowsableState State + { + get { return state; } + } + } + + + [AttributeUsage(AttributeTargets.Struct | AttributeTargets.Class | AttributeTargets.Assembly, AllowMultiple = true)] + // [ComVisible(true)] + public sealed class DebuggerTypeProxyAttribute: Attribute + { + private string typeName; + private string targetName; + private Type target; + + public DebuggerTypeProxyAttribute(Type type) + { + if (type == null) { + throw new ArgumentNullException("type"); + } + // Contract.EndContractBlock(); + + this.typeName = type.AssemblyQualifiedName; + } + + public DebuggerTypeProxyAttribute(string typeName) + { + this.typeName = typeName; + } + public string ProxyTypeName + { + get { return typeName; } + } + + public Type Target + { + set { + if( value == null) { + throw new ArgumentNullException("value"); + } + // Contract.EndContractBlock(); + + targetName = value.AssemblyQualifiedName; + target = value; + } + + get { return target; } + } + + public string TargetTypeName + { + get { return targetName; } + set { targetName = value; } + } + } + + // This attribute is used to control what is displayed for the given class or field + // in the data windows in the debugger. The single argument to this attribute is + // the string that will be displayed in the value column for instances of the type. + // This string can include text between { and } which can be either a field, + // property or method (as will be documented in mscorlib). In the C# case, + // a general expression will be allowed which only has implicit access to the this pointer + // for the current instance of the target type. The expression will be limited, + // however: there is no access to aliases, locals, or pointers. + // In addition, attributes on properties referenced in the expression are not processed. + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Delegate | AttributeTargets.Enum | AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Assembly, AllowMultiple = true)] + // [ComVisible(true)] + public sealed class DebuggerDisplayAttribute : Attribute + { + private string name; + private string value; + private string type; + private string targetName; + private Type target; + + public DebuggerDisplayAttribute(string value) + { + if( value == null ) { + this.value = ""; + } + else { + this.value = value; + } + name = ""; + type = ""; + } + + public string Value + { + get { return this.value; } + } + + public string Name + { + get { return name; } + set { name = value; } + } + + public string Type + { + get { return type; } + set { type = value; } + } + + public Type Target + { + set { + if( value == null) { + throw new ArgumentNullException("value"); + } + // Contract.EndContractBlock(); + + targetName = value.AssemblyQualifiedName; + target = value; + } + get { return target; } + } + + public string TargetTypeName + { + get { return targetName; } + set { targetName = value; } + } + } + + + // /// + // /// Signifies that the attributed type has a visualizer which is pointed + // /// to by the parameter type name strings. + // /// + // [AttributeUsage(AttributeTargets.Struct | AttributeTargets.Class | AttributeTargets.Assembly, AllowMultiple = true)] + // // [ComVisible(true)] + // public sealed class DebuggerVisualizerAttribute: Attribute + // { + // private string visualizerObjectSourceName; + // private string visualizerName; + // private string description; + // private string targetName; + // private Type target; + + // public DebuggerVisualizerAttribute(string visualizerTypeName) + // { + // this.visualizerName = visualizerTypeName; + // } + // public DebuggerVisualizerAttribute(string visualizerTypeName, string visualizerObjectSourceTypeName) + // { + // this.visualizerName = visualizerTypeName; + // this.visualizerObjectSourceName = visualizerObjectSourceTypeName; + // } + // public DebuggerVisualizerAttribute(string visualizerTypeName, Type visualizerObjectSource) + // { + // if (visualizerObjectSource == null) { + // throw new ArgumentNullException("visualizerObjectSource"); + // } + // // Contract.EndContractBlock(); + // this.visualizerName = visualizerTypeName; + // this.visualizerObjectSourceName = visualizerObjectSource.AssemblyQualifiedName; + // } + // public DebuggerVisualizerAttribute(Type visualizer) + // { + // if (visualizer == null) { + // throw new ArgumentNullException("visualizer"); + // } + // // Contract.EndContractBlock(); + // this.visualizerName = visualizer.AssemblyQualifiedName; + // } + // public DebuggerVisualizerAttribute(Type visualizer, Type visualizerObjectSource) + // { + // if (visualizer == null) { + // throw new ArgumentNullException("visualizer"); + // } + // if (visualizerObjectSource == null) { + // throw new ArgumentNullException("visualizerObjectSource"); + // } + // // Contract.EndContractBlock(); + // this.visualizerName = visualizer.AssemblyQualifiedName; + // this.visualizerObjectSourceName = visualizerObjectSource.AssemblyQualifiedName; + // } + // public DebuggerVisualizerAttribute(Type visualizer, string visualizerObjectSourceTypeName) + // { + // if (visualizer == null) { + // throw new ArgumentNullException("visualizer"); + // } + // // Contract.EndContractBlock(); + // this.visualizerName = visualizer.AssemblyQualifiedName; + // this.visualizerObjectSourceName = visualizerObjectSourceTypeName; + // } + + // public string VisualizerObjectSourceTypeName + // { + // get { return visualizerObjectSourceName; } + // } + // public string VisualizerTypeName + // { + // get { return visualizerName; } + // } + // public string Description + // { + // get { return description; } + // set { description = value; } + // } + + // public Type Target + // { + // set { + // if( value == null) { + // throw new ArgumentNullException("value"); + // } + // // Contract.EndContractBlock(); + + // targetName = value.AssemblyQualifiedName; + // target = value; + // } + + // get { return target; } + // } + + // public string TargetTypeName + // { + // set { targetName = value; } + // get { return targetName; } + // } + // } +} + + diff --git a/src/DNA/corlib/System.Globalization/CharUnicodeInfo.cs b/src/DNA/corlib/System.Globalization/CharUnicodeInfo.cs new file mode 100644 index 00000000..90819d46 --- /dev/null +++ b/src/DNA/corlib/System.Globalization/CharUnicodeInfo.cs @@ -0,0 +1,9 @@ +namespace System.Globalization { + + public static class CharUnicodeInfo { + + public static UnicodeCategory GetUnicodeCategory(char c) { + return System.Char.GetUnicodeCategory(c); + } + } +} diff --git a/src/DNA/corlib/System.Globalization/CultureInfo.cs b/src/DNA/corlib/System.Globalization/CultureInfo.cs index c9d46d77..193d78f9 100644 --- a/src/DNA/corlib/System.Globalization/CultureInfo.cs +++ b/src/DNA/corlib/System.Globalization/CultureInfo.cs @@ -5,7 +5,7 @@ using System.IO; namespace System.Globalization { - public class CultureInfo { + public class CultureInfo : IFormatProvider { #region Static methods @@ -267,6 +267,14 @@ public override string ToString() { return this.name; } + #region IFormatProvider Members + + object IFormatProvider.GetFormat(Type formatType) { + // throw new Exception("The method or operation is not implemented."); + return null; + } + + #endregion } } diff --git a/src/DNA/corlib/System.Globalization/DateTimeFormatInfo.cs b/src/DNA/corlib/System.Globalization/DateTimeFormatInfo.cs index a9bcfab3..123b97d9 100644 --- a/src/DNA/corlib/System.Globalization/DateTimeFormatInfo.cs +++ b/src/DNA/corlib/System.Globalization/DateTimeFormatInfo.cs @@ -3,7 +3,7 @@ using System.IO; using System.Threading; namespace System.Globalization { - public sealed class DateTimeFormatInfo { + public sealed class DateTimeFormatInfo : IFormatProvider { public static DateTimeFormatInfo InvariantInfo { get { @@ -164,6 +164,15 @@ public string GetEraName(int era) { public string GetMonthName(int m) { return this.monthNames[m]; } + + #region IFormatProvider Members + + object IFormatProvider.GetFormat(Type formatType) { + // throw new Exception("The method or operation is not implemented."); + return null; + } + + #endregion } } diff --git a/src/DNA/corlib/System.Globalization/NumberFormatInfo.cs b/src/DNA/corlib/System.Globalization/NumberFormatInfo.cs index becf5703..9126b644 100644 --- a/src/DNA/corlib/System.Globalization/NumberFormatInfo.cs +++ b/src/DNA/corlib/System.Globalization/NumberFormatInfo.cs @@ -172,8 +172,9 @@ public NumberFormatInfo() { #region IFormatProvider Members - public object GetFormat(Type formatType) { - throw new Exception("The method or operation is not implemented."); + object IFormatProvider.GetFormat(Type formatType) { + // throw new Exception("The method or operation is not implemented."); + return null; } #endregion diff --git a/src/DNA/corlib/System.IO/File.cs b/src/DNA/corlib/System.IO/File.cs index 415b2dcf..3ba3431f 100644 --- a/src/DNA/corlib/System.IO/File.cs +++ b/src/DNA/corlib/System.IO/File.cs @@ -19,6 +19,34 @@ public static bool Exists(string path) { return FileInternal.ExistsFile(path, out error); } + public static byte [] ReadAllBytes (string path) + { + using (FileStream s = OpenRead (path)) { + long size = s.Length; + // limited to 2GB according to http://msdn.microsoft.com/en-us/library/system.io.file.readallbytes.aspx + if (size > Int32.MaxValue) + throw new IOException ("Reading more than 2GB with this call is not supported"); + + int pos = 0; + int count = (int) size; + byte [] result = new byte [size]; + while (count > 0) { + int n = s.Read (result, pos, count); + if (n == 0) + throw new IOException ("Unexpected end of stream"); + pos += n; + count -= n; + } + return result; + } + } + + public static string ReadAllText (string path, System.Text.Encoding encoding) + { + using (StreamReader sr = new StreamReader (path, encoding)) { + return sr.ReadToEnd (); + } + } } } diff --git a/src/DNA/corlib/System.IO/FileInternal.cs b/src/DNA/corlib/System.IO/FileInternal.cs index 826649e9..ea254ee8 100644 --- a/src/DNA/corlib/System.IO/FileInternal.cs +++ b/src/DNA/corlib/System.IO/FileInternal.cs @@ -13,6 +13,9 @@ internal static class FileInternal { [MethodImpl(MethodImplOptions.InternalCall)] extern public static void Close(IntPtr handle, out int error); + [MethodImpl(MethodImplOptions.InternalCall)] + extern public static long Length(string fileName, out int error); + [MethodImpl(MethodImplOptions.InternalCall)] extern public static string GetCurrentDirectory(out int error); diff --git a/src/DNA/corlib/System.IO/FileStream.cs b/src/DNA/corlib/System.IO/FileStream.cs index 8f50acdd..15b7a560 100644 --- a/src/DNA/corlib/System.IO/FileStream.cs +++ b/src/DNA/corlib/System.IO/FileStream.cs @@ -5,6 +5,7 @@ public class FileStream : Stream { private IntPtr handle = IntPtr.Zero; private string filename; + private long filesize; private bool canRead, canWrite, canSeek; public FileStream(string filename, FileMode mode, FileAccess access, FileShare share) { @@ -13,8 +14,14 @@ public FileStream(string filename, FileMode mode, FileAccess access, FileShare s if (error != 0) { throw FileInternal.GetException(error, filename); } + long filesize = FileInternal.Length(filename, out error); + if (error != 0) { + throw FileInternal.GetException(error, filename); + } + this.handle = handle; this.filename = filename; + this.filesize = filesize; this.canRead = true; this.canWrite = true; @@ -89,7 +96,9 @@ public override bool CanWrite { } public override long Length { - get { throw new Exception("The method or operation is not implemented."); } + get { + return this.filesize; + } } public override long Position { diff --git a/src/DNA/corlib/System.IO/TextWriter.cs b/src/DNA/corlib/System.IO/TextWriter.cs new file mode 100644 index 00000000..a59d15d4 --- /dev/null +++ b/src/DNA/corlib/System.IO/TextWriter.cs @@ -0,0 +1,268 @@ +// source: https://bitbucket.org/danipen/mono/src/master/mcs/class/corlib/System.IO/TextWriter.cs +// Copyright 2011 Xamarin Inc. + +using System.Text; +using System.Runtime.InteropServices; + +namespace System.IO { + + [Serializable] + // [ComVisible (true)] + public abstract class TextWriter : MarshalByRefObject, IDisposable { + + // + // Null version of the TextWriter, for the `Null' instance variable + // + sealed class NullTextWriter : TextWriter { + public override Encoding Encoding { + get { + return Encoding.Default; + } + } + + public override void Write(string s) { + } + public override void Write(char value) { + } + public override void Write(char[] value, int index, int count) { + } + } + + protected TextWriter() { + CoreNewLine = System.Environment.NewLine.ToCharArray(); + } + + protected TextWriter(IFormatProvider formatProvider) { + CoreNewLine = System.Environment.NewLine.ToCharArray(); + internalFormatProvider = formatProvider; + } + + protected char[] CoreNewLine; + + internal IFormatProvider internalFormatProvider; + + public static readonly TextWriter Null = new NullTextWriter(); + + public abstract Encoding Encoding { get; } + + public virtual IFormatProvider FormatProvider { + get { + return internalFormatProvider; + } + } + + public virtual string NewLine { + get { + return new string(CoreNewLine); + } + set { + if (value == null) + value = Environment.NewLine; + + CoreNewLine = value.ToCharArray(); + } + } + + public virtual void Close() { + Dispose(true); + } + + protected virtual void Dispose(bool disposing) { + if (disposing) { + // If we are explicitly disposed, we can avoid finalization. + GC.SuppressFinalize(this); + } + } + + public void Dispose() { + Dispose(true); + + // If we are explicitly disposed, we can avoid finalization. + GC.SuppressFinalize(this); + } + + public virtual void Flush() { + // do nothing + } + + public static TextWriter Synchronized(TextWriter writer) { + throw new NotImplementedException(); + } + + public virtual void Write(bool value) { + Write(value.ToString()); + } + + public virtual void Write(char value) { + // Do nothing + } + + public virtual void Write(char[] buffer) { + if (buffer == null) + return; + Write(buffer, 0, buffer.Length); + } + + public virtual void Write(decimal value) { + Write(value.ToString()); // .ToString(internalFormatProvider)); + } + + public virtual void Write(double value) { + Write(value.ToString(internalFormatProvider)); + } + + public virtual void Write(int value) { + Write(value.ToString(internalFormatProvider)); + } + + public virtual void Write(long value) { + Write(value.ToString(internalFormatProvider)); + } + + public virtual void Write(object value) { + if (value != null) + Write(value.ToString()); + } + + public virtual void Write(float value) { + Write(value.ToString(internalFormatProvider)); + } + + public virtual void Write(string value) { + if (value != null) + Write(value.ToCharArray()); + } + + // [CLSCompliant (false)] + public virtual void Write(uint value) { + Write(value.ToString(internalFormatProvider)); + } + + // [CLSCompliant (false)] + public virtual void Write(ulong value) { + Write(value.ToString(internalFormatProvider)); + } + + public virtual void Write(string format, object arg0) { + Write(String.Format(format, arg0)); + } + + public virtual void Write(string format, params object[] arg) { + Write(String.Format(format, arg)); + } + + public virtual void Write(char[] buffer, int index, int count) { + if (buffer == null) + throw new ArgumentNullException("buffer"); + if (index < 0 || index > buffer.Length) + throw new ArgumentOutOfRangeException("index"); + // re-ordered to avoid possible integer overflow + if (count < 0 || (index > buffer.Length - count)) + throw new ArgumentOutOfRangeException("count"); + + for (; count > 0; --count, ++index) { + Write(buffer[index]); + } + } + + public virtual void Write(string format, object arg0, object arg1) { + Write(String.Format(format, arg0, arg1)); + } + + public virtual void Write(string format, object arg0, object arg1, object arg2) { + Write(String.Format(format, arg0, arg1, arg2)); + } + + public virtual void WriteLine() { + Write(CoreNewLine); + } + + public virtual void WriteLine(bool value) { + Write(value); + WriteLine(); + } + + public virtual void WriteLine(char value) { + Write(value); + WriteLine(); + } + + public virtual void WriteLine(char[] buffer) { + Write(buffer); + WriteLine(); + } + + public virtual void WriteLine(decimal value) { + Write(value); + WriteLine(); + } + + public virtual void WriteLine(double value) { + Write(value); + WriteLine(); + } + + public virtual void WriteLine(int value) { + Write(value); + WriteLine(); + } + + public virtual void WriteLine(long value) { + Write(value); + WriteLine(); + } + + public virtual void WriteLine(object value) { + Write(value); + WriteLine(); + } + + public virtual void WriteLine(float value) { + Write(value); + WriteLine(); + } + + public virtual void WriteLine(string value) { + Write(value); + WriteLine(); + } + + // [CLSCompliant (false)] + public virtual void WriteLine(uint value) { + Write(value); + WriteLine(); + } + + // [CLSCompliant (false)] + public virtual void WriteLine(ulong value) { + Write(value); + WriteLine(); + } + + public virtual void WriteLine(string format, object arg0) { + Write(format, arg0); + WriteLine(); + } + + public virtual void WriteLine(string format, params object[] arg) { + Write(format, arg); + WriteLine(); + } + + public virtual void WriteLine(char[] buffer, int index, int count) { + Write(buffer, index, count); + WriteLine(); + } + + public virtual void WriteLine(string format, object arg0, object arg1) { + Write(format, arg0, arg1); + WriteLine(); + } + + public virtual void WriteLine(string format, object arg0, object arg1, object arg2) { + Write(format, arg0, arg1, arg2); + WriteLine(); + } + + } +} diff --git a/src/DNA/corlib/System.Net.Http/HttpClient.cs b/src/DNA/corlib/System.Net.Http/HttpClient.cs index b11573b2..f7688876 100644 --- a/src/DNA/corlib/System.Net.Http/HttpClient.cs +++ b/src/DNA/corlib/System.Net.Http/HttpClient.cs @@ -1,4 +1,4 @@ -using Blazor.System.Runtime.InteropServices.Json; +using MiniJSON; using System.Collections.Generic; using System.Runtime.InteropServices; using System.Threading; @@ -34,30 +34,42 @@ private static int OnFetchCompleted(string descriptor) public Task SendAsync(HttpRequestMessage request) { var count = Interlocked.Increment(ref _sendAsyncCount); + Console.WriteLine($"CALLED SendAsync({request.Url}) [{count}]"); var tcs = new TaskCompletionSource(); var body = request.Content as StringContent; + Console.WriteLine($"CALLING BeginResponse({request.Method?.Method}, {request.Url}, ...) [{count}]"); BeginResponse(request.Method?.Method ?? HttpMethod.Get.Method, request.Url, body?.Content, body?.MediaType, ar => { + Console.WriteLine($"CALLED SendAsync({request.Url}).BeginResponse async callback [{count}]"); + try { + Console.WriteLine($"CALLING EndResponse({request.Url}) [{count}]"); var response = EndResponse(ar); + Console.WriteLine($"RETURNED EndResponse({request.Url}) [{count}]"); if ((int)response.StatusCode < 200 || (int)response.StatusCode >= 300) { throw new HttpClientException($"Response status code was {response.StatusCode}"); } + Console.WriteLine($"CALLING tcs.TrySetResult() [{count}]"); tcs.TrySetResult(response); + Console.WriteLine($"RETURNED tcs.TrySetResult() [{count}]"); } catch (Exception ex) { tcs.TrySetException(ex); } + + Console.WriteLine($"RETURNING SendAsync({request.Url}).BeginResponse async callback [{count}]"); }, null); + Console.WriteLine($"RETURNED BeginResponse({request.Method?.Method}, {request.Url}, ...) [{count}]"); + Console.WriteLine($"RETURNING SendAsync({request.Url}) [{count}]"); return tcs.Task; } @@ -72,6 +84,7 @@ public async Task GetStringAsync(string url) private IAsyncResult BeginResponse(string method, string url, string body, string mediaType, AsyncCallback asyncCallback, object state) { + Console.WriteLine($"CALLED BeginResponse({method}, {url}, {body}, {mediaType}, ...)"); var asyncResult = new HttpClientAsyncResult(asyncCallback, state); var gcHandle = GCHandle.Alloc(asyncResult, GCHandleType.Pinned); var descriptorDict = new Dictionary() @@ -83,6 +96,7 @@ private IAsyncResult BeginResponse(string method, string url, string body, strin { "asyncResultAddress", gcHandle.AddrOfPinnedObject().ToInt32() } }; BeginFetch(Json.Serialize(descriptorDict)); + Console.WriteLine($"RETURNING BeginResponse({method}, {url}, {body}, {mediaType}, ...)"); return asyncResult; } diff --git a/src/DNA/corlib/System.Net.Http/HttpRequestMessage.cs b/src/DNA/corlib/System.Net.Http/HttpRequestMessage.cs index 8f1f3adf..80d0429f 100644 --- a/src/DNA/corlib/System.Net.Http/HttpRequestMessage.cs +++ b/src/DNA/corlib/System.Net.Http/HttpRequestMessage.cs @@ -10,8 +10,10 @@ public class HttpRequestMessage public HttpRequestMessage(HttpMethod method, string requestUri) { + Console.WriteLine($"CALLED HttpRequestMessage.ctor({method}, {requestUri})"); Method = method; Url = requestUri; + Console.WriteLine($"RETURNING HttpRequestMessage.ctor({method}, {requestUri})"); } public HttpRequestMessage(IDictionary dictionary) diff --git a/src/DNA/corlib/System.Reflection/AmbiguousMatchException.cs b/src/DNA/corlib/System.Reflection/AmbiguousMatchException.cs new file mode 100644 index 00000000..9f1b46d9 --- /dev/null +++ b/src/DNA/corlib/System.Reflection/AmbiguousMatchException.cs @@ -0,0 +1,36 @@ +// Copyright (c) 2012 DotNetAnywhere +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#if !LOCALTEST + +namespace System.Reflection { + + public class AmbiguousMatchException : SystemException { + + public AmbiguousMatchException() : base("Ambiguous matching in method resolution.") { } + + public AmbiguousMatchException(string message) : base(message) { } + + public AmbiguousMatchException(string message, Exception inner) : base(message, inner) { } + + } +} + +#endif diff --git a/src/DNA/corlib/System.Reflection/ConstructorInfo.cs b/src/DNA/corlib/System.Reflection/ConstructorInfo.cs new file mode 100644 index 00000000..bb8b8d24 --- /dev/null +++ b/src/DNA/corlib/System.Reflection/ConstructorInfo.cs @@ -0,0 +1,8 @@ +using System.Runtime.CompilerServices; + +namespace System.Reflection +{ + public abstract class ConstructorInfo : MethodBase + { + } +} \ No newline at end of file diff --git a/src/DNA/corlib/System.Reflection/CustomAttributeExtensions.cs b/src/DNA/corlib/System.Reflection/CustomAttributeExtensions.cs index 7bbde0cd..1ba158fe 100644 --- a/src/DNA/corlib/System.Reflection/CustomAttributeExtensions.cs +++ b/src/DNA/corlib/System.Reflection/CustomAttributeExtensions.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Linq; using System.Runtime.CompilerServices; namespace System.Reflection @@ -21,14 +22,12 @@ public static IEnumerable GetCustomAttributes(this MemberInfo element } return result; } - } - internal struct InternalCustomAttributeInfo - { -#pragma warning disable 0649 - public Attribute UninitializedInstance; - public MethodBase ConstructorMethodBase; - public object[] ConstructorParams; -#pragma warning restore 0649 + public static IEnumerable GetCustomAttributes(this MemberInfo element, Type attributeType, bool inherit) + { + var attributes = GetCustomAttributes(element); + return attributes.Where(attr => attributeType.IsAssignableFrom(attr.GetType())); + } + } } diff --git a/src/DNA/corlib/System.Reflection/EventInfo.cs b/src/DNA/corlib/System.Reflection/EventInfo.cs new file mode 100644 index 00000000..c74b67f9 --- /dev/null +++ b/src/DNA/corlib/System.Reflection/EventInfo.cs @@ -0,0 +1,8 @@ +using System.Runtime.CompilerServices; + +namespace System.Reflection +{ + public abstract class EventInfo : MemberInfo + { + } +} \ No newline at end of file diff --git a/src/DNA/corlib/System.Reflection/FieldInfo.cs b/src/DNA/corlib/System.Reflection/FieldInfo.cs new file mode 100644 index 00000000..e3f376d9 --- /dev/null +++ b/src/DNA/corlib/System.Reflection/FieldInfo.cs @@ -0,0 +1,9 @@ +using System.Runtime.CompilerServices; + +namespace System.Reflection +{ + public abstract class FieldInfo : MemberInfo + { + public abstract object GetValue(object obj); + } +} \ No newline at end of file diff --git a/src/DNA/corlib/System.Reflection/ICustomAttributeProvider.cs b/src/DNA/corlib/System.Reflection/ICustomAttributeProvider.cs new file mode 100644 index 00000000..3950b63c --- /dev/null +++ b/src/DNA/corlib/System.Reflection/ICustomAttributeProvider.cs @@ -0,0 +1,36 @@ +// Copyright (c) 2012 DotNetAnywhere +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#if !LOCALTEST + +namespace System.Reflection { + + public interface ICustomAttributeProvider { + + bool IsDefined(Type attributeType, bool inherit); + + Object[] GetCustomAttributes(bool inherit); + + Object[] GetCustomAttributes(Type attributeType, bool inherit); + } + +} + +#endif diff --git a/src/DNA/corlib/System.Reflection/MemberInfo.cs b/src/DNA/corlib/System.Reflection/MemberInfo.cs index 9c49fecc..22681a3f 100644 --- a/src/DNA/corlib/System.Reflection/MemberInfo.cs +++ b/src/DNA/corlib/System.Reflection/MemberInfo.cs @@ -26,17 +26,32 @@ using System.Text; namespace System.Reflection { - public abstract class MemberInfo { + + internal struct InternalCustomAttributeInfo { +#pragma warning disable 0649 + public Attribute UninitializedInstance; + public MethodBase ConstructorMethodBase; + public object[] ConstructorParams; +#pragma warning restore 0649 + } + + public abstract class MemberInfo : ICustomAttributeProvider { + #pragma warning disable 0169, 0649 - protected readonly Type _ownerType; - protected readonly string _name; + protected readonly Type _ownerType; + protected readonly string _name; #pragma warning restore 0169, 0649 - protected MemberInfo() { + protected MemberInfo() { } - protected MemberInfo(Type ownerType, string name) - { + public abstract bool IsDefined(Type attributeType, bool inherit); + + public abstract Object[] GetCustomAttributes(bool inherit); + + public abstract Object[] GetCustomAttributes(Type attributeType, bool inherit); + + protected MemberInfo(Type ownerType, string name) { _ownerType = ownerType; _name = name; } diff --git a/src/DNA/corlib/System.Reflection/MethodAttributes.cs b/src/DNA/corlib/System.Reflection/MethodAttributes.cs new file mode 100644 index 00000000..82e2aedd --- /dev/null +++ b/src/DNA/corlib/System.Reflection/MethodAttributes.cs @@ -0,0 +1,69 @@ +// MethodAttributes.cs +// +// This code was automatically generated from +// ECMA CLI XML Library Specification. +// Generator: libgen.xsl [1.0; (C) Sergey Chaban (serge@wildwestsoftware.com)] +// Created: Wed, 5 Sep 2001 06:39:32 UTC +// Source file: all.xml +// URL: http://devresource.hp.com/devresource/Docs/TechPapers/CSharp/all.xml +// +// (C) 2001 Ximian, Inc. http://www.ximian.com + +// +// Copyright (C) 2004 Novell, Inc (http://www.novell.com) +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System.Runtime.InteropServices; + +namespace System.Reflection { + + // [ComVisible (true)] + [Serializable] + [Flags] + public enum MethodAttributes { + MemberAccessMask = 7, + PrivateScope = 0, + Private = 1, + FamANDAssem = 2, + Assembly = 3, + Family = 4, + FamORAssem = 5, + Public = 6, + Static = 16, + Final = 32, + Virtual = 64, + HideBySig = 128, + VtableLayoutMask = 256, + CheckAccessOnOverride = 512, + ReuseSlot = 0, + NewSlot = 256, + Abstract = 1024, + SpecialName = 2048, + PinvokeImpl = 8192, + UnmanagedExport = 8, + RTSpecialName = 4096, + ReservedMask = 53248, + HasSecurity = 16384, + RequireSecObject = 32768, + } // MethodAttributes + +} // System.Reflection diff --git a/src/DNA/corlib/System.Reflection/MethodBase.cs b/src/DNA/corlib/System.Reflection/MethodBase.cs new file mode 100644 index 00000000..c07dffc4 --- /dev/null +++ b/src/DNA/corlib/System.Reflection/MethodBase.cs @@ -0,0 +1,54 @@ + using System.Runtime.CompilerServices; + + namespace System.Reflection { + + public abstract class MethodBase : MemberInfo { +#pragma warning disable 0169, 0649 + // populated by interop, MUST be synced with C code + private readonly uint _flags; + private readonly IntPtr _methodDef; +#pragma warning restore 0169, 0649 + + public object Invoke(object target, object[] parameters) { + // This is not invoked at runtime, because the JITter specifically replaces calls + // to MethodBase.Invoke with its own special opcode + throw new NotImplementedException(); + } + + public MethodAttributes Attributes { get { return (MethodAttributes)_flags; } } + + public Boolean IsPublic { + get { return (Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.Public; } + } + public Boolean IsPrivate { + get { return (Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.Private; } + } + public Boolean IsFamily { + get { return (Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.Family; } + } + public Boolean IsAssembly { + get { return (Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.Assembly; } + } + public Boolean IsFamilyAndAssembly { + get { return (Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.FamANDAssem; } + } + public Boolean IsFamilyOrAssembly { + get { return (Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.FamORAssem; } + } + public Boolean IsStatic { + get { return (Attributes & MethodAttributes.Static) != 0; } + } + public Boolean IsFinal { + get { return (Attributes & MethodAttributes.Final) != 0; } + } + public Boolean IsVirtual { + get { return (Attributes & MethodAttributes.Virtual) != 0; } + } + public Boolean IsHideBySig { + get { return (Attributes & MethodAttributes.HideBySig) != 0; } + } + public Boolean IsAbstract { + get { return (Attributes & MethodAttributes.Abstract) != 0; } + } + } +} \ No newline at end of file diff --git a/src/DNA/corlib/System.Reflection/MethodInfo.cs b/src/DNA/corlib/System.Reflection/MethodInfo.cs index b3108d60..b483f74d 100644 --- a/src/DNA/corlib/System.Reflection/MethodInfo.cs +++ b/src/DNA/corlib/System.Reflection/MethodInfo.cs @@ -1,22 +1,10 @@ using System.Runtime.CompilerServices; -namespace System.Reflection -{ - public abstract class MethodInfo : MethodBase - { - } +namespace System.Reflection { + + public abstract class MethodInfo : MethodBase { - public abstract class MethodBase : MemberInfo - { -#pragma warning disable 0169, 0649 - private readonly IntPtr _methodDef; -#pragma warning restore 0169, 0649 - - public object Invoke(object target, object[] parameters) - { - // This is not invoked at runtime, because the JITter specifically replaces calls - // to MethodBase.Invoke with its own special opcode - throw new NotImplementedException(); - } + [MethodImpl(MethodImplOptions.InternalCall)] + extern public virtual MethodInfo MakeGenericMethod(params Type[] typeArguments); } } \ No newline at end of file diff --git a/src/DNA/corlib/System.Reflection/Module.cs b/src/DNA/corlib/System.Reflection/Module.cs new file mode 100644 index 00000000..e1f50fe9 --- /dev/null +++ b/src/DNA/corlib/System.Reflection/Module.cs @@ -0,0 +1,15 @@ +namespace System.Reflection { + public abstract class Module : ICustomAttributeProvider { + + protected Module() { + } + + public abstract string Name { get; } + + public abstract bool IsDefined(Type attributeType, bool inherit); + + public abstract Object[] GetCustomAttributes(bool inherit); + + public abstract Object[] GetCustomAttributes(Type attributeType, bool inherit); + } +} diff --git a/src/DNA/corlib/System.Reflection/ParameterInfo.cs b/src/DNA/corlib/System.Reflection/ParameterInfo.cs new file mode 100644 index 00000000..bfa3113d --- /dev/null +++ b/src/DNA/corlib/System.Reflection/ParameterInfo.cs @@ -0,0 +1,15 @@ +namespace System.Reflection { + public abstract class ParameterInfo : ICustomAttributeProvider { + + protected ParameterInfo() { + } + + public abstract string Name { get; } + + public abstract bool IsDefined(Type attributeType, bool inherit); + + public abstract Object[] GetCustomAttributes(bool inherit); + + public abstract Object[] GetCustomAttributes(Type attributeType, bool inherit); + } +} diff --git a/src/DNA/corlib/System.Reflection/PropertyInfo.cs b/src/DNA/corlib/System.Reflection/PropertyInfo.cs index ec09db70..f190e829 100644 --- a/src/DNA/corlib/System.Reflection/PropertyInfo.cs +++ b/src/DNA/corlib/System.Reflection/PropertyInfo.cs @@ -1,24 +1,55 @@ -namespace System.Reflection -{ - public abstract class PropertyInfo : MemberInfo - { +namespace System.Reflection { + public abstract class PropertyInfo : MemberInfo { + #pragma warning disable 0649 private readonly Type _propertyType; #pragma warning restore 0649 public Type PropertyType => _propertyType; - public MethodInfo GetGetMethod() - { - return _ownerType.GetMethod("get_" + _name); + public MethodInfo GetGetMethod() { + return _ownerType.GetMethod("get_" + Name); } - public MethodInfo GetSetMethod() - { - return _ownerType.GetMethod("set_" + _name); + public MethodInfo GetSetMethod() { + return _ownerType.GetMethod("set_" + Name); } public MethodInfo GetMethod => GetGetMethod(); public MethodInfo SetMethod => GetSetMethod(); + + public virtual object GetValue(object obj, object[] index) { + object ret = null; + + MethodInfo method = GetGetMethod (); + if (method == null) + throw new ArgumentException ("Get Method not found for '" + Name + "'"); + + if (index == null || index.Length == 0) { + ret = method.Invoke (obj, null); + } else { + ret = method.Invoke (obj, index); + } + + return ret; + } + + public virtual void SetValue (object obj, object value, object[] index) { + MethodInfo method = GetSetMethod (); + if (method == null) + throw new ArgumentException ("Set Method not found for '" + Name + "'"); + + object [] parms; + if (index == null || index.Length == 0) { + parms = new object [] { value }; + } else { + int ilen = index.Length; + parms = new object [ilen + 1]; + index.CopyTo (parms, 0); + parms [ilen] = value; + } + + method.Invoke (obj, parms); + } } } diff --git a/src/DNA/corlib/System.Reflection/RuntimeReflectionExtensions.cs b/src/DNA/corlib/System.Reflection/RuntimeReflectionExtensions.cs index 5a1c1216..aaa016e1 100644 --- a/src/DNA/corlib/System.Reflection/RuntimeReflectionExtensions.cs +++ b/src/DNA/corlib/System.Reflection/RuntimeReflectionExtensions.cs @@ -2,13 +2,13 @@ using System.Collections.Generic; using System.Text; -namespace System.Reflection -{ - public static class RuntimeReflectionExtensions - { - public static IEnumerable GetRuntimeProperties(this Type type) - { - return type.GetProperties(); - } +namespace System.Reflection { + + public static class RuntimeReflectionExtensions { + + // public static MethodInfo GetRuntimeMethod(this Type type, string name, Type[] parameters) => type.GetMethod(name); + public static PropertyInfo GetRuntimeProperty(this Type type, string name) => type.GetProperty(name); + public static IEnumerable GetRuntimeMethods(this Type type) => type.GetMethods(); + public static IEnumerable GetRuntimeProperties(this Type type) => type.GetProperties(); } } diff --git a/src/DNA/corlib/System.Reflection/TypeAttributes.cs b/src/DNA/corlib/System.Reflection/TypeAttributes.cs new file mode 100644 index 00000000..dacd7002 --- /dev/null +++ b/src/DNA/corlib/System.Reflection/TypeAttributes.cs @@ -0,0 +1,65 @@ +// source: https://github.com/Microsoft/referencesource/blob/master/mscorlib/system/reflection/typeattributes.cs +// Copyright (c) Microsoft Corporation. All rights reserved. + +namespace System.Reflection { + using System.Runtime.InteropServices; + using System; + // This Enum matches the CorTypeAttr defined in CorHdr.h +[Serializable] +[Flags] +// [System.Runtime.InteropServices.ComVisible(true)] + public enum TypeAttributes + { + VisibilityMask = 0x00000007, + NotPublic = 0x00000000, // Class is not public scope. + Public = 0x00000001, // Class is public scope. + NestedPublic = 0x00000002, // Class is nested with public visibility. + NestedPrivate = 0x00000003, // Class is nested with private visibility. + NestedFamily = 0x00000004, // Class is nested with family visibility. + NestedAssembly = 0x00000005, // Class is nested with assembly visibility. + NestedFamANDAssem = 0x00000006, // Class is nested with family and assembly visibility. + NestedFamORAssem = 0x00000007, // Class is nested with family or assembly visibility. + + // Use this mask to retrieve class layout informaiton + // 0 is AutoLayout, 0x2 is SequentialLayout, 4 is ExplicitLayout + LayoutMask = 0x00000018, + AutoLayout = 0x00000000, // Class fields are auto-laid out + SequentialLayout = 0x00000008, // Class fields are laid out sequentially + ExplicitLayout = 0x00000010, // Layout is supplied explicitly + // end layout mask + + // Use this mask to distinguish whether a type declaration is an interface. (Class vs. ValueType done based on whether it subclasses S.ValueType) + ClassSemanticsMask= 0x00000020, + Class = 0x00000000, // Type is a class (or a value type). + Interface = 0x00000020, // Type is an interface. + + // Special semantics in addition to class semantics. + Abstract = 0x00000080, // Class is abstract + Sealed = 0x00000100, // Class is concrete and may not be extended + SpecialName = 0x00000400, // Class name is special. Name describes how. + + // Implementation attributes. + Import = 0x00001000, // Class / interface is imported + Serializable = 0x00002000, // The class is Serializable. + + // [ComVisible(false)] + WindowsRuntime = 0x00004000, // Type is a Windows Runtime type. + + // Use tdStringFormatMask to retrieve string information for native interop + StringFormatMask = 0x00030000, + AnsiClass = 0x00000000, // LPTSTR is interpreted as ANSI in this class + UnicodeClass = 0x00010000, // LPTSTR is interpreted as UNICODE + AutoClass = 0x00020000, // LPTSTR is interpreted automatically + CustomFormatClass = 0x00030000, // A non-standard encoding specified by CustomFormatMask + CustomFormatMask = 0x00C00000, // Use this mask to retrieve non-standard encoding information for native interop. The meaning of the values of these 2 bits is unspecified. + + // end string format mask + + BeforeFieldInit = 0x00100000, // Initialize the class any time before first static field access. + + // Flags reserved for runtime use. + ReservedMask = 0x00040800, + RTSpecialName = 0x00000800, // Runtime should check name encoding. + HasSecurity = 0x00040000, // Class has security associate with it. + } +} diff --git a/src/DNA/corlib/System.Reflection/TypeExtensions.cs b/src/DNA/corlib/System.Reflection/TypeExtensions.cs new file mode 100644 index 00000000..6e377c9d --- /dev/null +++ b/src/DNA/corlib/System.Reflection/TypeExtensions.cs @@ -0,0 +1,13 @@ +using System; + +namespace System.Reflection { + + public static class TypeExtensions { + + public static Type[] GetGenericArguments(Type type) => type.GetGenericArguments(); + public static MethodInfo[] GetMethods(Type type) => type.GetMethods(); + public static PropertyInfo[] GetProperties(Type type) => type.GetProperties(); + public static MethodInfo GetMethod(Type type, string name) => type.GetMethod(name); + public static PropertyInfo GetProperty(Type type, string name) => type.GetProperty(name); + } +} diff --git a/src/DNA/corlib/System.Reflection/TypeInfo.cs b/src/DNA/corlib/System.Reflection/TypeInfo.cs index 6f0c63b7..c2eccfa1 100644 --- a/src/DNA/corlib/System.Reflection/TypeInfo.cs +++ b/src/DNA/corlib/System.Reflection/TypeInfo.cs @@ -1,14 +1,66 @@ -namespace System.Reflection -{ - public class TypeInfo : MemberInfo - { +using System.Collections.Generic; + +namespace System.Reflection { + + public class TypeInfo { + private readonly Type _type; - internal TypeInfo(Type type) : base(type, type.Name) - { + internal TypeInfo(Type type) { _type = type; } - public bool IsValueType => _type.IsValueType; + public bool IsAnsiClass => _type.IsAnsiClass; + public bool IsUnicodeClass => _type.IsUnicodeClass; + public bool IsAutoClass => _type.IsAutoClass; + public bool IsNotPublic => _type.IsNotPublic; + public bool IsPublic => _type.IsPublic; + public bool IsNestedPublic => _type.IsNestedPublic; + public bool IsNestedPrivate => _type.IsNestedPrivate; + public bool IsNestedFamily => _type.IsNestedFamily; + public bool IsNestedAssembly => _type.IsNestedAssembly; + public bool IsNestedFamANDAssem => _type.IsNestedFamANDAssem; + public bool IsNestedFamORAssem => _type.IsNestedFamORAssem; + public bool IsAutoLayout => _type.IsAutoLayout; + public bool IsLayoutSequential => _type.IsLayoutSequential; + public bool IsExplicitLayout => _type.IsExplicitLayout; + public bool IsClass => _type.IsClass; + public bool IsInterface => _type.IsInterface; + public bool IsAbstract => _type.IsAbstract; + public bool IsSealed => _type.IsSealed; + public bool IsSpecialName => _type.IsSpecialName; + public bool IsImport => _type.IsImport; + public bool IsSerializable => _type.IsSerializable; + + public virtual Type BaseType => _type.BaseType; + public virtual bool IsValueType => _type.IsValueType; + public virtual bool IsGenericType => _type.IsGenericType; + public virtual bool IsGenericTypeDefinition => _type.IsGenericTypeDefinition; + public virtual bool IsAssignableFrom(TypeInfo ti) => _type.IsAssignableFrom(ti._type); + + public virtual Type[] GenericTypeParameters => _type.GetGenericArguments(); + public virtual IEnumerable ImplementedInterfaces => _type.GetInterfaces(); + public virtual IEnumerable DeclaredMethods => _type.GetMethods(); + public virtual IEnumerable DeclaredProperties => _type.GetProperties(); + + public virtual IEnumerable DeclaredNestedTypes { + get { + var types = _type.GetNestedTypes(); + var typeInfos = new TypeInfo[types.Length]; + for (int i = 0; i < types.Length; i++) { + typeInfos[i] = new TypeInfo(types[i]); + } + return typeInfos; + } + } + + public virtual MethodInfo GetDeclaredMethod(string name) => _type.GetMethod(name); + public virtual PropertyInfo GetDeclaredProperty(string name) => _type.GetProperty(name); + + public virtual TypeInfo GetDeclaredNestedType(string name) { + var type = _type.GetNestedType(name); + return (type != null) ? new TypeInfo(type) : null; + } + } } \ No newline at end of file diff --git a/src/DNA/corlib/System.Runtime.CompilerServices/CompilerGeneratedAttribute.cs b/src/DNA/corlib/System.Runtime.CompilerServices/CompilerGeneratedAttribute.cs new file mode 100644 index 00000000..82b64b64 --- /dev/null +++ b/src/DNA/corlib/System.Runtime.CompilerServices/CompilerGeneratedAttribute.cs @@ -0,0 +1,13 @@ +// From https://github.com/Microsoft/referencesource +// See copyright and license details in that repo + +namespace System.Runtime.CompilerServices { + + [Serializable] + [AttributeUsage(AttributeTargets.All, Inherited = true)] + public sealed class CompilerGeneratedAttribute : Attribute + { + public CompilerGeneratedAttribute () {} + } +} + diff --git a/src/DNA/corlib/System.Runtime.InteropServices/CharSet.cs b/src/DNA/corlib/System.Runtime.InteropServices/CharSet.cs index d506e2ac..a9ef5a9a 100644 --- a/src/DNA/corlib/System.Runtime.InteropServices/CharSet.cs +++ b/src/DNA/corlib/System.Runtime.InteropServices/CharSet.cs @@ -21,6 +21,7 @@ #if !LOCALTEST namespace System.Runtime.InteropServices { + [Serializable] public enum CharSet { None = 1, Ansi = 2, diff --git a/src/DNA/corlib/System.Runtime.InteropServices/FieldOffsetAttribute.cs b/src/DNA/corlib/System.Runtime.InteropServices/FieldOffsetAttribute.cs new file mode 100644 index 00000000..8befab8e --- /dev/null +++ b/src/DNA/corlib/System.Runtime.InteropServices/FieldOffsetAttribute.cs @@ -0,0 +1,33 @@ +// Copyright (c) 2012 DotNetAnywhere +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#if !LOCALTEST + +namespace System.Runtime.InteropServices { + + [AttributeUsage (AttributeTargets.Field, Inherited=false)] + public sealed class FieldOffsetAttribute : Attribute { + private int val; + public FieldOffsetAttribute( int offset) { val = offset; } + public int Value { get { return val; } } + } +} + +#endif diff --git a/src/DNA/corlib/System.Runtime.InteropServices/Json/Json.cs b/src/DNA/corlib/System.Runtime.InteropServices/Json/Json.cs index 40d13c3c..a162979c 100644 --- a/src/DNA/corlib/System.Runtime.InteropServices/Json/Json.cs +++ b/src/DNA/corlib/System.Runtime.InteropServices/Json/Json.cs @@ -30,16 +30,10 @@ using System.Collections; using System.Collections.Generic; using System.IO; -using System.Text; using System.Reflection; +using System.Text; -// This is currently duplicated in both the corlib code (because it can't directly address -// anything in Blazor.Runtime), and in Blazor.Runtime (because it can only see corlib APIs -// that are also part of netstandard). Consider restructuring these assemblies and their -// references to one another. - -namespace Blazor.System.Runtime.InteropServices.Json -{ +namespace MiniJSON { // Example usage: // // using UnityEngine; @@ -102,6 +96,12 @@ public static bool IsWordBreak(char c) { return Char.IsWhiteSpace(c) || WORD_BREAK.IndexOf(c) != -1; } + const string HEX_DIGIT = "0123456789ABCDEFabcdef"; + + public static bool IsHexDigit(char c) { + return HEX_DIGIT.IndexOf(c) != -1; + } + enum TOKEN { NONE, CURLY_OPEN, @@ -149,7 +149,7 @@ Dictionary ParseObject() { continue; case TOKEN.CURLY_CLOSE: return table; - default: + case TOKEN.STRING: // name string name = ParseString(); if (name == null) { @@ -164,8 +164,14 @@ Dictionary ParseObject() { json.Read(); // value - table[name] = ParseValue(); + TOKEN valueToken = NextToken; + object value = ParseByToken(valueToken); + if(value==null && valueToken!=TOKEN.NULL) + return null; + table[name] = value; break; + default: + return null; } } } @@ -191,7 +197,8 @@ List ParseArray() { break; default: object value = ParseByToken(nextToken); - + if(value==null && nextToken!=TOKEN.NULL) + return null; array.Add(value); break; } @@ -279,10 +286,12 @@ string ParseString() { for (int i=0; i< 4; i++) { hex[i] = NextChar; + if (!IsHexDigit(hex[i])) + return null; } - throw new NotImplementedException("Parsing incoming \\u values"); - //s.Append((char) Convert.ToInt32(new string(hex), 16)); - //break; + + s.Append((char) Convert.ToInt32(new string(hex), 16)); + break; } break; default: @@ -297,19 +306,15 @@ string ParseString() { object ParseNumber() { string number = NextWord; - if (number.IndexOf('.') == -1) { + if (number.IndexOf('.') == -1 && number.IndexOf('E') == -1 && number.IndexOf('e') == -1) { int parsedInt; Int32.TryParse(number, out parsedInt); - return parsedInt; + return (double)parsedInt; } - // TODO: Actually parse doubles - return 0; - /* - float parsedDouble; - Single.TryParse(number, out parsedDouble); + double parsedDouble; + Double.TryParse(number, out parsedDouble); return parsedDouble; - */ } void EatWhitespace() { diff --git a/src/DNA/corlib/System.Runtime.InteropServices/LayoutKind.cs b/src/DNA/corlib/System.Runtime.InteropServices/LayoutKind.cs new file mode 100644 index 00000000..1266c4f1 --- /dev/null +++ b/src/DNA/corlib/System.Runtime.InteropServices/LayoutKind.cs @@ -0,0 +1,32 @@ +// Copyright (c) 2012 DotNetAnywhere +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#if !LOCALTEST + +namespace System.Runtime.InteropServices { + [Serializable] + public enum LayoutKind { + Sequential = 0, + Explicit = 2, + Auto = 3 + } +} + +#endif diff --git a/src/DNA/corlib/System.Runtime.InteropServices/StructLayoutAttribute.cs b/src/DNA/corlib/System.Runtime.InteropServices/StructLayoutAttribute.cs new file mode 100644 index 00000000..5d3c9bc1 --- /dev/null +++ b/src/DNA/corlib/System.Runtime.InteropServices/StructLayoutAttribute.cs @@ -0,0 +1,48 @@ +// Copyright (c) 2012 DotNetAnywhere +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#if !LOCALTEST + +namespace System.Runtime.InteropServices { + + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, Inherited = false)] + public sealed class StructLayoutAttribute : Attribute { + + private readonly LayoutKind _value; + + public LayoutKind Value { get { return _value; } } + + public int Pack; + + public int Size; + + public CharSet CharSet; + + public StructLayoutAttribute(LayoutKind layoutKind) { + _value = layoutKind; + } + + public StructLayoutAttribute(short layoutKind) { + _value = (LayoutKind)layoutKind; + } + } +} + +#endif \ No newline at end of file diff --git a/src/DNA/corlib/System.Text/Encoding.cs b/src/DNA/corlib/System.Text/Encoding.cs index 04e3f706..77a3936e 100644 --- a/src/DNA/corlib/System.Text/Encoding.cs +++ b/src/DNA/corlib/System.Text/Encoding.cs @@ -22,74 +22,80 @@ namespace System.Text { - public abstract class Encoding : ICloneable { - - private static object lockObj = new object(); - - #region Static common Encoding properties - - private static Encoding unicodeEncoding = null; - private static Encoding utf8Encoding = null; - private static Encoding utf8UnmarkedEncoding = null; - - public static Encoding Unicode { - get { - if (unicodeEncoding == null) { - lock (lockObj) { - if (unicodeEncoding == null) { - unicodeEncoding = new UnicodeEncoding(true, false); - } - } - } - return unicodeEncoding; - } - } - - public static Encoding UTF8 { - get { - if (utf8Encoding == null) { - lock (lockObj) { - if (utf8Encoding == null) { - utf8Encoding = new UTF8Encoding(true); - } - } - } - return utf8Encoding; - } - } - - public static Encoding UTF8Unmarked { - get { - if (utf8UnmarkedEncoding == null) { - lock (lockObj) { - if (utf8UnmarkedEncoding == null) { - utf8UnmarkedEncoding = new UTF8Encoding(false); - } - } - } - return utf8UnmarkedEncoding; - } - } - - #endregion - - public virtual byte[] GetPreamble() { - return new byte[0]; - } - - public abstract int GetMaxCharCount(int byteCount); - - public abstract Decoder GetDecoder(); - - - #region ICloneable Members - - public object Clone() { - return (Encoding)object.Clone(this); - } - - #endregion - } + public abstract class Encoding : ICloneable { + + private static object lockObj = new object(); + + #region Static common Encoding properties + + private static Encoding unicodeEncoding = null; + private static Encoding utf8Encoding = null; + private static Encoding utf8UnmarkedEncoding = null; + + public static Encoding Default { + get { + return Encoding.UTF8; + } + } + + public static Encoding Unicode { + get { + if (unicodeEncoding == null) { + lock (lockObj) { + if (unicodeEncoding == null) { + unicodeEncoding = new UnicodeEncoding(true, false); + } + } + } + return unicodeEncoding; + } + } + + public static Encoding UTF8 { + get { + if (utf8Encoding == null) { + lock (lockObj) { + if (utf8Encoding == null) { + utf8Encoding = new UTF8Encoding(true); + } + } + } + return utf8Encoding; + } + } + + public static Encoding UTF8Unmarked { + get { + if (utf8UnmarkedEncoding == null) { + lock (lockObj) { + if (utf8UnmarkedEncoding == null) { + utf8UnmarkedEncoding = new UTF8Encoding(false); + } + } + } + return utf8UnmarkedEncoding; + } + } + + #endregion + + public virtual byte[] GetPreamble() { + return new byte[0]; + } + + public abstract int GetMaxCharCount(int byteCount); + + public abstract Decoder GetDecoder(); + + + #region ICloneable Members + + public object Clone() { + return (Encoding)object.Clone(this); + } + + #endregion + } } diff --git a/src/DNA/corlib/System.Text/StringBuilder.cs b/src/DNA/corlib/System.Text/StringBuilder.cs index bae6057d..fddcfd54 100644 --- a/src/DNA/corlib/System.Text/StringBuilder.cs +++ b/src/DNA/corlib/System.Text/StringBuilder.cs @@ -166,11 +166,13 @@ public StringBuilder Remove(int startIndex, int length) { #region Append Methods public StringBuilder Append(string value) { + if (value == null) { + return this; + } int len = value.Length; this.EnsureSpace(len); - for (int i = 0; i < len; i++) { - this.data[this.length++] = value[i]; - } + value.CopyTo(0, this.data, this.length, len); + this.length += len; return this; } @@ -178,13 +180,12 @@ public StringBuilder Append(string value, int startIndex, int count) { if (value == null) { return this; } - if (startIndex < 0 || count < 0 || value.Length < startIndex + count) { + if (startIndex < 0 || count < 0 || startIndex + count > value.Length) { throw new ArgumentOutOfRangeException(); } this.EnsureSpace(count); - for (int i = 0; i < count; i++) { - this.data[this.length++] = value[startIndex + i]; - } + value.CopyTo(startIndex, this.data, this.length, count); + this.length += count; return this; } @@ -331,7 +332,7 @@ public StringBuilder AppendLine(string value) { public StringBuilder Insert(int index, string value) { if (index < 0 || index > this.length) { - throw new ArgumentOutOfRangeException(); + throw new ArgumentOutOfRangeException("index"); } if (string.IsNullOrEmpty(value)) { return this; @@ -339,9 +340,7 @@ public StringBuilder Insert(int index, string value) { int len = value.Length; EnsureSpace(len); Array.Copy(this.data, index, this.data, index + len, this.length - index); - for (int i = 0; i < len; i++) { - this.data[index + i] = value[i]; - } + value.CopyTo(0, this.data, index, len); this.length += len; return this; } @@ -359,6 +358,9 @@ public StringBuilder Insert(int index, char value) { } public StringBuilder Insert(int index, char[] value) { + if (value == null) { + return this; + } return this.Insert(index, new string(value)); } @@ -383,6 +385,9 @@ public StringBuilder Insert(int index, long value) { } public StringBuilder Insert(int index, object value) { + if (value == null) { + return this; + } return this.Insert(index, value.ToString()); } diff --git a/src/DNA/corlib/System.Threading/Tasks/Task.cs b/src/DNA/corlib/System.Threading.Tasks/Task.cs similarity index 56% rename from src/DNA/corlib/System.Threading/Tasks/Task.cs rename to src/DNA/corlib/System.Threading.Tasks/Task.cs index a88c40dd..988fdf37 100644 --- a/src/DNA/corlib/System.Threading/Tasks/Task.cs +++ b/src/DNA/corlib/System.Threading.Tasks/Task.cs @@ -1,8 +1,7 @@ using System.Collections.Generic; using System.Runtime.CompilerServices; -namespace System.Threading.Tasks -{ +namespace System.Threading.Tasks { /// /// This is a highly incomplete approximation to System.Threading.Tasks.Task. It can only handle /// 'ContinueWith' continuations that themselves return void (not nested tasks). Various other Task @@ -11,125 +10,120 @@ namespace System.Threading.Tasks /// For a proper implementation, consider pulling in the real Task sources that were backported to /// .NET 3.5 or later. The functionality provied here is only sufficient for experimentation. /// - public class Task - { + public class Task { private List _continuations = new List(); private object _result; private Exception _exception; public bool IsCompleted { get; private set; } + public bool IsCanceled { get; private set; } public bool IsFaulted => _exception != null; public AggregateException Exception => _exception != null ? new AggregateException(_exception) : null; - public object Result - { - get - { - if (!IsCompleted) - { - throw new InvalidOperationException("Not implemented: blocking until result is ready."); + public object Result { + get { + if (!IsCompleted) { + Wait(); } - - if (_exception != null) - { + if (IsCanceled) { + // throw new AggregateException (new TaskCanceledException (this)); + throw new NotImplementedException("Not implemented: Task cancellation."); + } + if (_exception != null) { throw _exception; } - return _result; } } - internal void MarkCompleted(object result) - { + internal void MarkCompleted(object result) { _result = result; InvokeContinuations(); } - internal void MarkFailed(Exception ex) - { + internal void MarkFailed(Exception ex) { _exception = ex; InvokeContinuations(); } - protected Task ContinueWith(object continuation) - { - if (IsCompleted) - { + protected Task ContinueWith(object continuation) { + if (IsCompleted) { InvokeContinuation(continuation); } - else - { + else { _continuations.Add(continuation); } - return this; // TODO: Async continuations } - public Task ContinueWith(Action continuation) - { + public Task ContinueWith(Action continuation) { return ContinueWith((object)continuation); } - private void InvokeContinuations() - { - IsCompleted = true; + public Task ContinueWith(Func continuation) { + Action cont = task => { continuation(task); }; // see disclaimer above + return ContinueWith((object)cont); + } - foreach (var continuation in _continuations) - { + private void InvokeContinuations() { + IsCompleted = true; + foreach (var continuation in _continuations) { InvokeContinuation(continuation); } - _continuations.Clear(); } - protected virtual void InvokeContinuation(object continuation) - { + protected virtual void InvokeContinuation(object continuation) { ((Action)continuation)(this); } - public TaskAwaiter GetAwaiter() - { + public TaskAwaiter GetAwaiter() { return new TaskAwaiter(this); } - public static Task Delay(int millisecondsTimeout) - { + public void Wait() { + // throw new NotImplementedException("Not implemented: Task.Wait()."); + //TODO: implement + } + + public static Task Delay(int millisecondsTimeout) { var tcs = new TaskCompletionSource(); - new Thread(_ => - { + new Thread(_ => { Thread.Sleep(millisecondsTimeout); tcs.TrySetResult(null); }).Start(); return tcs.Task; } + + public static Task FromResult (TResult result) { + var tcs = new TaskCompletionSource (); + tcs.SetResult (result); + return tcs.Task; + } } - public class Task : Task - { - public new T Result => (T)base.Result; + public class Task : Task { + public new T Result { + get { return (T)base.Result; } + } - public Task ContinueWith(Action> continuation) - { + public Task ContinueWith(Action> continuation) { return ContinueWith((object)continuation); } - protected override void InvokeContinuation(object continuation) - { + protected override void InvokeContinuation(object continuation) { var typedContinuation = continuation as Action>; - if (typedContinuation != null) - { + if (typedContinuation != null) { typedContinuation(this); } - else - { + else { base.InvokeContinuation(continuation); } } - public new TaskAwaiter GetAwaiter() - { + public new TaskAwaiter GetAwaiter() { return new TaskAwaiter(this); } } diff --git a/src/DNA/corlib/System.Threading.Tasks/TaskCompletionSource.cs b/src/DNA/corlib/System.Threading.Tasks/TaskCompletionSource.cs new file mode 100644 index 00000000..3b4c9c79 --- /dev/null +++ b/src/DNA/corlib/System.Threading.Tasks/TaskCompletionSource.cs @@ -0,0 +1,85 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace System.Threading.Tasks { + + public class TaskCompletionSource { + + private Task _task = new Task(); + + public Task Task => _task; + + static void ThrowInvalidException () { + throw new InvalidOperationException ("The underlying Task is already in one of the three final states: RanToCompletion, Faulted, or Canceled."); + } + + public void SetResult(T result) { + if (!TrySetResult (result)) { + ThrowInvalidException (); + } + } + + public void SetCanceled () { + if (!TrySetCanceled ()) { + ThrowInvalidException (); + } + } + + public void SetException (Exception exception) { + if (!TrySetException (exception)) { + ThrowInvalidException (); + } + } + + public void SetException (IEnumerable exceptions) { + if (!TrySetException (exceptions)) + ThrowInvalidException (); + } + + public Task FromResult(T i) { + return Task; + } + + // Note: Don't add a generic param here (e.g., TrySetResult) because it triggers + // some bug in the DNA runtime leading to crashes at the start of any method that contains + // a call to this. + internal bool TrySetResult(object result) { + if (_task.IsCompleted) { + return false; + } + else { + _task.MarkCompleted(result); + return true; + } + } + + internal bool TrySetCanceled() { + throw new NotImplementedException("Task cancellation"); + } + + internal bool TrySetException(Exception exception) { + if (exception == null) + throw new ArgumentNullException ("exception"); + + if (_task.IsCompleted) { + return false; + } + else { + _task.MarkFailed(exception); + return true; + } + } + + internal bool TrySetException (IEnumerable exceptions) { + if (exceptions == null) + throw new ArgumentNullException ("exceptions"); + + var aggregate = new AggregateException (exceptions); + if (aggregate.InnerExceptions.Count == 0) + throw new ArgumentNullException ("exceptions"); + + return TrySetException (aggregate); + } + } +} diff --git a/src/DNA/corlib/System.Threading.Tasks/TaskExtensions.cs b/src/DNA/corlib/System.Threading.Tasks/TaskExtensions.cs new file mode 100644 index 00000000..7bad665b --- /dev/null +++ b/src/DNA/corlib/System.Threading.Tasks/TaskExtensions.cs @@ -0,0 +1,89 @@ +// +// TaskExtensionsImpl.cs +// +// Authors: +// Jérémie "Garuma" Laval +// Marek Safar (marek.safar@gmail.com) +// +// Copyright (c) 2010 Jérémie "Garuma" Laval +// Copyright (C) 2013 Xamarin, Inc (http://www.xamarin.com) +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +namespace System.Threading.Tasks { + + static class TaskExtensions { + // const TaskContinuationOptions options = TaskContinuationOptions.ExecuteSynchronously; + + public static Task Unwrap (Task> task) { + var src = new TaskCompletionSource (); + task.ContinueWith ((t) => Cont (t, src)); + // task.ContinueWith ((t, arg) => Cont (t, (TaskCompletionSource) arg), src, CancellationToken.None, options, TaskScheduler.Current); + return src.Task; + } + + public static Task Unwrap (Task task) { + var src = new TaskCompletionSource (); + task.ContinueWith ((t) => Cont (t, src)); + // task.ContinueWith ((t, arg) => Cont (t, (TaskCompletionSource) arg), src, CancellationToken.None, options, TaskScheduler.Current); + return src.Task; + } + + static void SetResult (Task source, TaskCompletionSource dest) { + if (source.IsCanceled) + dest.TrySetCanceled (); + else if (source.IsFaulted) + dest.SetException (source.Exception.InnerExceptions); + else + dest.SetResult (null); + } + + static void Cont (Task source, TaskCompletionSource dest) { + if (source.IsCanceled) + dest.SetCanceled (); + else if (source.IsFaulted) + dest.SetException (source.Exception.InnerExceptions); + else + source.Result.ContinueWith ((t) => SetResult (t, dest)); + // source.Result.ContinueWith ((t, arg) => SetResult (t, (TaskCompletionSource) arg), dest, CancellationToken.None, options, TaskScheduler.Current); + } + + static void SetResult (Task source, TaskCompletionSource dest) { + if (source.IsCanceled) + dest.SetCanceled (); + else if (source.IsFaulted) + dest.SetException (source.Exception.InnerExceptions); + else + dest.SetResult (source.Result); + } + + static void Cont (Task> source, TaskCompletionSource dest) { + if (source.IsCanceled) + dest.SetCanceled (); + else if (source.IsFaulted) + dest.SetException (source.Exception.InnerExceptions); + else + source.Result.ContinueWith ((t) => SetResult (t, dest)); + // source.Result.ContinueWith ((t, arg) => SetResult (t, (TaskCompletionSource) arg), dest, CancellationToken.None, options, TaskScheduler.Current); + } + } +} + diff --git a/src/DNA/corlib/System.Threading/LazyThreadSafetyMode.cs b/src/DNA/corlib/System.Threading/LazyThreadSafetyMode.cs new file mode 100644 index 00000000..4c43cc5b --- /dev/null +++ b/src/DNA/corlib/System.Threading/LazyThreadSafetyMode.cs @@ -0,0 +1,40 @@ +// +// Lazy.cs +// +// Authors: +// Rodrigo Kumpera (kumpera@gmail.com) +// +// Copyright (C) 2010 Novell +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; + +namespace System.Threading +{ + public enum LazyThreadSafetyMode + { + None, + PublicationOnly, + ExecutionAndPublication + } +} + diff --git a/src/DNA/corlib/System.Threading/Tasks/TaskCompletionSource.cs b/src/DNA/corlib/System.Threading/Tasks/TaskCompletionSource.cs deleted file mode 100644 index 29f2c552..00000000 --- a/src/DNA/corlib/System.Threading/Tasks/TaskCompletionSource.cs +++ /dev/null @@ -1,62 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace System.Threading.Tasks -{ - public class TaskCompletionSource - { - private Task _task = new Task(); - - public Task Task => _task; - - void SetResult(T result) - { - _task.MarkCompleted(result); - } - - void SetException(Exception ex) - { - _task.MarkFailed(ex); - } - - public Task FromResult(T i) - { - return Task; - } - - // Note: Don't add a generic param here (e.g., TrySetResult) because it triggers - // some bug in the DNA runtime leading to crashes at the start of any method that contains - // a call to this. - internal bool TrySetResult(object result) - { - if (_task.IsCompleted) - { - return false; - } - else - { - _task.MarkCompleted(result); - return true; - } - } - - internal bool TrySetCanceled() - { - throw new NotImplementedException("Task cancellation"); - } - - internal bool TrySetException(Exception exception) - { - if (_task.IsCompleted) - { - return false; - } - else - { - _task.MarkFailed(exception); - return true; - } - } - } -} diff --git a/src/DNA/corlib/System.Threading/Thread.cs b/src/DNA/corlib/System.Threading/Thread.cs index 57c04aab..01414fd4 100644 --- a/src/DNA/corlib/System.Threading/Thread.cs +++ b/src/DNA/corlib/System.Threading/Thread.cs @@ -26,12 +26,12 @@ namespace System.Threading { public sealed class Thread { - // These member vars MUST be synced with C code. + // These member vars MUST be synced with C code. #pragma warning disable 0169, 0414, 0649 - private int managedThreadID = 0; + private int managedThreadID = 0; private MulticastDelegate threadStart = null; #pragma warning restore 0169, 0414, 0649 - private object param = null; + private object param = null; private ThreadState threadState = ThreadState.Unstarted; private CultureInfo currentCulture; @@ -97,6 +97,12 @@ public CultureInfo CurrentCulture { this.currentCulture = value; } } + + // [MethodImplAttribute(MethodImplOptions.InternalCall)] + // public static extern void MemoryBarrier(); + public static void MemoryBarrier() { + // does nothing + } } } diff --git a/src/DNA/corlib/System/Activator.cs b/src/DNA/corlib/System/Activator.cs index 10503a13..96f37ec7 100644 --- a/src/DNA/corlib/System/Activator.cs +++ b/src/DNA/corlib/System/Activator.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2012 DotNetAnywhere +// Copyright (c) 2012 DotNetAnywhere // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -26,8 +26,13 @@ namespace System { public static class Activator { - [MethodImpl(MethodImplOptions.InternalCall)] - public extern static object CreateInstance(Type type); - } + [MethodImpl(MethodImplOptions.InternalCall)] + public extern static object CreateInstance (Type type); + + public static T CreateInstance () { + return (T) CreateInstance (typeof (T)); + } + + } } diff --git a/src/DNA/corlib/System/AggregateException.cs b/src/DNA/corlib/System/AggregateException.cs index 2f925819..44b53091 100644 --- a/src/DNA/corlib/System/AggregateException.cs +++ b/src/DNA/corlib/System/AggregateException.cs @@ -2,12 +2,36 @@ using System.Collections.Generic; using System.Text; -namespace System -{ - public class AggregateException : Exception - { - public AggregateException(Exception exception) : base("Error occurred: " + exception.Message, exception) +namespace System { + + public class AggregateException : Exception { + + List _innerExceptions = new List (); + const string defaultMessage = "One or more errors occured"; + + public AggregateException(Exception exception) + : this(defaultMessage, exception) { + } + + public AggregateException (IEnumerable innerExceptions) + : this (defaultMessage, new List (innerExceptions).ToArray ()) + { + } + + public AggregateException (string message, params Exception[] innerExceptions) + : base (message, innerExceptions == null || innerExceptions.Length == 0 ? null : innerExceptions[0]) + { + if (innerExceptions == null) + throw new ArgumentNullException ("innerExceptions"); + foreach (var exception in innerExceptions) + if (exception == null) + throw new ArgumentException ("One of the inner exception is null", "innerExceptions"); + _innerExceptions.AddRange (innerExceptions); + } + + public IReadOnlyCollection InnerExceptions { + get { return _innerExceptions; } } } } diff --git a/src/DNA/corlib/System/ArgumentOutOfRangeException.cs b/src/DNA/corlib/System/ArgumentOutOfRangeException.cs index 875c6f19..8e286ccd 100644 --- a/src/DNA/corlib/System/ArgumentOutOfRangeException.cs +++ b/src/DNA/corlib/System/ArgumentOutOfRangeException.cs @@ -28,6 +28,11 @@ public ArgumentOutOfRangeException() : base("Argument is out of range.") { } public ArgumentOutOfRangeException(string paramName) : base("Argument is out of range.", paramName) { } public ArgumentOutOfRangeException(string paramName, string msg) : base(msg, paramName) { } + + public ArgumentOutOfRangeException(String paramName, Object actualValue, String message) + : base(message, paramName) + { + } } } diff --git a/src/DNA/corlib/System/ArithmeticException.cs b/src/DNA/corlib/System/ArithmeticException.cs index d31c3c3d..c9014b43 100644 --- a/src/DNA/corlib/System/ArithmeticException.cs +++ b/src/DNA/corlib/System/ArithmeticException.cs @@ -24,8 +24,8 @@ namespace System { public class ArithmeticException : SystemException { public ArithmeticException() : base("Overflow or underflow in the arithmetic operation.") { } - public ArithmeticException(string msg) : base(msg) { } - + public ArithmeticException(string message) : base(message) { } + public ArithmeticException(string message, Exception innerException) : base (message, innerException) { } } } diff --git a/src/DNA/corlib/System/Array.cs b/src/DNA/corlib/System/Array.cs index 88013d22..251d81ba 100644 --- a/src/DNA/corlib/System/Array.cs +++ b/src/DNA/corlib/System/Array.cs @@ -326,15 +326,88 @@ public static TOutput[] ConvertAll(TInput[] array, Converter(T[] array) where T: IComparable, IComparable { + Sort(array, 0, array.Length); + } - public static T[] Empty() - { - return (T[])CreateInstance(typeof(T), 0); - } + public static void Sort(T[] array, int index, int count) where T: IComparable, IComparable { + void swap(T[] a, int i, int j) { T t = a[i]; a[i] = a[j]; a[j] = t; } + int gap = count; + bool swapped; + do { + swapped = false; + gap = gap * 4 / 5; // 80% gap reduction + gap = gap < 1 ? 1 : (gap == 9 || gap == 10) ? 11 : gap; + for (int i = index; i < count - gap; ++i) { + if (array[i].CompareTo(array[i + gap]) > 0) { + swapped = true; + swap(array, i, i + gap); + } + } + } while (gap > 1 || swapped); + } - [MethodImpl(MethodImplOptions.InternalCall)] - extern public static Array CreateInstance(Type elementType, int length); + public static void Sort(T[] array, Comparison comparison) { + Sort(array, 0, array.Length, comparison); + } + + public static void Sort(T[] array, IComparer comparer) { + Sort(array, 0, array.Length, comparer); + } + + public static void Sort(T[] array, int index, int count, Comparison comparison) { + Sort(array, index, count, Comparer.Create(comparison)); + } + + public static void Sort(T[] array, int index, int count, IComparer comparer) { + void swap(T[] a, int i, int j) { T t = a[i]; a[i] = a[j]; a[j] = t; } + comparer = comparer ?? Comparer.Default; + int gap = count; + bool swapped; + do { + swapped = false; + gap = gap * 4 / 5; // 80% gap reduction + gap = gap < 1 ? 1 : (gap == 9 || gap == 10) ? 11 : gap; + for (int i = index; i < count - gap; ++i) { + if (comparer.Compare(array[i], array[i + gap]) > 0) { + swapped = true; + swap(array, i, i + gap); + } + } + } while (gap > 1 || swapped); + } + + public static void Sort(TKey[] keys, TValue[] items, IComparer comparer) { + Sort(keys, items, 0, keys.Length, comparer); + } + + public static void Sort(TKey[] keys, TValue[] items, int index, int count, IComparer comparer) { + void swap(V[] a, int i, int j) { V t = a[i]; a[i] = a[j]; a[j] = t; } + comparer = comparer ?? Comparer.Default; + int gap = count; + bool swapped; + do { + swapped = false; + gap = gap * 4 / 5; // 80% gap reduction + gap = gap < 1 ? 1 : (gap == 9 || gap == 10) ? 11 : gap; + for (int i = index; i < count - gap; ++i) { + if (comparer.Compare(keys[i], keys[i + gap]) > 0) { + swapped = true; + swap(keys, i, i + gap); + swap(items, i, i + gap); + } + } + } while (gap > 1 || swapped); + } + + public static T[] Empty() { + return (T[])CreateInstance(typeof(T), 0); + } + + [MethodImpl(MethodImplOptions.InternalCall)] + extern public static Array CreateInstance(Type elementType, int length); #region Interface Members diff --git a/src/DNA/corlib/System/Attribute.cs b/src/DNA/corlib/System/Attribute.cs index 83b3af6c..4b484598 100644 --- a/src/DNA/corlib/System/Attribute.cs +++ b/src/DNA/corlib/System/Attribute.cs @@ -18,10 +18,24 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. +using System.Collections.Generic; +using System.Reflection; + #if !LOCALTEST namespace System { public abstract class Attribute { + + public virtual object TypeId { + get { + return this.GetType(); + } + } + + public static IEnumerable GetCustomAttributes(MemberInfo element, bool inherit) + { + return null; + } } } diff --git a/src/DNA/corlib/System/AttributeTargets.cs b/src/DNA/corlib/System/AttributeTargets.cs index 77a98180..ea55153a 100644 --- a/src/DNA/corlib/System/AttributeTargets.cs +++ b/src/DNA/corlib/System/AttributeTargets.cs @@ -22,6 +22,7 @@ namespace System { + [Flags, Serializable] public enum AttributeTargets { Assembly = 0x00000001, Module = 0x00000002, diff --git a/src/DNA/corlib/System/BitConverter.cs b/src/DNA/corlib/System/BitConverter.cs index e66583ab..b371c36b 100644 --- a/src/DNA/corlib/System/BitConverter.cs +++ b/src/DNA/corlib/System/BitConverter.cs @@ -1,22 +1,318 @@ -#if !LOCALTEST +// Copyright (c) 2012 DotNetAnywhere +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +using System; using System.Runtime.CompilerServices; +using System.Text; + namespace System { + public static class BitConverter { + private static readonly bool SwappedWordsInDouble = DoubleWordsAreSwapped (); + public static readonly bool IsLittleEndian = AmILittleEndian (); + + static unsafe bool AmILittleEndian () { + // binary representations of 1.0: + // big endian: 3f f0 00 00 00 00 00 00 + // little endian: 00 00 00 00 00 00 f0 3f + // arm fpa little endian: 00 00 f0 3f 00 00 00 00 + double d = 1.0; + byte *b = (byte*)&d; + return (b [0] == 0); + } + + static unsafe bool DoubleWordsAreSwapped () { + // binary representations of 1.0: + // big endian: 3f f0 00 00 00 00 00 00 + // little endian: 00 00 00 00 00 00 f0 3f + // arm fpa little endian: 00 00 f0 3f 00 00 00 00 + double d = 1.0; + byte *b = (byte*)&d; + return b [2] == 0xf0; + } + + public unsafe static long DoubleToInt64Bits (double value) { + return *(long *) &value; + } + + public unsafe static double Int64BitsToDouble (long value) { + return *(double *) &value; + } + + unsafe static byte[] GetBytes (byte *ptr, int count) { + byte [] ret = new byte [count]; + for (int i = 0; i < count; i++) { + ret [i] = ptr [i]; + } + return ret; + } + + unsafe public static byte[] GetBytes (bool value) { + return GetBytes ((byte *) &value, 1); + } + + unsafe public static byte[] GetBytes (char value) { + return GetBytes ((byte *) &value, 2); + } + + unsafe public static byte[] GetBytes (short value) { + return GetBytes ((byte *) &value, 2); + } + + unsafe public static byte[] GetBytes (int value) { + return GetBytes ((byte *) &value, 4); + } - public static readonly bool IsLittleEndian = AmILittleEndian(); + unsafe public static byte[] GetBytes (long value) { + return GetBytes ((byte *) &value, 8); + } + + //[CLSCompliant (false)] + unsafe public static byte[] GetBytes (ushort value) { + return GetBytes ((byte *) &value, 2); + } + + //[CLSCompliant (false)] + unsafe public static byte[] GetBytes (uint value) { + return GetBytes ((byte *) &value, 4); + } + + //[CLSCompliant (false)] + unsafe public static byte[] GetBytes (ulong value) { + return GetBytes ((byte *) &value, 8); + } + + unsafe public static byte[] GetBytes (float value) { + return GetBytes ((byte *) &value, 4); + } + + unsafe public static byte[] GetBytes (double value) { + if (SwappedWordsInDouble) { + byte[] data = new byte [8]; + byte *p = (byte*)&value; + data [0] = p [4]; + data [1] = p [5]; + data [2] = p [6]; + data [3] = p [7]; + data [4] = p [0]; + data [5] = p [1]; + data [6] = p [2]; + data [7] = p [3]; + return data; + } else { + return GetBytes ((byte *) &value, 8); + } + } + + unsafe static void PutBytes (byte *dst, byte[] src, int start_index, int count) { + if (src == null) + throw new ArgumentNullException ("value"); + + if (start_index < 0 || (start_index > src.Length - 1)) + throw new ArgumentOutOfRangeException ("startIndex", "Index was" + + " out of range. Must be non-negative and less than the" + + " size of the collection."); + + // avoid integer overflow (with large pos/neg start_index values) + if (src.Length - count < start_index) + throw new ArgumentException ("Destination array is not long" + + " enough to copy all the items in the collection." + + " Check array index and length."); + + for (int i = 0; i < count; i++) + dst[i] = src[i + start_index]; + } + + unsafe public static bool ToBoolean (byte[] value, int startIndex) { + if (value == null) + throw new ArgumentNullException ("value"); + + if (startIndex < 0 || (startIndex > value.Length - 1)) + throw new ArgumentOutOfRangeException ("startIndex", "Index was" + + " out of range. Must be non-negative and less than the" + + " size of the collection."); + + if (value [startIndex] != 0) + return true; + + return false; + } - private unsafe static bool AmILittleEndian() { - int i = 1; - byte b = *((byte*)&i); - return (b == 1); + unsafe public static char ToChar (byte[] value, int startIndex) { + char ret; + PutBytes ((byte *) &ret, value, startIndex, 2); + return ret; } - public unsafe static long DoubleToInt64Bits(double value) { - return *((long*)&value); + unsafe public static short ToInt16 (byte[] value, int startIndex) { + short ret; + PutBytes ((byte *) &ret, value, startIndex, 2); + return ret; + } + + unsafe public static int ToInt32 (byte[] value, int startIndex) { + int ret; + PutBytes ((byte *) &ret, value, startIndex, 4); + return ret; + } + + unsafe public static long ToInt64 (byte[] value, int startIndex) { + long ret; + PutBytes ((byte *) &ret, value, startIndex, 8); + return ret; + } + + //[CLSCompliant (false)] + unsafe public static ushort ToUInt16 (byte[] value, int startIndex) { + ushort ret; + PutBytes ((byte *) &ret, value, startIndex, 2); + return ret; + } + + //[CLSCompliant (false)] + unsafe public static uint ToUInt32 (byte[] value, int startIndex) { + uint ret; + PutBytes ((byte *) &ret, value, startIndex, 4); + return ret; + } + + //[CLSCompliant (false)] + unsafe public static ulong ToUInt64 (byte[] value, int startIndex) { + ulong ret; + PutBytes ((byte *) &ret, value, startIndex, 8); + return ret; + } + + unsafe public static float ToSingle (byte[] value, int startIndex) { + float ret; + PutBytes ((byte *) &ret, value, startIndex, 4); + return ret; + } + + unsafe public static double ToDouble (byte[] value, int startIndex) { + double ret; + + if (SwappedWordsInDouble) { + byte* p = (byte*)&ret; + if (value == null) + throw new ArgumentNullException ("value"); + + if (startIndex < 0 || (startIndex > value.Length - 1)) + throw new ArgumentOutOfRangeException ("startIndex", "Index was" + + " out of range. Must be non-negative and less than the" + + " size of the collection."); + + // avoid integer overflow (with large pos/neg start_index values) + if (value.Length - 8 < startIndex) + throw new ArgumentException ("Destination array is not long" + + " enough to copy all the items in the collection." + + " Check array index and length."); + + p [0] = value [startIndex + 4]; + p [1] = value [startIndex + 5]; + p [2] = value [startIndex + 6]; + p [3] = value [startIndex + 7]; + p [4] = value [startIndex + 0]; + p [5] = value [startIndex + 1]; + p [6] = value [startIndex + 2]; + p [7] = value [startIndex + 3]; + + return ret; + } + + PutBytes ((byte *) &ret, value, startIndex, 8); + + return ret; + } + + public static string ToString (byte[] value) { + if (value == null) + throw new ArgumentNullException ("value"); + + return ToString (value, 0, value.Length); + } + + public static string ToString (byte[] value, int startIndex) { + if (value == null) + throw new ArgumentNullException ("value"); + + return ToString (value, startIndex, value.Length - startIndex); + } + + public static string ToString (byte[] value, int startIndex, int length) { + if (value == null) + throw new ArgumentNullException ("byteArray"); + + // The 4th and last clause (start_index >= value.Length) + // was added as a small fix to a very obscure bug. + // It makes a small difference when start_index is + // outside the range and length==0. + if (startIndex < 0 || startIndex >= value.Length) { + // special (but valid) case (e.g. new byte [0]) + if ((startIndex == 0) && (value.Length == 0)) + return String.Empty; + throw new ArgumentOutOfRangeException ("startIndex", "Index was" + + " out of range. Must be non-negative and less than the" + + " size of the collection."); + } + + if (length < 0) + throw new ArgumentOutOfRangeException ("length", + "Value must be positive."); + + // note: re-ordered to avoid possible integer overflow + if (startIndex > value.Length - length) + throw new ArgumentException ("startIndex + length > value.Length"); + + if (length == 0) + return string.Empty; + + StringBuilder builder = new StringBuilder(length * 3 - 1); + int end = startIndex + length; + + for (int i = startIndex; i < end; i++) { + if (i > startIndex) + builder.Append('-'); + + char high = (char)((value[i] >> 4) & 0x0f); + char low = (char)(value[i] & 0x0f); + + if (high < 10) + high += '0'; + else { + high -= (char) 10; + high += 'A'; + } + + if (low < 10) + low += '0'; + else { + low -= (char) 10; + low += 'A'; + } + builder.Append(high); + builder.Append(low); + } + + return builder.ToString (); } } } - -#endif diff --git a/src/DNA/corlib/System/Boolean.cs b/src/DNA/corlib/System/Boolean.cs index 56edc562..520481ad 100644 --- a/src/DNA/corlib/System/Boolean.cs +++ b/src/DNA/corlib/System/Boolean.cs @@ -26,11 +26,11 @@ public struct Boolean : IComparable, IComparable, IEquatable { public static readonly string TrueString = "True"; public static readonly string FalseString = "False"; -#pragma warning disable 0649 - internal bool m_value; -#pragma warning disable 0649 +#pragma warning disable 0169, 0649 + internal bool m_value; +#pragma warning restore 0169, 0649 - public override string ToString() { + public override string ToString() { return this.m_value ? TrueString : FalseString; } diff --git a/src/DNA/corlib/System/Byte.cs b/src/DNA/corlib/System/Byte.cs index 0ec79645..cd2592d7 100644 --- a/src/DNA/corlib/System/Byte.cs +++ b/src/DNA/corlib/System/Byte.cs @@ -7,10 +7,10 @@ public struct Byte : IFormattable, IComparable, IComparable, IEquatable, IEquatable { (char) 0x2006, (char) 0x2007, (char) 0x2008, (char) 0x2009, (char) 0x200A, (char) 0x200B, (char) 0x3000, (char) 0xFEFF }; -#pragma warning disable 0649 - internal char m_value; -#pragma warning restore 0649 +#pragma warning disable 0169, 0649 + internal char m_value; +#pragma warning restore 0169, 0649 - public override string ToString() { + public override string ToString() { return new string(m_value, 1); } @@ -54,37 +54,53 @@ public override int GetHashCode() { return (int)this.m_value; } - [MethodImpl(MethodImplOptions.InternalCall)] - extern static public UnicodeCategory GetUnicodeCategory(char c); - - public static UnicodeCategory GetUnicodeCategory(string str, int index) { + private static char GetChar(string str, int index) { if (str == null) { throw new ArgumentNullException("str"); } if (index < 0 || index >= str.Length) { throw new ArgumentOutOfRangeException("index"); } - return GetUnicodeCategory(str[index]); + return str[index]; + } + + [MethodImpl(MethodImplOptions.InternalCall)] + extern static public UnicodeCategory GetUnicodeCategory(char c); + + public static UnicodeCategory GetUnicodeCategory(string str, int index) { + return GetUnicodeCategory(GetChar(str, index)); + } + + private static bool IsLatin1(char c) => c <= '\x00ff'; + private static bool IsAscii(char c) => c <= '\x007f'; + + private static bool IsWhiteSpaceLatin1(char c) { + return (c == ' ') || (c >= '\x0009' && c <= '\x000d') || (c == '\x00a0') || (c == '\x0085'); } public static bool IsWhiteSpace(char c) { - // TODO: Make this use Array.BinarySearch() when implemented - for (int i = 0; i < WhiteChars.Length; i++) { - if (WhiteChars[i] == c) { + // // TODO: Make this use Array.BinarySearch() when implemented + // for (int i = 0; i < WhiteChars.Length; i++) { + // if (WhiteChars[i] == c) { + // return true; + // } + // } + + if (IsLatin1(c)) { + return (IsWhiteSpaceLatin1(c)); + } + switch (GetUnicodeCategory(c)) { + case (UnicodeCategory.SpaceSeparator): + case (UnicodeCategory.LineSeparator): + case (UnicodeCategory.ParagraphSeparator): return true; - } } + return false; } public static bool IsWhiteSpace(string str, int index) { - if (str == null) { - throw new ArgumentNullException("str"); - } - if (index < 0 || index >= str.Length) { - throw new ArgumentOutOfRangeException("index"); - } - return IsWhiteSpace(str[index]); + return IsWhiteSpace(GetChar(str, index)); } public static bool IsLetter(char c) { @@ -92,13 +108,7 @@ public static bool IsLetter(char c) { } public static bool IsLetter(string str, int index) { - if (str == null) { - throw new ArgumentNullException("str"); - } - if (index < 0 || index >= str.Length) { - throw new ArgumentOutOfRangeException("index"); - } - return IsLetter(str[index]); + return IsLetter(GetChar(str, index)); } public static bool IsDigit(char c) { @@ -106,13 +116,15 @@ public static bool IsDigit(char c) { } public static bool IsDigit(string str, int index) { - if (str == null) { - throw new ArgumentNullException("str"); - } - if (index < 0 || index >= str.Length) { - throw new ArgumentOutOfRangeException("index"); - } - return IsDigit(str[index]); + return IsDigit(GetChar(str, index)); + } + + public static bool IsLetterOrDigit(char c) { + return IsLetter(c) || IsDigit(c); + } + + public static bool IsLetterOrDigit(string str, int index) { + return IsLetter(str, index) || IsDigit(str, index); } public static bool IsLower(char c) { @@ -120,13 +132,7 @@ public static bool IsLower(char c) { } public static bool IsLower(string str, int index) { - if (str == null) { - throw new ArgumentNullException("str"); - } - if (index < 0 || index >= str.Length) { - throw new ArgumentOutOfRangeException("index"); - } - return IsLower(str[index]); + return IsLower(GetChar(str, index)); } public static bool IsUpper(char c) { @@ -134,20 +140,15 @@ public static bool IsUpper(char c) { } public static bool IsUpper(string str, int index) { - if (str == null) { - throw new ArgumentNullException("str"); - } - if (index < 0 || index >= str.Length) { - throw new ArgumentOutOfRangeException("index"); - } - return IsUpper(str[index]); + return IsUpper(GetChar(str, index)); } [MethodImpl(MethodImplOptions.InternalCall)] extern public static char ToLowerInvariant(char c); public static char ToLower(char c) { - return ToLower(c, CultureInfo.CurrentCulture); + // return ToLower(c, CultureInfo.CurrentCulture); + return ToLowerInvariant(c); //TODO: current culture } public static char ToLower(char c, CultureInfo culture) { @@ -166,7 +167,8 @@ public static char ToLower(char c, CultureInfo culture) { extern public static char ToUpperInvariant(char c); public static char ToUpper(char c) { - return ToUpper(c, CultureInfo.CurrentCulture); + // return ToUpper(c, CultureInfo.CurrentCulture); + return ToUpperInvariant(c); //TODO: current culture } public static char ToUpper(char c, CultureInfo culture) { diff --git a/src/DNA/corlib/System/Comparison.cs b/src/DNA/corlib/System/Comparison.cs new file mode 100644 index 00000000..a250305b --- /dev/null +++ b/src/DNA/corlib/System/Comparison.cs @@ -0,0 +1,4 @@ +namespace System +{ + public delegate int Comparison (T x, T y); +} \ No newline at end of file diff --git a/src/DNA/corlib/System/Console.cs b/src/DNA/corlib/System/Console.cs index 51150152..007fa4e8 100644 --- a/src/DNA/corlib/System/Console.cs +++ b/src/DNA/corlib/System/Console.cs @@ -45,6 +45,25 @@ public static class Console { [MethodImpl(MethodImplOptions.InternalCall)] extern private static bool Internal_KeyAvailable(); + sealed class InternalTextWriter : IO.TextWriter { + public override System.Text.Encoding Encoding { + get { + return System.Text.Encoding.Default; + } + } + + public override void Write(string s) { + Console.Write(s); + } + public override void Write(char value) { + Console.Write(value.ToString()); + } + } + + public static IO.TextWriter Error { get; } = new InternalTextWriter(); + + public static IO.TextWriter Out { get; } = new InternalTextWriter(); + #region Write Methods public static void Write(object value) { diff --git a/src/DNA/corlib/System/Converter.cs b/src/DNA/corlib/System/Converter.cs index fd598288..f790e8da 100644 --- a/src/DNA/corlib/System/Converter.cs +++ b/src/DNA/corlib/System/Converter.cs @@ -22,6 +22,30 @@ namespace System { public delegate TOutput Converter(TInput input); + + public class Convert { + public static int ToInt32(Byte b) => (int)b; + public static int ToInt32(Single f) => (int)f; + public static int ToInt32(Double d) => (int)d; + + public static int ToInt32(string value) { + return ToInt32(value, 0); // 0 makes it accept hex prefix + } + + public static int ToInt32(string value, int fromBase) { + if (value == null) { return 0; } + int error = 0; + int result = value.InternalToInt32(out error, fromBase); + if (error != 0) { throw String.GetFormatException(error); } + return result; + } + + public static uint ToUInt32(UInt64 i) => (uint)i; + + public static decimal ToDecimal(Int32 i) => throw new NotImplementedException(); + public static decimal ToDecimal(string str) => throw new NotImplementedException(); + + } } #endif diff --git a/src/DNA/corlib/System/Decimal.cs b/src/DNA/corlib/System/Decimal.cs index e290cc0d..488ba2f3 100644 --- a/src/DNA/corlib/System/Decimal.cs +++ b/src/DNA/corlib/System/Decimal.cs @@ -20,19 +20,83 @@ #if !LOCALTEST +using System.Globalization; namespace System { public struct Decimal { + // some constants + private const uint MAX_SCALE = 28; + private const uint SIGN_FLAG = 0x80000000; + private const int SCALE_SHIFT = 16; + private const uint RESERVED_SS32_BITS = 0x7F00FFFF; // internal representation of decimal #pragma warning disable 0169, 0649 - private uint flags; + private uint flags; private uint hi; private uint lo; private uint mid; #pragma warning restore 0169, 0649 - public static int[] GetBits(Decimal d) { - return new int[] { 0, 0, 0, 0 }; + public Decimal(int[] bits) { + if (bits == null || bits.Length != 4) { + throw new ArgumentException("bits"); + } + lo = (uint) bits[0]; + mid = (uint) bits[1]; + hi = (uint) bits[2]; + flags = (uint) bits[3]; + byte scale = (byte)(flags >> SCALE_SHIFT); + if (scale > MAX_SCALE || (flags & RESERVED_SS32_BITS) != 0) { + throw new ArgumentException ("Invalid bits[3]"); + } + } + + public static bool operator ==(Decimal d1, Decimal d2) { + return Equals(d1, d2); + } + + public static bool operator !=(Decimal d1, Decimal d2) { + return !Equals(d1, d2); + } + + public static Decimal operator -(Decimal d) { + d.flags ^= SIGN_FLAG; + return d; + } + + public static int[] GetBits(Decimal d) { + return new int[] { (int)d.lo, (int)d.mid, (int)d.hi, (int)d.flags }; + } + + public static bool Equals (Decimal d1, Decimal d2) { + return d1.lo == d2.lo && d1.mid == d2.mid && d1.hi == d2.hi && d1.flags == d2.flags; + } + + public override bool Equals (object value) { + if (!(value is Decimal)) + return false; + return Equals((Decimal) value, this); + } + + public override int GetHashCode () { + return (int) (flags ^ hi ^ lo ^ mid); + } + + public override string ToString() { + return ToString(null, null); + } + + public string ToString(IFormatProvider fp) { + return ToString(null, fp); + } + + public string ToString(string format) { + return ToString(format, null); + } + + public string ToString(string format, IFormatProvider fp) { + NumberFormatInfo nfi = NumberFormatInfo.GetInstance(fp); + return NumberFormatter.NumberToString(format, this, nfi); } } diff --git a/src/DNA/corlib/System/DivideByZeroException.cs b/src/DNA/corlib/System/DivideByZeroException.cs new file mode 100644 index 00000000..e7ea0410 --- /dev/null +++ b/src/DNA/corlib/System/DivideByZeroException.cs @@ -0,0 +1,69 @@ +// +// System.DivideByZeroException.cs +// +// Authors: +// Joe Shaw (joe@ximian.com) +// Andreas Nahr (ClassDevelopment@A-SoftTech.com) +// +// (C) 2001 Ximian, Inc. http://www.ximian.com +// + +// +// Copyright (C) 2004 Novell, Inc (http://www.novell.com) +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +// using System.Runtime.Serialization; +using System.Runtime.InteropServices; + +namespace System +{ + [Serializable] + // [ComVisible (true)] + public class DivideByZeroException : ArithmeticException + { + const int Result = unchecked ((int)0x80020012); + + // Constructors + public DivideByZeroException () + : base ("Division by zero") + { + HResult = Result; + } + + public DivideByZeroException (string message) + : base (message) + { + HResult = Result; + } + + public DivideByZeroException (string message, Exception innerException) + : base (message, innerException) + { + HResult = Result; + } + + // protected DivideByZeroException (SerializationInfo info, StreamingContext context) + // : base (info, context) + // { + // } + } +} diff --git a/src/DNA/corlib/System/Double.cs b/src/DNA/corlib/System/Double.cs index 97b13714..ac828c62 100644 --- a/src/DNA/corlib/System/Double.cs +++ b/src/DNA/corlib/System/Double.cs @@ -31,7 +31,9 @@ public struct Double : IFormattable, IComparable, IComparable, IEquatabl public const double NegativeInfinity = -1.0d / 0.0d; public const double PositiveInfinity = 1.0d / 0.0d; +#pragma warning disable 0169, 0649 internal double m_value; +#pragma warning restore 0169, 0649 public static bool IsNaN(double d) { #pragma warning disable 1718 @@ -61,28 +63,77 @@ public override bool Equals(object o) { return ((double)o) == this.m_value; } - public override unsafe int GetHashCode() { + public override int GetHashCode() { double d = m_value; - return (*((long*)&d)).GetHashCode(); + return BitConverter.DoubleToInt64Bits(d).GetHashCode(); } + #region Parsing + + public static double Parse(string s) { + return Parse(s, NumberStyles.Float, null); + } + + public static double Parse(string s, NumberStyles style) { + return Parse(s, style, null); + } + + public static double Parse(string s, IFormatProvider formatProvider) { + return Parse(s, NumberStyles.Float, formatProvider); + } + + public static double Parse(string s, NumberStyles style, IFormatProvider formatProvider) { + if (s == null) { + throw new ArgumentNullException(); + } + //TODO: use style and provider + int error = 0; + double result = s.InternalToDouble(out error); + if (error != 0) { + throw String.GetFormatException(error); + } + return result; + } + + public static bool TryParse(string s, out double result) { + return TryParse(s, NumberStyles.Float, null, out result); + } + + public static bool TryParse(string s, NumberStyles style, IFormatProvider provider, out double result) { + if (s == null) { + result = 0; + return false; + } + //TODO: use style and provider + int error; + result = s.InternalToDouble(out error); + return error == 0; + } + + #endregion + + #region ToString methods + public override string ToString() { - return ToString(null, null); + // return ToString(null, null); + return String.InternalFromDouble(this.m_value); } - public string ToString(IFormatProvider fp) { - return ToString(null, fp); + public string ToString(IFormatProvider formatProvider) { + return ToString(null, formatProvider); } public string ToString(string format) { return ToString(format, null); } - public string ToString(string format, IFormatProvider fp) { - NumberFormatInfo nfi = NumberFormatInfo.GetInstance(fp); + public string ToString(string format, IFormatProvider formatProvider) { + NumberFormatInfo nfi = NumberFormatInfo.GetInstance(formatProvider); return NumberFormatter.NumberToString(format, this.m_value, nfi); } + #endregion + #region IComparable Members public int CompareTo(object obj) { diff --git a/src/DNA/corlib/System/IObservable.cs b/src/DNA/corlib/System/IObservable.cs new file mode 100644 index 00000000..9a30ef9c --- /dev/null +++ b/src/DNA/corlib/System/IObservable.cs @@ -0,0 +1,36 @@ +// +// IObservable.cs +// +// Authors: +// Marek Safar +// +// Copyright (C) 2009 Novell, Inc (http://www.novell.com) +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +namespace System +{ + public interface IObservable + { + IDisposable Subscribe (IObserver observer); + } +} + diff --git a/src/DNA/corlib/System/IObserver.cs b/src/DNA/corlib/System/IObserver.cs new file mode 100644 index 00000000..e002c9ba --- /dev/null +++ b/src/DNA/corlib/System/IObserver.cs @@ -0,0 +1,38 @@ +// +// IObserver.cs +// +// Authors: +// Marek Safar +// +// Copyright (C) 2009 Novell, Inc (http://www.novell.com) +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +namespace System +{ + public interface IObserver + { + void OnCompleted (); + void OnError (Exception error); + void OnNext(T value); + } +} + diff --git a/src/DNA/corlib/System/Int16.cs b/src/DNA/corlib/System/Int16.cs index 3409c699..1d64447b 100644 --- a/src/DNA/corlib/System/Int16.cs +++ b/src/DNA/corlib/System/Int16.cs @@ -27,10 +27,10 @@ public struct Int16 : IFormattable, IComparable, IComparable, IEquatable< public const short MinValue = -32768; #pragma warning disable 0169, 0649 - internal short m_value; + internal short m_value; #pragma warning restore 0169, 0649 - public override bool Equals(object obj) { + public override bool Equals(object obj) { return (obj is short) && ((short)obj).m_value == this.m_value; } @@ -38,8 +38,11 @@ public override int GetHashCode() { return (int)this.m_value; } + #region ToString methods + public override string ToString() { - return NumberFormatter.FormatGeneral(new NumberFormatter.NumberStore(this.m_value)); + // return NumberFormatter.FormatGeneral(new NumberFormatter.NumberStore(this.m_value)); + return String.InternalFromInt32(this.m_value); } public string ToString(IFormatProvider formatProvider) { @@ -47,14 +50,16 @@ public string ToString(IFormatProvider formatProvider) { } public string ToString(string format) { - return ToString(format, null); + return this.ToString(format, null); } public string ToString(string format, IFormatProvider formatProvider) { NumberFormatInfo nfi = NumberFormatInfo.GetInstance(formatProvider); - return NumberFormatter.NumberToString(format, m_value, nfi); + return NumberFormatter.NumberToString(format, this.m_value, nfi); } + #endregion + #region IComparable Members public int CompareTo(object obj) { diff --git a/src/DNA/corlib/System/Int32.cs b/src/DNA/corlib/System/Int32.cs index 428d19b3..820b65c8 100644 --- a/src/DNA/corlib/System/Int32.cs +++ b/src/DNA/corlib/System/Int32.cs @@ -9,7 +9,9 @@ public struct Int32 : IFormattable, IComparable, IComparable,IEquatable, IEquatable> 32); } + #region Parse methods + + public static long Parse(string s) { + return Parse(s, NumberStyles.Integer, null); + } + + public static long Parse(string s, NumberStyles style) { + return Parse(s, style, null); + } + + public static long Parse(string s, IFormatProvider formatProvider) { + return Parse(s, NumberStyles.Integer, formatProvider); + } + + public static long Parse(string s, NumberStyles style, IFormatProvider formatProvider) { + if (s == null) { + throw new ArgumentNullException(); + } + //TODO: use style and provider + int error = 0; + int radix = (style & NumberStyles.AllowHexSpecifier) != 0 ? 16 : 10; + long result = s.InternalToInt64(out error, radix); + if (error != 0) { + throw String.GetFormatException(error); + } + return result; + } + + public static bool TryParse(string s, out long result) { + return TryParse(s, NumberStyles.Integer, null, out result); + } + + private static bool TryParse(string s, NumberStyles style, IFormatProvider provider, out long result) { + if (s == null) { + result = 0; + return false; + } + //TODO: use style and provider + int error = 0; + int radix = (style & NumberStyles.AllowHexSpecifier) != 0 ? 16 : 10; + result = s.InternalToInt64(out error, radix); + return error == 0; + } + + #endregion + + #region ToString methods + public override string ToString() { - return NumberFormatter.FormatGeneral(new NumberFormatter.NumberStore(this.m_value)); + // return NumberFormatter.FormatGeneral(new NumberFormatter.NumberStore(this.m_value)); + return String.InternalFromInt64(this.m_value); } public string ToString(IFormatProvider formatProvider) { @@ -48,14 +97,16 @@ public string ToString(IFormatProvider formatProvider) { } public string ToString(string format) { - return ToString(format, null); + return this.ToString(format, null); } public string ToString(string format, IFormatProvider formatProvider) { NumberFormatInfo nfi = NumberFormatInfo.GetInstance(formatProvider); - return NumberFormatter.NumberToString(format, m_value, nfi); + return NumberFormatter.NumberToString(format, this.m_value, nfi); } + #endregion + #region IComparable Members public int CompareTo(object obj) { diff --git a/src/DNA/corlib/System/Lazy.cs b/src/DNA/corlib/System/Lazy.cs new file mode 100644 index 00000000..d98f3df6 --- /dev/null +++ b/src/DNA/corlib/System/Lazy.cs @@ -0,0 +1,180 @@ +// +// Lazy.cs +// +// Authors: +// Zoltan Varga (vargaz@gmail.com) +// Marek Safar (marek.safar@gmail.com) +// +// Copyright (C) 2009 Novell +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +// using System.Runtime.Serialization; +using System.Runtime.InteropServices; +// using System.Security.Permissions; +using System.Threading; +using System.Diagnostics; + +namespace System { + + // [SerializableAttribute] + // [ComVisibleAttribute(false)] + // [HostProtectionAttribute(SecurityAction.LinkDemand, Synchronization = true, ExternalThreading = true)] + // [DebuggerDisplay ("ThreadSafetyMode={Mode}, IsValueCreated={IsValueCreated}, IsValueFaulted={IsValueFaulted}, Value={ValueForDebugDisplay}")] + public class Lazy { + T value; + Func factory; + object monitor; + Exception exception; + LazyThreadSafetyMode mode; + bool inited; + + public Lazy () + : this (LazyThreadSafetyMode.ExecutionAndPublication) + { + } + + public Lazy (Func valueFactory) + : this (valueFactory, LazyThreadSafetyMode.ExecutionAndPublication) + { + } + + public Lazy (bool isThreadSafe) + : this (() => Activator.CreateInstance (), isThreadSafe ? LazyThreadSafetyMode.ExecutionAndPublication : LazyThreadSafetyMode.None) + { + } + + public Lazy (Func valueFactory, bool isThreadSafe) + : this (valueFactory, isThreadSafe ? LazyThreadSafetyMode.ExecutionAndPublication : LazyThreadSafetyMode.None) + { + } + + public Lazy (LazyThreadSafetyMode mode) + : this (() => Activator.CreateInstance (), mode) + { + } + + public Lazy (Func valueFactory, LazyThreadSafetyMode mode) { + if (valueFactory == null) + throw new ArgumentNullException ("valueFactory"); + this.factory = valueFactory; + if (mode != LazyThreadSafetyMode.None) + monitor = new object (); + this.mode = mode; + } + + // Don't trigger expensive initialization + // [DebuggerBrowsable (DebuggerBrowsableState.Never)] + public T Value { + get { + if (inited) + return value; + if (exception != null) + throw exception; + + return InitValue (); + } + } + + T InitValue () { + Func init_factory; + T v; + + switch (mode) { + case LazyThreadSafetyMode.None: + init_factory = factory; + if (init_factory == null) + throw exception = new InvalidOperationException ("The initialization function tries to access Value on this instance"); + try { + factory = null; + v = init_factory (); + value = v; + Thread.MemoryBarrier (); + inited = true; + } catch (Exception ex) { + exception = ex; + throw; + } + break; + + case LazyThreadSafetyMode.PublicationOnly: + init_factory = factory; + + //exceptions are ignored + if (init_factory != null) + v = init_factory (); + else + v = default (T); + + lock (monitor) { + if (inited) + return value; + value = v; + Thread.MemoryBarrier (); + inited = true; + factory = null; + } + break; + + case LazyThreadSafetyMode.ExecutionAndPublication: + lock (monitor) { + if (inited) + return value; + + if (factory == null) + throw exception = new InvalidOperationException ("The initialization function tries to access Value on this instance"); + + init_factory = factory; + try { + factory = null; + v = init_factory (); + value = v; + Thread.MemoryBarrier (); + inited = true; + } catch (Exception ex) { + exception = ex; + throw; + } + } + break; + + default: + throw new InvalidOperationException ("Invalid LazyThreadSafetyMode " + mode); + } + + return value; + } + + public bool IsValueCreated { + get { + return inited; + } + } + + public override string ToString () { + if (inited) + return value.ToString (); + else + return "Value is not created"; + } + } +} diff --git a/src/DNA/corlib/System/Math.cs b/src/DNA/corlib/System/Math.cs index 9b3e1f59..0654b79a 100644 --- a/src/DNA/corlib/System/Math.cs +++ b/src/DNA/corlib/System/Math.cs @@ -219,5 +219,14 @@ public static int Sign(double v) { [MethodImplAttribute(MethodImplOptions.InternalCall)] public extern static double Sqrt(double x); + + [MethodImplAttribute(MethodImplOptions.InternalCall)] + public static extern double Ceiling(double a); + + [MethodImplAttribute(MethodImplOptions.InternalCall)] + public static extern double Floor(double d); + + [MethodImplAttribute(MethodImplOptions.InternalCall)] + public static extern double Round(double d); } } diff --git a/src/DNA/corlib/System/NumberFormatter.cs b/src/DNA/corlib/System/NumberFormatter.cs index 1095defe..e9cd2e72 100644 --- a/src/DNA/corlib/System/NumberFormatter.cs +++ b/src/DNA/corlib/System/NumberFormatter.cs @@ -1554,20 +1554,17 @@ public NumberStore(byte value) } public NumberStore(double value) { - _digits = null; + _digits = new byte[] {}; _defByteSize = 64; _defPrecision = 15; _defMaxPrecision = _defPrecision + 2; + _NaN = double.IsNaN(value); + _infinity = double.IsInfinity(value); + _positive = value > 0; + _decPointPos = 0; - if (double.IsNaN(value) || double.IsInfinity(value)) { - _NaN = double.IsNaN(value); - _infinity = double.IsInfinity(value); - _positive = value > 0; - _decPointPos = 0; + if (_NaN || _infinity) return; - } else { - _NaN = _infinity = false; - } long bits = BitConverter.DoubleToInt64Bits(value); _positive = (bits >= 0); @@ -1583,7 +1580,7 @@ public NumberStore(double value) { if (e == 0) { e++; - } else if (e != 0) { + } else { m |= (1L << 52); } @@ -1610,13 +1607,13 @@ public NumberStore(double value) { if (e >= 0) { for (int i = 0; i < e; i++) { - if (MultiplyBy(ref temp, ref length, 2)) { + if (MultiplyBy(temp, ref length, 2)) { _decPointPos++; } } } else { for (int i = 0; i < -e; i++) { - if (MultiplyBy(ref temp, ref length, 5)) { + if (MultiplyBy(temp, ref length, 5)) { _decPointPos++; } } @@ -1641,20 +1638,19 @@ public NumberStore(double value) { RoundEffectiveDigits(17, true, true); } + public NumberStore(float value) { - _digits = null; + _digits = new byte[] {}; _defByteSize = 32; _defPrecision = 7; _defMaxPrecision = _defPrecision + 2; + _NaN = float.IsNaN(value); + _infinity = float.IsInfinity(value); + _positive = value > 0; + _decPointPos = 0; - if (float.IsNaN(value) || float.IsInfinity(value)) { - _NaN = float.IsNaN(value); - _infinity = float.IsInfinity(value); - _positive = value > 0; - _decPointPos = 0; + if (_NaN || _infinity) return; - } else - _infinity = _NaN = false; long bits = BitConverter.DoubleToInt64Bits(value); _positive = (bits >= 0); @@ -1670,7 +1666,7 @@ public NumberStore(float value) { if (e == 0) { e++; - } else if (e != 0) { + } else { m |= (1L << 52); } @@ -1697,13 +1693,13 @@ public NumberStore(float value) { if (e >= 0) { for (int i = 0; i < e; i++) { - if (MultiplyBy(ref temp, ref length, 2)) { + if (MultiplyBy(temp, ref length, 2)) { _decPointPos++; } } } else { for (int i = 0; i < -e; i++) { - if (MultiplyBy(ref temp, ref length, 5)) { + if (MultiplyBy(temp, ref length, 5)) { _decPointPos++; } } @@ -1729,7 +1725,7 @@ public NumberStore(float value) { RoundEffectiveDigits(9, true, true); } - internal bool MultiplyBy(ref byte[] buffer, ref int length, int amount) { + internal bool MultiplyBy(byte[] buffer, ref int length, int amount) { int mod = 0; int ret; int start = buffer.Length - length - 1; diff --git a/src/DNA/corlib/System/OperationCanceledException.cs b/src/DNA/corlib/System/OperationCanceledException.cs index 8101be69..e4d49ae7 100644 --- a/src/DNA/corlib/System/OperationCanceledException.cs +++ b/src/DNA/corlib/System/OperationCanceledException.cs @@ -2,9 +2,9 @@ using System.Collections.Generic; using System.Text; -namespace System -{ - public class OperationCanceledException : Exception - { +namespace System { + public class OperationCanceledException : Exception { + public OperationCanceledException(String message) + : base(message) { } } } diff --git a/src/DNA/corlib/System/RuntimeType.cs b/src/DNA/corlib/System/RuntimeType.cs index 06b19fae..98098b82 100644 --- a/src/DNA/corlib/System/RuntimeType.cs +++ b/src/DNA/corlib/System/RuntimeType.cs @@ -20,13 +20,14 @@ #if !LOCALTEST +using System.Reflection; using System.Runtime.CompilerServices; using System.Text; using System.Collections.Generic; namespace System { - class RuntimeType : Type { + sealed class RuntimeType : Type { [MethodImpl(MethodImplOptions.InternalCall)] extern private RuntimeType GetNestingParentType(); @@ -54,6 +55,8 @@ extern public override string Name { get; } + public override string AssemblyQualifiedName => FullName; + public override string FullName { get { StringBuilder ret = new StringBuilder(32); @@ -93,10 +96,29 @@ public override Type GetGenericTypeDefinition() { [MethodImpl(MethodImplOptions.InternalCall)] extern public override Type[] GetGenericArguments(); - [MethodImpl(MethodImplOptions.InternalCall)] - extern public override Type GetElementType(); + [MethodImpl(MethodImplOptions.InternalCall)] + extern public override bool IsDefined(Type attributeType, bool inherit); + + public override Object[] GetCustomAttributes(bool inherit) + { + return Internal_GetCustomAttributes(null, inherit); + } + + public override Object[] GetCustomAttributes(Type attributeType, bool inherit) + { + if (attributeType == null) + throw new ArgumentNullException(); + + return Internal_GetCustomAttributes(attributeType, inherit); + } + + [MethodImpl(MethodImplOptions.InternalCall)] + extern private Object[] Internal_GetCustomAttributes(Type attributeType, bool inherit); + + [MethodImpl(MethodImplOptions.InternalCall)] + extern public override Type GetElementType(); - } + } } diff --git a/src/DNA/corlib/System/SByte.cs b/src/DNA/corlib/System/SByte.cs index df97ff40..6060ff7e 100644 --- a/src/DNA/corlib/System/SByte.cs +++ b/src/DNA/corlib/System/SByte.cs @@ -27,10 +27,10 @@ public struct SByte : IFormattable, IComparable, IComparable, IEquatable< public const sbyte MaxValue = 127; #pragma warning disable 0169, 0649 - internal sbyte m_value; + internal sbyte m_value; #pragma warning restore 0169, 0649 - public override bool Equals(object obj) { + public override bool Equals(object obj) { return (obj is sbyte) && ((sbyte)obj).m_value == this.m_value; } @@ -41,7 +41,8 @@ public override int GetHashCode() { #region ToString methods public override string ToString() { - return NumberFormatter.FormatGeneral(new NumberFormatter.NumberStore(this.m_value)); + // return NumberFormatter.FormatGeneral(new NumberFormatter.NumberStore(this.m_value)); + return String.InternalFromInt32(this.m_value); } public string ToString(IFormatProvider formatProvider) { diff --git a/src/DNA/corlib/System/SerializableAttribute.cs b/src/DNA/corlib/System/SerializableAttribute.cs new file mode 100644 index 00000000..99b8cbcb --- /dev/null +++ b/src/DNA/corlib/System/SerializableAttribute.cs @@ -0,0 +1,31 @@ +// Copyright (c) 2012 DotNetAnywhere +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#if !LOCALTEST + +namespace System { + + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Delegate, Inherited = false)] + public sealed class SerializableAttribute : Attribute { + } + +} + +#endif \ No newline at end of file diff --git a/src/DNA/corlib/System/Single.cs b/src/DNA/corlib/System/Single.cs index 919d78e9..0c45fa9c 100644 --- a/src/DNA/corlib/System/Single.cs +++ b/src/DNA/corlib/System/Single.cs @@ -31,7 +31,9 @@ public struct Single : IFormattable, IComparable, IComparable, IEquatable public const float PositiveInfinity = 1.0f / 0.0f; public const float NegativeInfinity = -1.0f / 0.0f; +#pragma warning disable 0169, 0649 private float m_value; +#pragma warning restore 0169, 0649 public static bool IsNaN(float f) { #pragma warning disable 1718 @@ -61,28 +63,77 @@ public override bool Equals(object o) { return ((float)o).m_value == this.m_value; } - public unsafe override int GetHashCode() { + public override int GetHashCode() { float f = this.m_value; - return (*((int*)&f)).GetHashCode(); + return BitConverter.DoubleToInt64Bits(f).GetHashCode(); } + #region Parsing + + public static float Parse(string s) { + return Parse(s, NumberStyles.Float, null); + } + + public static float Parse(string s, NumberStyles style) { + return Parse(s, style, null); + } + + public static float Parse(string s, IFormatProvider formatProvider) { + return Parse(s, NumberStyles.Float, formatProvider); + } + + public static float Parse(string s, NumberStyles style, IFormatProvider formatProvider) { + if (s == null) { + throw new ArgumentNullException(); + } + //TODO: use style and provider + int error = 0; + float result = s.InternalToSingle(out error); + if (error != 0) { + throw String.GetFormatException(error); + } + return result; + } + + public static bool TryParse(string s, out float result) { + return TryParse(s, NumberStyles.Float, null, out result); + } + + public static bool TryParse(string s, NumberStyles style, IFormatProvider provider, out float result) { + if (s == null) { + result = 0; + return false; + } + //TODO: use style and provider + int error; + result = s.InternalToSingle(out error); + return error == 0; + } + + #endregion + + #region ToString methods + public override string ToString() { - return ToString(null, null); + // return ToString(null, null); + return String.InternalFromSingle(this.m_value); } - public string ToString(IFormatProvider provider) { - return ToString(null, provider); + public string ToString(IFormatProvider formatProvider) { + return ToString(null, formatProvider); } public string ToString(string format) { return ToString(format, null); } - public string ToString(string format, IFormatProvider provider) { - NumberFormatInfo nfi = NumberFormatInfo.GetInstance(provider); + public string ToString(string format, IFormatProvider formatProvider) { + NumberFormatInfo nfi = NumberFormatInfo.GetInstance(formatProvider); return NumberFormatter.NumberToString(format, this.m_value, nfi); } + #endregion + #region IComparable Members public int CompareTo(object obj) { diff --git a/src/DNA/corlib/System/String.cs b/src/DNA/corlib/System/String.cs index b0c1efa5..78dddc5d 100644 --- a/src/DNA/corlib/System/String.cs +++ b/src/DNA/corlib/System/String.cs @@ -33,7 +33,11 @@ public class String : ICloneable, IEnumerable, IEnumerable, public static readonly string Empty = ""; public static bool IsNullOrEmpty(string value) { - return (value == null) || (value.length == 0); + return (value == null) || (value.Length == 0); + } + + public static bool IsNullOrWhiteSpace(string value) { + return (value == null) || IsNullOrEmpty(value.Trim()); } // This field must be the only field, to tie up with C code @@ -56,6 +60,9 @@ public static bool IsNullOrEmpty(string value) { [MethodImpl(MethodImplOptions.InternalCall)] extern private static string InternalConcat(string str0, string str1); + [MethodImpl(MethodImplOptions.InternalCall)] + extern private void InternalCopyTo(int sourceIndex, char[] destination, int destinationIndex, int count); + [MethodImpl(MethodImplOptions.InternalCall)] extern private string InternalReplace(string oldValue, string newValue); @@ -64,11 +71,14 @@ public static bool IsNullOrEmpty(string value) { extern private string InternalTrim(char[] trimChars, int trimType); [MethodImpl(MethodImplOptions.InternalCall)] - extern private int InternalIndexOf(char value, int startIndex, int count, bool forwards); + extern private int InternalIndexOf(char value, int startIndex, int count, bool forward); [MethodImpl(MethodImplOptions.InternalCall)] extern private int InternalIndexOfAny(char[] anyOf, int startIndex, int count, bool forward); + [MethodImpl(MethodImplOptions.InternalCall)] + extern private int InternalIndexOfStr(string value, int startIndex, int count, bool forward); + #endregion public virtual int Length { @@ -85,14 +95,33 @@ extern virtual public char this[int index] { #region Misc Methods - public static string Join(string separator, string[] value) { - return Join(separator, value, 0, value.Length); + public char[] ToCharArray () { + char[] chars = new char [this.length]; + InternalCopyTo(0, chars, 0, this.length); + return chars; + } + + public static string Join(string separator, string[] values) { + return Join(separator, values, 0, values.Length); + } + + public static string Join(string separator, IEnumerable values) { + return Join(separator, values); } - public static string Join(string separator, string[] value, int startIndex, int count) { + public static string Join(string separator, string[] values, int startIndex, int count) { StringBuilder sb = new StringBuilder(); for (int i = startIndex; i < count; i++) { - sb.Append(value[i]); + sb.Append(values[i]); + sb.Append(separator); + } + return sb.ToString(0, sb.Length - separator.Length); + } + + public static string Join(string separator, IEnumerable values) { + StringBuilder sb = new StringBuilder(); + foreach(var v in values) { + sb.Append(v); sb.Append(separator); } return sb.ToString(0, sb.Length - separator.Length); @@ -102,7 +131,19 @@ public string[] Split(params char[] separator) { return this.Split(separator, int.MaxValue); } + public string[] Split(char separator, StringSplitOptions options) { + return this.Split(new char[] { separator }, int.MaxValue, options); + } + + public string[] Split(char[] separator, StringSplitOptions options) { + return this.Split(separator, int.MaxValue, options); + } + public string[] Split(char[] separator, int count) { + return this.Split(separator, count, StringSplitOptions.None); + } + + public string[] Split(char[] separator, int count, StringSplitOptions options) { if (count < 0) { throw new ArgumentException("count"); } @@ -122,7 +163,9 @@ public string[] Split(char[] separator, int count) { ret.Add(new string(this, pos, this.length - pos)); break; } - ret.Add(new string(this, pos, sepPos - pos)); + if (options != StringSplitOptions.RemoveEmptyEntries || sepPos > pos) { + ret.Add(new string(this, pos, sepPos - pos)); + } pos = sepPos + 1; } @@ -130,11 +173,43 @@ public string[] Split(char[] separator, int count) { } public bool StartsWith(string str) { - return this.Substring(0, str.length) == str; + return this.length < str.Length ? false : this.Substring(0, str.Length) == str; } public bool EndsWith(string str) { - return this.Substring(this.length - str.length, str.length) == str; + return this.length < str.Length ? false : this.Substring(this.length - str.Length, str.Length) == str; + } + + public bool StartsWith(string str, StringComparison comparisonType) { + switch (comparisonType) { + case StringComparison.CurrentCulture: + case StringComparison.InvariantCulture: + case StringComparison.Ordinal: + return StartsWith(str); + case StringComparison.CurrentCultureIgnoreCase: + throw new Exception("String.StartsWith(s,StringComparison.CurrentCultureIgnoreCase) is not implemented."); + case StringComparison.InvariantCultureIgnoreCase: + case StringComparison.OrdinalIgnoreCase: + return this.ToUpperInvariant().StartsWith(str.ToUpperInvariant()); + default: + throw new ArgumentException ("comparisonType"); + } + } + + public bool EndsWith(string str, StringComparison comparisonType) { + switch (comparisonType) { + case StringComparison.CurrentCulture: + case StringComparison.InvariantCulture: + case StringComparison.Ordinal: + return EndsWith(str); + case StringComparison.CurrentCultureIgnoreCase: + throw new Exception("String.EndsWith(s,StringComparison.CurrentCultureIgnoreCase) is not implemented."); + case StringComparison.InvariantCultureIgnoreCase: + case StringComparison.OrdinalIgnoreCase: + return this.ToUpperInvariant().EndsWith(str.ToUpperInvariant()); + default: + throw new ArgumentException ("comparisonType"); + } } #endregion @@ -160,30 +235,28 @@ public static string Concat(string str0, string str1, string str2, string str3) } public static string Concat(params string[] values) { + return Concat((IEnumerable)values); + } + + public static string Concat(IEnumerable values) { if (values == null) { - throw new ArgumentNullException("args"); - } - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < values.Length; i++) { - sb.Append(values[i]); + throw new ArgumentNullException("values"); } + int capacity = 0; + foreach (var s in values) { if (s != null) { capacity += s.Length; } } + StringBuilder sb = new StringBuilder(capacity); + foreach (var s in values) { if (s != null) { sb.Append(s); } } return sb.ToString(); } public static string Concat(object obj0) { - return obj0.ToString(); + return (obj0 == null) ? null : obj0.ToString(); } public static string Concat(object obj0, object obj1) { string str0 = (obj0 == null) ? null : obj0.ToString(); string str1 = (obj1 == null) ? null : obj1.ToString(); - if (str0 == null) { - return str1 ?? string.Empty; - } - if (str1 == null) { - return str0; - } - return InternalConcat(str0, str1); + return Concat(str0, str1); } public static string Concat(object obj0, object obj1, object obj2) { @@ -194,13 +267,13 @@ public static string Concat(object obj0, object obj1, object obj2, object obj3) return Concat(new object[] { obj0, obj1, obj2, obj3 }); } - public static string Concat(params object[] objs) { - if (objs == null) { - throw new ArgumentNullException("args"); + public static string Concat(params object[] values) { + if (values == null) { + throw new ArgumentNullException("values"); } StringBuilder sb = new StringBuilder(); - for (int i = 0; i < objs.Length; i++) { - sb.Append(objs[i]); + for (int i = 0; i < values.Length; i++) { + sb.Append(values[i]); } return sb.ToString(); } @@ -320,24 +393,27 @@ public string Remove(int startIndex, int count) { return (new string(this, 0, startIndex)) + (new string(this, pos2, this.length - pos2)); } - public void CopyTo( - int sourceIndex, - char[] destination, - int destinationIndex, - int count - ) - { - for (var i = 0; i < count; i++) - { - destination[destinationIndex + i] = this[sourceIndex + i]; - } - } + public void CopyTo(int sourceIndex, char[] destination, int destinationIndex, int count) { + if (destination == null) { + throw new ArgumentNullException("destination"); + } + if (sourceIndex < 0 || sourceIndex > this.length) { + throw new ArgumentOutOfRangeException ("sourceIndex"); + } + if (destinationIndex < 0 || destinationIndex > destination.Length) { + throw new ArgumentOutOfRangeException ("destinationIndex"); + } + if (count < 0 || count > this.length - sourceIndex || count > destination.Length - destinationIndex) { + throw new ArgumentOutOfRangeException ("count"); + } + InternalCopyTo(sourceIndex, destination, destinationIndex, count); + } - #endregion + #endregion - #region Compare and CompareOrdinal Methods + #region Compare and CompareOrdinal Methods - public static int Compare(string strA, string strB) { + public static int Compare(string strA, string strB) { return CompareOrdinal(strA, strB); } @@ -345,139 +421,193 @@ public static int Compare(string strA, int indexA, string strB, int indexB, int return CompareOrdinal(strA.Substring(indexA, length), strB.Substring(indexB, length)); } - public static int CompareOrdinal(string strA, string strB) { - if (strA == null) { - if (strB == null) { - return 0; - } - return -1; - } - if (strB == null) { - return 1; - } - int top = Math.Min(strA.Length, strB.Length); - for (int i = 0; i < top; i++) { - if (strA[i] != strB[i]) { - return (strA[i] - strB[i]); - } + public static int Compare(string strA, int indexA, string strB, int indexB, int length, StringComparison comparisonType) { + return Compare(strA.Substring(indexA, length), strB.Substring(indexB, length), comparisonType); + } + + public static int Compare(string strA, string strB, StringComparison comparisonType) { + switch (comparisonType) { + case StringComparison.CurrentCulture: + case StringComparison.CurrentCultureIgnoreCase: + throw new Exception("String.Compare(a,b,StringComparison.CurrentCulture) is not implemented."); + case StringComparison.InvariantCulture: + case StringComparison.Ordinal: + return CompareOrdinal(strA, strB); + case StringComparison.InvariantCultureIgnoreCase: + case StringComparison.OrdinalIgnoreCase: + return CompareOrdinal(strA.ToUpperInvariant(), strB.ToUpperInvariant()); + default: + throw new ArgumentException ("comparisonType"); } - return strA.Length - strB.Length; } + [MethodImpl(MethodImplOptions.InternalCall)] + extern public static int CompareOrdinal(string strA, string strB); + #endregion #region IndexOf... Methods public int IndexOf(string value) { - return IndexOf(value, 0, this.length); + return IndexOfOrdinal(value, 0, this.length, forward: true); } public int IndexOf(string value, int startIndex) { - return IndexOf(value, startIndex, this.length - startIndex); + return IndexOfOrdinal(value, startIndex, this.length - startIndex, forward: true); } public int IndexOf(string value, int startIndex, int count) { + return IndexOfOrdinal(value, startIndex, count, forward: true); + } + + public int IndexOf(string value, StringComparison comparisonType) { + return IndexOf(value, 0, this.length, comparisonType); + } + + public int IndexOf(string value, int startIndex, StringComparison comparisonType) { + return IndexOf(value, startIndex, this.length - startIndex, comparisonType); + } + + public int IndexOf(string value, int startIndex, int count, StringComparison comparisonType) { + switch (comparisonType) { + case StringComparison.CurrentCulture: + case StringComparison.InvariantCulture: + case StringComparison.Ordinal: + return IndexOfOrdinal(value, startIndex, count, forward: true); + case StringComparison.CurrentCultureIgnoreCase: + throw new Exception("String.IndexOf(s,i,c,StringComparison.CurrentCultureIgnoreCase) is not implemented."); + case StringComparison.InvariantCultureIgnoreCase: + case StringComparison.OrdinalIgnoreCase: + return ToUpperInvariant().IndexOfOrdinal(value.ToUpperInvariant(), startIndex, count, forward: true); + default: + throw new ArgumentException ("comparisonType"); + } + } + + public int LastIndexOf(string value) { + return IndexOfOrdinal(value, this.length - 1, this.length, forward: false); + } + + public int LastIndexOf(string value, int startIndex) { + return IndexOfOrdinal(value, startIndex, startIndex + 1, forward: false); + } + + public int LastIndexOf(string value, int startIndex, int count) { + return IndexOfOrdinal(value, startIndex, count, forward: false); + } + + public int LastIndexOf(string value, StringComparison comparisonType) { + return LastIndexOf(value, this.length - 1, this.length, comparisonType); + } + + public int LastIndexOf(string value, int startIndex, StringComparison comparisonType) { + return LastIndexOf(value, startIndex, startIndex + 1, comparisonType); + } + + public int LastIndexOf(string value, int startIndex, int count, StringComparison comparisonType) { + switch (comparisonType) { + case StringComparison.CurrentCulture: + case StringComparison.InvariantCulture: + case StringComparison.Ordinal: + return IndexOfOrdinal(value, startIndex, count, forward: false); + case StringComparison.CurrentCultureIgnoreCase: + throw new Exception("String.LastIndexOf(s,i,c,StringComparison.CurrentCultureIgnoreCase) is not implemented."); + case StringComparison.InvariantCultureIgnoreCase: + case StringComparison.OrdinalIgnoreCase: + return ToUpperInvariant().IndexOfOrdinal(value.ToUpperInvariant(), startIndex, count, forward: false); + default: + throw new ArgumentException ("comparisonType"); + } + } + + private int IndexOfOrdinal(string value, int startIndex, int count, bool forward) { if (value == null) { throw new ArgumentNullException("value"); } - if (startIndex < 0 || count < 0 || startIndex + count > this.length) { - throw new ArgumentOutOfRangeException(); + if (this.length == 0) { + return value.Length == 0 ? 0 : -1; } - if (value.length == 0) { - return startIndex; - } - int valueLen = value.length; - int finalIndex = startIndex + count - valueLen + 1; - char char0 = value[0]; - for (int i = startIndex; i < finalIndex; i++) { - if (this[i] == char0) { - bool ok = true; - for (int j = 1; j < valueLen; j++) { - if (this[i + j] != value[j]) { - ok = false; - break; - } - } - if (ok) { - return i; - } - } + if (startIndex < 0 || startIndex > this.length) { + throw new ArgumentOutOfRangeException ("startIndex"); + } + if (count < 0 || count > (forward ? this.length - startIndex : startIndex + 1)) { + throw new ArgumentOutOfRangeException ("count"); } - return -1; + return InternalIndexOfStr(value, startIndex, count, forward); } public int IndexOf(char value) { - return this.IndexOf(value, 0, this.length, true); + return IndexOfOrdinal(value, 0, this.length, forward: true); } public int IndexOf(char value, int startIndex) { - return this.IndexOf(value, startIndex, this.length - startIndex, true); + return IndexOfOrdinal(value, startIndex, this.length - startIndex, forward: true); } public int IndexOf(char value, int startIndex, int count) { - return this.IndexOf(value, startIndex, count, true); + return IndexOfOrdinal(value, startIndex, count, forward: true); } public int LastIndexOf(char value) { - return this.IndexOf(value, 0, this.length, false); + return IndexOfOrdinal(value, this.length - 1, this.length, forward: false); } public int LastIndexOf(char value, int startIndex) { - return this.IndexOf(value, startIndex, this.length - startIndex, false); + return IndexOfOrdinal(value, startIndex, startIndex + 1, forward: false); } public int LastIndexOf(char value, int startIndex, int count) { - return this.IndexOf(value, startIndex, count, false); + return IndexOfOrdinal(value, startIndex, count, forward: false); } - private int IndexOf(char value, int startIndex, int count, bool forwards) { - if (startIndex < 0 || count < 0 || startIndex + count > this.length) { - throw new ArgumentOutOfRangeException(); + private int IndexOfOrdinal(char value, int startIndex, int count, bool forward) { + if (this.length == 0) { + return -1; + } + if (startIndex < 0 || startIndex > this.length) { + throw new ArgumentOutOfRangeException ("startIndex"); } - return this.InternalIndexOf(value, startIndex, count, forwards); + if (count < 0 || count > (forward ? this.length - startIndex: startIndex + 1)) { + throw new ArgumentOutOfRangeException ("count"); + } + return InternalIndexOf(value, startIndex, count, forward); } public int IndexOfAny(char[] anyOf) { - return this.IndexOfAny(anyOf, 0, this.length, true); + return IndexOfOrdinal(anyOf, 0, this.length, forward: true); } public int IndexOfAny(char[] anyOf, int startIndex) { - return this.IndexOfAny(anyOf, startIndex, this.length - startIndex, true); + return IndexOfOrdinal(anyOf, startIndex, this.length - startIndex, forward: true); } public int IndexOfAny(char[] anyOf, int startIndex, int count) { - return this.IndexOfAny(anyOf, startIndex, count, true); + return IndexOfOrdinal(anyOf, startIndex, count, forward: true); } public int LastIndexOfAny(char[] anyOf) { - return this.IndexOfAny(anyOf, 0, this.length, false); + return IndexOfOrdinal(anyOf, this.length - 1, this.length, forward: false); } public int LastIndexOfAny(char[] anyOf, int startIndex) { - return this.IndexOfAny(anyOf, startIndex, this.length - startIndex, false); + return IndexOfOrdinal(anyOf, startIndex, startIndex + 1, forward: false); } public int LastIndexOfAny(char[] anyOf, int startIndex, int count) { - return this.IndexOfAny(anyOf, startIndex, count, false); + return IndexOfOrdinal(anyOf, startIndex, count, forward: false); } - private int IndexOfAny(char[] anyOf, int startIndex, int count, bool forward) { - if (startIndex < 0 || count < 0 || startIndex + count > this.length) { - throw new ArgumentOutOfRangeException(); + private int IndexOfOrdinal(char[] anyOf, int startIndex, int count, bool forward) { + if (this.length == 0) { + return -1; } - /*int anyOfLen = anyOf.Length; - int finIndex = (forward) ? (startIndex + count) : (startIndex - 1); - int inc = (forward) ? 1 : -1; - for (int i = (forward) ? startIndex : (startIndex + count - 1); i != finIndex; i += inc) { - char c = this[i]; - for (int j = 0; j < anyOfLen; j++) { - if (c == anyOf[j]) { - return i; - } - } + if (startIndex < 0 || startIndex > this.length) { + throw new ArgumentOutOfRangeException ("startIndex"); } - return -1;*/ - return this.InternalIndexOfAny(anyOf, startIndex, count, forward); + if (count < 0 || count > (forward ? this.length - startIndex: startIndex + 1)) { + throw new ArgumentOutOfRangeException ("count"); + } + return InternalIndexOfAny(anyOf, startIndex, count, forward); } #endregion @@ -498,17 +628,11 @@ public string ToLower(CultureInfo culture) { return culture.TextInfo.ToLower(this); } - public string ToLowerInvariant() { - int len = this.length; - StringBuilder sb = new StringBuilder(len); - for (int i = 0; i < len; i++) { - sb.Append(char.ToLowerInvariant(this[i])); - } - return sb.ToString(); - } + [MethodImpl(MethodImplOptions.InternalCall)] + extern public string ToLowerInvariant(); public string ToUpper() { - return ToLower(CultureInfo.CurrentCulture); + return ToUpper(CultureInfo.CurrentCulture); } public string ToUpper(CultureInfo culture) { @@ -521,14 +645,8 @@ public string ToUpper(CultureInfo culture) { return culture.TextInfo.ToUpper(this); } - public string ToUpperInvariant() { - int len = this.length; - StringBuilder sb = new StringBuilder(len); - for (int i = 0; i < len; i++) { - sb.Append(char.ToUpperInvariant(this[i])); - } - return sb.ToString(); - } + [MethodImpl(MethodImplOptions.InternalCall)] + extern public string ToUpperInvariant(); #endregion @@ -542,6 +660,14 @@ public override bool Equals(object obj) { return Equals(this, obj as string); } + public bool Equals(string value) { + return Equals(this, value); + } + + public bool Equals(string value, StringComparison comparisonType) { + return Equals(this, value, comparisonType); + } + public static bool operator ==(string a, string b) { return Equals(a, b); } @@ -550,6 +676,22 @@ public override bool Equals(object obj) { return !Equals(a, b); } + public static bool Equals(string a, string b, StringComparison comparisonType) { + switch (comparisonType) { + case StringComparison.CurrentCulture: + case StringComparison.InvariantCulture: + case StringComparison.Ordinal: + return Equals(a, b); + case StringComparison.CurrentCultureIgnoreCase: + throw new Exception("String.Equals(a,b,StringComparison.CurrentCultureIgnoreCase) is not implemented."); + case StringComparison.InvariantCultureIgnoreCase: + case StringComparison.OrdinalIgnoreCase: + return Equals(a.ToUpperInvariant(), b.ToUpperInvariant()); + default: + throw new ArgumentException ("comparisonType"); + } + } + [MethodImpl(MethodImplOptions.InternalCall)] extern public static bool Equals(string a, string b); @@ -587,14 +729,6 @@ public int CompareTo(string value) { #endregion - #region IEquatable Members - - public bool Equals(string other) { - return Equals(this, other); - } - - #endregion - #region IEnumerable Members public IEnumerator GetEnumerator() { @@ -606,6 +740,41 @@ IEnumerator IEnumerable.GetEnumerator() { } #endregion + + #region Parsing + + [MethodImpl(MethodImplOptions.InternalCall)] + extern internal static string InternalFromInt32(int value); + [MethodImpl(MethodImplOptions.InternalCall)] + extern internal static string InternalFromInt64(long value); + [MethodImpl(MethodImplOptions.InternalCall)] + extern internal static string InternalFromUInt32(uint value); + [MethodImpl(MethodImplOptions.InternalCall)] + extern internal static string InternalFromUInt64(ulong value); + [MethodImpl(MethodImplOptions.InternalCall)] + extern internal static string InternalFromSingle(float value); + [MethodImpl(MethodImplOptions.InternalCall)] + extern internal static string InternalFromDouble(double value); + + [MethodImpl(MethodImplOptions.InternalCall)] + extern internal int InternalToInt32(out int error, int radix); + [MethodImpl(MethodImplOptions.InternalCall)] + extern internal long InternalToInt64(out int error, int radix); + [MethodImpl(MethodImplOptions.InternalCall)] + extern internal uint InternalToUInt32(out int error, int radix); + [MethodImpl(MethodImplOptions.InternalCall)] + extern internal ulong InternalToUInt64(out int error, int radix); + [MethodImpl(MethodImplOptions.InternalCall)] + extern internal float InternalToSingle(out int error); + [MethodImpl(MethodImplOptions.InternalCall)] + extern internal double InternalToDouble(out int error); + + internal static Exception GetFormatException(int error) { + //TODO: exception based on error + return new FormatException("Input string was not in the correct format"); + } + + #endregion } } #endif diff --git a/src/DNA/corlib/System/StringSplitOptions.cs b/src/DNA/corlib/System/StringSplitOptions.cs new file mode 100644 index 00000000..98f2b88b --- /dev/null +++ b/src/DNA/corlib/System/StringSplitOptions.cs @@ -0,0 +1,38 @@ +// +// System.StringSplitOptions.cs +// +// Copyright (C) 2004-2005 Novell (http://www.novell.com) +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + + +using System.Runtime.InteropServices; + +namespace System +{ + [Flags] + // [ComVisible (false)] + public enum StringSplitOptions + { + None = 0, + RemoveEmptyEntries = 1 + } +} diff --git a/src/DNA/corlib/System/Tuple.cs b/src/DNA/corlib/System/Tuple.cs new file mode 100644 index 00000000..ac5c2427 --- /dev/null +++ b/src/DNA/corlib/System/Tuple.cs @@ -0,0 +1,820 @@ +// +// Tuples.cs +// +// Authors: +// Zoltan Varga (vargaz@gmail.com) +// Marek Safar (marek.safar@gmail.com) +// +// Copyright (C) 2009 Novell +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Collections; +using System.Collections.Generic; + +namespace System { + public static class Tuple { + public static Tuple> Create + ( + T1 item1, + T2 item2, + T3 item3, + T4 item4, + T5 item5, + T6 item6, + T7 item7, + T8 item8) { + return new Tuple>(item1, item2, item3, item4, item5, item6, item7, new Tuple(item8)); + } + + public static Tuple Create + ( + T1 item1, + T2 item2, + T3 item3, + T4 item4, + T5 item5, + T6 item6, + T7 item7) { + return new Tuple(item1, item2, item3, item4, item5, item6, item7); + } + + public static Tuple Create + ( + T1 item1, + T2 item2, + T3 item3, + T4 item4, + T5 item5, + T6 item6) { + return new Tuple(item1, item2, item3, item4, item5, item6); + } + + public static Tuple Create + ( + T1 item1, + T2 item2, + T3 item3, + T4 item4, + T5 item5) { + return new Tuple(item1, item2, item3, item4, item5); + } + + public static Tuple Create + ( + T1 item1, + T2 item2, + T3 item3, + T4 item4) { + return new Tuple(item1, item2, item3, item4); + } + + public static Tuple Create + ( + T1 item1, + T2 item2, + T3 item3) { + return new Tuple(item1, item2, item3); + } + + public static Tuple Create + ( + T1 item1, + T2 item2) { + return new Tuple(item1, item2); + } + + public static Tuple Create + ( + T1 item1) { + return new Tuple(item1); + } + } + + public partial class Tuple { + public Tuple(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item7, TRest rest) { + this.item1 = item1; + this.item2 = item2; + this.item3 = item3; + this.item4 = item4; + this.item5 = item5; + this.item6 = item6; + this.item7 = item7; + this.rest = rest; + + bool ok = true; + if (!typeof(TRest).IsGenericType) + ok = false; + if (ok) { + Type t = typeof(TRest).GetGenericTypeDefinition(); + if (!(t == typeof(Tuple<>) || t == typeof(Tuple<,>) || t == typeof(Tuple<,,>) || t == typeof(Tuple<,,,>) || t == typeof(Tuple<,,,,>) || t == typeof(Tuple<,,,,,>) || t == typeof(Tuple<,,,,,,>) || t == typeof(Tuple<,,,,,,,>))) + ok = false; + } + if (!ok) + throw new ArgumentException("rest", "The last element of an eight element tuple must be a Tuple."); + } + } + + [Serializable] + public class Tuple : IStructuralEquatable, IStructuralComparable, IComparable { + T1 item1; + + public Tuple(T1 item1) { + this.item1 = item1; + } + + public T1 Item1 { + get { return item1; } + } + + int IComparable.CompareTo(object obj) { + return ((IStructuralComparable)this).CompareTo(obj, Comparer.Default); + } + + int IStructuralComparable.CompareTo(object other, IComparer comparer) { + var t = other as Tuple; + if (t == null) { + if (other == null) return 1; + throw new ArgumentException("other"); + } + + return comparer.Compare(item1, t.item1); + } + + public override bool Equals(object obj) { + return ((IStructuralEquatable)this).Equals(obj, EqualityComparer.Default); + } + + bool IStructuralEquatable.Equals(object other, IEqualityComparer comparer) { + var t = other as Tuple; + if (t == null) + return false; + + return comparer.Equals(item1, t.item1); + } + + public override int GetHashCode() { + return ((IStructuralEquatable)this).GetHashCode(EqualityComparer.Default); + } + + int IStructuralEquatable.GetHashCode(IEqualityComparer comparer) { + return comparer.GetHashCode(item1); + } + + public override string ToString() { + return String.Format("({0})", item1); + } + } + + [Serializable] + public class Tuple : IStructuralEquatable, IStructuralComparable, IComparable { + T1 item1; + T2 item2; + + public Tuple(T1 item1, T2 item2) { + this.item1 = item1; + this.item2 = item2; + } + + public T1 Item1 { + get { return item1; } + } + + public T2 Item2 { + get { return item2; } + } + + int IComparable.CompareTo(object obj) { + return ((IStructuralComparable)this).CompareTo(obj, Comparer.Default); + } + + int IStructuralComparable.CompareTo(object other, IComparer comparer) { + var t = other as Tuple; + if (t == null) { + if (other == null) return 1; + throw new ArgumentException("other"); + } + + int res = comparer.Compare(item1, t.item1); + if (res != 0) return res; + return comparer.Compare(item2, t.item2); + } + + public override bool Equals(object obj) { + return ((IStructuralEquatable)this).Equals(obj, EqualityComparer.Default); + } + + bool IStructuralEquatable.Equals(object other, IEqualityComparer comparer) { + var t = other as Tuple; + if (t == null) + return false; + + return comparer.Equals(item1, t.item1) && + comparer.Equals(item2, t.item2); + } + + public override int GetHashCode() { + return ((IStructuralEquatable)this).GetHashCode(EqualityComparer.Default); + } + + int IStructuralEquatable.GetHashCode(IEqualityComparer comparer) { + int h = comparer.GetHashCode(item1); + h = (h << 5) - h + comparer.GetHashCode(item2); + return h; + } + + public override string ToString() { + return String.Format("({0}, {1})", item1, item2); + } + } + + [Serializable] + public class Tuple : IStructuralEquatable, IStructuralComparable, IComparable { + T1 item1; + T2 item2; + T3 item3; + + public Tuple(T1 item1, T2 item2, T3 item3) { + this.item1 = item1; + this.item2 = item2; + this.item3 = item3; + } + + public T1 Item1 { + get { return item1; } + } + + public T2 Item2 { + get { return item2; } + } + + public T3 Item3 { + get { return item3; } + } + + int IComparable.CompareTo(object obj) { + return ((IStructuralComparable)this).CompareTo(obj, Comparer.Default); + } + + int IStructuralComparable.CompareTo(object other, IComparer comparer) { + var t = other as Tuple; + if (t == null) { + if (other == null) return 1; + throw new ArgumentException("other"); + } + + int res = comparer.Compare(item1, t.item1); + if (res != 0) return res; + res = comparer.Compare(item2, t.item2); + if (res != 0) return res; + return comparer.Compare(item3, t.item3); + } + + public override bool Equals(object obj) { + return ((IStructuralEquatable)this).Equals(obj, EqualityComparer.Default); + } + + bool IStructuralEquatable.Equals(object other, IEqualityComparer comparer) { + var t = other as Tuple; + if (t == null) + return false; + + return comparer.Equals(item1, t.item1) && + comparer.Equals(item2, t.item2) && + comparer.Equals(item3, t.item3); + } + + public override int GetHashCode() { + return ((IStructuralEquatable)this).GetHashCode(EqualityComparer.Default); + } + + int IStructuralEquatable.GetHashCode(IEqualityComparer comparer) { + int h = comparer.GetHashCode(item1); + h = (h << 5) - h + comparer.GetHashCode(item2); + h = (h << 5) - h + comparer.GetHashCode(item3); + return h; + } + + public override string ToString() { + return String.Format("({0}, {1}, {2})", item1, item2, item3); + } + } + + [Serializable] + public class Tuple : IStructuralEquatable, IStructuralComparable, IComparable { + T1 item1; + T2 item2; + T3 item3; + T4 item4; + + public Tuple(T1 item1, T2 item2, T3 item3, T4 item4) { + this.item1 = item1; + this.item2 = item2; + this.item3 = item3; + this.item4 = item4; + } + + public T1 Item1 { + get { return item1; } + } + + public T2 Item2 { + get { return item2; } + } + + public T3 Item3 { + get { return item3; } + } + + public T4 Item4 { + get { return item4; } + } + + int IComparable.CompareTo(object obj) { + return ((IStructuralComparable)this).CompareTo(obj, Comparer.Default); + } + + int IStructuralComparable.CompareTo(object other, IComparer comparer) { + var t = other as Tuple; + if (t == null) { + if (other == null) return 1; + throw new ArgumentException("other"); + } + + int res = comparer.Compare(item1, t.item1); + if (res != 0) return res; + res = comparer.Compare(item2, t.item2); + if (res != 0) return res; + res = comparer.Compare(item3, t.item3); + if (res != 0) return res; + return comparer.Compare(item4, t.item4); + } + + public override bool Equals(object obj) { + return ((IStructuralEquatable)this).Equals(obj, EqualityComparer.Default); + } + + bool IStructuralEquatable.Equals(object other, IEqualityComparer comparer) { + var t = other as Tuple; + if (t == null) + return false; + + return comparer.Equals(item1, t.item1) && + comparer.Equals(item2, t.item2) && + comparer.Equals(item3, t.item3) && + comparer.Equals(item4, t.item4); + } + + public override int GetHashCode() { + return ((IStructuralEquatable)this).GetHashCode(EqualityComparer.Default); + } + + int IStructuralEquatable.GetHashCode(IEqualityComparer comparer) { + int h = comparer.GetHashCode(item1); + h = (h << 5) - h + comparer.GetHashCode(item2); + h = (h << 5) - h + comparer.GetHashCode(item3); + h = (h << 5) - h + comparer.GetHashCode(item4); + return h; + } + + public override string ToString() { + return String.Format("({0}, {1}, {2}, {3})", item1, item2, item3, item4); + } + } + + [Serializable] + public class Tuple : IStructuralEquatable, IStructuralComparable, IComparable { + T1 item1; + T2 item2; + T3 item3; + T4 item4; + T5 item5; + + public Tuple(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5) { + this.item1 = item1; + this.item2 = item2; + this.item3 = item3; + this.item4 = item4; + this.item5 = item5; + } + + public T1 Item1 { + get { return item1; } + } + + public T2 Item2 { + get { return item2; } + } + + public T3 Item3 { + get { return item3; } + } + + public T4 Item4 { + get { return item4; } + } + + public T5 Item5 { + get { return item5; } + } + + int IComparable.CompareTo(object obj) { + return ((IStructuralComparable)this).CompareTo(obj, Comparer.Default); + } + + int IStructuralComparable.CompareTo(object other, IComparer comparer) { + var t = other as Tuple; + if (t == null) { + if (other == null) return 1; + throw new ArgumentException("other"); + } + + int res = comparer.Compare(item1, t.item1); + if (res != 0) return res; + res = comparer.Compare(item2, t.item2); + if (res != 0) return res; + res = comparer.Compare(item3, t.item3); + if (res != 0) return res; + res = comparer.Compare(item4, t.item4); + if (res != 0) return res; + return comparer.Compare(item5, t.item5); + } + + public override bool Equals(object obj) { + return ((IStructuralEquatable)this).Equals(obj, EqualityComparer.Default); + } + + bool IStructuralEquatable.Equals(object other, IEqualityComparer comparer) { + var t = other as Tuple; + if (t == null) + return false; + + return comparer.Equals(item1, t.item1) && + comparer.Equals(item2, t.item2) && + comparer.Equals(item3, t.item3) && + comparer.Equals(item4, t.item4) && + comparer.Equals(item5, t.item5); + } + + public override int GetHashCode() { + return ((IStructuralEquatable)this).GetHashCode(EqualityComparer.Default); + } + + int IStructuralEquatable.GetHashCode(IEqualityComparer comparer) { + int h = comparer.GetHashCode(item1); + h = (h << 5) - h + comparer.GetHashCode(item2); + h = (h << 5) - h + comparer.GetHashCode(item3); + h = (h << 5) - h + comparer.GetHashCode(item4); + h = (h << 5) - h + comparer.GetHashCode(item5); + return h; + } + + public override string ToString() { + return String.Format("({0}, {1}, {2}, {3}, {4})", item1, item2, item3, item4, item5); + } + } + + [Serializable] + public class Tuple : IStructuralEquatable, IStructuralComparable, IComparable { + T1 item1; + T2 item2; + T3 item3; + T4 item4; + T5 item5; + T6 item6; + + public Tuple(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6) { + this.item1 = item1; + this.item2 = item2; + this.item3 = item3; + this.item4 = item4; + this.item5 = item5; + this.item6 = item6; + } + + public T1 Item1 { + get { return item1; } + } + + public T2 Item2 { + get { return item2; } + } + + public T3 Item3 { + get { return item3; } + } + + public T4 Item4 { + get { return item4; } + } + + public T5 Item5 { + get { return item5; } + } + + public T6 Item6 { + get { return item6; } + } + + int IComparable.CompareTo(object obj) { + return ((IStructuralComparable)this).CompareTo(obj, Comparer.Default); + } + + int IStructuralComparable.CompareTo(object other, IComparer comparer) { + var t = other as Tuple; + if (t == null) { + if (other == null) return 1; + throw new ArgumentException("other"); + } + + int res = comparer.Compare(item1, t.item1); + if (res != 0) return res; + res = comparer.Compare(item2, t.item2); + if (res != 0) return res; + res = comparer.Compare(item3, t.item3); + if (res != 0) return res; + res = comparer.Compare(item4, t.item4); + if (res != 0) return res; + res = comparer.Compare(item5, t.item5); + if (res != 0) return res; + return comparer.Compare(item6, t.item6); + } + + public override bool Equals(object obj) { + return ((IStructuralEquatable)this).Equals(obj, EqualityComparer.Default); + } + + bool IStructuralEquatable.Equals(object other, IEqualityComparer comparer) { + var t = other as Tuple; + if (t == null) + return false; + + return comparer.Equals(item1, t.item1) && + comparer.Equals(item2, t.item2) && + comparer.Equals(item3, t.item3) && + comparer.Equals(item4, t.item4) && + comparer.Equals(item5, t.item5) && + comparer.Equals(item6, t.item6); + } + + public override int GetHashCode() { + return ((IStructuralEquatable)this).GetHashCode(EqualityComparer.Default); + } + + int IStructuralEquatable.GetHashCode(IEqualityComparer comparer) { + int h = comparer.GetHashCode(item1); + h = (h << 5) - h + comparer.GetHashCode(item2); + h = (h << 5) - h + comparer.GetHashCode(item3); + h = (h << 5) - h + comparer.GetHashCode(item4); + h = (h << 5) - h + comparer.GetHashCode(item5); + h = (h << 5) - h + comparer.GetHashCode(item6); + return h; + } + + public override string ToString() { + return String.Format("({0}, {1}, {2}, {3}, {4}, {5})", item1, item2, item3, item4, item5, item6); + } + } + + [Serializable] + public class Tuple : IStructuralEquatable, IStructuralComparable, IComparable { + T1 item1; + T2 item2; + T3 item3; + T4 item4; + T5 item5; + T6 item6; + T7 item7; + + public Tuple(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item7) { + this.item1 = item1; + this.item2 = item2; + this.item3 = item3; + this.item4 = item4; + this.item5 = item5; + this.item6 = item6; + this.item7 = item7; + } + + public T1 Item1 { + get { return item1; } + } + + public T2 Item2 { + get { return item2; } + } + + public T3 Item3 { + get { return item3; } + } + + public T4 Item4 { + get { return item4; } + } + + public T5 Item5 { + get { return item5; } + } + + public T6 Item6 { + get { return item6; } + } + + public T7 Item7 { + get { return item7; } + } + + int IComparable.CompareTo(object obj) { + return ((IStructuralComparable)this).CompareTo(obj, Comparer.Default); + } + + int IStructuralComparable.CompareTo(object other, IComparer comparer) { + var t = other as Tuple; + if (t == null) { + if (other == null) return 1; + throw new ArgumentException("other"); + } + + int res = comparer.Compare(item1, t.item1); + if (res != 0) return res; + res = comparer.Compare(item2, t.item2); + if (res != 0) return res; + res = comparer.Compare(item3, t.item3); + if (res != 0) return res; + res = comparer.Compare(item4, t.item4); + if (res != 0) return res; + res = comparer.Compare(item5, t.item5); + if (res != 0) return res; + res = comparer.Compare(item6, t.item6); + if (res != 0) return res; + return comparer.Compare(item7, t.item7); + } + + public override bool Equals(object obj) { + return ((IStructuralEquatable)this).Equals(obj, EqualityComparer.Default); + } + + bool IStructuralEquatable.Equals(object other, IEqualityComparer comparer) { + var t = other as Tuple; + if (t == null) + return false; + + return comparer.Equals(item1, t.item1) && + comparer.Equals(item2, t.item2) && + comparer.Equals(item3, t.item3) && + comparer.Equals(item4, t.item4) && + comparer.Equals(item5, t.item5) && + comparer.Equals(item6, t.item6) && + comparer.Equals(item7, t.item7); + } + + public override int GetHashCode() { + return ((IStructuralEquatable)this).GetHashCode(EqualityComparer.Default); + } + + int IStructuralEquatable.GetHashCode(IEqualityComparer comparer) { + int h = comparer.GetHashCode(item1); + h = (h << 5) - h + comparer.GetHashCode(item2); + h = (h << 5) - h + comparer.GetHashCode(item3); + h = (h << 5) - h + comparer.GetHashCode(item4); + h = (h << 5) - h + comparer.GetHashCode(item5); + h = (h << 5) - h + comparer.GetHashCode(item6); + h = (h << 5) - h + comparer.GetHashCode(item7); + return h; + } + + public override string ToString() { + return String.Format("({0}, {1}, {2}, {3}, {4}, {5}, {6})", item1, item2, item3, item4, item5, item6, item7); + } + } + + [Serializable] + public partial class Tuple : IStructuralEquatable, IStructuralComparable, IComparable { + T1 item1; + T2 item2; + T3 item3; + T4 item4; + T5 item5; + T6 item6; + T7 item7; + TRest rest; + + public T1 Item1 { + get { return item1; } + } + + public T2 Item2 { + get { return item2; } + } + + public T3 Item3 { + get { return item3; } + } + + public T4 Item4 { + get { return item4; } + } + + public T5 Item5 { + get { return item5; } + } + + public T6 Item6 { + get { return item6; } + } + + public T7 Item7 { + get { return item7; } + } + + public TRest Rest { + get { return rest; } + } + + int IComparable.CompareTo(object obj) { + return ((IStructuralComparable)this).CompareTo(obj, Comparer.Default); + } + + int IStructuralComparable.CompareTo(object other, IComparer comparer) { + var t = other as Tuple; + if (t == null) { + if (other == null) return 1; + throw new ArgumentException("other"); + } + + int res = comparer.Compare(item1, t.item1); + if (res != 0) return res; + res = comparer.Compare(item2, t.item2); + if (res != 0) return res; + res = comparer.Compare(item3, t.item3); + if (res != 0) return res; + res = comparer.Compare(item4, t.item4); + if (res != 0) return res; + res = comparer.Compare(item5, t.item5); + if (res != 0) return res; + res = comparer.Compare(item6, t.item6); + if (res != 0) return res; + res = comparer.Compare(item7, t.item7); + if (res != 0) return res; + return comparer.Compare(rest, t.rest); + } + + public override bool Equals(object obj) { + return ((IStructuralEquatable)this).Equals(obj, EqualityComparer.Default); + } + + bool IStructuralEquatable.Equals(object other, IEqualityComparer comparer) { + var t = other as Tuple; + if (t == null) + return false; + + return comparer.Equals(item1, t.item1) && + comparer.Equals(item2, t.item2) && + comparer.Equals(item3, t.item3) && + comparer.Equals(item4, t.item4) && + comparer.Equals(item5, t.item5) && + comparer.Equals(item6, t.item6) && + comparer.Equals(item7, t.item7) && + comparer.Equals(rest, t.rest); + } + + public override int GetHashCode() { + return ((IStructuralEquatable)this).GetHashCode(EqualityComparer.Default); + } + + int IStructuralEquatable.GetHashCode(IEqualityComparer comparer) { + int h = comparer.GetHashCode(item1); + h = (h << 5) - h + comparer.GetHashCode(item2); + h = (h << 5) - h + comparer.GetHashCode(item3); + h = (h << 5) - h + comparer.GetHashCode(item4); + h = (h << 5) - h + comparer.GetHashCode(item5); + h = (h << 5) - h + comparer.GetHashCode(item6); + h = (h << 5) - h + comparer.GetHashCode(item7); + h = (h << 5) - h + comparer.GetHashCode(rest); + return h; + } + + public override string ToString() { + return String.Format("({0}, {1}, {2}, {3}, {4}, {5}, {6}, {7})", item1, item2, item3, item4, item5, item6, item7, rest); + } + } +} diff --git a/src/DNA/corlib/System/Type.cs b/src/DNA/corlib/System/Type.cs index 2373708e..a748d323 100644 --- a/src/DNA/corlib/System/Type.cs +++ b/src/DNA/corlib/System/Type.cs @@ -30,55 +30,96 @@ public abstract class Type : MemberInfo { private static IDictionary typesByNameCache = new Dictionary(); - public static readonly Type[] EmptyTypes = new Type[0]; + public static readonly Type[] EmptyTypes = new Type[0]; - [MethodImpl(MethodImplOptions.InternalCall)] - extern public static Type GetTypeFromHandle(RuntimeTypeHandle handle); + [MethodImpl(MethodImplOptions.InternalCall)] + extern public static Type GetTypeFromHandle(RuntimeTypeHandle handle); + + extern public TypeAttributes Attributes { [MethodImpl(MethodImplOptions.InternalCall)] get; } - public abstract Type BaseType { - get; - } + public abstract string AssemblyQualifiedName { get; } - public abstract bool IsEnum { - get; - } + public abstract Type BaseType { get; } - public abstract string Namespace { - get; - } + public abstract bool IsEnum { get; } - public abstract string FullName { - get; - } + public abstract string Namespace { get; } - public abstract bool IsGenericType { - get; - } + public abstract string FullName { get; } - public abstract Type GetGenericTypeDefinition(); + public abstract bool IsGenericType { get; } - public abstract Type[] GetGenericArguments(); + public abstract Type GetGenericTypeDefinition(); + + public abstract Type[] GetGenericArguments(); public abstract Type GetElementType(); public virtual bool IsArray => GetElementType() != null; - extern public bool IsValueType { - [MethodImpl(MethodImplOptions.InternalCall)] - get; - } + public virtual bool IsByRef => false; + + public virtual bool IsPointer => false; + + extern public bool IsValueType { [MethodImpl(MethodImplOptions.InternalCall)] get; } + + public bool IsAnsiClass => (Attributes & TypeAttributes.StringFormatMask) == TypeAttributes.AnsiClass; + public bool IsUnicodeClass => (Attributes & TypeAttributes.StringFormatMask) == TypeAttributes.UnicodeClass; + public bool IsAutoClass => (Attributes & TypeAttributes.StringFormatMask) == TypeAttributes.AutoClass; + public bool IsNotPublic => (Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NotPublic; + public bool IsPublic => (Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.Public; + public bool IsNestedPublic => (Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedPublic; + public bool IsNestedPrivate => (Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedPrivate; + public bool IsNestedFamily => (Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedFamily; + public bool IsNestedAssembly => (Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedAssembly; + public bool IsNestedFamANDAssem => (Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedFamANDAssem; + public bool IsNestedFamORAssem => (Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedFamORAssem; + public bool IsAutoLayout => (Attributes & TypeAttributes.LayoutMask) == TypeAttributes.AutoLayout; + public bool IsLayoutSequential => (Attributes & TypeAttributes.LayoutMask) == TypeAttributes.SequentialLayout; + public bool IsExplicitLayout => (Attributes & TypeAttributes.LayoutMask) == TypeAttributes.ExplicitLayout; + public bool IsClass => (Attributes & TypeAttributes.ClassSemanticsMask) == TypeAttributes.Class && !IsValueType; + public bool IsInterface => (Attributes & TypeAttributes.ClassSemanticsMask) == TypeAttributes.Interface; + public bool IsAbstract => (Attributes & TypeAttributes.Abstract) != 0; + public bool IsSealed => (Attributes & TypeAttributes.Sealed) != 0; + public bool IsSpecialName => (Attributes & TypeAttributes.SpecialName) != 0; + public bool IsImport => (Attributes & TypeAttributes.Import) != 0; + public virtual bool IsSerializable => (Attributes & TypeAttributes.Serializable) != 0; + + public override string ToString() { + return this.FullName; + } + + public virtual bool Equals (Type o) { + return Object.Equals(this, o); + } + + public virtual Type[] GenericTypeArguments { + get { + if (IsGenericType && !IsGenericTypeDefinition) { + return GetGenericArguments(); + } else { + return Type.EmptyTypes; + } + } + } + + public virtual bool IsGenericTypeDefinition { + get { return false; } + } + + [MethodImpl(MethodImplOptions.InternalCall)] + extern public virtual bool IsAssignableFrom(Type c); + + [MethodImpl(MethodImplOptions.InternalCall)] + extern public virtual bool IsSubclassOf(Type c); - public override string ToString() { - return this.FullName; - } + [MethodImpl(MethodImplOptions.InternalCall)] + extern public virtual Type MakeGenericType(params Type[] typeArguments); - public static Type GetType(string typeName) - { - lock (typesByNameCache) - { + public static Type GetType(string typeName) { + lock (typesByNameCache) { Type cachedResult; - if (typesByNameCache.TryGetValue(typeName, out cachedResult)) - { + if (typesByNameCache.TryGetValue(typeName, out cachedResult)) { return cachedResult; } } @@ -86,15 +127,12 @@ public static Type GetType(string typeName) string assemblyName; string namespaceQualifiedTypeName; - if (typeName.IndexOf(',') > 0) - { + if (typeName.IndexOf(',') > 0) { // Assembly is specified var parts = typeName.Split(','); assemblyName = parts[1].Trim(); namespaceQualifiedTypeName = parts[0]; - } - else - { + } else { // No assembly specified assemblyName = null; namespaceQualifiedTypeName = typeName; @@ -105,10 +143,8 @@ public static Type GetType(string typeName) var className = namespaceQualifiedTypeName.Substring(namespaceSplitPoint + 1).Trim(); var result = GetType(assemblyName, namespaceName, className); - if (result != null) - { - lock (typesByNameCache) - { + if (result != null) { + lock (typesByNameCache) { typesByNameCache[typeName] = result; } } @@ -116,13 +152,26 @@ public static Type GetType(string typeName) return result; } + [MethodImpl(MethodImplOptions.InternalCall)] + extern public Type[] GetNestedTypes(); + + [MethodImpl(MethodImplOptions.InternalCall)] + extern public Type GetNestedType(string name); + + [MethodImpl(MethodImplOptions.InternalCall)] + extern public Type[] GetInterfaces(); + + [MethodImpl(MethodImplOptions.InternalCall)] + extern public MethodInfo[] GetMethods(); + + [MethodImpl(MethodImplOptions.InternalCall)] + extern public MethodInfo GetMethod(string name); + [MethodImpl(MethodImplOptions.InternalCall)] extern public PropertyInfo[] GetProperties(); - public MethodInfo GetMethod(string name) - { - return (MethodInfo)GetMethodInternal(name); - } + [MethodImpl(MethodImplOptions.InternalCall)] + extern public PropertyInfo GetProperty(string name); [MethodImpl(MethodImplOptions.InternalCall)] extern public static void EnsureAssemblyLoaded(string assemblyName); @@ -130,16 +179,11 @@ public MethodInfo GetMethod(string name) [MethodImpl(MethodImplOptions.InternalCall)] extern private static Type GetType(string assemblyName, string namespaceName, string className); - [MethodImpl(MethodImplOptions.InternalCall)] - extern private object GetMethodInternal(string name); - - public static bool operator ==(Type t1, Type t2) - { + public static bool operator ==(Type t1, Type t2) { return t1?.FullName.Equals(t2?.FullName) == true; } - public static bool operator !=(Type t1, Type t2) - { + public static bool operator !=(Type t1, Type t2) { return t1?.FullName.Equals(t2?.FullName) == false; } } diff --git a/src/DNA/corlib/System/UInt16.cs b/src/DNA/corlib/System/UInt16.cs index 7d7ca135..af5334e7 100644 --- a/src/DNA/corlib/System/UInt16.cs +++ b/src/DNA/corlib/System/UInt16.cs @@ -27,10 +27,10 @@ public struct UInt16:IFormattable,IComparable,IComparable,IEquatable, IEquatable< public const uint MinValue = 0; #pragma warning disable 0169, 0649 - internal uint m_value; + internal uint m_value; #pragma warning restore 0169, 0649 - public override bool Equals(object obj) { + public override bool Equals(object obj) { return (obj is uint) && ((uint)obj).m_value == this.m_value; } @@ -39,10 +39,57 @@ public override int GetHashCode() { return (int)this.m_value; } + #region Parse methods + + public static uint Parse(string s) { + return Parse(s, NumberStyles.Integer, null); + } + + public static uint Parse(string s, NumberStyles style) { + return Parse(s, style, null); + } + + public static uint Parse(string s, IFormatProvider formatProvider) { + return Parse(s, NumberStyles.Integer, formatProvider); + } + + public static uint Parse(string s, NumberStyles style, IFormatProvider formatProvider) { + if (s == null) { + throw new ArgumentNullException(); + } + //TODO: use style and provider + int error = 0; + int radix = (style & NumberStyles.AllowHexSpecifier) != 0 ? 16 : 10; + uint result = s.InternalToUInt32(out error, radix); + if (error != 0) { + throw String.GetFormatException(error); + } + return result; + } + + public static bool TryParse(string s, out uint result) { + return TryParse(s, NumberStyles.Integer, null, out result); + } + + private static bool TryParse(string s, NumberStyles style, IFormatProvider provider, out uint result) { + if (s == null) { + result = 0; + return false; + } + //TODO: use style and provider + int error = 0; + int radix = (style & NumberStyles.AllowHexSpecifier) != 0 ? 16 : 10; + result = s.InternalToUInt32(out error, radix); + return error == 0; + } + + #endregion + #region ToString methods public override string ToString() { - return NumberFormatter.FormatGeneral(new NumberFormatter.NumberStore(this.m_value)); + // return NumberFormatter.FormatGeneral(new NumberFormatter.NumberStore(this.m_value)); + return String.InternalFromUInt32(this.m_value); } public string ToString(IFormatProvider formatProvider) { @@ -50,12 +97,12 @@ public string ToString(IFormatProvider formatProvider) { } public string ToString(string format) { - return ToString(format, null); + return this.ToString(format, null); } public string ToString(string format, IFormatProvider formatProvider) { NumberFormatInfo nfi = NumberFormatInfo.GetInstance(formatProvider); - return NumberFormatter.NumberToString(format, m_value, nfi); + return NumberFormatter.NumberToString(format, this.m_value, nfi); } #endregion diff --git a/src/DNA/corlib/System/UInt64.cs b/src/DNA/corlib/System/UInt64.cs index cc48caf1..d02d401d 100644 --- a/src/DNA/corlib/System/UInt64.cs +++ b/src/DNA/corlib/System/UInt64.cs @@ -28,10 +28,10 @@ public struct UInt64 : IFormattable, IComparable, IComparable, IEquatable public const ulong MaxValue = 0xffffffffffffffffL; #pragma warning disable 0169, 0649 - internal ulong m_value; + internal ulong m_value; #pragma warning restore 0169, 0649 - public override bool Equals(object obj) { + public override bool Equals(object obj) { return (obj is ulong) && ((ulong)obj).m_value == this.m_value; } @@ -39,10 +39,57 @@ public override int GetHashCode() { return (int)(this.m_value & 0xffffffff) ^ (int)(this.m_value >> 32); } + #region Parse methods + + public static ulong Parse(string s) { + return Parse(s, NumberStyles.Integer, null); + } + + public static ulong Parse(string s, NumberStyles style) { + return Parse(s, style, null); + } + + public static ulong Parse(string s, IFormatProvider formatProvider) { + return Parse(s, NumberStyles.Integer, formatProvider); + } + + public static ulong Parse(string s, NumberStyles style, IFormatProvider formatProvider) { + if (s == null) { + throw new ArgumentNullException(); + } + //TODO: use style and provider + int error = 0; + int radix = (style & NumberStyles.AllowHexSpecifier) != 0 ? 16 : 10; + ulong result = s.InternalToUInt64(out error, radix); + if (error != 0) { + throw String.GetFormatException(error); + } + return result; + } + + public static bool TryParse(string s, out ulong result) { + return TryParse(s, NumberStyles.Integer, null, out result); + } + + private static bool TryParse(string s, NumberStyles style, IFormatProvider provider, out ulong result) { + if (s == null) { + result = 0; + return false; + } + //TODO: use style and provider + int error = 0; + int radix = (style & NumberStyles.AllowHexSpecifier) != 0 ? 16 : 10; + result = s.InternalToUInt64(out error, radix); + return error == 0; + } + + #endregion + #region ToString methods public override string ToString() { - return NumberFormatter.FormatGeneral(new NumberFormatter.NumberStore(this.m_value)); + // return NumberFormatter.FormatGeneral(new NumberFormatter.NumberStore(this.m_value)); + return String.InternalFromUInt64(this.m_value); } public string ToString(IFormatProvider formatProvider) { diff --git a/src/DNA/dna.sln b/src/DNA/dna.sln index 6021234a..19a7252c 100644 --- a/src/DNA/dna.sln +++ b/src/DNA/dna.sln @@ -1,50 +1,31 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 -VisualStudioVersion = 15.0.26720.2 +VisualStudioVersion = 15.0.27004.2005 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dna", "native\dna.vcxproj", "{F7FFFA55-C1B3-4961-8DAB-C1527EF2FF22}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "corlib", "corlib\corlib.csproj", "{E236041A-1327-4A58-9D44-5DB389FB6071}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU Debug|x64 = Debug|x64 Debug|x86 = Debug|x86 - Release|Any CPU = Release|Any CPU Release|x64 = Release|x64 Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {F7FFFA55-C1B3-4961-8DAB-C1527EF2FF22}.Debug|Any CPU.ActiveCfg = Debug|Win32 - {F7FFFA55-C1B3-4961-8DAB-C1527EF2FF22}.Debug|Any CPU.Build.0 = Debug|Win32 - {F7FFFA55-C1B3-4961-8DAB-C1527EF2FF22}.Debug|x64.ActiveCfg = Debug|Win32 - {F7FFFA55-C1B3-4961-8DAB-C1527EF2FF22}.Debug|x64.Build.0 = Debug|Win32 + {F7FFFA55-C1B3-4961-8DAB-C1527EF2FF22}.Debug|x64.ActiveCfg = Debug|x64 + {F7FFFA55-C1B3-4961-8DAB-C1527EF2FF22}.Debug|x64.Build.0 = Debug|x64 {F7FFFA55-C1B3-4961-8DAB-C1527EF2FF22}.Debug|x86.ActiveCfg = Debug|Win32 {F7FFFA55-C1B3-4961-8DAB-C1527EF2FF22}.Debug|x86.Build.0 = Debug|Win32 - {F7FFFA55-C1B3-4961-8DAB-C1527EF2FF22}.Release|Any CPU.ActiveCfg = Release|Win32 {F7FFFA55-C1B3-4961-8DAB-C1527EF2FF22}.Release|x64.ActiveCfg = Release|x64 {F7FFFA55-C1B3-4961-8DAB-C1527EF2FF22}.Release|x64.Build.0 = Release|x64 {F7FFFA55-C1B3-4961-8DAB-C1527EF2FF22}.Release|x86.ActiveCfg = Release|Win32 {F7FFFA55-C1B3-4961-8DAB-C1527EF2FF22}.Release|x86.Build.0 = Release|Win32 - {E236041A-1327-4A58-9D44-5DB389FB6071}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E236041A-1327-4A58-9D44-5DB389FB6071}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E236041A-1327-4A58-9D44-5DB389FB6071}.Debug|x64.ActiveCfg = Debug|Any CPU - {E236041A-1327-4A58-9D44-5DB389FB6071}.Debug|x64.Build.0 = Debug|Any CPU - {E236041A-1327-4A58-9D44-5DB389FB6071}.Debug|x86.ActiveCfg = Debug|Any CPU - {E236041A-1327-4A58-9D44-5DB389FB6071}.Debug|x86.Build.0 = Debug|Any CPU - {E236041A-1327-4A58-9D44-5DB389FB6071}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E236041A-1327-4A58-9D44-5DB389FB6071}.Release|Any CPU.Build.0 = Release|Any CPU - {E236041A-1327-4A58-9D44-5DB389FB6071}.Release|x64.ActiveCfg = Release|Any CPU - {E236041A-1327-4A58-9D44-5DB389FB6071}.Release|x64.Build.0 = Release|Any CPU - {E236041A-1327-4A58-9D44-5DB389FB6071}.Release|x86.ActiveCfg = Release|Any CPU - {E236041A-1327-4A58-9D44-5DB389FB6071}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {845A18BB-B6E4-470A-9B9B-9B9B9D902828} + SolutionGuid = {B25A33C5-CF74-4F54-B0E6-3DAACCF2B8D0} EndGlobalSection EndGlobal diff --git a/src/DNA/native/src/ChangeLog.txt b/src/DNA/native/ChangeLog.txt similarity index 100% rename from src/DNA/native/src/ChangeLog.txt rename to src/DNA/native/ChangeLog.txt diff --git a/src/DNA/native/src/License.txt b/src/DNA/native/License.txt similarity index 100% rename from src/DNA/native/src/License.txt rename to src/DNA/native/License.txt diff --git a/src/DNA/native/System.Attribute.h b/src/DNA/native/System.Attribute.h deleted file mode 100644 index 83d20a1c..00000000 --- a/src/DNA/native/System.Attribute.h +++ /dev/null @@ -1,8 +0,0 @@ -#if !defined(__SYSTEM_ATTRIBUTE_H) -#define __SYSTEM_ATTRIBUTE_H - -typedef struct tSystemAttribute_ tSystemAttribute; -struct tSystemAttribute_ { -}; - -#endif \ No newline at end of file diff --git a/src/DNA/native/build.cmd b/src/DNA/native/build.cmd index 7cd3c0d3..190b73be 100644 --- a/src/DNA/native/build.cmd +++ b/src/DNA/native/build.cmd @@ -5,7 +5,8 @@ cd /d %~dp0 set sourceFiles= for /f "delims=" %%a in ('dir /b src\*.c') do set sourceFiles=!sourceFiles! src\%%a -set emccOptions= %sourceFiles% ^ +set emccOptions=%sourceFiles% ^ + -DJS_INTEROP ^ -Wno-pointer-sign ^ -Oz ^ -s NO_EXIT_RUNTIME=1 ^ diff --git a/src/DNA/native/dna.pro b/src/DNA/native/dna.pro new file mode 100644 index 00000000..b497c8ce --- /dev/null +++ b/src/DNA/native/dna.pro @@ -0,0 +1,108 @@ +TEMPLATE = app +CONFIG += console +CONFIG -= app_bundle +CONFIG -= qt + +LIBS += -lm -ldl +#QMAKE_CXXFLAGS += -DJS_INTEROP +#QMAKE_CFLAGS += -DJS_INTEROP + +SOURCES = \ + src/CLIFile.c \ + src/Delegate.c \ + src/dna.c \ + src/Finalizer.c \ + src/Generics.c \ + src/Heap.c \ + src/InternalCall.c \ + src/JIT_Execute.c \ + src/JIT.c \ + src/JSInterop.c \ + src/MetaData_Fill.c \ + src/MetaData_Search.c \ + src/MetaData.c \ + src/MethodState.c \ + src/PInvoke.c \ + src/Reflection.c \ + src/RVA.c \ + src/Sys.c \ + src/System.Array.c \ + src/System.Char.c \ + src/System.Console.c \ + src/System.DateTime.c \ + src/System.Diagnostics.Debugger.c \ + src/System.Enum.c \ + src/System.Environment.c \ + src/System.GC.c \ + src/System.IO.FileInternal.c \ + src/System.Math.c \ + src/System.Net.Dns.c \ + src/System.Net.Sockets.Socket.c \ + src/System.Object.c \ + src/System.Runtime.CompilerServices.RuntimeHelpers.c \ + src/System.RuntimeType.c \ + src/System.String.c \ + src/System.Threading.Interlocked.c \ + src/System.Threading.Monitor.c \ + src/System.Threading.Thread.c \ + src/System.Type.c \ + src/System.ValueType.c \ + src/System.WeakReference.c \ + src/Thread.c \ + src/Type.c + +HEADERS += \ + src/CIL_OpCodes.h \ + src/CLIFile.h \ + src/Compat.h \ + src/Config.h \ + src/Delegate.h \ + src/EvalStack.h \ + src/Finalizer.h \ + src/Generics.h \ + src/Heap.h \ + src/InternalCall.h \ + src/JIT_OpCodes.h \ + src/JIT.h \ + src/JSInterop.h \ + src/MetaData.h \ + src/MetaDataTables.h \ + src/MethodState.h \ + src/PInvoke_CaseCode.h \ + src/PInvoke_TypeDef.h \ + src/PInvoke.h \ + src/Reflection.h \ + src/RVA.h \ + src/Sys.h \ + src/System.Array.h \ + src/System.Attribute.h \ + src/System.Char.CaseConversion.h \ + src/System.Char.h \ + src/System.Char.UC_IndexRuns.h \ + src/System.Console.h \ + src/System.DateTime.h \ + src/System.Diagnostics.Debugger.h \ + src/System.Enum.h \ + src/System.Environment.h \ + src/System.GC.h \ + src/System.IO.FileInternal.h \ + src/System.Math.h \ + src/System.Net.Dns.h \ + src/System.Net.Sockets.Socket.h \ + src/System.Object.h \ + src/System.Reflection.MemberInfo.h \ + src/System.Reflection.MethodBase.h \ + src/System.Reflection.MethodInfo.h \ + src/System.Reflection.PropertyInfo.h \ + src/System.Runtime.CompilerServices.RuntimeHelpers.h \ + src/System.RuntimeType.h \ + src/System.String.h \ + src/System.Threading.Interlocked.h \ + src/System.Threading.Monitor.h \ + src/System.Threading.Thread.h \ + src/System.Type.h \ + src/System.ValueType.h \ + src/System.WeakReference.h \ + src/Thread.h \ + src/Type.h \ + src/Types.h diff --git a/src/DNA/native/dna.vcxproj b/src/DNA/native/dna.vcxproj index ea656ecb..e60046cb 100644 --- a/src/DNA/native/dna.vcxproj +++ b/src/DNA/native/dna.vcxproj @@ -5,14 +5,14 @@ Debug Win32 - - Release - Win32 - Debug x64 + + Release + Win32 + Release x64 @@ -131,17 +131,17 @@ v141 Unicode - + Application - false + true v141 - true Unicode - + Application - true + false v141 + true Unicode @@ -159,13 +159,13 @@ - + - + - + @@ -187,12 +187,12 @@ Level3 Disabled - WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + DEBUG_PRINT;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) Console true - ws2_32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + ws2_32.lib;%(AdditionalDependencies) @@ -201,11 +201,12 @@ Level3 Disabled - _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + DEBUG_PRINT;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) Console true + ws2_32.lib;%(AdditionalDependencies) @@ -223,6 +224,7 @@ true true true + ws2_32.lib;%(AdditionalDependencies) @@ -233,19 +235,17 @@ MaxSpeed true true - NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) Console true true true + ws2_32.lib;%(AdditionalDependencies) - - - \ No newline at end of file diff --git a/src/DNA/native/dna.vcxproj.filters b/src/DNA/native/dna.vcxproj.filters deleted file mode 100644 index b0154b68..00000000 --- a/src/DNA/native/dna.vcxproj.filters +++ /dev/null @@ -1,309 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hh;hpp;hxx;hm;inl;inc;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - \ No newline at end of file diff --git a/src/DNA/native/js-interop.js b/src/DNA/native/js-interop.js index 037945a8..fb0fc8ef 100644 --- a/src/DNA/native/js-interop.js +++ b/src/DNA/native/js-interop.js @@ -18,15 +18,17 @@ mergeInto(LibraryManager.library, { funcName = Pointer_stringify(funcName); arg0 = Pointer_stringify(arg0); - if (!(libName in window)) { + var globalRef = ENVIRONMENT_IS_NODE ? global : window; + + if (!(libName in globalRef)) { throw new Error('No such library \'' + libName + '\''); } - if (!(funcName in window[libName])) { + if (!(funcName in globalRef[libName])) { throw new Error('No such function \'' + funcName + '\' on library \'' + libName + '\''); } - var result = window[libName][funcName](arg0); + var result = globalRef[libName][funcName](arg0); if (result !== null && result !== undefined) { var resultString = result.toString(); var resultPtr = allocate(intArrayFromString(resultString), 'i8', ALLOC_NORMAL); diff --git a/src/DNA/native/post.js b/src/DNA/native/post.js new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/src/DNA/native/post.js @@ -0,0 +1 @@ + diff --git a/src/DNA/native/pre.js b/src/DNA/native/pre.js new file mode 100644 index 00000000..945b01e8 --- /dev/null +++ b/src/DNA/native/pre.js @@ -0,0 +1,17 @@ +var Browser = (typeof Browser === "object") ? Browser : { + init: (function () { }), + asyncLoad: (function (url, onload, onerror, noRunDep) { + var dep = !noRunDep ? getUniqueRunDependency('al ' + url) : ''; + Module['readAsync'](url, + function (arrayBuffer) { + assert(arrayBuffer, 'Loading data file "' + url + '" failed (no arrayBuffer).'); + onload(new Uint8Array(arrayBuffer)); + if (dep) { removeRunDependency(dep); } + }, + function (event) { + if (onerror) { onerror(); } + else { throw 'Loading data file "' + url + '" failed.'; } + }); + if (dep) { addRunDependency(dep); } + }) +}; \ No newline at end of file diff --git a/src/DNA/native/src/CIL_OpCodes.h b/src/DNA/native/src/CIL_OpCodes.h index 9a79fb64..b6bd833d 100644 --- a/src/DNA/native/src/CIL_OpCodes.h +++ b/src/DNA/native/src/CIL_OpCodes.h @@ -20,6 +20,8 @@ #define CIL_NOP 0x00 +#define CIL_BREAK 0x01 + #define CIL_LDARG_0 0x02 #define CIL_LDARG_1 0x03 #define CIL_LDARG_2 0x04 @@ -103,6 +105,9 @@ #define CIL_STIND_I1 0x52 #define CIL_STIND_I2 0x53 #define CIL_STIND_I4 0x54 +#define CIL_STIND_I8 0x55 +#define CIL_STIND_R4 0x56 +#define CIL_STIND_R8 0x57 #define CIL_ADD 0x58 #define CIL_SUB 0x59 @@ -194,6 +199,8 @@ #define CIL_CONV_U2 0xd1 #define CIL_CONV_U1 0xd2 #define CIL_CONV_I 0xd3 +#define CIL_CONV_OVF_I 0xd4 +#define CIL_CONV_OVF_U 0xd5 #define CIL_ADD_OVF 0xd6 #define CIL_ADD_OVF_UN 0xd7 @@ -218,7 +225,13 @@ #define CILX_CLT 0x04 #define CILX_CLT_UN 0x05 #define CILX_LOADFUNCTION 0x06 +#define CILX_LOADVIRTFN 0x07 + +#define CILX_LDLOC 0x0c +#define CILX_STLOC 0x0e +#define CILX_VOLATILE 0x13 +#define CILX_TAIL 0x14 #define CILX_INITOBJ 0x15 #define CILX_CONSTRAINED 0x16 diff --git a/src/DNA/native/src/CLIFile.c b/src/DNA/native/src/CLIFile.c index 1f062133..82cb8806 100644 --- a/src/DNA/native/src/CLIFile.c +++ b/src/DNA/native/src/CLIFile.c @@ -34,16 +34,11 @@ // Is this exe/dll file for the .NET virtual machine? #define DOT_NET_MACHINE 0x14c -typedef struct tFilesLoaded_ tFilesLoaded; -struct tFilesLoaded_ { - tCLIFile *pCLIFile; - tFilesLoaded *pNext; -}; - // In .NET Core, the core libraries are split over numerous assemblies. For simplicity, // the DNA corlib just puts them in one assembly static STRING assembliesMappedToDnaCorlib[] = { - "mscorlib" + "mscorlib", + "netstandard" // Also, "System.*" is implemented below }; static int numAssembliesMappedToDnaCorlib = sizeof(assembliesMappedToDnaCorlib)/sizeof(STRING); @@ -51,6 +46,10 @@ static int numAssembliesMappedToDnaCorlib = sizeof(assembliesMappedToDnaCorlib)/ // Keep track of all the files currently loaded static tFilesLoaded *pFilesLoaded = NULL; +tFilesLoaded* CLIFile_GetLoadedAssemblies() { + return pFilesLoaded; +} + tMetaData* CLIFile_GetMetaDataForLoadedAssembly(unsigned char *pLoadedAssemblyName) { tFilesLoaded *pFiles = pFilesLoaded; @@ -86,7 +85,7 @@ tMetaData* CLIFile_GetMetaDataForAssembly(unsigned char *pAssemblyName) { } // Look in already-loaded files first - pFiles = pFilesLoaded; + pFiles = CLIFile_GetLoadedAssemblies(); while (pFiles != NULL) { tCLIFile *pCLIFile; tMD_Assembly *pThisAssembly; @@ -115,7 +114,7 @@ tMetaData* CLIFile_GetMetaDataForAssembly(unsigned char *pAssemblyName) { } tMD_TypeDef* CLIFile_FindTypeInAllLoadedAssemblies(STRING nameSpace, STRING name) { - tFilesLoaded *pFiles = pFilesLoaded; + tFilesLoaded *pFiles = CLIFile_GetLoadedAssemblies(); while (pFiles != NULL) { tCLIFile *pCLIFile = pFiles->pCLIFile; @@ -157,7 +156,7 @@ static void* LoadFileFromDisk(char *pFileName) { char* GetNullTerminatedString(PTR pData, int* length) { - *length = strlen(pData) + 1; + *length = (int)strlen(pData) + 1; return pData; } @@ -175,7 +174,7 @@ static unsigned int GetU32(unsigned char *pSource, int* length) { } static tDebugMetaData* LoadDebugFile(PTR pData) { - tDebugMetaData *pRet = TMALLOC(tDebugMetaData); + tDebugMetaData *pRet = TMALLOC(1, tDebugMetaData); tDebugMetaDataEntry* pPrevious = NULL; tDebugMetaDataEntry* pFirst = NULL; int moduleLength; @@ -186,7 +185,7 @@ static tDebugMetaData* LoadDebugFile(PTR pData) { int IdLength; while (*pData) { - tDebugMetaDataEntry* pEntry = TMALLOC(tDebugMetaDataEntry); + tDebugMetaDataEntry* pEntry = TMALLOC(1, tDebugMetaDataEntry); IdLength = 0; pEntry->sequencePointsCount = 0; pEntry->pModuleName = GetNullTerminatedString(pData, &moduleLength); @@ -238,7 +237,7 @@ static tDebugMetaData* LoadDebugFile(PTR pData) { } static tCLIFile* LoadPEFile(void *pData) { - tCLIFile *pRet = TMALLOC(tCLIFile); + tCLIFile *pRet = TMALLOCFOREVER(1, tCLIFile); unsigned char *pMSDOSHeader = (unsigned char*)&(((unsigned char*)pData)[0]); unsigned char *pPEHeader; @@ -386,7 +385,7 @@ tCLIFile* CLIFile_Load(char *pFileName) { // Assume it ends in .dll char* pDebugFileName = (char*)mallocForever((U32)strlen(pFileName) + 1); - U32 fileLengthWithoutExt = strlen(pFileName) - 3; + U32 fileLengthWithoutExt = (int)strlen(pFileName) - 3; strncpy(pDebugFileName, pFileName, fileLengthWithoutExt); strncpy(pDebugFileName + fileLengthWithoutExt, "wdb", 3); *(pDebugFileName + fileLengthWithoutExt + 3) = '\0'; @@ -402,7 +401,7 @@ tCLIFile* CLIFile_Load(char *pFileName) { } // Record that we've loaded this file - pNewFile = TMALLOCFOREVER(tFilesLoaded); + pNewFile = TMALLOCFOREVER(1, tFilesLoaded); pNewFile->pCLIFile = pRet; pNewFile->pNext = pFilesLoaded; pFilesLoaded = pNewFile; @@ -434,11 +433,11 @@ I32 CLIFile_Execute(tCLIFile *pThis, int argc, char **argp) { } void CLIFile_GetHeapRoots(tHeapRoots *pHeapRoots) { - tFilesLoaded *pFile; + tFilesLoaded *pFiles; - pFile = pFilesLoaded; - while (pFile != NULL) { - MetaData_GetHeapRoots(pHeapRoots, pFile->pCLIFile->pMetaData); - pFile = pFile->pNext; + pFiles = CLIFile_GetLoadedAssemblies(); + while (pFiles != NULL) { + MetaData_GetHeapRoots(pHeapRoots, pFiles->pCLIFile->pMetaData); + pFiles = pFiles->pNext; } } diff --git a/src/DNA/native/src/CLIFile.h b/src/DNA/native/src/CLIFile.h index df49e0e5..a4606d83 100644 --- a/src/DNA/native/src/CLIFile.h +++ b/src/DNA/native/src/CLIFile.h @@ -41,7 +41,14 @@ struct tCLIFile_ { tMetaData *pMetaData; }; +typedef struct tFilesLoaded_ tFilesLoaded; +struct tFilesLoaded_ { + tCLIFile *pCLIFile; + tFilesLoaded *pNext; +}; + // static methods +tFilesLoaded* CLIFile_GetLoadedAssemblies(); tMetaData* CLIFile_GetMetaDataForAssembly(unsigned char *pAssemblyName); tMetaData* CLIFile_GetMetaDataForLoadedAssembly(unsigned char *pLoadedAssemblyName); tMD_TypeDef* CLIFile_FindTypeInAllLoadedAssemblies(STRING nameSpace, STRING name); diff --git a/src/DNA/native/src/Compat.h b/src/DNA/native/src/Compat.h index 60324707..6f23ab1e 100644 --- a/src/DNA/native/src/Compat.h +++ b/src/DNA/native/src/Compat.h @@ -26,6 +26,7 @@ #include #ifdef _WIN32 + #include // winsock2.h must be included before windows.h #include #include @@ -84,9 +85,19 @@ #define LIB_SUFFIX "so" #define STDCALL +#ifndef max +#define max(a,b) (((a) > (b)) ? (a) : (b)) +#endif + +#ifndef min +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#endif + #endif // _WIN32 -#define TMALLOC(t) (t*)malloc(sizeof(t)) -#define TMALLOCFOREVER(t) (t*)mallocForever(sizeof(t)) +#define TMALLOC(c, t) (t*)malloc(c * sizeof(t)) +#define TCALLOC(c, t) (t*)calloc(c, sizeof(t)) +#define TMALLOCFOREVER(c, t) (t*)mallocForever(c * sizeof(t)) +#define TCALLOCFOREVER(c, t) (t*)callocForever(c, sizeof(t)) #endif diff --git a/src/DNA/native/src/Config.h b/src/DNA/native/src/Config.h index f107b929..b31a7355 100644 --- a/src/DNA/native/src/Config.h +++ b/src/DNA/native/src/Config.h @@ -28,25 +28,30 @@ // instruction on x86 - so the results are in ticks, not seconds) // Count how many times each .NET method is called -#undef DIAG_METHOD_CALLS +//#define DIAG_METHOD_CALLS + +// Maintain and print a callstack buffer +//#define DIAG_CALL_STACK // Measure how much time is spent in each .NET opcode // This only works on Windows // This is not currently implemented, after the change to threaded code -#undef DIAG_OPCODE_TIMES +//#define DIAG_OPCODE_TIMES // Count how many times each .NET opcode is used #ifdef _DEBUG -#undef DIAG_OPCODE_USE +//#define DIAG_OPCODE_USES #endif // Measure how much time is spent in the garbage collector -#undef DIAG_GC +//#define DIAG_GC // Measure how long the entire .NET programme execution takes #define DIAG_TOTAL_TIME - +#ifdef _DEBUG +//#define DIAG_MEMORY_LEAKS +#endif // Non-diagnostic stuff @@ -58,4 +63,21 @@ #define GEN_COMBINED_OPCODES_MAX_MEMORY 0x4000 #define GEN_COMBINED_OPCODES_CALL_TRIGGER 20 +// Performance improvements + +// minor perf improvement: space vs speed trade-off +// (disabled by default) +#ifdef _DEBUG +//#define STORE_HEAPENTRY_SIZE +#endif + +// perf improvement: switch on JIT ops instead of labels +// (enabled in WIN64 by default, but works well in 32-bit too) +//#ifdef _WIN64 +#define SWITCH_ON_JIT_OP +//#endif + +// disable GC completely (for perf testing/tuning) +//#define NO_GC_WHATSOEVER + #endif diff --git a/src/DNA/native/src/Finalizer.c b/src/DNA/native/src/Finalizer.c index 80c9001d..a3717ba8 100644 --- a/src/DNA/native/src/Finalizer.c +++ b/src/DNA/native/src/Finalizer.c @@ -28,10 +28,20 @@ static int toFinalizeOfs, toFinalizeCapacity; void Finalizer_Init() { toFinalizeCapacity = 4; - ppToFinalize = (HEAP_PTR*)malloc(toFinalizeCapacity * sizeof(void*)); + ppToFinalize = (HEAP_PTR*)TMALLOC(toFinalizeCapacity, void*); toFinalizeOfs = 0; } +void Finalizer_Free() { + toFinalizeCapacity = 0; + toFinalizeOfs = 0; + free(ppToFinalize); +} + +int Finalizer_Count() { + return toFinalizeOfs; +} + void AddFinalizer(HEAP_PTR ptr) { if (toFinalizeOfs >= toFinalizeCapacity) { toFinalizeCapacity <<= 1; @@ -45,4 +55,4 @@ HEAP_PTR GetNextFinalizer() { return NULL; } return ppToFinalize[--toFinalizeOfs]; -} \ No newline at end of file +} diff --git a/src/DNA/native/src/Finalizer.h b/src/DNA/native/src/Finalizer.h index eead303b..928bb592 100644 --- a/src/DNA/native/src/Finalizer.h +++ b/src/DNA/native/src/Finalizer.h @@ -22,6 +22,8 @@ #define __FINALIZER_H void Finalizer_Init(); +void Finalizer_Free(); +int Finalizer_Count(); void AddFinalizer(PTR ptr); HEAP_PTR GetNextFinalizer(); diff --git a/src/DNA/native/src/Generics.c b/src/DNA/native/src/Generics.c index 2ac5918e..3ac73cce 100644 --- a/src/DNA/native/src/Generics.c +++ b/src/DNA/native/src/Generics.c @@ -41,23 +41,20 @@ void Generic_GetHeapRoots(tHeapRoots *pHeapRoots, tMD_TypeDef *pTypeDef) { tMD_TypeDef* Generics_GetGenericTypeFromSig (tMetaData *pMetaData, SIG *pSig, tMD_TypeDef **ppCallingClassTypeArgs, tMD_TypeDef **ppCallingMethodTypeArgs) { - tMD_TypeDef *pCoreType, *pRet; - U32 numTypeArgs, i; - tMD_TypeDef **ppTypeArgs; - pCoreType = Type_GetTypeFromSig(pMetaData, pSig, ppCallingClassTypeArgs, ppCallingMethodTypeArgs); - MetaData_Fill_TypeDef(pCoreType, ppCallingClassTypeArgs, ppCallingMethodTypeArgs); //NULL, NULL); + tMD_TypeDef *pCoreType = Type_GetTypeFromSig(pMetaData, pSig, ppCallingClassTypeArgs, ppCallingMethodTypeArgs); + MetaData_Fill_TypeDef(pCoreType, NULL, NULL); - numTypeArgs = MetaData_DecodeSigEntry(pSig); - ppTypeArgs = (tMD_TypeDef**)malloc(numTypeArgs * sizeof(tMD_TypeDef*)); - for (i=0; ipMetaData, MAKE_TABLE_INDEX(MD_TABLE_GENERICPARAM, 1)); - - for (i=0; ipMetaData->tables.numRows[MD_TABLE_GENERICPARAM]; i++, pGenericParam++) { - if (pGenericParam->owner == pCoreType->tableIndex && pGenericParam->number == typeArgIndex) { + U32 rows = pCoreType->pMetaData->tables.numRows[MD_TABLE_GENERICPARAM]; + IDX_TABLE ownerToken = pCoreType->tableIndex; + for (U32 i = 0; i < rows; i++, pGenericParam++) { + if (pGenericParam->owner == ownerToken && pGenericParam->number == typeArgIndex) { return pGenericParam; } } return NULL; } +//static tMD_GenericParam* FindGenericParam(tMD_TypeDef *pCoreType, U32 typeArgIndex) { +// U32 rows = pCoreType->pMetaData->tables.numRows[MD_TABLE_GENERICPARAM]; +// tMD_GenericParam *pGenericParam = (tMD_GenericParam*)MetaData_GetTableRow(pCoreType->pMetaData, MAKE_TABLE_INDEX(MD_TABLE_GENERICPARAM, 1)); +// IDX_TABLE ownerToken = pCoreType->tableIndex; +// +// // binary search in GenericParams table +// int lo = 0; +// int hi = rows - 1; +// while (lo <= hi) { +// int i = lo + ((hi - lo) >> 1); +// if (pGenericParam[i].owner < ownerToken) { lo = i + 1; } +// else { +// if (pGenericParam[i].owner > ownerToken) { hi = i - 1; } +// else { +// while (pGenericParam[i].owner == ownerToken) { +// if (pGenericParam[i].number < typeArgIndex) { ++i; } +// else { +// if (pGenericParam[i].number > typeArgIndex) { --i; } +// else { return (pGenericParam + i); } +// } +// } +// } +// } +// } +// return NULL; +//} + tMD_TypeDef* Generics_GetGenericTypeFromCoreType(tMD_TypeDef *pCoreType, U32 numTypeArgs, tMD_TypeDef **ppTypeArgs) { tGenericInstance *pInst; tMD_TypeDef *pTypeDef; U32 i; - unsigned char name[2048]; + unsigned char name[8192]; // must be big enough to handle the biggest types tMetaData *pMetaData; pMetaData = pCoreType->pMetaData; @@ -108,11 +131,11 @@ tMD_TypeDef* Generics_GetGenericTypeFromCoreType(tMD_TypeDef *pCoreType, U32 num memcpy(pInst->pTypeArgs, ppTypeArgs, numTypeArgs * sizeof(tMD_TypeDef*)); // Create the new instantiated type - pInst->pInstanceTypeDef = pTypeDef = TMALLOCFOREVER(tMD_TypeDef); - memset(pTypeDef, 0, sizeof(tMD_TypeDef)); + pInst->pInstanceTypeDef = pTypeDef = TCALLOCFOREVER(1, tMD_TypeDef); + //memset(pTypeDef, 0, sizeof(tMD_TypeDef)); // Make the name of the instantiation. strcpy(name, pCoreType->name); - strcat(name, "["); + strcat(name, "<"); for (i=0; i 0) { strcat(name, ","); @@ -122,13 +145,13 @@ tMD_TypeDef* Generics_GetGenericTypeFromCoreType(tMD_TypeDef *pCoreType, U32 num } else { tMD_GenericParam *pGenericParam = FindGenericParam(pCoreType, i); if (pGenericParam != NULL) { - sprintf(strchr(name, 0), pGenericParam->name); + sprintf(strchr(name, 0), "%s", pGenericParam->name); } else { sprintf(strchr(name, 0), "???"); } } } - strcat(name, "]"); + strcat(name, ">"); // Fill in the basic bits of the new type def. pTypeDef->pTypeDef = pTypeDef; pTypeDef->pMetaData = pMetaData; @@ -143,6 +166,7 @@ tMD_TypeDef* Generics_GetGenericTypeFromCoreType(tMD_TypeDef *pCoreType, U32 num pTypeDef->nameSpace = pCoreType->nameSpace; pTypeDef->name = (STRING)mallocForever((U32)strlen(name)+1); strcpy(pTypeDef->name, name); + // dprintfn("Instantiated type %s.%s", pTypeDef->nameSpace, pTypeDef->name); pTypeDef->ppClassTypeArgs = pInst->pTypeArgs; pTypeDef->extends = pCoreType->extends; pTypeDef->tableIndex = pCoreType->tableIndex; @@ -163,25 +187,22 @@ tMD_MethodDef* Generics_GetMethodDefFromSpec (tMD_MethodSpec *pMethodSpec, tMD_TypeDef **ppCallingClassTypeArgs, tMD_TypeDef **ppCallingMethodTypeArgs) { tMD_MethodDef *pCoreMethod, *pMethod; - SIG sig; - U32 argCount, i; - tMD_TypeDef **ppTypeArgs; - + pCoreMethod = MetaData_GetMethodDefFromDefRefOrSpec(pMethodSpec->pMetaData, pMethodSpec->method, ppCallingClassTypeArgs, ppCallingMethodTypeArgs); + if (pCoreMethod->pParentType == NULL) { + pCoreMethod->pParentType = MetaData_GetTypeDefFromMethodDef(pCoreMethod); + } - //ppClassTypeArgs = pCoreMethod->pParentType->ppClassTypeArgs; - sig = MetaData_GetBlob(pMethodSpec->instantiation, NULL); + SIG sig = MetaData_GetBlob(pMethodSpec->instantiation, NULL); MetaData_DecodeSigEntry(&sig); // always 0x0a - argCount = MetaData_DecodeSigEntry(&sig); - ppTypeArgs = malloc(argCount * sizeof(tMD_TypeDef*)); - - for (i=0; ipMetaData, &sig, ppCallingClassTypeArgs, ppCallingMethodTypeArgs); + U32 argCount = MetaData_DecodeSigEntry(&sig); + tMD_TypeDef **ppTypeArgs = TMALLOC(argCount, tMD_TypeDef*); + for (U32 i = 0; ipMetaData, &sig, ppCallingClassTypeArgs, ppCallingMethodTypeArgs); ppTypeArgs[i] = pArgType; } + //ppClassTypeArgs = pCoreMethod->pParentType->ppClassTypeArgs; pMethod = Generics_GetMethodDefFromCoreMethod(pCoreMethod, pCoreMethod->pParentType, argCount, ppTypeArgs); free(ppTypeArgs); @@ -211,8 +232,8 @@ tMD_MethodDef* Generics_GetMethodDefFromCoreMethod pInst->numTypeArgs = numTypeArgs; memcpy(pInst->pTypeArgs, ppTypeArgs, numTypeArgs * sizeof(tMD_TypeDef*)); - pInst->pInstanceMethodDef = pMethod = TMALLOCFOREVER(tMD_MethodDef); - memset(pMethod, 0, sizeof(tMD_MethodDef)); + pInst->pInstanceMethodDef = pMethod = TCALLOCFOREVER(1, tMD_MethodDef); + //memset(pMethod, 0, sizeof(tMD_MethodDef)); pMethod->pMethodDef = pMethod; pMethod->pMetaData = pCoreMethod->pMetaData; pMethod->pCIL = pCoreMethod->pCIL; @@ -221,6 +242,9 @@ tMD_MethodDef* Generics_GetMethodDefFromCoreMethod pMethod->name = pCoreMethod->name; pMethod->signature = pCoreMethod->signature; pMethod->vTableOfs = pCoreMethod->vTableOfs; + + // TODO: refactor to store pInst itself, to speedup the lookup at runtime + pMethod->numMethodTypeArgs = pInst->numTypeArgs; pMethod->ppMethodTypeArgs = pInst->pTypeArgs; MetaData_Fill_MethodDef(pParentType, pMethod, pParentType->ppClassTypeArgs, pInst->pTypeArgs); diff --git a/src/DNA/native/src/Heap.c b/src/DNA/native/src/Heap.c index 8c31592e..251061be 100644 --- a/src/DNA/native/src/Heap.c +++ b/src/DNA/native/src/Heap.c @@ -72,6 +72,10 @@ struct tHeapEntry_ { // unused U8 padding; +#ifdef STORE_HEAPENTRY_SIZE + U32 totalSize; +#endif + // The type in this heap entry tMD_TypeDef *pTypeDef; @@ -97,6 +101,8 @@ static U32 trackHeapSize; static U32 heapSizeMax; // The number of allocated memory nodes static U32 numNodes = 0; +// The number of pinned memory nodes +static U32 numPinned = 0; // The number of collections done static U32 numCollections = 0; @@ -105,21 +111,26 @@ static U32 numCollections = 0; U64 gcTotalTime = 0; #endif -#define MIN_HEAP_SIZE 50000 -#define MAX_HEAP_EXCESS 200000 +#define MIN_HEAP_SIZE 1000000 +#define MAX_HEAP_EXCESS 4000000 void Heap_Init() { // Initialise vars trackHeapSize = 0; heapSizeMax = MIN_HEAP_SIZE; // Create nil node - for leaf termination - nil = TMALLOCFOREVER(tHeapEntry); - memset(nil, 0, sizeof(tHeapEntry)); + nil = TCALLOCFOREVER(1, tHeapEntry); + //memset(nil, 0, sizeof(tHeapEntry)); nil->pLink[0] = nil->pLink[1] = nil; // Set the heap tree as empty pHeapTreeRoot = nil; } +#ifdef STORE_HEAPENTRY_SIZE +#define HEAPENTRY_TOTALSIZE(pNode) pNode->totalSize +#else +#define HEAPENTRY_TOTALSIZE(pNode) GetSize(pNode) + sizeof(tHeapEntry) + // Get the size of a heap entry, NOT including the header // This works by returning the size of the type, unless the type is an array or a string, // which are the only two types that can have variable sizes @@ -136,6 +147,7 @@ static U32 GetSize(tHeapEntry *pHeapEntry) { // If it's not string or array, just return the instance memory size return pType->instanceMemSize; } +#endif static tHeapEntry* TreeSkew(tHeapEntry *pRoot) { if (pRoot->pLink[0]->level == pRoot->level && pRoot->level != 0) { @@ -158,6 +170,39 @@ static tHeapEntry* TreeSplit(tHeapEntry *pRoot) { return pRoot; } +static tHeapEntry* TreeBalance(tHeapEntry *pRoot) { + if (pRoot->pLink[0]->level < pRoot->level - 1 || pRoot->pLink[1]->level < pRoot->level - 1) { + if (pRoot->pLink[1]->level > --pRoot->level) { + pRoot->pLink[1]->level = pRoot->level; + } + pRoot = TreeSkew(pRoot); + pRoot->pLink[1] = TreeSkew(pRoot->pLink[1]); + pRoot->pLink[1]->pLink[1] = TreeSkew(pRoot->pLink[1]->pLink[1]); + pRoot = TreeSplit(pRoot); + pRoot->pLink[1] = TreeSplit(pRoot->pLink[1]); + } + return pRoot; +} + +static tHeapEntry* TreeSearch(tHeapEntry *pNode, char *pMemRef) { + // Find this piece of heap memory in the tracking tree. + // Note that the 2nd memory address comparison MUST be >, not >= as might be expected, + // to allow for a zero-sized memory to be detected (and not garbage collected) properly. + // E.g. The object class has zero memory. + while (pNode != nil) { + if (pMemRef < (char*)pNode) { + pNode = pNode->pLink[0]; + } + else if (pMemRef > (char*)pNode + HEAPENTRY_TOTALSIZE(pNode)) { + pNode = pNode->pLink[1]; + } + else { + break; + } + } + return pNode; +} + static tHeapEntry* TreeInsert(tHeapEntry *pRoot, tHeapEntry *pEntry) { if (pRoot == nil) { pRoot = pEntry; @@ -165,36 +210,10 @@ static tHeapEntry* TreeInsert(tHeapEntry *pRoot, tHeapEntry *pEntry) { pRoot->pLink[0] = pRoot->pLink[1] = nil; pRoot->marked = 0; } else { - tHeapEntry *pNode = pHeapTreeRoot; - tHeapEntry *pUp[MAX_TREE_DEPTH]; - I32 top = 0, dir; - // Find leaf position to insert into tree. This first step is unbalanced - for (;;) { - pUp[top++] = pNode; - dir = pNode < pEntry; // 0 for left, 1 for right - if (pNode->pLink[dir] == nil) { - break; - } - pNode = pNode->pLink[dir]; - } - // Create new node - pNode->pLink[dir] = pEntry; - pEntry->level = 1; - pEntry->pLink[0] = pEntry->pLink[1] = nil; - pEntry->marked = 0; - // Balance the tree - while (--top >= 0) { - if (top != 0) { - dir = pUp[top-1]->pLink[1] == pUp[top]; - } - pUp[top] = TreeSkew(pUp[top]); - pUp[top] = TreeSplit(pUp[top]); - if (top != 0) { - pUp[top-1]->pLink[dir] = pUp[top]; - } else { - pRoot = pUp[0]; - } - } + I32 dir = pRoot < pEntry; // 0 for left, 1 for right + pRoot->pLink[dir] = TreeInsert(pRoot->pLink[dir], pEntry); + pRoot = TreeSkew(pRoot); + pRoot = TreeSplit(pRoot); } return pRoot; } @@ -227,50 +246,25 @@ static tHeapEntry* TreeRemove(tHeapEntry *pRoot, tHeapEntry *pDelete) { pRoot = pHeir; // Delete the node that's been sent down pRoot->pLink[0] = TreeRemove(pRoot->pLink[0], pL0); - } else { + } + else { pRoot = pRoot->pLink[pRoot->pLink[0] == nil]; } - } else { + } + else { I32 dir = pRoot < pDelete; pRoot->pLink[dir] = TreeRemove(pRoot->pLink[dir], pDelete); } } - if (pRoot->pLink[0]->level < pRoot->level-1 || pRoot->pLink[1]->level < pRoot->level-1) { - if (pRoot->pLink[1]->level > --pRoot->level) { - pRoot->pLink[1]->level = pRoot->level; - } - pRoot = TreeSkew(pRoot); - pRoot->pLink[1] = TreeSkew(pRoot->pLink[1]); - pRoot->pLink[1]->pLink[1] = TreeSkew(pRoot->pLink[1]->pLink[1]); - pRoot = TreeSplit(pRoot); - pRoot->pLink[1] = TreeSplit(pRoot->pLink[1]); - } - - return pRoot; + return TreeBalance(pRoot); } -static void GarbageCollect() { +static void GC_Mark() { tHeapRoots heapRoots; - tHeapEntry *pNode; - tHeapEntry *pUp[MAX_TREE_DEPTH * 2]; - I32 top; - tHeapEntry *pToDelete = NULL; - U32 orgHeapSize = trackHeapSize; - U32 orgNumNodes = numNodes; -#ifdef DIAG_GC - U64 startTime; -#endif - - numCollections++; - -#ifdef DIAG_GC - startTime = microTime(); -#endif - heapRoots.capacity = 64; heapRoots.num = 0; - heapRoots.pHeapEntries = malloc(heapRoots.capacity * sizeof(tHeapRootEntry)); + heapRoots.pHeapEntries = TMALLOC(heapRoots.capacity, tHeapRootEntry); Thread_GetHeapRoots(&heapRoots); CLIFile_GetHeapRoots(&heapRoots); @@ -278,7 +272,6 @@ static void GarbageCollect() { // Mark phase while (heapRoots.num > 0) { tHeapRootEntry *pRootsEntry; - U32 i; U32 moreRootsAdded = 0; U32 rootsEntryNumPointers; void **pRootsEntryMem; @@ -291,51 +284,41 @@ static void GarbageCollect() { pRootsEntry->numPointers = 0; pRootsEntry->pMem = NULL; // Iterate through all pointers in it - for (i=0; i, not >= as might be expected, - // to allow for a zero-sized memory to be detected (and not garbage collected) properly. - // E.g. The object class has zero memory. - pNode = pHeapTreeRoot; - while (pNode != nil) { - if (pMemRef < (void*)pNode) { - pNode = pNode->pLink[0]; - } else if ((char*)pMemRef > ((char*)pNode) + GetSize(pNode) + sizeof(tHeapEntry)) { - pNode = pNode->pLink[1]; - } else { - // Found memory. See if it's already been marked. - // If it's already marked, then don't do anything. - // It it's not marked, then add all of its memory to the roots, and mark it. - if (pNode->marked == 0) { - tMD_TypeDef *pType = pNode->pTypeDef; - - // Not yet marked, so mark it, and add it to heap roots. - pNode->marked = 1; - - // Don't look at the contents of strings, arrays of primitive types, or WeakReferences - if (pType->stackType == EVALSTACK_O || - pType->stackType == EVALSTACK_VALUETYPE || - pType->stackType == EVALSTACK_PTR) { - - if (pType != types[TYPE_SYSTEM_STRING] && - (!TYPE_ISARRAY(pType) || + tHeapEntry *pNode = TreeSearch(pHeapTreeRoot, pMemRef); + if (pNode != nil) { + // Found memory. See if it's already been marked. + // If it's already marked, then don't do anything. + // It it's not marked, then add all of its memory to the roots, and mark it. + if (pNode->marked == 0) { + tMD_TypeDef *pType = pNode->pTypeDef; + + // Not yet marked, so mark it, and add it to heap roots. + pNode->marked = 1; + + // Don't look at the contents of strings, arrays of primitive types, or WeakReferences + if (pType->stackType == EVALSTACK_O || + pType->stackType == EVALSTACK_VALUETYPE || + pType->stackType == EVALSTACK_PTR) { + + if (pType != types[TYPE_SYSTEM_STRING] && + (!TYPE_ISARRAY(pType) || pType->pArrayElementType->stackType == EVALSTACK_O || pType->pArrayElementType->stackType == EVALSTACK_VALUETYPE || pType->pArrayElementType->stackType == EVALSTACK_PTR)) { - if (pType != types[TYPE_SYSTEM_WEAKREFERENCE]) { - Heap_SetRoots(&heapRoots,pNode->memory, GetSize(pNode)); - moreRootsAdded = 1; - } + if (pType != types[TYPE_SYSTEM_WEAKREFERENCE]) { + Heap_SetRoots(&heapRoots, pNode->memory, HEAPENTRY_TOTALSIZE(pNode) - sizeof(tHeapEntry)); + moreRootsAdded = 1; } } } - break; } } } @@ -345,11 +328,19 @@ static void GarbageCollect() { } free(heapRoots.pHeapEntries); +} + +static void GC_Sweep() { + + tHeapEntry *pUp[MAX_TREE_DEPTH * 2]; + tHeapEntry *pToDelete = NULL; + tHeapEntry *pNode; // Sweep phase // Traverse nodes pUp[0] = pHeapTreeRoot; - top = 1; + I32 top = 1; + numPinned = 0; while (top != 0) { // Get this node pNode = pUp[--top]; @@ -359,13 +350,17 @@ static void GarbageCollect() { // Still in use (but not marked undeletable), so unmark pNode->marked = 0; } - } else { + else { + numPinned++; + } + } + else { // Not in use any more, so put in deletion queue if it does not need Finalizing // If it does need Finalizing, then don't garbage collect, and put in Finalization queue. if (pNode->needToFinalize) { if (pNode->needToFinalize == 1) { AddFinalizer((HEAP_PTR)pNode + sizeof(tHeapEntry)); - // Mark it has having been placed in the finalization queue. + // Mark it as having been placed in the finalization queue. // When it has been finalized, then this will be set to 0 pNode->needToFinalize = 2; // If this object is being targetted by weak-ref(s), handle it @@ -374,7 +369,8 @@ static void GarbageCollect() { free(pNode->pSync); } } - } else { + } + else { // If this object is being targetted by weak-ref(s), handle it if (pNode->pSync != NULL) { RemoveWeakRefTarget(pNode, 1); @@ -401,16 +397,34 @@ static void GarbageCollect() { pToDelete = (tHeapEntry*)(pToDelete->pSync); pHeapTreeRoot = TreeRemove(pHeapTreeRoot, pThis); numNodes--; - trackHeapSize -= GetSize(pThis) + sizeof(tHeapEntry); + trackHeapSize -= HEAPENTRY_TOTALSIZE(pThis); free(pThis); } +} + +static void GarbageCollect() { + U32 orgHeapSize = trackHeapSize; + U32 orgNumNodes = numNodes; + U32 orgPinned = numPinned; +#ifdef DIAG_GC + U64 startTime; +#endif + + numCollections++; + +#ifdef DIAG_GC + startTime = microTime(); +#endif + + GC_Mark(); + GC_Sweep(); #ifdef DIAG_GC gcTotalTime += microTime() - startTime; #endif - log_f(1, "--- GARBAGE --- [Size: %d -> %d] [Nodes: %d -> %d]\n", - orgHeapSize, trackHeapSize, orgNumNodes, numNodes); + log_f(1, "--- GARBAGE --- [Size: %d -> %d] [Nodes: %d -> %d] [Pinned: %d -> %d]\n", + orgHeapSize, trackHeapSize, orgNumNodes, numNodes, orgPinned, numPinned); #ifdef DIAG_GC log_f(1, "GC time = %d ms\n", gcTotalTime / 1000); @@ -422,7 +436,9 @@ void Heap_UnmarkFinalizer(HEAP_PTR heapPtr) { } void Heap_GarbageCollect() { +#if !defined(NO_GC_WHATSOEVER) GarbageCollect(); +#endif } U32 Heap_NumCollections() { @@ -466,14 +482,20 @@ HEAP_PTR Heap_Alloc(tMD_TypeDef *pTypeDef, U32 size) { } } - pHeapEntry = (tHeapEntry*)malloc(totalSize); + pHeapEntry = (tHeapEntry*)calloc(1, totalSize); + //memset(pHeapEntry, 0, totalSize); +#ifdef STORE_HEAPENTRY_SIZE + pHeapEntry->totalSize = totalSize; +#endif pHeapEntry->pTypeDef = pTypeDef; pHeapEntry->pSync = NULL; pHeapEntry->needToFinalize = (pTypeDef->pFinalizer != NULL); - memset(pHeapEntry->memory, 0, size); - trackHeapSize += totalSize; +#if !defined(NO_GC_WHATSOEVER) + trackHeapSize += totalSize; pHeapTreeRoot = TreeInsert(pHeapTreeRoot, pHeapEntry); +#endif + numNodes++; return pHeapEntry->memory; @@ -511,7 +533,7 @@ HEAP_PTR Heap_Box(tMD_TypeDef *pType, PTR pMem) { HEAP_PTR Heap_Clone(HEAP_PTR obj) { tHeapEntry *pObj = GET_HEAPENTRY(obj); HEAP_PTR clone; - U32 size = GetSize(pObj); + U32 size = HEAPENTRY_TOTALSIZE(pObj) - sizeof(tHeapEntry); clone = Heap_Alloc(pObj->pTypeDef, size); memcpy(clone, pObj->memory, size); @@ -521,8 +543,8 @@ HEAP_PTR Heap_Clone(HEAP_PTR obj) { static tSync* EnsureSync(tHeapEntry *pHeapEntry) { if (pHeapEntry->pSync == NULL) { - tSync *pSync = TMALLOC(tSync); - memset(pSync, 0, sizeof(tSync)); + tSync *pSync = TCALLOC(1, tSync); + //memset(pSync, 0, sizeof(tSync)); pHeapEntry->pSync = pSync; } return pHeapEntry->pSync; diff --git a/src/DNA/native/src/InternalCall.c b/src/DNA/native/src/InternalCall.c index 44d19eed..57af03f0 100644 --- a/src/DNA/native/src/InternalCall.c +++ b/src/DNA/native/src/InternalCall.c @@ -72,17 +72,35 @@ static tInternalCall internalCalls[] = { {NULL, NULL, "GetHashCode", System_Object_GetHashCode, TYPE_SYSTEM_INT32, 0}, {NULL, NULL, "GetType", System_Object_GetType, TYPE_SYSTEM_TYPE, 0}, - {NULL, "String", ".ctor", System_String_ctor_CharInt32, TYPE_SYSTEM_VOID, 2, {TYPE_SYSTEM_CHAR, TYPE_SYSTEM_INT32}}, + {NULL, "String", ".ctor", System_String_ctor_CharInt32, TYPE_SYSTEM_VOID, 2, { TYPE_SYSTEM_CHAR, TYPE_SYSTEM_INT32 } }, + {NULL, NULL, ".ctor", System_String_ctor_CharA, TYPE_SYSTEM_VOID, 1, { TYPE_SYSTEM_ARRAY_CHAR } }, {NULL, NULL, ".ctor", System_String_ctor_CharAIntInt, TYPE_SYSTEM_VOID, 3, {TYPE_SYSTEM_ARRAY_CHAR, TYPE_SYSTEM_INT32, TYPE_SYSTEM_INT32}}, {NULL, NULL, ".ctor", System_String_ctor_StringIntInt, TYPE_SYSTEM_VOID, 3, {TYPE_SYSTEM_STRING, TYPE_SYSTEM_INT32, TYPE_SYSTEM_INT32}}, {NULL, NULL, "get_Chars", System_String_get_Chars, TYPE_SYSTEM_CHAR, 1, {TYPE_SYSTEM_INT32}}, {NULL, NULL, "InternalConcat", System_String_InternalConcat, TYPE_SYSTEM_STRING, 2, {TYPE_SYSTEM_STRING, TYPE_SYSTEM_STRING}}, + {NULL, NULL, "InternalCopyTo", System_String_InternalCopyTo, TYPE_SYSTEM_VOID, 4, {TYPE_SYSTEM_INT32, TYPE_SYSTEM_ARRAY_CHAR, TYPE_SYSTEM_INT32, TYPE_SYSTEM_INT32}}, {NULL, NULL, "InternalTrim", System_String_InternalTrim, TYPE_SYSTEM_STRING, 2, {TYPE_SYSTEM_ARRAY_CHAR, TYPE_SYSTEM_INT32}}, + {NULL, NULL, "CompareOrdinal", System_String_CompareOrdinal, TYPE_SYSTEM_INT32, 2, {TYPE_SYSTEM_STRING, TYPE_SYSTEM_STRING}}, {NULL, NULL, "Equals", System_String_Equals, TYPE_SYSTEM_BOOLEAN, 2, {TYPE_SYSTEM_STRING, TYPE_SYSTEM_STRING}}, {NULL, NULL, "GetHashCode", System_String_GetHashCode, TYPE_SYSTEM_INT32, 0}, {NULL, NULL, "InternalReplace", System_String_InternalReplace, TYPE_SYSTEM_STRING, 2, {TYPE_SYSTEM_STRING, TYPE_SYSTEM_STRING}}, {NULL, NULL, "InternalIndexOf", System_String_InternalIndexOf, TYPE_SYSTEM_INT32, 4, {TYPE_SYSTEM_CHAR, TYPE_SYSTEM_INT32, TYPE_SYSTEM_INT32, TYPE_SYSTEM_BOOLEAN}}, {NULL, NULL, "InternalIndexOfAny", System_String_InternalIndexOfAny, TYPE_SYSTEM_INT32, 4, {TYPE_SYSTEM_ARRAY_CHAR, TYPE_SYSTEM_INT32, TYPE_SYSTEM_INT32, TYPE_SYSTEM_BOOLEAN}}, + {NULL, NULL, "InternalIndexOfStr", System_String_InternalIndexOfStr, TYPE_SYSTEM_INT32, 4, {TYPE_SYSTEM_STRING, TYPE_SYSTEM_INT32, TYPE_SYSTEM_INT32, TYPE_SYSTEM_BOOLEAN}}, + {NULL, NULL, "InternalFromInt32", System_String_InternalFromInt32, TYPE_SYSTEM_STRING, 1, {TYPE_SYSTEM_INT32}}, + {NULL, NULL, "InternalFromInt64", System_String_InternalFromInt64, TYPE_SYSTEM_STRING, 1, {TYPE_SYSTEM_INT64}}, + {NULL, NULL, "InternalFromUInt32", System_String_InternalFromUInt32, TYPE_SYSTEM_STRING, 1, {TYPE_SYSTEM_UINT32}}, + {NULL, NULL, "InternalFromUInt64", System_String_InternalFromUInt64, TYPE_SYSTEM_STRING, 1, {TYPE_SYSTEM_UINT64}}, + {NULL, NULL, "InternalFromSingle", System_String_InternalFromSingle, TYPE_SYSTEM_STRING, 1, {TYPE_SYSTEM_SINGLE}}, + {NULL, NULL, "InternalFromDouble", System_String_InternalFromDouble, TYPE_SYSTEM_STRING, 1, {TYPE_SYSTEM_DOUBLE}}, + {NULL, NULL, "InternalToInt32", System_String_InternalToInt32, TYPE_SYSTEM_INT32, 2, {TYPE_SYSTEM_INTPTR, TYPE_SYSTEM_INT32}}, + {NULL, NULL, "InternalToInt64", System_String_InternalToInt64, TYPE_SYSTEM_INT64, 2, {TYPE_SYSTEM_INTPTR, TYPE_SYSTEM_INT32}}, + {NULL, NULL, "InternalToUInt32", System_String_InternalToUInt32, TYPE_SYSTEM_UINT32, 2, {TYPE_SYSTEM_INTPTR, TYPE_SYSTEM_INT32}}, + {NULL, NULL, "InternalToUInt64", System_String_InternalToUInt64, TYPE_SYSTEM_UINT64, 2, {TYPE_SYSTEM_INTPTR, TYPE_SYSTEM_INT32}}, + {NULL, NULL, "InternalToSingle", System_String_InternalToSingle, TYPE_SYSTEM_SINGLE, 1, {TYPE_SYSTEM_INTPTR}}, + {NULL, NULL, "InternalToDouble", System_String_InternalToDouble, TYPE_SYSTEM_DOUBLE, 1, {TYPE_SYSTEM_INTPTR}}, + {NULL, NULL, "ToLowerInvariant", System_String_ToLowerInvariant, TYPE_SYSTEM_STRING, 0}, + {NULL, NULL, "ToUpperInvariant", System_String_ToUpperInvariant, TYPE_SYSTEM_STRING, 0}, {NULL, "Activator", "CreateInstance", Framework_JSInterop_Activator_CreateInstance, TYPE_SYSTEM_OBJECT, 1, {TYPE_SYSTEM_TYPE}}, @@ -104,11 +122,20 @@ static tInternalCall internalCalls[] = { {NULL, "Type", "GetTypeFromHandle", System_Type_GetTypeFromHandle, TYPE_SYSTEM_TYPE, 1, {TYPE_SYSTEM_RUNTIMETYPEHANDLE}}, {NULL, NULL, "EnsureAssemblyLoaded", System_Type_EnsureAssemblyLoaded, TYPE_SYSTEM_VOID, 1, {TYPE_SYSTEM_STRING}}, - {NULL, NULL, "GetMethodInternal", System_Type_GetMethod, TYPE_SYSTEM_OBJECT, 1, {TYPE_SYSTEM_STRING}}, + {NULL, NULL, "GetInterfaces", System_Type_GetInterfaces, TYPE_SYSTEM_ARRAY_NO_TYPE, 0}, {NULL, NULL, "GetProperties", System_Type_GetProperties, TYPE_SYSTEM_ARRAY_NO_TYPE, 0}, + {NULL, NULL, "GetProperty", System_Type_GetProperty, TYPE_SYSTEM_REFLECTION_PROPERTYINFO, 1, {TYPE_SYSTEM_STRING}}, + {NULL, NULL, "GetMethods", System_Type_GetMethods, TYPE_SYSTEM_ARRAY_NO_TYPE, 0}, + {NULL, NULL, "GetMethod", System_Type_GetMethod, TYPE_SYSTEM_REFLECTION_METHODINFO, 1, {TYPE_SYSTEM_STRING}}, {NULL, NULL, "GetType", System_Type_GetTypeFromName, TYPE_SYSTEM_TYPE, 3, {TYPE_SYSTEM_STRING, TYPE_SYSTEM_STRING, TYPE_SYSTEM_STRING}}, + {NULL, NULL, "GetNestedType", System_Type_GetNestedType, TYPE_SYSTEM_TYPE, 1, {TYPE_SYSTEM_STRING}}, + {NULL, NULL, "GetNestedTypes", System_Type_GetNestedTypes, TYPE_SYSTEM_ARRAY_NO_TYPE, 0 }, + {NULL, NULL, "get_Attributes", System_Type_get_Attributes, TYPE_SYSTEM_UINT32, 0}, {NULL, NULL, "get_IsValueType", System_Type_get_IsValueType, TYPE_SYSTEM_BOOLEAN, 0}, - + {NULL, NULL, "IsAssignableFrom", System_Type_IsAssignableFrom, TYPE_SYSTEM_BOOLEAN, 1, {TYPE_SYSTEM_TYPE}}, + {NULL, NULL, "IsSubclassOf", System_Type_IsSubclassOf, TYPE_SYSTEM_BOOLEAN, 1, {TYPE_SYSTEM_TYPE}}, + {NULL, NULL, "MakeGenericType", System_Type_MakeGenericType, TYPE_SYSTEM_TYPE, 1, {TYPE_SYSTEM_ARRAY_TYPE}}, + {NULL, "RuntimeType", "get_Name", System_RuntimeType_get_Name, TYPE_SYSTEM_STRING, 0}, {NULL, NULL, "get_Namespace", System_RuntimeType_get_Namespace, TYPE_SYSTEM_STRING, 0}, {NULL, NULL, "GetNestingParentType", System_RuntimeType_GetNestingParentType, TYPE_SYSTEM_RUNTIMETYPE, 0}, @@ -117,6 +144,8 @@ static tInternalCall internalCalls[] = { {NULL, NULL, "get_IsGenericType", System_RuntimeType_get_IsGenericType, TYPE_SYSTEM_BOOLEAN, 0}, {NULL, NULL, "Internal_GetGenericTypeDefinition", System_RuntimeType_Internal_GetGenericTypeDefinition, TYPE_SYSTEM_RUNTIMETYPE, 0}, {NULL, NULL, "GetGenericArguments", System_RuntimeType_GetGenericArguments, TYPE_SYSTEM_ARRAY_TYPE, 0}, + {NULL, NULL, "IsDefined", System_RuntimeType_IsDefined, TYPE_SYSTEM_BOOLEAN, 2, {TYPE_SYSTEM_TYPE, TYPE_SYSTEM_BOOLEAN}}, + {NULL, NULL, "Internal_GetCustomAttributes", System_RuntimeType_GetCustomAttributes, TYPE_SYSTEM_ARRAY_OBJECT, 2, {TYPE_SYSTEM_TYPE, TYPE_SYSTEM_BOOLEAN}}, {NULL, NULL, "GetElementType", System_RuntimeType_GetElementType, TYPE_SYSTEM_TYPE, 0}, {NULL, "Char", "GetUnicodeCategory", System_Char_GetUnicodeCategory, TYPE_SYSTEM_GLOBALIZATION_UNICODECATEGORY, 1, {TYPE_SYSTEM_CHAR}}, @@ -142,9 +171,10 @@ static tInternalCall internalCalls[] = { {NULL, NULL, "Cos", System_Math_Cos, TYPE_SYSTEM_DOUBLE, 1, {TYPE_SYSTEM_DOUBLE}}, {NULL, NULL, "Tan", System_Math_Tan, TYPE_SYSTEM_DOUBLE, 1, {TYPE_SYSTEM_DOUBLE}}, {NULL, NULL, "Pow", System_Math_Pow, TYPE_SYSTEM_DOUBLE, 2, {TYPE_SYSTEM_DOUBLE, TYPE_SYSTEM_DOUBLE}}, - {NULL, NULL, "Sqrt", System_Math_Sqrt, TYPE_SYSTEM_DOUBLE, 1, {TYPE_SYSTEM_DOUBLE}}, - - {"System.Reflection", "MemberInfo", "GetCustomAttributes", Reflection_MemberInfo_GetCustomAttributes, TYPE_SYSTEM_ARRAY_NO_TYPE, 0}, + {NULL, NULL, "Sqrt", System_Math_Sqrt, TYPE_SYSTEM_DOUBLE, 1, { TYPE_SYSTEM_DOUBLE}}, + {NULL, NULL, "Ceiling", System_Math_Ceiling, TYPE_SYSTEM_DOUBLE, 1, {TYPE_SYSTEM_DOUBLE}}, + {NULL, NULL, "Floor", System_Math_Floor, TYPE_SYSTEM_DOUBLE, 1, {TYPE_SYSTEM_DOUBLE}}, + {NULL, NULL, "Round", System_Math_Round, TYPE_SYSTEM_DOUBLE, 1, {TYPE_SYSTEM_DOUBLE}}, {"System.Threading", "Thread", ".ctor", System_Threading_Thread_ctor, TYPE_SYSTEM_VOID, 1, {TYPE_SYSTEM_THREADING_THREADSTART}}, {NULL, NULL, ".ctor", System_Threading_Thread_ctorParam, TYPE_SYSTEM_VOID, 1, {TYPE_SYSTEM_THREADING_PARAMETERIZEDTHREADSTART}}, @@ -164,10 +194,15 @@ static tInternalCall internalCalls[] = { {"System.IO", "FileInternal", "Open", System_IO_FileInternal_Open, TYPE_SYSTEM_INTPTR, 5, {TYPE_SYSTEM_STRING, TYPE_SYSTEM_IO_FILEMODE, TYPE_SYSTEM_IO_FILEACCESS, TYPE_SYSTEM_IO_FILESHARE, TYPE_SYSTEM_INTPTR}}, {NULL, NULL, "Read", System_IO_FileInternal_Read, TYPE_SYSTEM_INT32, 5, {TYPE_SYSTEM_INTPTR, TYPE_SYSTEM_ARRAY_BYTE, TYPE_SYSTEM_INT32, TYPE_SYSTEM_INT32, TYPE_SYSTEM_INTPTR}}, {NULL, NULL, "Close", System_IO_FileInternal_Close, TYPE_SYSTEM_VOID, 2, {TYPE_SYSTEM_INTPTR, TYPE_SYSTEM_INTPTR}}, + {NULL, NULL, "Length", System_IO_FileInternal_Length, TYPE_SYSTEM_INT64, 2, { TYPE_SYSTEM_STRING, TYPE_SYSTEM_INTPTR}}, {NULL, NULL, "GetCurrentDirectory", System_IO_FileInternal_GetCurrentDirectory, TYPE_SYSTEM_STRING, 1, {TYPE_SYSTEM_INTPTR}}, {NULL, NULL, "GetFileAttributes", System_IO_FileInternal_GetFileAttributes, TYPE_SYSTEM_IO_FILESYSTEMATTRIBUTES, 2, {TYPE_SYSTEM_STRING, TYPE_SYSTEM_INTPTR}}, {NULL, NULL, "GetFileSystemEntries", System_IO_FileInternal_GetFileSystemEntries, TYPE_SYSTEM_ARRAY_STRING, 5, {TYPE_SYSTEM_STRING, TYPE_SYSTEM_STRING, TYPE_SYSTEM_IO_FILESYSTEMATTRIBUTES, TYPE_SYSTEM_IO_FILESYSTEMATTRIBUTES, TYPE_SYSTEM_INTPTR}}, + {"System.Reflection", "MemberInfo", "GetCustomAttributes", Reflection_MemberInfo_GetCustomAttributes, TYPE_SYSTEM_ARRAY_NO_TYPE, 0}, + + {"System.Reflection", "MethodInfo", "MakeGenericMethod", Reflection_MethodInfo_MakeGenericMethod, TYPE_SYSTEM_REFLECTION_METHODINFO, 1, {TYPE_SYSTEM_ARRAY_TYPE}}, + {"System.Runtime.CompilerServices", "RuntimeHelpers", "InitializeArray", System_Runtime_CompilerServices_InitializeArray, TYPE_SYSTEM_VOID, 2, {TYPE_SYSTEM_ARRAY_NO_TYPE, TYPE_SYSTEM_RUNTIMEFIELDHANDLE}}, {"System.Diagnostics", "Debugger", "Break", System_Diagnostics_Debugger_Break, TYPE_SYSTEM_VOID, 0}, @@ -183,8 +218,9 @@ static tInternalCall internalCalls[] = { {NULL, NULL, "Internal_Receive", System_Net_Sockets_Internal_Receive, TYPE_SYSTEM_INT32, 6, {TYPE_SYSTEM_INTPTR, TYPE_SYSTEM_ARRAY_BYTE, TYPE_SYSTEM_INT32, TYPE_SYSTEM_INT32, TYPE_SYSTEM_INT32, TYPE_SYSTEM_INTPTR}}, {NULL, NULL, "Internal_Send", System_Net_Sockets_Internal_Send, TYPE_SYSTEM_INT32, 6, {TYPE_SYSTEM_INTPTR, TYPE_SYSTEM_ARRAY_BYTE, TYPE_SYSTEM_INT32, TYPE_SYSTEM_INT32, TYPE_SYSTEM_INT32, TYPE_SYSTEM_INTPTR}}, - {"System.Runtime.InteropServices", "GCHandle", "ToHeapRef", Framework_JSInterop_ToHeapRef, TYPE_SYSTEM_INT32, 1, {TYPE_SYSTEM_OBJECT}}, - {NULL, NULL, "FromHeapRef", Framework_JSInterop_FromHeapRefImpl, TYPE_SYSTEM_OBJECT, 1, {TYPE_SYSTEM_INT32}}, + {"System.Runtime.InteropServices", "GCHandle", "ToHeapRef", Framework_JSInterop_ToHeapRef, TYPE_SYSTEM_INT32, 1, {TYPE_SYSTEM_OBJECT}}, + {NULL, NULL, "FromHeapRef", Framework_JSInterop_FromHeapRefImpl, TYPE_SYSTEM_OBJECT, 1, {TYPE_SYSTEM_INT32}}, + {NULL, NULL, NULL, NULL} }; @@ -218,6 +254,6 @@ fnInternalCall InternalCall_Map(tMD_MethodDef *pMethod) { } } - Crash("InternalCall_Map(): Cannot map [%s]%s.%s", pMethod->pParentType->nameSpace, pMethod->pParentType->name, pMethod->name); + Crash("InternalCall_Map(): Cannot map %s.%s.%s", pMethod->pParentType->nameSpace, pMethod->pParentType->name, pMethod->name); FAKE_RETURN; } diff --git a/src/DNA/native/src/JIT.c b/src/DNA/native/src/JIT.c index 083bcfd1..1b6548df 100644 --- a/src/DNA/native/src/JIT.c +++ b/src/DNA/native/src/JIT.c @@ -62,9 +62,12 @@ struct tTypeStack_ { U32 maxBytes; // The max size of the stack in bytes }; -#define InitOps(ops_, initialCapacity) ops_.capacity = initialCapacity; ops_.ofs = 0; ops_.p = malloc((initialCapacity) * sizeof(U32)); ops_.pSequencePoints = malloc((initialCapacity) * sizeof(I32)); +#define InitOps(ops_, initialCapacity) ops_.capacity = initialCapacity; ops_.ofs = 0; ops_.p = TMALLOC(initialCapacity, U32); ops_.pSequencePoints = TMALLOC(initialCapacity, I32); #define DeleteOps(ops_) free(ops_.p); free(ops_.pSequencePoints) +#ifdef SWITCH_ON_JIT_OP +#define Translate(op, getDynamic) op +#else // Turn this into a MACRO at some point? static U32 Translate(U32 op, U32 getDynamic) { if (op >= JIT_OPCODE_MAXNUM) { @@ -79,6 +82,7 @@ static U32 Translate(U32 op, U32 getDynamic) { return (U32)jitCodeInfo[op].pStart; } } +#endif #ifdef GEN_COMBINED_OPCODES #define PushU32(v) PushU32_(&ops, (U32)(v)); PushU32_(&isDynamic, 0) @@ -86,7 +90,7 @@ static U32 Translate(U32 op, U32 getDynamic) { #define PushFloat(v) convFloat.f=(float)(v); PushU32_(&ops, convFloat.u32); PushU32_(&isDynamic, 0) #define PushDouble(v) convDouble.d=(double)(v); PushU32_(&ops, convDouble.u32.a); PushU32_(&ops, convDouble.u32.b); PushU32_(&isDynamic, 0); PushU32_(&isDynamic, 0) #define PushPTR(ptr) PushU32_(&ops, (U32)(ptr)); PushU32_(&isDynamic, 0) -#define PushOp(op) PushU32_(&ops, Translate((U32)(op), 0)); PushU32_(&isDynamic, Translate((U32)(op), 1)) +#define PushOp(op) PushU32_(&ops, Translate((U32)(op), 0)); PushU32_(&isDynamic, Translate((U32)(op), 1)) #define PushOpParam(op, param) PushOp(op); PushU32_(&ops, (U32)(param)); PushU32_(&isDynamic, 0) #else #define PushU32(v) PushU32_(&ops, (U32)(v), -1) @@ -94,7 +98,7 @@ static U32 Translate(U32 op, U32 getDynamic) { #define PushFloat(v) convFloat.f=(float)(v); PushU32_(&ops, convFloat.u32, -1) #define PushDouble(v) convDouble.d=(double)(v); PushU32_(&ops, convDouble.u32.a, -1); PushU32_(&ops, convDouble.u32.b, -1) #define PushPTR(ptr) PushU32_(&ops, (U32)(ptr), -1) -#define PushOp(op) PushU32_(&ops, Translate((U32)(op), 0), nextOpSequencePoint) +#define PushOp(op) PushU32_(&ops, Translate((U32)(op), 0), nextOpSequencePoint); //dprintfn("PushOp: 0x%03x (%s)", op, Sys_JIT_OpCodeName(op)); #define PushOpParam(op, param) PushOp(op); PushU32_(&ops, (U32)(param), -1) #endif @@ -106,7 +110,7 @@ static U32 Translate(U32 op, U32 getDynamic) { #define PopStackTypeMulti(number) typeStack.ofs -= number #define PopStackTypeAll() typeStack.ofs = 0; -#define MayCopyTypeStack() if (u32Value > cilOfs) ppTypeStacks[u32Value] = DeepCopyTypeStack(&typeStack) +#define MayCopyTypeStack() if (u32Value > cilOfs) DeepCopyTypeStack(ppTypeStacks, u32Value, &typeStack) static void PushStackType_(tTypeStack *pTypeStack, tMD_TypeDef *pType) { U32 i, size; @@ -121,13 +125,13 @@ static void PushStackType_(tTypeStack *pTypeStack, tMD_TypeDef *pType) { if (size > pTypeStack->maxBytes) { pTypeStack->maxBytes = size; } - //printf("Stack ofs = %d; Max stack size: %d (0x%x)\n", pTypeStack->ofs, size, size); + //dprintfn("Stack ofs = %d; Max stack size: %d (0x%x)", pTypeStack->ofs, size, size); } static void PushU32_(tOps *pOps, U32 v, I32 opSequencePoint) { if (pOps->ofs >= pOps->capacity) { pOps->capacity <<= 1; -// printf("a.pOps->p = 0x%08x size=%d\n", pOps->p, pOps->capacity * sizeof(U32)); + //dprintfn("a.pOps->p = 0x%08x size=%d", pOps->p, pOps->capacity * sizeof(U32)); pOps->p = realloc(pOps->p, pOps->capacity * sizeof(U32)); pOps->pSequencePoints = realloc(pOps->pSequencePoints, pOps->capacity * sizeof(U32)); } @@ -135,6 +139,13 @@ static void PushU32_(tOps *pOps, U32 v, I32 opSequencePoint) { pOps->p[pOps->ofs++] = v; } +static U32 GetUnalignedU16(U8 *pCIL, U32 *pCILOfs) { + U32 a, b; + a = pCIL[(*pCILOfs)++]; + b = pCIL[(*pCILOfs)++]; + return a | (b << 8); +} + static U32 GetUnalignedU32(U8 *pCIL, U32 *pCILOfs) { U32 a,b,c,d; a = pCIL[(*pCILOfs)++]; @@ -144,19 +155,29 @@ static U32 GetUnalignedU32(U8 *pCIL, U32 *pCILOfs) { return a | (b << 8) | (c << 16) | (d << 24); } -static tTypeStack* DeepCopyTypeStack(tTypeStack *pToCopy) { +static void FreeTypeStack(tTypeStack *pStack) { + if (pStack != NULL) { + if (pStack->ppTypes != NULL) { + free(pStack->ppTypes); + } + free(pStack); + } +} + +static void DeepCopyTypeStack(tTypeStack **ppTypeStacks, U32 index, tTypeStack *pCopyFrom) { tTypeStack *pCopy; - pCopy = TMALLOC(tTypeStack); - pCopy->maxBytes = pToCopy->maxBytes; - pCopy->ofs = pToCopy->ofs; - if (pToCopy->ofs > 0) { - pCopy->ppTypes = malloc(pToCopy->ofs * sizeof(tMD_TypeDef*)); - memcpy(pCopy->ppTypes, pToCopy->ppTypes, pToCopy->ofs * sizeof(tMD_TypeDef*)); + pCopy = TMALLOC(1, tTypeStack); + pCopy->maxBytes = pCopyFrom->maxBytes; + pCopy->ofs = pCopyFrom->ofs; + if (pCopyFrom->ofs > 0) { + pCopy->ppTypes = TMALLOC(pCopyFrom->ofs, tMD_TypeDef*); + memcpy(pCopy->ppTypes, pCopyFrom->ppTypes, pCopyFrom->ofs * sizeof(tMD_TypeDef*)); } else { pCopy->ppTypes = NULL; } - return pCopy; + FreeTypeStack(ppTypeStacks[index]); + ppTypeStacks[index] = pCopy; } static void RestoreTypeStack(tTypeStack *pMainStack, tTypeStack *pCopyFrom) { @@ -233,9 +254,8 @@ static U32 GenCombined(tOps *pOps, tOps *pIsDynamic, U32 startOfs, U32 count, U3 } #endif -static SetBreakPoint(tMD_MethodDef *pMethodDef, U32 cilOfs, tOps ops) -{ - +static void SetBreakPoint(tMD_MethodDef *pMethodDef, U32 cilOfs, tOps ops) { + } static U32* JITit(tMD_MethodDef *pMethodDef, U8 *pCIL, U32 codeSize, tParameter *pLocals, tJITted *pJITted, U32 genCombinedOpcodes, I32 **ppSequencePoints) { @@ -262,43 +282,43 @@ static U32* JITit(tMD_MethodDef *pMethodDef, U8 *pCIL, U32 codeSize, tParameter tMD_TypeDef *pTypeA, *pTypeB; PTR pMem; tMetaData *pMetaData; - tDebugMetaData* pDebugMetadata; - tDebugMetaDataEntry* pDebugMetadataEntry = NULL; - int sequencePointIndex; + tDebugMetaData* pDebugMetadata; + tDebugMetaDataEntry* pDebugMetadataEntry = NULL; + int sequencePointIndex; pMetaData = pMethodDef->pMetaData; - pDebugMetadata = pMetaData->debugMetadata; - - // TODO: Use a hash table as this is super slow - if (pDebugMetadata != NULL) { - tDebugMetaDataEntry* pEntry = pDebugMetadata->entries; - - while (pEntry != NULL) { - // TODO: Compare namespace, type and module name - if (strcmp(pEntry->pMethodName, pMethodDef->name) == 0) { - if (pMethodDef->pParentType != NULL) { - if (strcmp(pEntry->pClassName, pMethodDef->pParentType->name) == 0 && strcmp(pEntry->pNamespaceName, pMethodDef->pParentType->nameSpace) == 0) { - pDebugMetadataEntry = pEntry; - break; - } - } - else { - pDebugMetadataEntry = pEntry; - break; - } - } - pEntry = pEntry->next; - } - } - - pJITOffsets = malloc(codeSize * sizeof(U32)); + pDebugMetadata = pMetaData->debugMetadata; + + // TODO: Use a hash table as this is super slow + if (pDebugMetadata != NULL) { + tDebugMetaDataEntry* pEntry = pDebugMetadata->entries; + + while (pEntry != NULL) { + // TODO: Compare namespace, type and module name + if (strcmp(pEntry->pMethodName, pMethodDef->name) == 0) { + if (pMethodDef->pParentType != NULL) { + if (strcmp(pEntry->pClassName, pMethodDef->pParentType->name) == 0 && strcmp(pEntry->pNamespaceName, pMethodDef->pParentType->nameSpace) == 0) { + pDebugMetadataEntry = pEntry; + break; + } + } + else { + pDebugMetadataEntry = pEntry; + break; + } + } + pEntry = pEntry->next; + } + } + + pJITOffsets = TMALLOC(codeSize, U32); // + 1 to handle cases where the stack is being restored at the last instruction in a method - ppTypeStacks = malloc((codeSize + 1) * sizeof(tTypeStack*)); - memset(ppTypeStacks, 0, (codeSize + 1) * sizeof(tTypeStack*)); + ppTypeStacks = TCALLOC(codeSize + 1, tTypeStack*); + //memset(ppTypeStacks, 0, (codeSize + 1) * sizeof(tTypeStack*)); typeStack.maxBytes = 0; typeStack.ofs = 0; - typeStack.ppTypes = malloc(maxStack * sizeof(tMD_TypeDef*)); - sequencePointIndex = 0; + typeStack.ppTypes = TMALLOC(maxStack, tMD_TypeDef*); + sequencePointIndex = 0; // Set up all exception 'catch' blocks with the correct stack information, // So they'll have just the exception type on the stack when entered @@ -309,10 +329,10 @@ static U32* JITit(tMD_MethodDef *pMethodDef, U8 *pCIL, U32 codeSize, tParameter if (pEx->flags == COR_ILEXCEPTION_CLAUSE_EXCEPTION) { tTypeStack *pTypeStack; - ppTypeStacks[pEx->handlerStart] = pTypeStack = TMALLOC(tTypeStack); + ppTypeStacks[pEx->handlerStart] = pTypeStack = TMALLOC(1, tTypeStack); pTypeStack->maxBytes = 4; pTypeStack->ofs = 1; - pTypeStack->ppTypes = TMALLOC(tMD_TypeDef*); + pTypeStack->ppTypes = TMALLOC(1, tMD_TypeDef*); pTypeStack->ppTypes[0] = pEx->u.pCatchTypeDef; } } @@ -332,25 +352,30 @@ static U32* JITit(tMD_MethodDef *pMethodDef, U8 *pCIL, U32 codeSize, tParameter // Set the JIT offset for this CIL opcode pJITOffsets[cilOfs] = ops.ofs; - U32 pcilOfs = cilOfs; + U32 pcilOfs = cilOfs; op = pCIL[cilOfs++]; - //printf("Opcode: 0x%02x\n", op); - if (pDebugMetadataEntry != NULL && sequencePointIndex < pDebugMetadataEntry->sequencePointsCount) { - U32 spOffset = pDebugMetadataEntry->sequencePoints[sequencePointIndex]; - if (spOffset == pcilOfs) { - nextOpSequencePoint = sequencePointIndex; - sequencePointIndex++; - } else { - nextOpSequencePoint = -1; - } - } - + //U32 op2 = (op == CIL_EXTENDED) ? 0xFE00 + pCIL[cilOfs] : op; + //dprintfn("CIL op: 0x%02x (%s)", op2, Sys_CIL_OpCodeName(op2)); + + if (pDebugMetadataEntry != NULL && sequencePointIndex < pDebugMetadataEntry->sequencePointsCount) { + U32 spOffset = pDebugMetadataEntry->sequencePoints[sequencePointIndex]; + if (spOffset == pcilOfs) { + nextOpSequencePoint = sequencePointIndex; + sequencePointIndex++; + } else { + nextOpSequencePoint = -1; + } + } + switch (op) { case CIL_NOP: - { - PushOp(JIT_NOP); - } + { + PushOp(JIT_NOP); + } + break; + case CIL_BREAK: + Crash("Break-point requested."); break; case CIL_LDNULL: @@ -582,6 +607,9 @@ static U32* JITit(tMD_MethodDef *pMethodDef, U8 *pCIL, U32 codeSize, tParameter case CIL_STIND_I1: case CIL_STIND_I2: case CIL_STIND_I4: + case CIL_STIND_I8: + case CIL_STIND_R4: + case CIL_STIND_R8: PopStackTypeMulti(2); // Don't care what they are PushOp(JIT_STOREINDIRECT_REF + (op - CIL_STIND_REF)); break; @@ -596,7 +624,7 @@ static U32* JITit(tMD_MethodDef *pMethodDef, U8 *pCIL, U32 codeSize, tParameter { tMD_MethodDef *pCallMethod; tMD_TypeDef *pBoxCallType; - U32 derefRefType; + U32 derefRefType = 0; U8 dynamicallyBoxReturnValue = 0; u32Value2 = 0; @@ -604,6 +632,7 @@ static U32* JITit(tMD_MethodDef *pMethodDef, U8 *pCIL, U32 codeSize, tParameter cilCallVirtConstrained: pBoxCallType = NULL; derefRefType = 0; + dynamicallyBoxReturnValue = 0; u32Value = GetUnalignedU32(pCIL, &cilOfs); pCallMethod = MetaData_GetMethodDefFromDefRefOrSpec(pMetaData, u32Value, pMethodDef->pParentType->ppClassTypeArgs, pMethodDef->ppMethodTypeArgs); @@ -619,43 +648,45 @@ static U32* JITit(tMD_MethodDef *pMethodDef, U8 *pCIL, U32 codeSize, tParameter tMD_TypeDef *pConstrainedType; pConstrainedType = MetaData_GetTypeDefFromDefRefOrSpec(pMetaData, u32Value2, pMethodDef->pParentType->ppClassTypeArgs, pMethodDef->ppMethodTypeArgs); + MetaData_Fill_TypeDef(pConstrainedType, NULL, NULL); + if (TYPE_ISINTERFACE(pCallMethod->pParentType)) { - u32Value2 = 0xffffffff; // Find the interface that we're dealing with for (i=0; inumInterfaces; i++) { if (pConstrainedType->pInterfaceMaps[i].pInterface == pCallMethod->pParentType) { - u32Value2 = pConstrainedType->pInterfaceMaps[i].pVTableLookup[pCallMethod->vTableOfs]; - break; + U32 vTableOfs = pConstrainedType->pInterfaceMaps[i].pVTableLookup[pCallMethod->vTableOfs]; + // if method is implemented on this class, make it a normal CALL op + if (pConstrainedType->pVTable[vTableOfs]->pParentType == pConstrainedType) { + op = CIL_CALL; + pCallMethod = pConstrainedType->pVTable[vTableOfs]; + //dprintfn("Calling interface method: %s", pCallMethod->name); + goto cilCallAll; + } } } - Assert(u32Value2 != 0xffffffff); - if (pConstrainedType->pVTable[u32Value2]->pParentType == pConstrainedType) { - // This method is implemented on this class, so make it a normal CALL op - op = CIL_CALL; - pCallMethod = pConstrainedType->pVTable[u32Value2]; - } - } else { - if (pConstrainedType->isValueType) { - tMD_MethodDef *pImplMethod; - // If pConstraintedType directly implements the call then don't do anything - // otherwise the 'this' pointer must be boxed (BoxedCall) - pImplMethod = pConstrainedType->pVTable[pCallMethod->vTableOfs]; + } + + if (pConstrainedType->isValueType) { + // If pConstrainedType directly implements the call then don't do anything + // otherwise the 'this' pointer must be boxed (BoxedCall) + if (pCallMethod->vTableOfs != 0xffffffff) { + tMD_MethodDef *pImplMethod = pConstrainedType->pVTable[pCallMethod->vTableOfs]; if (pImplMethod->pParentType == pConstrainedType) { op = CIL_CALL; pCallMethod = pImplMethod; - } else { - pBoxCallType = pConstrainedType; + goto cilCallAll; } - } else { - // Reference-type, so dereference the PTR to 'this' and use that for the 'this' for the call. - derefRefType = 1; } + pBoxCallType = pConstrainedType; + } else { + // Reference-type, so dereference the PTR to 'this' and use that for the 'this' for the call. + derefRefType = 1; } } - +cilCallAll: // Pop stack type for each argument. Don't actually care what these are, // except the last one which will be the 'this' object type of a non-static method - //printf("Call %s() - popping %d stack args\n", pCallMethod->name, pCallMethod->numberOfParameters); + //dprintfn("Call %s() - popping %d stack args", pCallMethod->name, pCallMethod->numberOfParameters); for (i=0; inumberOfParameters; i++) { pStackType = PopStackType(); } @@ -664,6 +695,7 @@ static U32* JITit(tMD_MethodDef *pMethodDef, U8 *pCIL, U32 codeSize, tParameter pStackType = types[TYPE_SYSTEM_OBJECT]; } MetaData_Fill_TypeDef(pStackType, NULL, NULL); + if (TYPE_ISINTERFACE(pCallMethod->pParentType) && op == CIL_CALLVIRT) { PushOp(JIT_CALL_INTERFACE); } else if (pCallMethod->pParentType->pParent == types[TYPE_SYSTEM_MULTICASTDELEGATE]) { @@ -753,17 +785,21 @@ static U32* JITit(tMD_MethodDef *pMethodDef, U8 *pCIL, U32 codeSize, tParameter case CIL_BRFALSE_S: case CIL_BRTRUE_S: u32Value = (I8)pCIL[cilOfs++]; - u32Value2 = JIT_BRANCH_FALSE + (op - CIL_BRFALSE_S); + u32Value2 = (op - CIL_BRFALSE_S); goto cilBrFalseTrue; case CIL_BRFALSE: case CIL_BRTRUE: u32Value = GetUnalignedU32(pCIL, &cilOfs); - u32Value2 = JIT_BRANCH_FALSE + (op - CIL_BRFALSE); + u32Value2 = (op - CIL_BRFALSE); cilBrFalseTrue: - PopStackTypeDontCare(); // Don't care what it is + pStackType = PopStackType(); + if (pStackType->stackSize > 8) { + Crash("JITit(): Cannot perform branch operation on type: %s", pStackType->name); + } // Put a temporary CIL offset value into the JITted code. This will be updated later u32Value = cilOfs + (I32)u32Value; + u32Value2 = (pStackType->stackSize == 4 ? JIT_BRANCH_FALSE : JIT_BRANCH64_FALSE) + u32Value2; MayCopyTypeStack(); PushOp(u32Value2); PushBranch(); @@ -801,8 +837,7 @@ static U32* JITit(tMD_MethodDef *pMethodDef, U8 *pCIL, U32 codeSize, tParameter pTypeA = PopStackType(); u32Value = cilOfs + (I32)u32Value; MayCopyTypeStack(); - if ((pTypeA->stackType == EVALSTACK_INT32 && pTypeB->stackType == EVALSTACK_INT32) || - (pTypeA->stackType == EVALSTACK_O && pTypeB->stackType == EVALSTACK_O)) { + if (pTypeA->stackType == EVALSTACK_INT32 && pTypeB->stackType == EVALSTACK_INT32) { PushOp(JIT_BEQ_I32I32 + (op - u32Value2)); } else if (pTypeA->stackType == EVALSTACK_INT64 && pTypeB->stackType == EVALSTACK_INT64) { PushOp(JIT_BEQ_I64I64 + (op - u32Value2)); @@ -810,6 +845,12 @@ static U32* JITit(tMD_MethodDef *pMethodDef, U8 *pCIL, U32 codeSize, tParameter PushOp(JIT_BEQ_F32F32 + (op - u32Value2)); } else if (pTypeA->stackType == EVALSTACK_F64 && pTypeB->stackType == EVALSTACK_F64) { PushOp(JIT_BEQ_F64F64 + (op - u32Value2)); + } else if (pTypeA->stackType == EVALSTACK_O && pTypeB->stackType == EVALSTACK_O) { + //pTypeA->stackType == EVALSTACK_O && pTypeB->stackType == EVALSTACK_INT32 || + //pTypeA->stackType == EVALSTACK_INT32 && pTypeB->stackType == EVALSTACK_O) { + PushOp(JIT_BEQ_I32I32 + (op - u32Value2)); + } else if (pTypeA->stackType == EVALSTACK_PTR && pTypeB->stackType == EVALSTACK_PTR) { + PushOp((sizeof(void*) == 4 ? JIT_BEQ_I32I32 : JIT_BEQ_I64I64) + (op - u32Value2)); } else { Crash("JITit(): Cannot perform conditional branch on stack types: %d and %d", pTypeA->stackType, pTypeB->stackType); } @@ -839,21 +880,24 @@ static U32* JITit(tMD_MethodDef *pMethodDef, U8 *pCIL, U32 codeSize, tParameter cilBinaryArithOp: pTypeB = PopStackType(); pTypeA = PopStackType(); - if (pTypeA->stackType == EVALSTACK_INT32 && pTypeB->stackType == EVALSTACK_INT32) { + if ((pTypeA->stackType == EVALSTACK_INT32 && pTypeB->stackType == EVALSTACK_INT32)) { PushOp(JIT_ADD_I32I32 + (op - CIL_ADD) - u32Value); - PushStackType(types[TYPE_SYSTEM_INT32]); } else if (pTypeA->stackType == EVALSTACK_INT64 && pTypeB->stackType == EVALSTACK_INT64) { PushOp(JIT_ADD_I64I64 + (op - CIL_ADD) - u32Value); - PushStackType(types[TYPE_SYSTEM_INT64]); } else if (pTypeA->stackType == EVALSTACK_F32 && pTypeB->stackType == EVALSTACK_F32) { PushOp(JIT_ADD_F32F32 + (op - CIL_ADD) - u32Value); - PushStackType(pTypeA); } else if (pTypeA->stackType == EVALSTACK_F64 && pTypeB->stackType == EVALSTACK_F64) { PushOp(JIT_ADD_F64F64 + (op - CIL_ADD) - u32Value); - PushStackType(pTypeA); + } else if (pTypeA->stackType == EVALSTACK_O && pTypeB->stackType == EVALSTACK_O) { + //pTypeA->stackType == EVALSTACK_O && pTypeB->stackType == EVALSTACK_INT32 || + //pTypeA->stackType == EVALSTACK_INT32 && pTypeB->stackType == EVALSTACK_O) { + PushOp(JIT_ADD_I32I32 + (op - CIL_ADD) - u32Value); + } else if (pTypeA->stackType == EVALSTACK_PTR && pTypeB->stackType == EVALSTACK_INT32 && (op == CIL_ADD || op == CIL_SUB)) { + PushOp((sizeof(void*) == 4 ? JIT_ADD_I32I32 : JIT_ADD_I64I64) + (op - CIL_ADD)); } else { Crash("JITit(): Cannot perform binary numeric operand on stack types: %d and %d", pTypeA->stackType, pTypeB->stackType); } + PushStackType(pTypeA); break; case CIL_NEG: @@ -865,6 +909,12 @@ static U32* JITit(tMD_MethodDef *pMethodDef, U8 *pCIL, U32 codeSize, tParameter } else if (pTypeA->stackType == EVALSTACK_INT64) { PushOp(JIT_NEG_I64 + (op - CIL_NEG)); PushStackType(types[TYPE_SYSTEM_INT64]); + } else if (pTypeA->stackType == EVALSTACK_F32) { + PushOp(JIT_NEG_F32); + PushStackType(types[TYPE_SYSTEM_SINGLE]); + } else if (pTypeA->stackType == EVALSTACK_F64) { + PushOp(JIT_NEG_F64); + PushStackType(types[TYPE_SYSTEM_DOUBLE]); } else { Crash("JITit(): Cannot perform unary operand on stack types: %d", pTypeA->stackType); } @@ -907,6 +957,7 @@ static U32* JITit(tMD_MethodDef *pMethodDef, U8 *pCIL, U32 codeSize, tParameter case CIL_CONV_OVF_I4: // Fix this later - will never overflow case CIL_CONV_OVF_I4_UN: // Fix this later - will never overflow case CIL_CONV_I: // Only on 32-bit + case CIL_CONV_OVF_I: // Only on 32-bit case CIL_CONV_OVF_I_UN: // Only on 32-bit; Fix this later - will never overflow toBitCount = 32; toType = TYPE_SYSTEM_INT32; @@ -929,6 +980,7 @@ static U32* JITit(tMD_MethodDef *pMethodDef, U8 *pCIL, U32 codeSize, tParameter case CIL_CONV_OVF_U4: // Fix this later - will never overflow case CIL_CONV_OVF_U4_UN: // Fix this later - will never overflow case CIL_CONV_U: // Only on 32-bit + case CIL_CONV_OVF_U: // Only on 32-bit case CIL_CONV_OVF_U_UN: // Only on 32-bit; Fix this later - will never overflow toBitCount = 32; toType = TYPE_SYSTEM_UINT32; @@ -1273,24 +1325,45 @@ static U32* JITit(tMD_MethodDef *pMethodDef, U8 *pCIL, U32 codeSize, tParameter case CIL_LDFLD: { tMD_FieldDef *pFieldDef; + tMD_TypeDef *pTypeDef; // Get the FieldRef or FieldDef of the field to load u32Value = GetUnalignedU32(pCIL, &cilOfs); pFieldDef = MetaData_GetFieldDefFromDefOrRef(pMethodDef->pMetaData, u32Value, pMethodDef->pParentType->ppClassTypeArgs, pMethodDef->ppMethodTypeArgs); + // Sometimes, the type def will not have been filled, so ensure it's filled. + pTypeDef = MetaData_GetTypeDefFromFieldDef(pFieldDef); + MetaData_Fill_TypeDef(pTypeDef, NULL, NULL); + // Pop the object/valuetype on which to load the field. pStackType = PopStackType(); - if (pStackType->stackType == EVALSTACK_VALUETYPE) { - PushOpParam(JIT_LOADFIELD_VALUETYPE, pStackType->stackSize); - PushPTR(pFieldDef); - } else { + + switch (pStackType->stackType) + { + case EVALSTACK_INTNATIVE: + case EVALSTACK_INT32: + case EVALSTACK_F32: + case EVALSTACK_PTR: + case EVALSTACK_O: if (pFieldDef->memSize <= 4) { - PushOp(JIT_LOADFIELD_4); - PushU32(pFieldDef->memOffset); - } else { + PushOpParam(JIT_LOADFIELD_4, pFieldDef->memOffset); + } + else { PushOp(JIT_LOADFIELD); PushPTR(pFieldDef); } + break; + case EVALSTACK_INT64: + case EVALSTACK_F64: + PushOpParam(JIT_LOADFIELD_8, pFieldDef->memOffset); + break; + case EVALSTACK_VALUETYPE: + PushOpParam(JIT_LOADFIELD_VALUETYPE, pStackType->stackSize); + PushPTR(pFieldDef); + break; + default: + Crash("JITit(): Cannot load field on stack type: %d", pStackType->stackType); } + // Push the stack type of the just-read field PushStackType(pFieldDef->pType); } @@ -1470,6 +1543,7 @@ static U32* JITit(tMD_MethodDef *pMethodDef, U8 *pCIL, U32 codeSize, tParameter break; case CILX_LOADFUNCTION: + case CILX_LOADVIRTFN: { tMD_MethodDef *pFuncMethodDef; @@ -1488,10 +1562,7 @@ static U32* JITit(tMD_MethodDef *pMethodDef, U8 *pCIL, U32 codeSize, tParameter case CILX_CLT_UN: pTypeB = PopStackType(); pTypeA = PopStackType(); - if ((pTypeA->stackType == EVALSTACK_INT32 && pTypeB->stackType == EVALSTACK_INT32) || - (pTypeA->stackType == EVALSTACK_O && pTypeB->stackType == EVALSTACK_O) || - // Next line: only on 32-bit - (pTypeA->stackType == EVALSTACK_PTR && pTypeB->stackType == EVALSTACK_PTR)) { + if (pTypeA->stackType == EVALSTACK_INT32 && pTypeB->stackType == EVALSTACK_INT32) { PushOp(JIT_CEQ_I32I32 + (op - CILX_CEQ)); } else if (pTypeA->stackType == EVALSTACK_INT64 && pTypeB->stackType == EVALSTACK_INT64) { PushOp(JIT_CEQ_I64I64 + (op - CILX_CEQ)); @@ -1499,27 +1570,47 @@ static U32* JITit(tMD_MethodDef *pMethodDef, U8 *pCIL, U32 codeSize, tParameter PushOp(JIT_CEQ_F32F32 + (op - CILX_CEQ)); } else if (pTypeA->stackType == EVALSTACK_F64 && pTypeB->stackType == EVALSTACK_F64) { PushOp(JIT_CEQ_F64F64 + (op - CILX_CEQ)); + } else if (pTypeA->stackType == EVALSTACK_O && pTypeB->stackType == EVALSTACK_O) { + PushOp(JIT_CEQ_I32I32 + (op - CILX_CEQ)); + } else if (pTypeA->stackType == EVALSTACK_PTR && pTypeB->stackType == EVALSTACK_PTR) { + PushOp((sizeof(void*) == 4 ? JIT_CEQ_I32I32 : JIT_CEQ_I64I64) + (op - CILX_CEQ)); } else { Crash("JITit(): Cannot perform comparison operand on stack types: %s and %s", pTypeA->name, pTypeB->name); } PushStackType(types[TYPE_SYSTEM_INT32]); break; - + + case CILX_LDLOC: + u32Value = GetUnalignedU16(pCIL, &cilOfs); + goto cilLdLoc; + + case CILX_STLOC: + u32Value = GetUnalignedU16(pCIL, &cilOfs); + goto cilStLoc; + case CILX_RETHROW: PushOp(JIT_RETHROW); break; case CILX_CONSTRAINED: u32Value2 = GetUnalignedU32(pCIL, &cilOfs); - cilOfs++; + op = pCIL[cilOfs++]; // always CIL_CALLVIRT goto cilCallVirtConstrained; case CILX_READONLY: // Do nothing break; + case CILX_VOLATILE: + // Do nothing + break; + + case CILX_TAIL: + PushOp(JIT_TAILCALL_PREFIX); + break; + default: - Crash("JITit(): JITter cannot handle extended op-code:0x%02x", op); + Crash("JITit(): JITter cannot handle extended op-code: 0x%02x", op); } break; @@ -1594,7 +1685,7 @@ static U32* JITit(tMD_MethodDef *pMethodDef, U8 *pCIL, U32 codeSize, tParameter shrinkOpsBy = 0; if (opCodeCount > 1) { U32 combinedSize; - tCombinedOpcodesMem *pCOMem = TMALLOC(tCombinedOpcodesMem); + tCombinedOpcodesMem *pCOMem = TMALLOC(1, tCombinedOpcodesMem); shrinkOpsBy = GenCombined(&ops, &isDynamic, inst0, instCount, &combinedSize, &pCOMem->pMem); pCOMem->pNext = pJITted->pCombinedOpcodesMem; pJITted->pCombinedOpcodesMem = pCOMem; @@ -1643,10 +1734,8 @@ static U32* JITit(tMD_MethodDef *pMethodDef, U8 *pCIL, U32 codeSize, tParameter free(typeStack.ppTypes); - for (i=0; ippTypes); - } + for (i=0; i <= codeSize; i++) { + FreeTypeStack(ppTypeStacks[i]); } free(ppTypeStacks); @@ -1655,7 +1744,7 @@ static U32* JITit(tMD_MethodDef *pMethodDef, U8 *pCIL, U32 codeSize, tParameter // Copy ops to some memory of exactly the correct size. To not waste memory. u32Value = ops.ofs * sizeof(U32); - pFinalOps = genCombinedOpcodes?malloc(u32Value):mallocForever(u32Value); + pFinalOps = genCombinedOpcodes ? malloc(u32Value) : mallocForever(u32Value); memcpy(pFinalOps, ops.p, u32Value); pJITted->pDebugMetadataEntry = pDebugMetadataEntry; @@ -1693,7 +1782,7 @@ void JIT_Prepare(tMD_MethodDef *pMethodDef, U32 genCombinedOpcodes) { log_f(2, "JIT: %s\n", Sys_GetMethodDesc(pMethodDef)); pMetaData = pMethodDef->pMetaData; - pJITted = (genCombinedOpcodes)?TMALLOC(tJITted):TMALLOCFOREVER(tJITted); + pJITted = (genCombinedOpcodes) ? TMALLOC(1, tJITted) : TMALLOCFOREVER(1, tJITted); #ifdef GEN_COMBINED_OPCODES pJITted->pCombinedOpcodesMem = NULL; pJITted->opsMemSize = 0; @@ -1717,7 +1806,7 @@ void JIT_Prepare(tMD_MethodDef *pMethodDef, U32 genCombinedOpcodes) { } else { pJITted->maxStack = (pMethodDef->pReturnType == NULL)?0:pMethodDef->pReturnType->stackSize; // For return value } - pCallNative = TMALLOCFOREVER(tJITCallNative); + pCallNative = TMALLOCFOREVER(1, tJITCallNative); pCallNative->opCode = Translate(JIT_CALL_NATIVE, 0); pCallNative->pMethodDef = pMethodDef; pCallNative->fn = InternalCall_Map(pMethodDef); @@ -1739,7 +1828,7 @@ void JIT_Prepare(tMD_MethodDef *pMethodDef, U32 genCombinedOpcodes) { Crash("PInvoke library or function not found: %s()", pImplMap->importName); } - pCallPInvoke = TMALLOCFOREVER(tJITCallPInvoke); + pCallPInvoke = TMALLOCFOREVER(1, tJITCallPInvoke); pCallPInvoke->opCode = Translate(JIT_CALL_PINVOKE, 0); pCallPInvoke->fn = fn; pCallPInvoke->pMethod = pMethodDef; @@ -1780,7 +1869,7 @@ void JIT_Prepare(tMD_MethodDef *pMethodDef, U32 genCombinedOpcodes) { //pJITted->pExceptionHeaders = (tExceptionHeader*)(pMethodHeader + 4); exSize = numClauses * sizeof(tExceptionHeader); pJITted->pExceptionHeaders = - (tExceptionHeader*)(genCombinedOpcodes?malloc(exSize):mallocForever(exSize)); + (tExceptionHeader*)(genCombinedOpcodes ? malloc(exSize) : mallocForever(exSize)); memcpy(pJITted->pExceptionHeaders, pMethodHeader + 4, exSize); } else { // Thin header @@ -1790,9 +1879,9 @@ void JIT_Prepare(tMD_MethodDef *pMethodDef, U32 genCombinedOpcodes) { numClauses = (((U8*)pMethodHeader)[1] - 4) / 12; exSize = numClauses * sizeof(tExceptionHeader); pMethodHeader += 4; - //pExHeaders = pJITted->pExceptionHeaders = (tExceptionHeader*)mallocForever(numClauses * sizeof(tExceptionHeader)); + //pExHeaders = pJITted->pExceptionHeaders = TMALLOCFOREVER(numClauses, tExceptionHeader); pExHeaders = pJITted->pExceptionHeaders = - (tExceptionHeader*)(genCombinedOpcodes?malloc(exSize):mallocForever(exSize)); + (tExceptionHeader*)(genCombinedOpcodes ? malloc(exSize) : mallocForever(exSize)); for (i=0; isignature, &sigLength); MetaData_DecodeSigEntry(&sig); // Always 0x07 numLocals = MetaData_DecodeSigEntry(&sig); - pLocals = (tParameter*)malloc(numLocals * sizeof(tParameter)); + pLocals = TMALLOC(numLocals, tParameter); totalSize = 0; for (i=0; ipEvalStack)), *(pCurOp++)) + +// PUSH/POP returns nothing - it just alters the stack offset correctly +#define PUSH(numBytes) (pCurEvalStack += numBytes) //, dprintfn("PUSH %d: stackOfs = %d", numBytes, (U32)(pCurEvalStack - pCurrentMethodState->pEvalStack)), pCurEvalStack) +#define POP(numBytes) (pCurEvalStack -= numBytes) //, dprintfn("POP %d: stackOfs = %d", numBytes, (U32)(pCurEvalStack - pCurrentMethodState->pEvalStack)), pCurEvalStack) // Push a PTR value on the top of the stack -#define PUSH_PTR(ptr) *(PTR*)pCurEvalStack = (PTR)(ptr); pCurEvalStack += sizeof(void*) +#define PUSH_PTR(ptr) *(PTR*)pCurEvalStack = (PTR)(ptr); PUSH(sizeof(void*)) // Push an arbitrarily-sized value-type onto the top of the stack -#define PUSH_VALUETYPE(ptr, valueSize, stackInc) memcpy(pCurEvalStack, ptr, valueSize); pCurEvalStack += stackInc +#define PUSH_VALUETYPE(ptr, valueSize, stackInc) memcpy(pCurEvalStack, ptr, valueSize); PUSH(stackInc) // Push a U32 value on the top of the stack -#define PUSH_U32(value) *(U32*)pCurEvalStack = (U32)(value); pCurEvalStack += 4 +#define PUSH_U32(value) *(U32*)pCurEvalStack = (U32)(value); PUSH(4) // Push a U64 value on the top of the stack -#define PUSH_U64(value) *(U64*)pCurEvalStack = (U64)(value); pCurEvalStack += 8 +#define PUSH_U64(value) *(U64*)pCurEvalStack = (U64)(value); PUSH(8) // Push a float value on the top of the stack -#define PUSH_FLOAT(value) *(float*)pCurEvalStack = (float)(value); pCurEvalStack += 4; +#define PUSH_FLOAT(value) *(float*)pCurEvalStack = (float)(value); PUSH(4) // Push a double value on the top of the stack -#define PUSH_DOUBLE(value) *(double*)pCurEvalStack = (double)(value); pCurEvalStack += 8; +#define PUSH_DOUBLE(value) *(double*)pCurEvalStack = (double)(value); PUSH(8) // Push a 4-byte heap pointer on to the top of the stack -#define PUSH_O(pHeap) *(void**)pCurEvalStack = (void*)(pHeap); pCurEvalStack += sizeof(void*) +#define PUSH_O(pHeap) *(HEAP_PTR*)pCurEvalStack = (HEAP_PTR)(pHeap); PUSH(4) // DUP4() duplicates the top 4 bytes on the eval stack -#define DUP4() *(U32*)pCurEvalStack = *(U32*)(pCurEvalStack - 4); pCurEvalStack += 4 +#define DUP4() *(U32*)pCurEvalStack = *(U32*)(pCurEvalStack - 4); PUSH(4) // DUP8() duplicates the top 4 bytes on the eval stack -#define DUP8() *(U64*)pCurEvalStack = *(U64*)(pCurEvalStack - 8); pCurEvalStack += 8 +#define DUP8() *(U64*)pCurEvalStack = *(U64*)(pCurEvalStack - 8); PUSH(8) // DUP() duplicates numBytes bytes from the top of the stack -#define DUP(numBytes) memcpy(pCurEvalStack, pCurEvalStack - numBytes, numBytes); pCurEvalStack += numBytes +#define DUP(numBytes) memcpy(pCurEvalStack, pCurEvalStack - numBytes, numBytes); PUSH(numBytes) // Pop a U32 value from the stack -#define POP_U32() (*(U32*)(pCurEvalStack -= 4)) +#define POP_U32() (*(U32*)(POP(4))) // Pop a U64 value from the stack -#define POP_U64() (*(U64*)(pCurEvalStack -= 8)) +#define POP_U64() (*(U64*)(POP(8))) // Pop a float value from the stack -#define POP_FLOAT() (*(float*)(pCurEvalStack -= 4)) +#define POP_FLOAT() (*(float*)(POP(4))) // Pop a double value from the stack -#define POP_DOUBLE() (*(double*)(pCurEvalStack -= 8)) +#define POP_DOUBLE() (*(double*)(POP(8))) // Pop 2 U32's from the stack -#define POP_U32_U32(v1,v2) pCurEvalStack -= 8; v1 = *(U32*)pCurEvalStack; v2 = *(U32*)(pCurEvalStack + 4) +#define POP_U32_U32(v1,v2) POP(8); v1 = *(U32*)pCurEvalStack; v2 = *(U32*)(pCurEvalStack + 4) // Pop 2 U64's from the stack -#define POP_U64_U64(v1,v2) pCurEvalStack -= 16; v1 = *(U64*)pCurEvalStack; v2 = *(U64*)(pCurEvalStack + 8) +#define POP_U64_U64(v1,v2) POP(16); v1 = *(U64*)pCurEvalStack; v2 = *(U64*)(pCurEvalStack + 8) // Pop 2 F32's from the stack -#define POP_F32_F32(v1,v2) pCurEvalStack -= 8; v1 = *(float*)pCurEvalStack; v2 = *(float*)(pCurEvalStack + 4) +#define POP_F32_F32(v1,v2) POP(8); v1 = *(float*)pCurEvalStack; v2 = *(float*)(pCurEvalStack + 4) // Pop 2 F64's from the stack -#define POP_F64_F64(v1,v2) pCurEvalStack -= 16; v1 = *(double*)pCurEvalStack; v2 = *(double*)(pCurEvalStack + 8) +#define POP_F64_F64(v1,v2) POP(16); v1 = *(double*)pCurEvalStack; v2 = *(double*)(pCurEvalStack + 8) // Pop a PTR value from the stack -#define POP_PTR() (*(PTR*)(pCurEvalStack -= sizeof(void*))) +#define POP_PTR() (*(PTR*)(POP(sizeof(void*)))) // Pop an arbitrarily-sized value-type from the stack (copies it to the specified memory location) -#define POP_VALUETYPE(ptr, valueSize, stackDec) memcpy(ptr, pCurEvalStack -= stackDec, valueSize) +#define POP_VALUETYPE(ptr, valueSize, stackDec) memcpy(ptr, POP(stackDec), valueSize) // Pop a Object (heap) pointer value from the stack -#define POP_O() (*(HEAP_PTR*)(pCurEvalStack -= 4)) -// POP() returns nothing - it just alters the stack offset correctly -#define POP(numBytes) pCurEvalStack -= numBytes +#define POP_O() (*(HEAP_PTR*)(POP(4))) // POP_ALL() empties the evaluation stack #define POP_ALL() pCurEvalStack = pCurrentMethodState->pEvalStack #define STACK_ADDR(type) *(type*)(pCurEvalStack - sizeof(type)) // General binary ops #define BINARY_OP(returnType, type1, type2, op) \ - pCurEvalStack -= sizeof(type1) + sizeof(type2) - sizeof(returnType); \ + POP(sizeof(type1) + sizeof(type2) - sizeof(returnType)); \ *(returnType*)(pCurEvalStack - sizeof(returnType)) = \ *(type1*)(pCurEvalStack - sizeof(returnType)) op \ *(type2*)(pCurEvalStack - sizeof(returnType) + sizeof(type1)) @@ -106,7 +114,7 @@ tJITCodeInfo jitCodeGoNext; // Set the new method state (for use when the method state changes - in calls mainly) #define SAVE_METHOD_STATE() \ pCurrentMethodState->stackOfs = (U32)(pCurEvalStack - pCurrentMethodState->pEvalStack); \ - pCurrentMethodState->ipOffset = (U32)(pCurOp - pOps) + pCurrentMethodState->ipOffset = (U32)(pCurOp - pOps) \ #define LOAD_METHOD_STATE() \ pCurrentMethodState = pThread->pCurrentMethodState; \ @@ -117,9 +125,23 @@ tJITCodeInfo jitCodeGoNext; pOpSequencePoints = pJIT->pOpSequencePoints; \ pCurOp = pOps + pCurrentMethodState->ipOffset +#ifdef DIAG_CALL_STACK +I32 nested = 0; +char callBuffer[8192] = ""; //increase if needed +char *pNextChar = callBuffer; + +#define INCREMENT_NESTED_LEVEL() nested = nested + 1 +#define DECREMENT_NESTED_LEVEL() nested = nested - 1 +#else +#define INCREMENT_NESTED_LEVEL() +#define DECREMENT_NESTED_LEVEL() +#endif + #define CHANGE_METHOD_STATE(pNewMethodState) \ - SAVE_METHOD_STATE(); \ - pThread->pCurrentMethodState = pNewMethodState; \ + if (pThread->pCurrentMethodState != pNewMethodState) { \ + SAVE_METHOD_STATE(); \ + pThread->pCurrentMethodState = pNewMethodState; \ + } \ LOAD_METHOD_STATE() // Easy access to method parameters and local variables @@ -138,20 +160,15 @@ static void CheckIfCurrentInstructionHasBreakpoint(tMethodState* pMethodState, U } } -// Note: newObj is only set if a constructor is being called -static void CreateParameters(PTR pParamsLocals, tMD_MethodDef *pCallMethod, PTR *ppCurEvalStack, HEAP_PTR newObj) { - U32 ofs; - - if (newObj != NULL) { - // If this is being called from JIT_NEW_OBJECT then need to specially push the new object - // onto parameter stack position 0 - *(HEAP_PTR*)pParamsLocals = newObj; - ofs = 4; - } else { - ofs = 0; +static void CopyParameters(PTR pParamsLocals, tMD_MethodDef *pCallMethod, PTR pParamsOrigin, HEAP_PTR obj) { + if (pParamsLocals != pParamsOrigin) { + memmove(pParamsLocals, pParamsOrigin, pCallMethod->parameterStackSize); + } + // Note: obj is only set if a constructor or delegate is being called + if (obj != NULL) { + // push the object onto parameter stack position 0 + *(HEAP_PTR*)pParamsLocals = obj; } - *ppCurEvalStack -= pCallMethod->parameterStackSize - ofs; - memcpy(pParamsLocals + ofs, *ppCurEvalStack, pCallMethod->parameterStackSize - ofs); } static tMethodState* RunFinalizer(tThread *pThread) { @@ -161,7 +178,7 @@ static tMethodState* RunFinalizer(tThread *pThread) { tMethodState *pFinalizerMethodState; tMD_TypeDef *pFinalizerType = Heap_GetType(heapPtr); - pFinalizerMethodState = MethodState_Direct(pThread, pFinalizerType->pFinalizer, pThread->pCurrentMethodState, 0); + pFinalizerMethodState = MethodState_Direct(pThread, pFinalizerType->pFinalizer, pThread->pCurrentMethodState, 0, 0); // Mark this methodState as a Finalizer pFinalizerMethodState->finalizerThis = heapPtr; // Put the object on the stack (the object that is being Finalized) @@ -183,17 +200,32 @@ static __inline unsigned __int64 __cdecl rdtsc() { } #endif -#ifdef DIAG_OPCODE_USE +#ifdef DIAG_OPCODE_USES U32 opcodeNumUses[JIT_OPCODE_MAXNUM]; #define OPCODE_USE(op) opcodeNumUses[op]++; #else -#define OPCODE_USE(op) +#define OPCODE_USE(op) //dprintfn("JIT op: 0x%03x (%s)", op, Sys_JIT_OpCodeName(op)) #endif +#ifdef SWITCH_ON_JIT_OP + +#define CHECK_FOR_BREAKPOINT() \ + if (pOpSequencePoints != NULL) { \ + I32 currentOpSequencePoint = pOpSequencePoints[pCurOp - pOps]; \ + if (currentOpSequencePoint >= 0) { \ + CheckIfSequencePointIsBreakpoint(pCurrentMethodState, currentOpSequencePoint); \ + } \ + } + +#define GO_NEXT() \ + goto goNext; + +#else + #define CHECK_FOR_BREAKPOINT() \ CheckIfCurrentInstructionHasBreakpoint(pCurrentMethodState, pCurOp - pOps, pOpSequencePoints); @@ -221,11 +253,22 @@ U32 opcodeNumUses[JIT_OPCODE_MAXNUM]; #endif #endif +#endif #define GO_NEXT_CHECK() \ if (--numInst == 0) goto done; \ GO_NEXT() +#ifdef SWITCH_ON_JIT_OP + +#define GET_LABELS(op) \ + case op: goto op##_start; + +#define GET_LABELS_DYNAMIC(op, extraBytes) \ + case op: goto op##_start; + +#else + #define GET_LABELS(op) \ GET_LABEL(pAddr, op##_start); \ jitCodeInfo[op].pStart = pAddr; \ @@ -240,6 +283,8 @@ U32 opcodeNumUses[JIT_OPCODE_MAXNUM]; jitCodeInfo[op].pEnd = pAddr; \ jitCodeInfo[op].isDynamic = 0x100 | (extraBytes & 0xff) +#endif + #define RUN_FINALIZER() {tMethodState *pMS = RunFinalizer(pThread);if(pMS) {CHANGE_METHOD_STATE(pMS);}} U32 JIT_Execute(tThread *pThread, U32 numInst) { @@ -254,22 +299,31 @@ U32 JIT_Execute(tThread *pThread, U32 numInst) { register U32 *pCurOp; // Pointer to eval-stack position register PTR pCurEvalStack; - PTR pTempPtr; U32 op; // General purpose variables - //I32 i32Value; - U32 u32Value; //, u32Value2; - //U64 u64Value; - //double dValue; - //float fValue; - //uConvDouble convDouble; - U32 ofs; + U32 u32Value; HEAP_PTR heapPtr; - PTR pMem; - + if (pThread == NULL) { + +#ifdef SWITCH_ON_JIT_OP + // no label initialization needed + return 0; + } + + LOAD_METHOD_STATE(); + GO_NEXT(); + +goNext: + CHECK_FOR_BREAKPOINT(); + op = GET_OP(); + + switch (op) { + +#else void *pAddr; + // Special case to get all the label addresses // Default all op-codes to noCode. GET_LABEL(pAddr, noCode); @@ -283,6 +337,7 @@ U32 JIT_Execute(tThread *pThread, U32 numInst) { GET_LABEL(jitCodeGoNext.pStart, JIT_GoNext_start); GET_LABEL(jitCodeGoNext.pEnd, JIT_GoNext_end); jitCodeGoNext.isDynamic = 0; +#endif // Get all defined opcodes GET_LABELS_DYNAMIC(JIT_NOP, 0); @@ -290,6 +345,7 @@ U32 JIT_Execute(tThread *pThread, U32 numInst) { GET_LABELS_DYNAMIC(JIT_LOAD_I32, 4); GET_LABELS(JIT_BRANCH); GET_LABELS(JIT_LOAD_STRING); + GET_LABELS(JIT_TAILCALL_PREFIX); GET_LABELS(JIT_CALLVIRT_O); GET_LABELS(JIT_CALL_NATIVE); GET_LABELS(JIT_CALL_O); @@ -382,6 +438,7 @@ U32 JIT_Execute(tThread *pThread, U32 numInst) { GET_LABELS(JIT_STOREFIELD_VALUETYPE); GET_LABELS(JIT_LOADSTATICFIELD_CHECKTYPEINIT_INT32); + GET_LABELS(JIT_LOADSTATICFIELD_CHECKTYPEINIT_INT64); GET_LABELS(JIT_LOADSTATICFIELD_CHECKTYPEINIT_VALUETYPE); GET_LABELS(JIT_LOADSTATICFIELD_CHECKTYPEINIT_O); GET_LABELS(JIT_LOADSTATICFIELD_CHECKTYPEINIT_INTNATIVE); @@ -411,6 +468,7 @@ U32 JIT_Execute(tThread *pThread, U32 numInst) { GET_LABELS_DYNAMIC(JIT_CGT_UN_I32I32, 0); GET_LABELS_DYNAMIC(JIT_CLT_I32I32, 0); GET_LABELS_DYNAMIC(JIT_CLT_UN_I32I32, 0); + GET_LABELS_DYNAMIC(JIT_CEQ_I64I64, 0); GET_LABELS_DYNAMIC(JIT_CGT_I64I64, 0); GET_LABELS_DYNAMIC(JIT_CGT_UN_I64I64, 0); @@ -437,6 +495,8 @@ U32 JIT_Execute(tThread *pThread, U32 numInst) { GET_LABELS_DYNAMIC(JIT_NOT_I32, 0); GET_LABELS_DYNAMIC(JIT_NEG_I64, 0); GET_LABELS_DYNAMIC(JIT_NOT_I64, 0); + GET_LABELS_DYNAMIC(JIT_NEG_F32, 0); + GET_LABELS_DYNAMIC(JIT_NEG_F64, 0); GET_LABELS(JIT_BOX_NULLABLE); GET_LABELS_DYNAMIC(JIT_LOAD_F64, 8); @@ -485,6 +545,11 @@ U32 JIT_Execute(tThread *pThread, U32 numInst) { GET_LABELS(JIT_BLE_UN_I32I32); GET_LABELS(JIT_BLT_UN_I32I32); + GET_LABELS(JIT_BGE_UN_I64I64); + GET_LABELS(JIT_BGT_UN_I64I64); + GET_LABELS(JIT_BLE_UN_I64I64); + GET_LABELS(JIT_BLT_UN_I64I64); + GET_LABELS_DYNAMIC(JIT_SHL_I32, 0); GET_LABELS_DYNAMIC(JIT_SHR_I32, 0); GET_LABELS_DYNAMIC(JIT_SHR_UN_I32, 0); @@ -494,6 +559,8 @@ U32 JIT_Execute(tThread *pThread, U32 numInst) { GET_LABELS(JIT_BRANCH_FALSE); GET_LABELS(JIT_BRANCH_TRUE); + GET_LABELS(JIT_BRANCH64_FALSE); + GET_LABELS(JIT_BRANCH64_TRUE); GET_LABELS(JIT_LOADTOKEN_TYPE); GET_LABELS(JIT_LOADTOKEN_FIELD); @@ -512,6 +579,9 @@ U32 JIT_Execute(tThread *pThread, U32 numInst) { GET_LABELS(JIT_STOREINDIRECT_U8); GET_LABELS(JIT_STOREINDIRECT_U16); GET_LABELS(JIT_STOREINDIRECT_U32); + GET_LABELS(JIT_STOREINDIRECT_U64); + GET_LABELS(JIT_STOREINDIRECT_R32); + GET_LABELS(JIT_STOREINDIRECT_R64); GET_LABELS_DYNAMIC(JIT_CONV_I32_I32, 4); GET_LABELS_DYNAMIC(JIT_CONV_I32_U32, 4); @@ -574,10 +644,15 @@ U32 JIT_Execute(tThread *pThread, U32 numInst) { GET_LABELS_DYNAMIC(JIT_CEQ_F32F32, 0); GET_LABELS_DYNAMIC(JIT_CGT_F32F32, 0); + GET_LABELS_DYNAMIC(JIT_CGT_UN_F32F32, 0); GET_LABELS_DYNAMIC(JIT_CLT_F32F32, 0); + GET_LABELS_DYNAMIC(JIT_CLT_UN_F32F32, 0); + GET_LABELS_DYNAMIC(JIT_CEQ_F64F64, 0); GET_LABELS_DYNAMIC(JIT_CGT_F64F64, 0); + GET_LABELS_DYNAMIC(JIT_CGT_UN_F64F64, 0); GET_LABELS_DYNAMIC(JIT_CLT_F64F64, 0); + GET_LABELS_DYNAMIC(JIT_CLT_UN_F64F64, 0); GET_LABELS_DYNAMIC(JIT_ADD_F32F32, 0); GET_LABELS_DYNAMIC(JIT_ADD_F64F64, 0); @@ -594,18 +669,26 @@ U32 JIT_Execute(tThread *pThread, U32 numInst) { GET_LABELS_DYNAMIC(JIT_LOAD_I4_2, 0); GET_LABELS_DYNAMIC(JIT_LOADFIELD_4, 4); + GET_LABELS_DYNAMIC(JIT_LOADFIELD_8, 8); +#ifdef SWITCH_ON_JIT_OP + default: goto noCode; + } +#else return 0; } +#endif #ifdef DIAG_OPCODE_TIMES U64 opcodeStartTime = rdtsc(); - U32 realOp; #endif +#ifdef SWITCH_ON_JIT_OP +#else LOAD_METHOD_STATE(); GO_NEXT(); +#endif noCode: Crash("No code for op-code"); @@ -625,6 +708,11 @@ U32 JIT_Execute(tThread *pThread, U32 numInst) { GO_NEXT(); JIT_GoNext_end: +JIT_TAILCALL_PREFIX_start: + OPCODE_USE(JIT_TAILCALL_PREFIX); +JIT_TAILCALL_PREFIX_end: + GO_NEXT(); + JIT_LOAD_NULL_start: OPCODE_USE(JIT_LOAD_NULL); PUSH_O(NULL); @@ -950,6 +1038,7 @@ U32 JIT_Execute(tThread *pThread, U32 numInst) { JIT_STOREINDIRECT_U16_start: JIT_STOREINDIRECT_U32_start: JIT_STOREINDIRECT_REF_start: +JIT_STOREINDIRECT_R32_start: OPCODE_USE(JIT_STOREINDIRECT_U32); { U32 value = POP_U32(); // The value to store @@ -960,6 +1049,19 @@ U32 JIT_Execute(tThread *pThread, U32 numInst) { JIT_STOREINDIRECT_U16_end: JIT_STOREINDIRECT_U32_end: JIT_STOREINDIRECT_REF_end: +JIT_STOREINDIRECT_R32_end: + GO_NEXT(); + +JIT_STOREINDIRECT_U64_start: +JIT_STOREINDIRECT_R64_start: + OPCODE_USE(JIT_STOREINDIRECT_U64); + { + U64 value = POP_U64(); // Value + PTR pMem = POP_PTR(); // The address to store to + *(U64*)pMem = value; + } +JIT_STOREINDIRECT_U64_end: +JIT_STOREINDIRECT_R64_end: GO_NEXT(); JIT_STORE_OBJECT_VALUETYPE_start: @@ -1007,6 +1109,13 @@ U32 JIT_Execute(tThread *pThread, U32 numInst) { // Internal constructors MUST leave the newly created object in the return value // (ie on top of the evaluation stack) pAsync = pCallNative->fn(pThis, pCurrentMethodState->pParamsLocals + thisOfs, pCurrentMethodState->pEvalStack); + // push return value + if (pCallNative->pMethodDef->pReturnType != NULL) { + PUSH(pCallNative->pMethodDef->pReturnType->stackSize); + } else if (pCurrentMethodState->isInternalNewObjCall) { + PUSH(sizeof(void*)); + } + if (pAsync != NULL) { // Save the method state SAVE_METHOD_STATE(); @@ -1026,7 +1135,9 @@ U32 JIT_Execute(tThread *pThread, U32 numInst) { JIT_RETURN_start: OPCODE_USE(JIT_RETURN); - //printf("Returned from %s() to %s()\n", pCurrentMethodState->pMethod->name, (pCurrentMethodState->pCaller)?pCurrentMethodState->pCaller->pMethod->name:""); + // dprintfn("Returned from %s() to %s()", pCurrentMethodState->pMethod->name, (pCurrentMethodState->pCaller)?pCurrentMethodState->pCaller->pMethod->name:(STRING)""); + DECREMENT_NESTED_LEVEL(); + if (pCurrentMethodState->pCaller == NULL) { // End of thread! if (pCurrentMethodState->pMethod->pReturnType == types[TYPE_SYSTEM_INT32]) { @@ -1043,15 +1154,16 @@ U32 JIT_Execute(tThread *pThread, U32 numInst) { } else { u32Value = 0; } - pMem = pCurrentMethodState->pEvalStack; { + Assert(pCurEvalStack - u32Value >= pCurrentMethodState->pEvalStack); + PTR pMem = pCurEvalStack - u32Value; tMethodState *pOldMethodState = pCurrentMethodState; pThread->pCurrentMethodState = pCurrentMethodState->pCaller; LOAD_METHOD_STATE(); // Copy return value to callers evaluation stack if (u32Value > 0) { memmove(pCurEvalStack, pMem, u32Value); - pCurEvalStack += u32Value; + PUSH(u32Value); } // Delete the current method state and go back to callers method state MethodState_Delete(pThread, &pOldMethodState); @@ -1066,30 +1178,29 @@ U32 JIT_Execute(tThread *pThread, U32 numInst) { OPCODE_USE(JIT_INVOKE_DELEGATE); { tMD_MethodDef *pDelegateMethod, *pCallMethod; + tMethodState *pCallMethodState; void *pDelegate; HEAP_PTR pDelegateThis; - tMethodState *pCallMethodState; - U32 ofs; if (pCurrentMethodState->pNextDelegate == NULL) { // First delegate, so get the Invoke() method defined within the delegate class pDelegateMethod = (tMD_MethodDef*)GET_OP(); // Take the params off the stack. This is the pointer to the tDelegate & params //pCurrentMethodState->stackOfs -= pDelegateMethod->parameterStackSize; - pCurEvalStack -= pDelegateMethod->parameterStackSize; + POP(pDelegateMethod->parameterStackSize); // Allocate memory for delegate params - pCurrentMethodState->pDelegateParams = malloc(pDelegateMethod->parameterStackSize - sizeof(void*)); + pCurrentMethodState->pDelegateParams = malloc(pDelegateMethod->parameterStackSize); memcpy( pCurrentMethodState->pDelegateParams, //pCurrentMethodState->pEvalStack + pCurrentMethodState->stackOfs + sizeof(void*), - pCurEvalStack + sizeof(void*), - pDelegateMethod->parameterStackSize - sizeof(void*)); + pCurEvalStack, + pDelegateMethod->parameterStackSize); // Get the actual delegate heap pointer pDelegate = *(void**)pCurEvalStack; } else { pDelegateMethod = Delegate_GetMethod(pCurrentMethodState->pNextDelegate); if (pDelegateMethod->pReturnType != NULL) { - pCurEvalStack -= pDelegateMethod->pReturnType->stackSize; + POP(pDelegateMethod->pReturnType->stackSize); } // Get the actual delegate heap pointer pDelegate = pCurrentMethodState->pNextDelegate; @@ -1099,17 +1210,14 @@ U32 JIT_Execute(tThread *pThread, U32 numInst) { } // Get the real method to call; the target of the delegate. pCallMethod = Delegate_GetMethodAndStore(pDelegate, &pDelegateThis, &pCurrentMethodState->pNextDelegate); + // Set up the call method state for the call. - pCallMethodState = MethodState_Direct(pThread, pCallMethod, pCurrentMethodState, 0); - if (pDelegateThis != NULL) { - *(HEAP_PTR*)pCallMethodState->pParamsLocals = pDelegateThis; - ofs = sizeof(void*); - } else { - ofs = 0; - } - memcpy(pCallMethodState->pParamsLocals + ofs, - pCurrentMethodState->pDelegateParams, - pCallMethod->parameterStackSize - ofs); + INCREMENT_NESTED_LEVEL(); + pCallMethodState = MethodState_Direct(pThread, pCallMethod, pCurrentMethodState, 0, 0); + // Fill in the parameters + CopyParameters(pCallMethodState->pParamsLocals, pCallMethod, pCurrentMethodState->pDelegateParams, pDelegateThis); + + // Set up the local variables for the new method state CHANGE_METHOD_STATE(pCallMethodState); } JIT_INVOKE_DELEGATE_end: @@ -1118,11 +1226,14 @@ U32 JIT_Execute(tThread *pThread, U32 numInst) { JIT_INVOKE_SYSTEM_REFLECTION_METHODBASE_start: OPCODE_USE(JIT_INVOKE_SYSTEM_REFLECTION_METHODBASE); { + // check if it's a tail call + U32 isTailCall = *(pCurOp - 2) == JIT_TAILCALL_PREFIX; + // Get the reference to MethodBase.Invoke tMD_MethodDef *pInvokeMethod = (tMD_MethodDef*)GET_OP(); // Take the MethodBase.Invoke params off the stack. - pCurEvalStack -= pInvokeMethod->parameterStackSize; + POP(pInvokeMethod->parameterStackSize); // Get a pointer to the MethodBase instance (e.g., a MethodInfo or ConstructorInfo), // and from that, determine which method we're going to invoke @@ -1134,37 +1245,41 @@ U32 JIT_Execute(tThread *pThread, U32 numInst) { pCurrentMethodState->pReflectionInvokeReturnType = pCallMethod->pReturnType; // Get the 'this' pointer for the call and the params array - PTR invocationThis = (PTR)(*(tMethodBase**)(pCurEvalStack + sizeof(HEAP_PTR))); - HEAP_PTR invocationParamsArray = *(HEAP_PTR*)(pCurEvalStack + sizeof(HEAP_PTR) + sizeof(PTR)); + PTR invocationThis = *(PTR*)(pCurEvalStack + sizeof(HEAP_PTR)); + HEAP_PTR invocationParamsArray = *(HEAP_PTR*)(pCurEvalStack + sizeof(HEAP_PTR) + sizeof(PTR)); + + // Change interpreter state so we continue execution inside the method being invoked + tMethodState *pCallMethodState = MethodState_Direct(pThread, pCallMethod, pCurrentMethodState, 0, isTailCall); + + // store current eval stack ptr for later + PTR pLastEvalStack = pCurEvalStack; + // use eval stack ptr to copy parameters to paramslocals + pCurEvalStack = pCallMethodState->pParamsLocals; // Put the new 'this' on the stack - PTR pPrevEvalStack = pCurEvalStack; - PUSH_PTR(invocationThis); + if (invocationThis != NULL) { + PUSH_PTR(invocationThis); + } // Put any other params on the stack if (invocationParamsArray != NULL) { U32 invocationParamsArrayLength = SystemArray_GetLength(invocationParamsArray); - PTR invocationParamsArrayElements = SystemArray_GetElements(invocationParamsArray); + HEAP_PTR* invocationParamsArrayElements = (HEAP_PTR*)SystemArray_GetElements(invocationParamsArray); for (U32 paramIndex = 0; paramIndex < invocationParamsArrayLength; paramIndex++) { - HEAP_PTR currentParam = (HEAP_PTR)(((U32*)(invocationParamsArrayElements))[paramIndex]); - if (currentParam == NULL) { - PUSH_O(NULL); + HEAP_PTR currentParam = invocationParamsArrayElements[paramIndex]; + tMD_TypeDef *pParamType = Heap_GetType(currentParam); + if (pParamType->isValueType) { + PUSH_VALUETYPE(currentParam, pParamType->stackSize, pParamType->stackSize); } else { - tMD_TypeDef *currentParamType = Heap_GetType(currentParam); - - if (Type_IsValueType(currentParamType)) { - PUSH_VALUETYPE(currentParam, currentParamType->stackSize, currentParamType->stackSize); - } else { - PUSH_O(currentParam); - } + PUSH_O(currentParam); } } } - pCurEvalStack = pPrevEvalStack; - // Change interpreter state so we continue execution inside the method being invoked - tMethodState *pCallMethodState = MethodState_Direct(pThread, pCallMethod, pCurrentMethodState, 0); - memcpy(pCallMethodState->pParamsLocals, pCurEvalStack, pCallMethod->parameterStackSize); + // restore current eval stack ptr + pCurEvalStack = pLastEvalStack; + + // Set up the local variables for the new method state CHANGE_METHOD_STATE(pCallMethodState); } JIT_INVOKE_SYSTEM_REFLECTION_METHODBASE_end: @@ -1207,81 +1322,98 @@ U32 JIT_Execute(tThread *pThread, U32 numInst) { goto allCallStart; JIT_CALL_INTERFACE_start: op = JIT_CALL_INTERFACE; + goto allCallStart; allCallStart: - OPCODE_USE(JIT_CALL_O); + OPCODE_USE(op); { tMD_MethodDef *pCallMethod; tMethodState *pCallMethodState; tMD_TypeDef *pBoxCallType; + // check if it's a tail call + U32 isTailCall = *(pCurOp - 2) == JIT_TAILCALL_PREFIX; + if (op == JIT_BOX_CALLVIRT) { pBoxCallType = (tMD_TypeDef*)GET_OP(); } pCallMethod = (tMD_MethodDef*)GET_OP(); + //dprintfn("Calling method: %s", Sys_GetMethodDesc(pCallMethod)); + +#ifdef DIAG_CALL_STACK + for (I32 i = nested/10; i > 0; i--) { *pNextChar++ = '*'; } // (optional) print call nested level, each '*' is 10 levels + for (I32 i = nested%10; i > 0; i--) { *pNextChar++ = '|'; } // (optional) print call nested level, each '|' is 1 level + I32 n = sizeof(callBuffer) - (pNextChar - callBuffer); // space left in buffer + I32 c = snprintf(pNextChar, n, "%d %s.%s\n", nested, pCallMethod->pParentType->name, pCallMethod->name); + pNextChar = (c >= 0 && c < n && (n-c) > 200) ? pNextChar + c : callBuffer; // circular buffer +#endif + heapPtr = NULL; + PTR pMem = pCurEvalStack - pCallMethod->parameterStackSize; + Assert(pMem >= pCurrentMethodState->pEvalStack); if (op == JIT_BOX_CALLVIRT) { // Need to de-ref and box the value-type before calling the function // TODO: Will this work on value-types that are not 4 bytes long? - pMem = pCurEvalStack - pCallMethod->parameterStackSize; heapPtr = Heap_Box(pBoxCallType, *(PTR*)pMem); *(HEAP_PTR*)pMem = heapPtr; } else if (op == JIT_DEREF_CALLVIRT) { - pMem = pCurEvalStack - pCallMethod->parameterStackSize; - *(HEAP_PTR*)pMem = **(HEAP_PTR**)pMem; + heapPtr = **(HEAP_PTR**)pMem; + *(HEAP_PTR*)pMem = heapPtr; + } else if (!METHOD_ISSTATIC(pCallMethod)) { + // Get the actual object that is becoming 'this' + heapPtr = *(HEAP_PTR*)pMem; } // If it's a virtual call then find the real correct method to call if (op == JIT_CALLVIRT_O || op == JIT_BOX_CALLVIRT || op == JIT_DEREF_CALLVIRT) { - tMD_TypeDef *pThisType; - // Get the actual object that is becoming 'this' - if (heapPtr == NULL) { - heapPtr = *(HEAP_PTR*)(pCurEvalStack - pCallMethod->parameterStackSize); - } + if (heapPtr == NULL) { //Crash("NULL 'this' in Virtual call: %s", Sys_GetMethodDesc(pCallMethod)); THROW(types[TYPE_SYSTEM_NULLREFERENCEEXCEPTION]); } - pThisType = Heap_GetType(heapPtr); if (METHOD_ISVIRTUAL(pCallMethod)) { - pCallMethod = pThisType->pVTable[pCallMethod->vTableOfs]; + tMD_TypeDef *pThisType = Heap_GetType(heapPtr); + tMD_MethodDef* pVirtualMethod = pThisType->pVTable[pCallMethod->vTableOfs]; + if (pVirtualMethod->isGenericDefinition) { + tMD_MethodDef* pInstMethod = Generics_GetMethodDefFromCoreMethod(pVirtualMethod, pVirtualMethod->pParentType, pCallMethod->numMethodTypeArgs, pCallMethod->ppMethodTypeArgs); + pCallMethod = pInstMethod; + } else { + //Assert(pCallMethod->parameterStackSize == pVirtualMethod->parameterStackSize); + pCallMethod = pVirtualMethod; + } + //dprintfn("Calling virtual method: %s", pCallMethod->name); } } else if (op == JIT_CALL_INTERFACE) { - tMD_TypeDef *pInterface, *pThisType; - U32 vIndex; - I32 i; + tMD_TypeDef *pThisType = Heap_GetType(heapPtr); + tMD_TypeDef *pInterface = pCallMethod->pParentType; - pInterface = pCallMethod->pParentType; - // Get the actual object that is becoming 'this' - heapPtr = *(HEAP_PTR*)(pCurEvalStack - pCallMethod->parameterStackSize); - pThisType = Heap_GetType(heapPtr); // Find the interface mapping on the 'this' type. - vIndex = 0xffffffff; // This must be searched backwards so if an interface is implemented more than // once in the type hierarchy, the most recent definition gets called - for (i=(I32)pThisType->numInterfaces-1; i >= 0; i--) { + for (I32 i=(I32)pThisType->numInterfaces-1; i >= 0; i--) { if (pThisType->pInterfaceMaps[i].pInterface == pInterface) { // Found the right interface map if (pThisType->pInterfaceMaps[i].pVTableLookup != NULL) { - vIndex = pThisType->pInterfaceMaps[i].pVTableLookup[pCallMethod->vTableOfs]; - break; + U32 vIndex = pThisType->pInterfaceMaps[i].pVTableLookup[pCallMethod->vTableOfs]; + pCallMethod = pThisType->pVTable[vIndex]; + } else { + pCallMethod = pThisType->pInterfaceMaps[i].ppMethodVLookup[pCallMethod->vTableOfs]; } - pCallMethod = pThisType->pInterfaceMaps[i].ppMethodVLookup[pCallMethod->vTableOfs]; + //dprintfn("Calling interface method: %s", pCallMethod->name); goto callMethodSet; } } - Assert(vIndex != 0xffffffff); - pCallMethod = pThisType->pVTable[vIndex]; + Crash("%s.%s is missing interface method: %s", pThisType->nameSpace, pThisType->name, Sys_GetMethodDesc(pCallMethod)); + //dprintfn("Calling interface method: %s", pCallMethod->name); } callMethodSet: - //printf("Calling method: %s\n", Sys_GetMethodDesc(pCallMethod)); // Set up the new method state for the called method - pCallMethodState = MethodState_Direct(pThread, pCallMethod, pCurrentMethodState, 0); + INCREMENT_NESTED_LEVEL(); + pCallMethodState = MethodState_Direct(pThread, pCallMethod, pCurrentMethodState, 0, isTailCall); // Set up the parameter stack for the method being called - pTempPtr = pCurEvalStack; - CreateParameters(pCallMethodState->pParamsLocals, pCallMethod, &/*pCurEvalStack*/pTempPtr, NULL); - pCurEvalStack = pTempPtr; + POP(pCallMethod->parameterStackSize); + CopyParameters(pCallMethodState->pParamsLocals, pCallMethod, pCurEvalStack, NULL); // Set up the local variables for the new method state CHANGE_METHOD_STATE(pCallMethodState); } @@ -1345,6 +1477,30 @@ U32 JIT_Execute(tThread *pThread, U32 numInst) { JIT_BRANCH_FALSE_end: GO_NEXT_CHECK(); +JIT_BRANCH64_TRUE_start: + OPCODE_USE(JIT_BRANCH64_TRUE); + { + U64 value = POP_U64(); + U32 ofs = GET_OP(); + if (value != 0) { + pCurOp = pOps + ofs; + } + } +JIT_BRANCH64_TRUE_end: + GO_NEXT_CHECK(); + +JIT_BRANCH64_FALSE_start: + OPCODE_USE(JIT_BRANCH64_FALSE); + { + U64 value = POP_U64(); + U32 ofs = GET_OP(); + if (value == 0) { + pCurOp = pOps + ofs; + } + } +JIT_BRANCH64_FALSE_end: + GO_NEXT_CHECK(); + JIT_BEQ_I32I32_start: OPCODE_USE(JIT_BEQ_I32I32); { @@ -1746,6 +1902,60 @@ U32 JIT_Execute(tThread *pThread, U32 numInst) { JIT_BLT_UN_I32I32_end: GO_NEXT_CHECK(); + +JIT_BGE_UN_I64I64_start: + OPCODE_USE(JIT_BGE_UN_I64I64); + { + U64 v1, v2, ofs; + POP_U64_U64(v1, v2); + ofs = GET_OP(); + if (v1 >= v2) { + pCurOp = pOps + ofs; + } + } +JIT_BGE_UN_I64I64_end: + GO_NEXT_CHECK(); + +JIT_BGT_UN_I64I64_start: + OPCODE_USE(JIT_BGT_UN_I64I64); + { + U64 v1, v2, ofs; + POP_U64_U64(v1, v2); + ofs = GET_OP(); + if (v1 > v2) { + pCurOp = pOps + ofs; + } + } +JIT_BGT_UN_I64I64_end: + GO_NEXT_CHECK(); + +JIT_BLE_UN_I64I64_start: + OPCODE_USE(JIT_BLE_UN_I64I64); + { + U64 v1, v2, ofs; + POP_U64_U64(v1, v2); + ofs = GET_OP(); + if (v1 <= v2) { + pCurOp = pOps + ofs; + } + } +JIT_BLE_UN_I64I64_end: + GO_NEXT_CHECK(); + +JIT_BLT_UN_I64I64_start: + OPCODE_USE(JIT_BLT_UN_I64I64); + { + U64 v1, v2, ofs; + POP_U64_U64(v1, v2); + ofs = GET_OP(); + if (v1 < v2) { + pCurOp = pOps + ofs; + } + } +JIT_BLT_UN_I64I64_end: + GO_NEXT_CHECK(); + + JIT_CEQ_I32I32_start: // Handles I32 and O OPCODE_USE(JIT_CEQ_I32I32); BINARY_OP(U32, U32, U32, ==); @@ -1819,27 +2029,35 @@ U32 JIT_Execute(tThread *pThread, U32 numInst) { GO_NEXT(); JIT_CGT_F32F32_start: +JIT_CGT_UN_F32F32_start: OPCODE_USE(JIT_CGT_F32F32); BINARY_OP(U32, float, float, >); JIT_CGT_F32F32_end: +JIT_CGT_UN_F32F32_end: GO_NEXT(); JIT_CGT_F64F64_start: +JIT_CGT_UN_F64F64_start: OPCODE_USE(JIT_CGT_F64F64); BINARY_OP(U32, double, double, >); JIT_CGT_F64F64_end: +JIT_CGT_UN_F64F64_end: GO_NEXT(); JIT_CLT_F32F32_start: +JIT_CLT_UN_F32F32_start: OPCODE_USE(JIT_CLT_F32F32); BINARY_OP(U32, float, float, <); JIT_CLT_F32F32_end: +JIT_CLT_UN_F32F32_end: GO_NEXT(); JIT_CLT_F64F64_start: +JIT_CLT_UN_F64F64_start: OPCODE_USE(JIT_CLT_F64F64); BINARY_OP(U32, double, double, <); JIT_CLT_F64F64_end: +JIT_CLT_UN_F64F64_end: GO_NEXT(); JIT_ADD_OVF_I32I32_start: @@ -2118,6 +2336,18 @@ U32 JIT_Execute(tThread *pThread, U32 numInst) { JIT_NEG_I64_end: GO_NEXT(); +JIT_NEG_F32_start: + OPCODE_USE(JIT_NEG_F32); + UNARY_OP(float, -); +JIT_NEG_F32_end: + GO_NEXT(); + +JIT_NEG_F64_start: + OPCODE_USE(JIT_NEG_F64); + UNARY_OP(double, -); +JIT_NEG_F64_end: + GO_NEXT(); + JIT_NOT_I32_start: OPCODE_USE(JIT_NOT_I32); UNARY_OP(U32, ~); @@ -2385,7 +2615,7 @@ U32 JIT_Execute(tThread *pThread, U32 numInst) { JIT_CONV_R64_I64_start: OPCODE_USE(JIT_CONV_R64_I64); { - float value = POP_FLOAT(); + double value = POP_DOUBLE(); PUSH_U64((I64)value); } JIT_CONV_R64_I64_end: @@ -2452,34 +2682,36 @@ U32 JIT_Execute(tThread *pThread, U32 numInst) { OPCODE_USE(JIT_NEWOBJECT); { tMD_MethodDef *pConstructorDef; - HEAP_PTR obj; tMethodState *pCallMethodState; - U32 isInternalConstructor; - PTR pTempPtr; + HEAP_PTR obj = NULL; pConstructorDef = (tMD_MethodDef*)GET_OP(); - isInternalConstructor = (pConstructorDef->implFlags & METHODIMPLATTRIBUTES_INTERNALCALL) != 0; + U32 isInternalConstructor = (pConstructorDef->implFlags & METHODIMPLATTRIBUTES_INTERNALCALL) != 0; + // All internal constructors MUST allocate their own 'this' objects if (!isInternalConstructor) { - // All internal constructors MUST allocate their own 'this' objects obj = Heap_AllocType(pConstructorDef->pParentType); - } else { - // Need to set this to something non-NULL so that CreateParameters() works properly - obj = (HEAP_PTR)-1; } +#ifdef DIAG_METHOD_CALLS + pCurrentMethodState->pMethod->heapAlloc++; +#endif + // Set up the new method state for the called method - pCallMethodState = MethodState_Direct(pThread, pConstructorDef, pCurrentMethodState, isInternalConstructor); + INCREMENT_NESTED_LEVEL(); + pCallMethodState = MethodState_Direct(pThread, pConstructorDef, pCurrentMethodState, isInternalConstructor, 0); // Fill in the parameters - pTempPtr = pCurEvalStack; - CreateParameters(pCallMethodState->pParamsLocals, pConstructorDef, &pTempPtr, obj); - pCurEvalStack = pTempPtr; + POP(pConstructorDef->parameterStackSize); + CopyParameters(pCallMethodState->pParamsLocals, pConstructorDef, pCurEvalStack, obj); + PUSH(sizeof(HEAP_PTR)); + + // Push the object here, so it's on the stack when the constructor returns if (!isInternalConstructor) { - // Push the object here, so it's on the stack when the constructor returns PUSH_O(obj); } - // Set up the local variables for the new method state (for the obj constructor) + // Set up the local variables for the new method state CHANGE_METHOD_STATE(pCallMethodState); + // Run any pending Finalizers RUN_FINALIZER(); } @@ -2492,22 +2724,26 @@ U32 JIT_Execute(tThread *pThread, U32 numInst) { tMD_MethodDef *pConstructorDef; tMethodState *pCallMethodState; U32 isInternalConstructor; - PTR pTempPtr, pMem; pConstructorDef = (tMD_MethodDef*)GET_OP(); isInternalConstructor = (pConstructorDef->implFlags & METHODIMPLATTRIBUTES_INTERNALCALL) != 0; // Allocate space on the eval-stack for the new value-type here - pMem = pCurEvalStack - (pConstructorDef->parameterStackSize - sizeof(PTR)); + PTR pMem = pCurEvalStack - (pConstructorDef->parameterStackSize - sizeof(PTR)); + Assert(pMem >= pCurrentMethodState->pEvalStack); // Set up the new method state for the called method - pCallMethodState = MethodState_Direct(pThread, pConstructorDef, pCurrentMethodState, isInternalConstructor); + INCREMENT_NESTED_LEVEL(); + pCallMethodState = MethodState_Direct(pThread, pConstructorDef, pCurrentMethodState, isInternalConstructor, 0); // Fill in the parameters - pTempPtr = pCurEvalStack; - CreateParameters(pCallMethodState->pParamsLocals, pConstructorDef, &pTempPtr, pMem); - pCurEvalStack = pTempPtr; + POP(pConstructorDef->parameterStackSize); + CopyParameters(pCallMethodState->pParamsLocals, pConstructorDef, pCurEvalStack, pMem); + PUSH(sizeof(PTR)); + // Set the stack state so it's correct for the constructor return - pCurEvalStack += pConstructorDef->pParentType->stackSize; + if (!isInternalConstructor) { + PUSH(pConstructorDef->pParentType->stackSize); + } // Set up the local variables for the new method state CHANGE_METHOD_STATE(pCallMethodState); // Run any pending Finalizers @@ -2522,7 +2758,7 @@ U32 JIT_Execute(tThread *pThread, U32 numInst) { JIT_CAST_CLASS_start: op = JIT_CAST_CLASS; jitCastClass: - OPCODE_USE(JIT_CAST_CLASS); + OPCODE_USE(op); { tMD_TypeDef *pToType, *pTestType; HEAP_PTR heapPtr; @@ -2535,8 +2771,11 @@ U32 JIT_Execute(tThread *pThread, U32 numInst) { } pTestType = Heap_GetType(heapPtr); if (TYPE_ISARRAY(pTestType) && TYPE_ISARRAY(pToType)) { - // Arrays are handled specially - check if the element type is compatible - if (Type_IsAssignableFrom(pToType->pArrayElementType, pTestType->pArrayElementType)) { + // Arrays are handled specially - check if the element type is compatible (or exact match for value types) + + if (pTestType->pArrayElementType->isValueType ? + pToType->pArrayElementType == pTestType->pArrayElementType : + Type_IsAssignableFrom(pToType->pArrayElementType, pTestType->pArrayElementType)) { PUSH_O(heapPtr); goto JIT_IS_INSTANCE_end; } @@ -2590,7 +2829,7 @@ U32 JIT_Execute(tThread *pThread, U32 numInst) { OPCODE_USE(JIT_LOAD_ELEMENT_I8); { U32 value, idx = POP_U32(); // Array index - HEAP_PTR heapPtr = POP_O(); + HEAP_PTR heapPtr = POP_O(); // Array object SystemArray_LoadElement(heapPtr, idx, (PTR)&value); PUSH_U32((I8)value); } @@ -2601,7 +2840,7 @@ U32 JIT_Execute(tThread *pThread, U32 numInst) { OPCODE_USE(JIT_LOAD_ELEMENT_U8); { U32 value, idx = POP_U32(); // Array index - HEAP_PTR heapPtr = POP_O(); + HEAP_PTR heapPtr = POP_O(); // Array object SystemArray_LoadElement(heapPtr, idx, (PTR)&value); PUSH_U32((U8)value); } @@ -2612,7 +2851,7 @@ U32 JIT_Execute(tThread *pThread, U32 numInst) { OPCODE_USE(JIT_LOAD_ELEMENT_I16); { U32 value, idx = POP_U32(); // Array index - HEAP_PTR heapPtr = POP_O(); + HEAP_PTR heapPtr = POP_O(); // Array object SystemArray_LoadElement(heapPtr, idx, (PTR)&value); PUSH_U32((I16)value); } @@ -2623,7 +2862,7 @@ U32 JIT_Execute(tThread *pThread, U32 numInst) { OPCODE_USE(JIT_LOAD_ELEMENT_U16); { U32 value, idx = POP_U32(); // Array index - HEAP_PTR heapPtr = POP_O(); + HEAP_PTR heapPtr = POP_O(); // Array object SystemArray_LoadElement(heapPtr, idx, (PTR)&value); PUSH_U32((U16)value); } @@ -2636,7 +2875,7 @@ U32 JIT_Execute(tThread *pThread, U32 numInst) { OPCODE_USE(JIT_LOAD_ELEMENT_I32); { U32 value, idx = POP_U32(); // Array index - HEAP_PTR heapPtr = POP_O(); + HEAP_PTR heapPtr = POP_O(); // Array object SystemArray_LoadElement(heapPtr, idx, (PTR)&value); PUSH_U32(value); } @@ -2649,8 +2888,8 @@ U32 JIT_Execute(tThread *pThread, U32 numInst) { JIT_LOAD_ELEMENT_R64_start: OPCODE_USE(JIT_LOAD_ELEMENT_I64); { - U32 idx = POP_U32(); // array index - HEAP_PTR heapPtr = POP_O(); + U32 idx = POP_U32(); // Array index + HEAP_PTR heapPtr = POP_O(); // Array object U64 value; SystemArray_LoadElement(heapPtr, idx, (PTR)&value); PUSH_U64(value); @@ -2662,12 +2901,12 @@ U32 JIT_Execute(tThread *pThread, U32 numInst) { JIT_LOAD_ELEMENT_start: OPCODE_USE(JIT_LOAD_ELEMENT); { - U32 idx = POP_U32(); // Array index - HEAP_PTR heapPtr = POP_O(); // array object + U32 idx = POP_U32(); // Array index + HEAP_PTR heapPtr = POP_O(); // Array object U32 size = GET_OP(); // size of type on stack *(U32*)pCurEvalStack = 0; // This is required to zero out the stack for types that are stored in <4 bytes in arrays SystemArray_LoadElement(heapPtr, idx, pCurEvalStack); - pCurEvalStack += size; + PUSH(size); } JIT_LOAD_ELEMENT_end: GO_NEXT(); @@ -2675,8 +2914,8 @@ U32 JIT_Execute(tThread *pThread, U32 numInst) { JIT_LOAD_ELEMENT_ADDR_start: OPCODE_USE(JIT_LOAD_ELEMENT_ADDR); { - U32 idx = POP_U32(); // Array index - PTR heapPtr = POP_O(); + U32 idx = POP_U32(); // Array index + PTR heapPtr = POP_O(); // Array object PTR pMem = SystemArray_LoadElementAddress(heapPtr, idx); PUSH_PTR(pMem); } @@ -2687,8 +2926,8 @@ U32 JIT_Execute(tThread *pThread, U32 numInst) { OPCODE_USE(JIT_STORE_ELEMENT_32); { U32 value = POP_U32(); // Value - U32 idx = POP_U32(); // Array index - PTR heapPtr = POP_O(); + U32 idx = POP_U32(); // Array index + PTR heapPtr = POP_O(); // Array object SystemArray_StoreElement(heapPtr, idx, (PTR)&value); } JIT_STORE_ELEMENT_32_end: @@ -2698,8 +2937,8 @@ U32 JIT_Execute(tThread *pThread, U32 numInst) { OPCODE_USE(JIT_STORE_ELEMENT_64); { U64 value = POP_U64(); // Value - U32 idx = POP_U32(); // Array index - PTR heapPtr = POP_O(); + U32 idx = POP_U32(); // Array index + PTR heapPtr = POP_O(); // Array object SystemArray_StoreElement(heapPtr, idx, (PTR)&value); } JIT_STORE_ELEMENT_64_end: @@ -2713,8 +2952,8 @@ U32 JIT_Execute(tThread *pThread, U32 numInst) { U32 idx, size = GET_OP(); // Size in bytes of value on stack POP(size); pMem = pCurEvalStack; - idx = POP_U32(); // Array index - heapPtr = POP_O(); // Array on heap + idx = POP_U32(); // Array index + heapPtr = POP_O(); // Array object SystemArray_StoreElement(heapPtr, idx, pMem); } JIT_STORE_ELEMENT_end: @@ -2771,7 +3010,7 @@ U32 JIT_Execute(tThread *pThread, U32 numInst) { PTR pMem; pFieldDef = (tMD_FieldDef*)GET_OP(); - pCurEvalStack -= pFieldDef->memSize; + POP(pFieldDef->memSize); pMem = pCurEvalStack; heapPtr = POP_O(); memcpy(heapPtr + pFieldDef->memOffset, pMem, pFieldDef->memSize); @@ -2787,7 +3026,7 @@ U32 JIT_Execute(tThread *pThread, U32 numInst) { pFieldDef = (tMD_FieldDef*)GET_OP(); heapPtr = POP_O(); - pMem = heapPtr + pFieldDef->memOffset; + PTR pMem = heapPtr + pFieldDef->memOffset; // It may not be a value-type, but this'll work anyway PUSH_VALUETYPE(pMem, pFieldDef->memSize, pFieldDef->memSize); } @@ -2798,12 +3037,22 @@ U32 JIT_Execute(tThread *pThread, U32 numInst) { OPCODE_USE(JIT_LOADFIELD_4); { U32 ofs = GET_OP(); - PTR heapPtr = POP_O(); + heapPtr = POP_O(); PUSH_U32(*(U32*)(heapPtr + ofs)); } JIT_LOADFIELD_4_end: GO_NEXT(); +JIT_LOADFIELD_8_start: + OPCODE_USE(JIT_LOADFIELD_8); + { + U32 ofs = GET_OP(); + heapPtr = POP_O(); + PUSH_U64(*(U64*)(heapPtr + ofs)); + } +JIT_LOADFIELD_8_end: + GO_NEXT(); + JIT_LOADFIELD_VALUETYPE_start: OPCODE_USE(JIT_LOADFIELD_VALUETYPE); { @@ -2818,10 +3067,10 @@ U32 JIT_Execute(tThread *pThread, U32 numInst) { // My guess is that at some point they refactored from using 'pEvalStack' to 'pCurEvalStack', but // didn't update this method (because nothing in corlib reads fields from structs). // I think the following line moves the stack pointer along correctly instead: - pCurEvalStack -= u32Value; + POP(u32Value); //pMem = pEvalStack + pCurrentMethodState->stackOfs + pFieldDef->memOffset; - pMem = pCurEvalStack + pFieldDef->memOffset; + PTR pMem = pCurEvalStack + pFieldDef->memOffset; // It may not be a value-type, but this'll work anyway PUSH_VALUETYPE(pMem, pFieldDef->memSize, pFieldDef->memSize); } @@ -2900,6 +3149,7 @@ U32 JIT_Execute(tThread *pThread, U32 numInst) { op = JIT_LOADSTATICFIELD_CHECKTYPEINIT_VALUETYPE; goto loadStaticFieldStart; JIT_LOADSTATICFIELD_CHECKTYPEINIT_F64_start: +JIT_LOADSTATICFIELD_CHECKTYPEINIT_INT64_start: op = JIT_LOADSTATICFIELD_CHECKTYPEINIT_F64; goto loadStaticFieldStart; JIT_LOADSTATICFIELD_CHECKTYPEINIT_INT32_start: @@ -2928,7 +3178,8 @@ U32 JIT_Execute(tThread *pThread, U32 numInst) { // Need to re-run this instruction when we return from static constructor call //pCurrentMethodState->ipOffset -= 2; pCurOp -= 2; - pCallMethodState = MethodState_Direct(pThread, pParentType->pStaticConstructor, pCurrentMethodState, 0); + INCREMENT_NESTED_LEVEL(); + pCallMethodState = MethodState_Direct(pThread, pParentType->pStaticConstructor, pCurrentMethodState, 0, 0); // There can be no parameters, so don't need to set them up CHANGE_METHOD_STATE(pCallMethodState); GO_NEXT_CHECK(); @@ -2952,6 +3203,7 @@ U32 JIT_Execute(tThread *pThread, U32 numInst) { } JIT_LOADSTATICFIELDADDRESS_CHECKTYPEINIT_end: JIT_LOADSTATICFIELD_CHECKTYPEINIT_VALUETYPE_end: +JIT_LOADSTATICFIELD_CHECKTYPEINIT_INT64_end: JIT_LOADSTATICFIELD_CHECKTYPEINIT_INT32_end: JIT_LOADSTATICFIELD_CHECKTYPEINIT_F32_end: JIT_LOADSTATICFIELD_CHECKTYPEINIT_F64_end: @@ -2966,7 +3218,7 @@ U32 JIT_Execute(tThread *pThread, U32 numInst) { tMD_TypeDef *pTypeDef; pTypeDef = (tMD_TypeDef*)GET_OP(); - pMem = POP_PTR(); + PTR pMem = POP_PTR(); memset(pMem, 0, pTypeDef->instanceMemSize); } JIT_INIT_VALUETYPE_end: @@ -3042,7 +3294,7 @@ OPCODE_USE(JIT_BOX_INT64); tMD_TypeDef *pType = (tMD_TypeDef*)GET_OP(); // Take the nullable type off the stack. The +4 is because the of the HasValue field (Bool, size = 4 bytes) - pCurEvalStack -= pType->stackSize + 4; + POP(pType->stackSize + 4); // If .HasValue if (*(U32*)pCurEvalStack) { // Box the underlying type @@ -3081,7 +3333,7 @@ OPCODE_USE(JIT_BOX_INT64); PUSH_U32(0); // And increase the stack pointer by the size of the underlying type // (the contents don't matter) - pCurEvalStack += pTypeDef->stackSize; + PUSH(pTypeDef->stackSize); } else { // Push .HasValue (= true) PUSH_U32(1); @@ -3202,8 +3454,9 @@ OPCODE_USE(JIT_BOX_INT64); // Set the IP to the catch handler pCurrentMethodState->ipOffset = pThread->pCatchExceptionHandler->handlerStart; // Set the current method state + pThread->pCurrentMethodState = pCurrentMethodState; LOAD_METHOD_STATE(); - // Push onto this stack-frame's evaluation stack the opject thrown + // Push onto this stack-frame's evaluation stack the object thrown POP_ALL(); PUSH_O(pThread->pCurrentExceptionObject); } @@ -3230,7 +3483,7 @@ OPCODE_USE(JIT_BOX_INT64); } } POP_ALL(); - ofs = GET_OP(); + U32 ofs = GET_OP(); if (pFinally != NULL) { // Jump to 'finally' section pCurOp = pOps + pFinally->handlerStart; @@ -3267,4 +3520,11 @@ OPCODE_USE(JIT_BOX_INT64); void JIT_Execute_Init() { // Initialise the JIT code addresses JIT_Execute(NULL, 0); -} \ No newline at end of file +} + +#ifdef DIAG_CALL_STACK +void PrintCallStackBuffer() { + printf(pNextChar + 1); + printf(callBuffer); +} +#endif diff --git a/src/DNA/native/src/JIT_OpCodes.h b/src/DNA/native/src/JIT_OpCodes.h index 82b3cb22..41398a32 100644 --- a/src/DNA/native/src/JIT_OpCodes.h +++ b/src/DNA/native/src/JIT_OpCodes.h @@ -140,7 +140,7 @@ #define JIT_LOADSTATICFIELD_O (JIT_LOADSTATICFIELD_TYPEID + EVALSTACK_O) //#define JIT_LOADSTATICFIELD_TRANSPTR (JIT_LOADSTATICFIELD_TYPEID + EVALSTACK_TRANSPTR) #define JIT_LOADSTATICFIELD_F64 (JIT_LOADSTATICFIELD_TYPEID + EVALSTACK_F64) -#define JIT_LOADSTATICFIELD_VALUEPTYE (JIT_LOADSTATICFIELD_TYPEID + EVALSTACK_VALUETYPE) +#define JIT_LOADSTATICFIELD_VALUETYPE (JIT_LOADSTATICFIELD_TYPEID + EVALSTACK_VALUETYPE) #define JIT_STORESTATICFIELD_TYPEID 0x60 #define JIT_STORESTATICFIELD_INT64 (JIT_STORESTATICFIELD_TYPEID + EVALSTACK_INT64) @@ -199,9 +199,8 @@ #define JIT_NOT_I32 0x8b #define JIT_NEG_I64 0x8c #define JIT_NOT_I64 0x8d - -#define JIT_BOX_NULLABLE 0x8e -#define JIT_LOAD_F64 0x8f +#define JIT_NEG_F32 0x8e +#define JIT_NEG_F64 0x8f #define JIT_BEQ_I32I32 0x90 #define JIT_BGE_I32I32 0x91 @@ -225,15 +224,20 @@ #define JIT_BLE_UN_I64I64 0xa2 #define JIT_BLT_UN_I64I64 0xa3 -#define JIT_SHL_I32 0xa8 -#define JIT_SHR_I32 0xa9 -#define JIT_SHR_UN_I32 0xaa -#define JIT_SHL_I64 0xab -#define JIT_SHR_I64 0xac -#define JIT_SHR_UN_I64 0xad +#define JIT_SHL_I32 0xa4 +#define JIT_SHR_I32 0xa5 +#define JIT_SHR_UN_I32 0xa6 +#define JIT_SHL_I64 0xa7 +#define JIT_SHR_I64 0xa8 +#define JIT_SHR_UN_I64 0xa9 + +#define JIT_BRANCH_FALSE 0xaa +#define JIT_BRANCH_TRUE 0xab +#define JIT_BRANCH64_FALSE 0xac +#define JIT_BRANCH64_TRUE 0xad -#define JIT_BRANCH_FALSE 0xae -#define JIT_BRANCH_TRUE 0xaf +#define JIT_BOX_NULLABLE 0xae +#define JIT_LOAD_F64 0xaf #define JIT_LOADTOKEN_BASE 0xb0 #define JIT_LOADTOKEN_TYPE (JIT_LOADTOKEN_BASE + 0) @@ -392,6 +396,7 @@ #define JIT_LOAD_I4_2 0x13a #define JIT_LOADFIELD_4 0x13b +#define JIT_LOADFIELD_8 0x13c #define JIT_CONV_OFFSET_I32 0 #define JIT_CONV_OFFSET_U32 1 @@ -450,5 +455,6 @@ #define JIT_INVOKE_SYSTEM_REFLECTION_METHODBASE 0x164 #define JIT_REFLECTION_DYNAMICALLY_BOX_RETURN_VALUE 0x165 +#define JIT_TAILCALL_PREFIX 0x166 #endif diff --git a/src/DNA/native/src/JSInterop.c b/src/DNA/native/src/JSInterop.c index 002dfebe..260e3b11 100644 --- a/src/DNA/native/src/JSInterop.c +++ b/src/DNA/native/src/JSInterop.c @@ -13,6 +13,8 @@ int JSInterop_CallDotNet(char* assemblyName, char* namespace, char* className, c // TODO: Can't we reuse threads? Need to reset their state somehow. tThread *pThread = Thread(); + log_f(1, "JSInterop_CallDotNet(%s, %s, %s, %s, %s)\n", assemblyName, namespace, className, methodName, stringArg); + HEAP_PTR arg = SystemString_FromCharPtrASCII(stringArg); Heap_MakeUndeletable(arg); @@ -22,18 +24,22 @@ int JSInterop_CallDotNet(char* assemblyName, char* namespace, char* className, c // Specifying it exactly (type generic args, method generic args, arguments themselves, picking the // inherited methods if needed), is complex and not required at the moment. tMD_TypeDef *pTypeDef = MetaData_GetTypeDefFromName(pAssemblyMetadata, namespace, className, NULL, /* assertExists */ 1); - MetaData_Fill_TypeDef(pTypeDef, NULL, NULL); - for (U32 i=0; inumMethods; i++) { - if (strcmp(pTypeDef->ppMethods[i]->name, methodName) == 0) { - tMD_MethodDef *pMethodDef = pTypeDef->ppMethods[i]; - - // We found the method - now call it - Thread_SetEntryPoint(pThread, pAssemblyMetadata, pMethodDef->tableIndex, (PTR)&arg, sizeof(void*)); - int result = Thread_Execute(); - - Heap_MakeDeletable(arg); - return result; + if (pTypeDef != NULL) { + MetaData_Fill_TypeDef(pTypeDef, NULL, NULL); + for (U32 i=0; inumMethods; i++) { + if (strcmp(pTypeDef->ppMethods[i]->name, methodName) == 0) { + tMD_MethodDef *pMethodDef = pTypeDef->ppMethods[i]; + + // We found the method - now call it + Thread_SetEntryPoint(pThread, pAssemblyMetadata, pMethodDef->tableIndex, (PTR)&arg, sizeof(void*)); + int result = Thread_Execute(); + + Heap_MakeDeletable(arg); + return result; + } } + } else { + Crash("Cannot find type %s.%s\n", namespace, className); } Crash("Found type %s, but no such method %s\n", className, methodName); diff --git a/src/DNA/native/src/MetaData.c b/src/DNA/native/src/MetaData.c index 5684de2c..39952728 100644 --- a/src/DNA/native/src/MetaData.c +++ b/src/DNA/native/src/MetaData.c @@ -62,8 +62,8 @@ IDX_TABLE MetaData_DecodeSigEntryToken(SIG *pSig) { } tMetaData* MetaData() { - tMetaData *pRet = TMALLOC(tMetaData); - memset(pRet, 0, sizeof(tMetaData)); + tMetaData *pRet = TCALLOCFOREVER(1, tMetaData); + //memset(pRet, 0, sizeof(tMetaData)); return pRet; } @@ -135,90 +135,189 @@ Always 2 characters to togther. 1st character defines source, 2nd defines destin *: 32-bit index into relevant heap; Or coded index - MSB = which table, other 3 bytes = table index Or 32-bit int - Or pointer (also RVA) + p: pointer (also RVA) s: 16-bit value c: 8-bit value */ -static char* tableDefs[] = { +static const unsigned char* tableDefs[] = { + // 0x00 + "sxSpGpGxGx", + // 0x01 + "xp;*SpSp", + // 0x02 + "xpmpi*SpSp0*\x04*\x06*xclcxcxcx*xpxpx*xpxcxcxcxcxpx*x*x*xpI*xpxpxpxpx*xpx*x*xpxpxpxp", + // 0x03 + NULL, + // 0x04 + "xpmpssxsSpBpxpxpx*x*I*xp", + // 0x05 + NULL, + // 0x06 + "xpmp^pssssSpBp\x08*xpxcxcxsxpx*xpxpI*x*x*xpxp" +#ifdef GEN_COMBINED_OPCODES + "x*x*x*x*x*x*" +#endif +#ifdef DIAG_METHOD_CALLS + "x*x*x*x*x*x*x*x*x*x*" +#endif + , + // 0x07 + NULL, + // 0x08 + "ssssSp", + // 0x09 + "\x02*0*", + // 0x0a + "xp5*SpBp", + // 0x0b + "ccccxs1*Bp", + // 0x0c + "2*:*Bp", + // 0x0d + NULL, + // 0x0e + "ssxs4*Bp", + // 0x0f + "ssxsi*\x02*", + // 0x10 + "i*\x04*", + // 0x11 + "Bp", + // 0x12 + "\x02*\x14*", + // 0x13 + NULL, + // 0x14 + "ssxsSp0*", + // 0x15 + "\x02*\x17*", + // 0x16 + NULL, + // 0x17 + "ssxsSpBp", + // 0x18 + "ssxs\x06*6*", + // 0x19 + "\x02*7*7*", + // 0x1a + "Sp", + // 0x1b + "xpmpBp", + // 0x1c + "ssxs8*Sp\x1a*", + // 0x1d + "^*\x04*", + // 0x1e + NULL, + // 0x1f + NULL, + // 0x20 + "i*ssssssssi*BpSpSp", + // 0x21 + NULL, + // 0x22 + NULL, + // 0x23 + "ssssssssi*BpSpSpBp", + // 0x24 + NULL, + // 0x25 + NULL, + // 0x26 + NULL, + // 0x27 + "i*i*SpSp9*", + // 0x28 + "i*i*Sp9*", + // 0x29 + "\x02*\x02*", + // 0x2a + "ssss<*Sp", + // 0x2b + "xpmp7*Bp", + // 0x2c + "\x2ap0*", + +/* // 0x00 - "sxS*G*GxGx", + "sxSpGpGxGx", // 0x01 - "x*;*S*S*", + "x*;*SpSp", // 0x02 - "x*m*i*S*S*0*\x04*\x06*xclcxcxcx*x*x*x*x*x*x*x*x*x*x*I*x*x*x*x*x*x*x*x*x*x*x*x*", + "x*mpi*SpSp0*\x04*\x06*xclcxcxcx*x*x*x*x*x*x*x*x*x*x*I*x*x*x*x*x*x*x*x*x*x*x*x*", // 0x03 NULL, // 0x04 - "x*m*ssxsS*B*x*x*x*x*I*x*", + "x*mpssxsSpBpx*x*x*x*I*x*", // 0x05 NULL, // 0x06 - "x*m*^*ssssS*B*\x08*x*x*x*x*x*x*I*x*x*x*" + "x*mp^pssssSpBp\x08*x*x*x*x*x*x*I*x*x*x*x*" #ifdef GEN_COMBINED_OPCODES "x*x*x*x*x*x*" #endif #ifdef DIAG_METHOD_CALLS - "x*x*x*" + "x*x*x*x*x*x*x*x*x*x*" #endif , // 0x07 NULL, // 0x08 - "ssssS*", + "ssssSp", // 0x09 "\x02*0*", // 0x0A - "x*5*S*B*", + "x*5*SpBp", // 0x0B - "ccccxs1*B*", + "ccccxs1*Bp", // 0x0C - "2*:*B*", + "2*:*Bp", // 0x0D NULL, // 0x0E - "ssxs4*B*", + "ssxs4*Bp", // 0x0F "ssxsi*\x02*", // 0x10 - NULL, + "i*\x04*", // 0x11 - "B*", + "Bp", // 0x12 "\x02*\x14*", // 0x13 NULL, // 0x14 - "ssxsS*0*", + "ssxsSp0*", // 0x15 "\x02*\x17*", // 0x16 NULL, // 0x17 - "ssxsS*B*", + "ssxsSpBp", // 0x18 "ssxs\06*6*", // 0x19 "\x02*7*7*", // 0x1A - "S*", + "Sp", // 0x1B - "x*m*B*", + "x*mpBp", // 0x1C - "ssxs8*S*\x1a*", + "ssxs8*Sp\x1a*", // 0x1D - "^*\x04*", + "^p\x04*", // 0x1E NULL, // 0x1F NULL, // 0x20 - "i*ssssssssi*B*S*S*", + "i*ssssssssi*BpSpSp", // 0x21 NULL, // 0x22 NULL, // 0x23 - "ssssssssi*B*S*S*B*", + "ssssssssi*BpSpSpBp", // 0x24 NULL, // 0x25 @@ -226,29 +325,29 @@ static char* tableDefs[] = { // 0x26 NULL, // 0x27 - NULL, + "i*i*SpSp9*", // 0x28 - NULL, + "i*i*Sp9*", // 0x29 "\x02*\x02*", // 0x2A - "ssss<*S*", + "ssss<*Sp", // 0x2B - "x*m*7*B*", + "x*mp7*Bp", // 0x2C - "\x2a*0*", + "\x2a*0*",*/ }; // Coded indexes use this lookup table. // Note that the extra 'z' characters are important! // (Because of how the lookup works each string must be a power of 2 in length) -static unsigned char* codedTags[] = { +static const char* codedTags[] = { // TypeDefOrRef "\x02\x01\x1Bz", // HasConstant "\x04\x08\x17z", // HasCustomAttribute - "\x06\x04\x01\x02\x08\x09\x0A\x00\x0E\x17\x14\x11\x1A\x1B\x20\x23\x26\x27\x28zzzzzzzzzzzzz", + "\x06\x04\x01\x02\x08\x09\x0A\x00\x0E\x17\x14\x11\x1A\x1B\x20\x23\x26\x27\x28\x2A\x2C\x2Bzzzzzzzzzz", // HasFieldMarshall "\x04\x08", // HasDeclSecurity @@ -307,17 +406,20 @@ static void* LoadSingleTable(tMetaData *pThis, tRVA *pRVA, int tableID, void **p int numRows = pThis->tables.numRows[tableID]; int rowLen = 0; // Number of bytes taken by each row in memory. int i, row; - char *pDef = tableDefs[tableID]; + const unsigned char *pDef = tableDefs[tableID]; int defLen = (int)strlen(pDef); void *pRet; unsigned char *pSource = *ppTable; unsigned char *pDest; - unsigned int v; + size_t v; // Calculate the destination row size from table definition, if it hasn't already been calculated if (tableRowSize[tableID] == 0) { for (i=0; itables.numRows[d] < 0x10000) { // Use 16-bit offset @@ -356,7 +458,7 @@ static void* LoadSingleTable(tMetaData *pThis, tRVA *pRVA, int tableID, void **p v = GetU32(pSource); pSource += 4; } - v |= d << 24; + v |= (size_t) (d << 24); } else { switch (d) { case 'c': // 8-bit value @@ -386,12 +488,12 @@ static void* LoadSingleTable(tMetaData *pThis, tRVA *pRVA, int tableID, void **p case '<': { int ofs = pDef[i] - '0'; - char* pCoding = codedTags[ofs]; - int tagBits = codedTagBits[ofs]; + const char* pCoding = codedTags[ofs]; + const int tagBits = codedTagBits[ofs]; unsigned char tag = *pSource & ((1 << tagBits) - 1); int idxIntoTableID = pCoding[tag]; // The actual table index that we're looking for if (idxIntoTableID < 0 || idxIntoTableID > MAX_TABLES) { - printf("Error: Bad table index: 0x%02x\n", idxIntoTableID); + printf("Error: tableID=%02x, row=%d, i=%d, d=%c, tag=%d : Bad table index: 0x%02x\n", tableID, row, i, d, tag, idxIntoTableID); exit(1); } if (pThis->tables.codedIndex32Bit[ofs]) { @@ -414,7 +516,7 @@ static void* LoadSingleTable(tMetaData *pThis, tRVA *pRVA, int tableID, void **p v = GetU16(pSource); pSource += 2; } - v = (unsigned int)(pThis->strings.pStart + v); + v = (size_t)(pThis->strings.pStart + v); break; case 'G': // index into GUID heap if (pThis->index32BitGUID) { @@ -424,7 +526,7 @@ static void* LoadSingleTable(tMetaData *pThis, tRVA *pRVA, int tableID, void **p v = GetU16(pSource); pSource += 2; } - v = (unsigned int)(pThis->GUIDs.pGUID1 + ((v-1) * 16)); + v = (size_t)(pThis->GUIDs.pGUID1 + ((v-1) * 16)); break; case 'B': // index into BLOB heap if (pThis->index32BitBlob) { @@ -434,15 +536,15 @@ static void* LoadSingleTable(tMetaData *pThis, tRVA *pRVA, int tableID, void **p v = GetU16(pSource); pSource += 2; } - v = (unsigned int)(pThis->blobs.pStart + v); + v = (size_t)(pThis->blobs.pStart + v); break; case '^': // RVA to convert to pointer v = GetU32(pSource); pSource += 4; - v = (unsigned int)RVA_FindData(pRVA, v); + v = (size_t)RVA_FindData(pRVA, v); break; case 'm': // Pointer to this metadata - v = (unsigned int)pThis; + v = (size_t)pThis; break; case 'l': // Is this the last table entry? v = (row == numRows - 1); @@ -458,6 +560,10 @@ static void* LoadSingleTable(tMetaData *pThis, tRVA *pRVA, int tableID, void **p } } switch (pDef[i+1]) { + case 'p': + *(size_t*)pDest = v; + pDest += sizeof(size_t); + break; case '*': *(unsigned int*)pDest = v; pDest += 4; @@ -514,8 +620,8 @@ void MetaData_LoadTables(tMetaData *pThis, tRVA *pRVA, void *pStream, unsigned i // Determine if each coded index lookup type needs to use 16 or 32 bit indexes for (i=0; i<13; i++) { - char* pCoding = codedTags[i]; - int tagBits = codedTagBits[i]; + const char* pCoding = codedTags[i]; + const int tagBits = codedTagBits[i]; // Discover max table size unsigned int maxTableLen = 0; for (k=0; k < (1<signature, NULL); entry = MetaData_DecodeSigEntry(&sig); - if (entry & SIG_METHODDEF_GENERIC) { + if (entry & SIG_CALLCONV_GENERIC) { // Has generic parameters. Read how many, but don't care about the answer MetaData_DecodeSigEntry(&sig); } @@ -104,7 +104,7 @@ void MetaData_Fill_MethodDef(tMD_TypeDef *pParentType, tMD_MethodDef *pMethodDef if (pMethodDef->pReturnType != NULL) { MetaData_Fill_TypeDef(pMethodDef->pReturnType, NULL, NULL); } - pMethodDef->pParams = (tParameter*)malloc(pMethodDef->numberOfParameters * sizeof(tParameter)); + pMethodDef->pParams = TMALLOCFOREVER(pMethodDef->numberOfParameters, tParameter); totalSize = 0; if (!METHOD_ISSTATIC(pMethodDef)) { // Fill in parameter info for the 'this' pointer @@ -119,7 +119,7 @@ void MetaData_Fill_MethodDef(tMD_TypeDef *pParentType, tMD_MethodDef *pMethodDef } totalSize = 4; } - for (i=totalSize>>2; inumberOfParameters; i++) { + for (i=METHOD_ISSTATIC(pMethodDef)?0:1; inumberOfParameters; i++) { tMD_TypeDef *pTypeDef; U32 size; @@ -127,6 +127,7 @@ void MetaData_Fill_MethodDef(tMD_TypeDef *pParentType, tMD_MethodDef *pMethodDef //if (pTypeDef != NULL) { MetaData_Fill_TypeDef(pTypeDef, NULL, NULL); size = pTypeDef->stackSize; + Assert(pTypeDef->isGenericDefinition || size != 0); // if this fails, there is a circular dependency on pTypeDef, so add it to Type.c //} else { // // If this method has generic-type-argument arguments, then we can't do anything very sensible yet // size = 0; @@ -139,47 +140,6 @@ void MetaData_Fill_MethodDef(tMD_TypeDef *pParentType, tMD_MethodDef *pMethodDef pMethodDef->parameterStackSize = totalSize; } -// Find the method that has been overridden by pMethodDef. -// This is to get the correct vTable offset for the method. -// This must search the MethodImpl table to see if the default inheritence rules are being overridden. -// Return NULL if this method does not override anything. -static tMD_MethodDef* FindVirtualOverriddenMethod(tMD_TypeDef *pTypeDef, tMD_MethodDef *pMethodDef) { - U32 i; - - do { - // Search MethodImpl table - for (i=pTypeDef->pMetaData->tables.numRows[MD_TABLE_METHODIMPL]; i>0; i--) { - tMD_MethodImpl *pMethodImpl; - - pMethodImpl = (tMD_MethodImpl*)MetaData_GetTableRow(pTypeDef->pMetaData, MAKE_TABLE_INDEX(MD_TABLE_METHODIMPL, i)); - if (pMethodImpl->class_ == pTypeDef->tableIndex) { - tMD_MethodDef *pMethodDeclDef; - - pMethodDeclDef = MetaData_GetMethodDefFromDefRefOrSpec(pTypeDef->pMetaData, pMethodImpl->methodDeclaration, pTypeDef->ppClassTypeArgs, pMethodDef->ppMethodTypeArgs); - if (pMethodDeclDef->tableIndex == pMethodDef->tableIndex) { - IDX_TABLE methodToken; - tMD_MethodDef *pMethod; - - methodToken = pMethodImpl->methodBody; - pMethod = (tMD_MethodDef*)MetaData_GetTableRow(pTypeDef->pMetaData, methodToken); - return pMethod; - } - } - } - - // Use normal inheritence rules - // It must be a virtual method that's being overridden. - for (i=pTypeDef->numVirtualMethods - 1; i != 0xffffffff; i--) { - if (MetaData_CompareNameAndSig(pMethodDef->name, pMethodDef->signature, pMethodDef->pMetaData, pMethodDef->pParentType->ppClassTypeArgs, pMethodDef->ppMethodTypeArgs, pTypeDef->pVTable[i], pTypeDef->ppClassTypeArgs, NULL)) { - return pTypeDef->pVTable[i]; - } - } - pTypeDef = pTypeDef->pParent; - } while (pTypeDef != NULL); - - return NULL; -} - void MetaData_Fill_TypeDef_(tMD_TypeDef *pTypeDef, tMD_TypeDef **ppClassTypeArgs, tMD_TypeDef **ppMethodTypeArgs) { IDX_TABLE firstIdx, lastIdx, token; U32 instanceMemSize, staticMemSize, virtualOfs, i, j; @@ -241,8 +201,14 @@ void MetaData_Fill_TypeDef_(tMD_TypeDef *pTypeDef, tMD_TypeDef **ppClassTypeArgs tMD_MethodDef *pVirtualOveriddenMethod; pVirtualOveriddenMethod = FindVirtualOverriddenMethod(pTypeDef->pParent, pMethodDef); - Assert(pVirtualOveriddenMethod != NULL); - pMethodDef->vTableOfs = pVirtualOveriddenMethod->vTableOfs; + if (pVirtualOveriddenMethod != NULL) { + //Assert(pVirtualOveriddenMethod != NULL); + pMethodDef->vTableOfs = pVirtualOveriddenMethod->vTableOfs; + } + else { + // perhaps virtual methods in abstract classes? + pMethodDef->vTableOfs = virtualOfs++; + } } } else { // Dummy value - make it obvious it's not valid! @@ -268,7 +234,7 @@ void MetaData_Fill_TypeDef_(tMD_TypeDef *pTypeDef, tMD_TypeDef **ppClassTypeArgs lastIdx = firstIdx + pTypeDef->numFields - 1; staticMemSize = 0; if (pTypeDef->numFields > 0) { - pTypeDef->ppFields = mallocForever(pTypeDef->numFields * sizeof(tMD_FieldDef*)); + pTypeDef->ppFields = TMALLOCFOREVER(pTypeDef->numFields, tMD_FieldDef*); } instanceMemSize = (pTypeDef->pParent == NULL)?0:pTypeDef->pParent->instanceMemSize; for (token = firstIdx, i=0; token <= lastIdx; token++, i++) { @@ -280,7 +246,7 @@ void MetaData_Fill_TypeDef_(tMD_TypeDef *pTypeDef, tMD_TypeDef **ppClassTypeArgs if (pTypeDef->pGenericDefinition != NULL) { // If this is a generic instantiation type, then all field defs need to be copied, // as there will be lots of different instantiations. - tMD_FieldDef *pFieldCopy = TMALLOCFOREVER(tMD_FieldDef); + tMD_FieldDef *pFieldCopy = TMALLOCFOREVER(1, tMD_FieldDef); memcpy(pFieldCopy, pFieldDef, sizeof(tMD_FieldDef)); pFieldDef = pFieldCopy; } @@ -303,6 +269,7 @@ void MetaData_Fill_TypeDef_(tMD_TypeDef *pTypeDef, tMD_TypeDef **ppClassTypeArgs // Note that this may already be set, as some basic types have this preset; // or if it's not a value-type it'll already be set if (pTypeDef->stackSize == 0) { + Assert(pTypeDef->isValueType); // if it gets here then it must be a value type pTypeDef->stackType = EVALSTACK_VALUETYPE; pTypeDef->stackSize = pTypeDef->instanceMemSize; @@ -322,7 +289,7 @@ void MetaData_Fill_TypeDef_(tMD_TypeDef *pTypeDef, tMD_TypeDef **ppClassTypeArgs if (pTypeDef->pGenericDefinition != NULL) { // If this is a generic instantiation type, then all field defs need to be copied, // as there will be lots of different instantiations. - tMD_FieldDef *pFieldCopy = TMALLOCFOREVER(tMD_FieldDef); + tMD_FieldDef *pFieldCopy = TMALLOCFOREVER(1, tMD_FieldDef); memcpy(pFieldCopy, pFieldDef, sizeof(tMD_FieldDef)); pFieldDef = pFieldCopy; } @@ -338,8 +305,8 @@ void MetaData_Fill_TypeDef_(tMD_TypeDef *pTypeDef, tMD_TypeDef **ppClassTypeArgs } } if (staticMemSize > 0) { - pTypeDef->pStaticFields = mallocForever(staticMemSize); - memset(pTypeDef->pStaticFields, 0, staticMemSize); + pTypeDef->pStaticFields = callocForever(1, staticMemSize); + //memset(pTypeDef->pStaticFields, 0, staticMemSize); // Set the field addresses (->pMemory) of all static fields for (i = 0; inumFields; i++) { tMD_FieldDef *pFieldDef; @@ -356,8 +323,8 @@ void MetaData_Fill_TypeDef_(tMD_TypeDef *pTypeDef, tMD_TypeDef **ppClassTypeArgs // Resolve all members firstIdx = pTypeDef->methodList; lastIdx = firstIdx + pTypeDef->numMethods - 1; - pTypeDef->ppMethods = mallocForever(pTypeDef->numMethods * sizeof(tMD_MethodDef*)); - pTypeDef->pVTable = mallocForever(pTypeDef->numVirtualMethods * sizeof(tMD_MethodDef*)); + pTypeDef->ppMethods = TMALLOCFOREVER(pTypeDef->numMethods, tMD_MethodDef*); + pTypeDef->pVTable = TMALLOCFOREVER(pTypeDef->numVirtualMethods, tMD_MethodDef*); // Copy initial vTable from parent if (pTypeDef->pParent != NULL) { memcpy(pTypeDef->pVTable, pTypeDef->pParent->pVTable, pTypeDef->pParent->numVirtualMethods * sizeof(tMD_MethodDef*)); @@ -369,7 +336,7 @@ void MetaData_Fill_TypeDef_(tMD_TypeDef *pTypeDef, tMD_TypeDef **ppClassTypeArgs if (pTypeDef->pGenericDefinition != NULL) { // If this is a generic instantiation type, then all method defs need to be copied, // as there will be lots of different instantiations. - tMD_MethodDef *pMethodCopy = TMALLOCFOREVER(tMD_MethodDef); + tMD_MethodDef *pMethodCopy = TMALLOCFOREVER(1, tMD_MethodDef); memcpy(pMethodCopy, pMethodDef, sizeof(tMD_MethodDef)); pMethodDef = pMethodCopy; } @@ -432,7 +399,7 @@ void MetaData_Fill_TypeDef_(tMD_TypeDef *pTypeDef, tMD_TypeDef **ppClassTypeArgs if (pTypeDef->numInterfaces > 0 && !pTypeDef->isGenericDefinition) { U32 mapNum; - pTypeDef->pInterfaceMaps = (tInterfaceMap*)mallocForever(pTypeDef->numInterfaces * sizeof(tInterfaceMap)); + pTypeDef->pInterfaceMaps = TMALLOCFOREVER(pTypeDef->numInterfaces, tInterfaceMap); // Copy interface maps from parent type if (j > 0) { memcpy(pTypeDef->pInterfaceMaps, pTypeDef->pParent->pInterfaceMaps, j * sizeof(tInterfaceMap)); @@ -452,7 +419,7 @@ void MetaData_Fill_TypeDef_(tMD_TypeDef *pTypeDef, tMD_TypeDef **ppClassTypeArgs MetaData_Fill_TypeDef(pInterface, NULL, NULL); pMap = &pTypeDef->pInterfaceMaps[mapNum]; pMap->pInterface = pInterface; - pMap->pVTableLookup = (U32*)mallocForever(pInterface->numVirtualMethods * sizeof(U32)); + pMap->pVTableLookup = TMALLOCFOREVER(pInterface->numVirtualMethods, U32); pMap->ppMethodVLookup = NULL; // Discover interface mapping for each interface method for (i=0; inumVirtualMethods; i++) { @@ -473,7 +440,7 @@ void MetaData_Fill_TypeDef_(tMD_TypeDef *pTypeDef, tMD_TypeDef **ppClassTypeArgs // If this is an enum type, then pretend its stack type is its underlying type if (pTypeDef->pParent == types[TYPE_SYSTEM_ENUM]) { - pTypeDef->stackType = EVALSTACK_INT32; + pTypeDef->stackType = EVALSTACK_INT32; // TODO: other integral types? } } diff --git a/src/DNA/native/src/MetaData_Search.c b/src/DNA/native/src/MetaData_Search.c index 847339de..8b9ef63f 100644 --- a/src/DNA/native/src/MetaData_Search.c +++ b/src/DNA/native/src/MetaData_Search.c @@ -29,11 +29,14 @@ U32 MetaData_CompareNameAndSig(STRING name, BLOB_ sigBlob, tMetaData *pSigMetaData, tMD_TypeDef **ppSigClassTypeArgs, tMD_TypeDef **ppSigMethodTypeArgs, tMD_MethodDef *pMethod, tMD_TypeDef **ppMethodClassTypeArgs, tMD_TypeDef **ppMethodMethodTypeArgs) { if (strcmp(name, pMethod->name) == 0) { SIG sig, thisSig; - U32 e, thisE, paramCount, i; + U32 e, thisE, paramCount, i, isGeneric, isSame; sig = MetaData_GetBlob(sigBlob, NULL); thisSig = MetaData_GetBlob(pMethod->signature, NULL); + // if signatures match + isSame = strcmp(sig, thisSig) == 0; + e = MetaData_DecodeSigEntry(&sig); thisE = MetaData_DecodeSigEntry(&thisSig); // Check method call type (static, etc...) @@ -42,7 +45,8 @@ U32 MetaData_CompareNameAndSig(STRING name, BLOB_ sigBlob, tMetaData *pSigMetaDa } // If method has generic arguments, check the generic type argument count - if (e & SIG_METHODDEF_GENERIC) { + isGeneric = e & SIG_CALLCONV_GENERIC; + if (isGeneric) { e = MetaData_DecodeSigEntry(&sig); thisE = MetaData_DecodeSigEntry(&thisSig); // Generic argument count @@ -63,8 +67,8 @@ U32 MetaData_CompareNameAndSig(STRING name, BLOB_ sigBlob, tMetaData *pSigMetaDa for (i=0; ipMetaData, &thisSig, ppMethodClassTypeArgs, ppMethodMethodTypeArgs); + pParamType = Type_GetTypeFromSig(pSigMetaData, &sig, ppSigClassTypeArgs, NULL); // ppSigMethodTypeArgs); + pThisParamType = Type_GetTypeFromSig(pMethod->pMetaData, &thisSig, ppMethodClassTypeArgs, NULL); // ppMethodMethodTypeArgs); if (pParamType != pThisParamType) { return 0; } @@ -75,18 +79,20 @@ U32 MetaData_CompareNameAndSig(STRING name, BLOB_ sigBlob, tMetaData *pSigMetaDa return 0; } -static tMD_MethodDef* FindMethodInType(tMD_TypeDef *pTypeDef, STRING name, tMetaData *pSigMetaData, BLOB_ sigBlob, tMD_TypeDef **ppClassTypeArgs, tMD_TypeDef **ppMethodTypeArgs) { - U32 i; - tMD_TypeDef *pLookInType = pTypeDef; +tMD_MethodDef* FindMethodInType(tMD_TypeDef *pTypeDef, STRING name, tMetaData *pSigMetaData, BLOB_ sigBlob, tMD_TypeDef **ppClassTypeArgs, tMD_TypeDef **ppMethodTypeArgs) { - do { - for (i=0; inumMethods; i++) { - if (MetaData_CompareNameAndSig(name, sigBlob, pSigMetaData, ppClassTypeArgs, ppMethodTypeArgs, pLookInType->ppMethods[i], pLookInType->ppClassTypeArgs, ppMethodTypeArgs)) { - return pLookInType->ppMethods[i]; + //dprintfn("Find method %s in type %s.%s", name, pTypeDef->nameSpace, pTypeDef->name); + + tMD_TypeDef *pLookInType = pTypeDef; + while (pLookInType != NULL) { + for (U32 i=0; inumMethods; i++) { + tMD_MethodDef *pMethodDef = pLookInType->ppMethods[i]; + if (MetaData_CompareNameAndSig(name, sigBlob, pSigMetaData, ppClassTypeArgs, ppMethodTypeArgs, pMethodDef, pMethodDef->pParentType->ppClassTypeArgs, pMethodDef->ppMethodTypeArgs)) { + return pMethodDef; } } pLookInType = pLookInType->pParent; - } while (pLookInType != NULL); + } { // Error reporting!! @@ -99,10 +105,10 @@ static tMD_MethodDef* FindMethodInType(tMD_TypeDef *pTypeDef, STRING name, tMeta *pMsg = 0; sig = MetaData_GetBlob(sigBlob, &i); entry = MetaData_DecodeSigEntry(&sig); - if ((entry & SIG_METHODDEF_HASTHIS) == 0) { + if ((entry & SIG_CALLCONV_HASTHIS) == 0) { sprintf(strchr(pMsg, 0), "static "); } - if (entry & SIG_METHODDEF_GENERIC) { + if (entry & SIG_CALLCONV_GENERIC) { // read number of generic type args - don't care what it is MetaData_DecodeSigEntry(&sig); } @@ -118,7 +124,7 @@ static tMD_MethodDef* FindMethodInType(tMD_TypeDef *pTypeDef, STRING name, tMeta sprintf(strchr(pMsg, 0), ","); } if (pParamTypeDef != NULL) { - sprintf(strchr(pMsg, 0), pParamTypeDef->name); + sprintf(strchr(pMsg, 0), "%s", pParamTypeDef->name); } else { sprintf(strchr(pMsg, 0), "???"); } @@ -128,12 +134,45 @@ static tMD_MethodDef* FindMethodInType(tMD_TypeDef *pTypeDef, STRING name, tMeta FAKE_RETURN; } +// Find the method that has been overridden by pMethodDef. +// This is to get the correct vTable offset for the method. +// This must search the MethodImpl table to see if the default inheritence rules are being overridden. +// Return NULL if this method does not override anything. +tMD_MethodDef* FindVirtualOverriddenMethod(tMD_TypeDef *pTypeDef, tMD_MethodDef *pMethodDef) { + do { + // Search MethodImpl table + U32 top = pTypeDef->pMetaData->tables.numRows[MD_TABLE_METHODIMPL]; + for (U32 i = top; i > 0; i--) { + tMD_MethodImpl *pMethodImpl = (tMD_MethodImpl*)MetaData_GetTableRow(pTypeDef->pMetaData, MAKE_TABLE_INDEX(MD_TABLE_METHODIMPL, i)); + if (pMethodImpl->class_ == pTypeDef->tableIndex) { + tMD_MethodDef *pMethodDeclDef = MetaData_GetMethodDefFromDefRefOrSpec(pTypeDef->pMetaData, pMethodImpl->methodDeclaration, pTypeDef->ppClassTypeArgs, pMethodDef->ppMethodTypeArgs); + if (pMethodDeclDef->tableIndex == pMethodDef->tableIndex) { + IDX_TABLE methodToken = pMethodImpl->methodBody; + tMD_MethodDef *pMethod = (tMD_MethodDef*)MetaData_GetTableRow(pTypeDef->pMetaData, methodToken); + return pMethod; + } + } + } + + // Use normal inheritence rules + // It must be a virtual method that's being overridden. + for (U32 i = pTypeDef->numVirtualMethods - 1; i != 0xffffffff; i--) { + tMD_MethodDef *pVirtualMethodDef = pTypeDef->pVTable[i]; + if (MetaData_CompareNameAndSig(pMethodDef->name, pMethodDef->signature, pMethodDef->pMetaData, pMethodDef->pParentType->ppClassTypeArgs, pMethodDef->ppMethodTypeArgs, pVirtualMethodDef, pTypeDef->ppClassTypeArgs, pVirtualMethodDef->ppMethodTypeArgs)) { + return pTypeDef->pVTable[i]; + } + } + pTypeDef = pTypeDef->pParent; + } while (pTypeDef != NULL); + + return NULL; +} + static tMD_FieldDef* FindFieldInType(tMD_TypeDef *pTypeDef, STRING name) { - U32 i; MetaData_Fill_TypeDef(pTypeDef, NULL, NULL); - for (i=0; inumFields; i++) { + for (U32 i=0; inumFields; i++) { if (strcmp(pTypeDef->ppFields[i]->name, name) == 0) { return pTypeDef->ppFields[i]; } @@ -168,9 +207,9 @@ tMetaData* MetaData_GetResolutionScopeMetaData(tMetaData *pMetaData, IDX_TABLE r } tMD_TypeDef* MetaData_GetTypeDefFromName(tMetaData *pMetaData, STRING nameSpace, STRING name, tMD_TypeDef *pInNestedClass, U8 assertExists) { - U32 i; - for (i=1; i<=pMetaData->tables.numRows[MD_TABLE_TYPEDEF]; i++) { + U32 rows = pMetaData->tables.numRows[MD_TABLE_TYPEDEF]; + for (U32 i=1; i<=rows; i++) { tMD_TypeDef *pTypeDef; pTypeDef = (tMD_TypeDef*)MetaData_GetTableRow(pMetaData, MAKE_TABLE_INDEX(MD_TABLE_TYPEDEF, i)); @@ -236,7 +275,7 @@ tMD_TypeDef* MetaData_GetTypeDefFromDefRefOrSpec(tMetaData *pMetaData, IDX_TABLE sig = MetaData_GetBlob(pTypeSpec->signature, NULL); pTypeDef = Type_GetTypeFromSig(pTypeSpec->pMetaData, &sig, ppClassTypeArgs, ppMethodTypeArgs); // Note: Cannot cache the TypeDef for this TypeSpec because it - // can change depending on class arguemnts given. + // can change depending on class arguments given. return pTypeDef; } @@ -248,11 +287,8 @@ tMD_TypeDef* MetaData_GetTypeDefFromDefRefOrSpec(tMetaData *pMetaData, IDX_TABLE } tMD_TypeDef* MetaData_GetTypeDefFromMethodDef(tMD_MethodDef *pMethodDef) { - tMetaData *pMetaData; - U32 i; - - pMetaData = pMethodDef->pMetaData; - for (i=pMetaData->tables.numRows[MD_TABLE_TYPEDEF]; i>0; i--) { + tMetaData *pMetaData = pMethodDef->pMetaData; + for (U32 i=pMetaData->tables.numRows[MD_TABLE_TYPEDEF]; i>0; i--) { tMD_TypeDef *pTypeDef; pTypeDef = (tMD_TypeDef*)MetaData_GetTableRow(pMetaData, MAKE_TABLE_INDEX(MD_TABLE_TYPEDEF, i)); @@ -266,11 +302,8 @@ tMD_TypeDef* MetaData_GetTypeDefFromMethodDef(tMD_MethodDef *pMethodDef) { } tMD_TypeDef* MetaData_GetTypeDefFromFieldDef(tMD_FieldDef *pFieldDef) { - tMetaData *pMetaData; - U32 i; - - pMetaData = pFieldDef->pMetaData; - for (i=pMetaData->tables.numRows[MD_TABLE_TYPEDEF]; i>0; i--) { + tMetaData *pMetaData = pFieldDef->pMetaData; + for (U32 i=pMetaData->tables.numRows[MD_TABLE_TYPEDEF]; i>0; i--) { tMD_TypeDef *pTypeDef; pTypeDef = (tMD_TypeDef*)MetaData_GetTableRow(pMetaData, MAKE_TABLE_INDEX(MD_TABLE_TYPEDEF, i)); @@ -339,10 +372,11 @@ tMD_MethodDef* MetaData_GetMethodDefFromDefRefOrSpec(tMetaData *pMetaData, IDX_T tMD_FieldDef* MetaData_GetFieldDefFromDefOrRef(tMetaData *pMetaData, IDX_TABLE token, tMD_TypeDef **ppClassTypeArgs, tMD_TypeDef **ppMethodTypeArgs) { void *pTableEntry; - pTableEntry = MetaData_GetTableRow(pMetaData, token); - if (((tMDC_ToFieldDef*)pTableEntry)->pFieldDef != NULL) { - return ((tMDC_ToFieldDef*)pTableEntry)->pFieldDef; + + tMD_FieldDef *pFieldDef = ((tMDC_ToFieldDef*)pTableEntry)->pFieldDef; + if (pFieldDef != NULL) { + return pFieldDef; } switch (TABLE_ID(token)) { @@ -452,9 +486,8 @@ PTR MetaData_GetTypeMethodField(tMetaData *pMetaData, IDX_TABLE token, U32 *pObj } tMD_ImplMap* MetaData_GetImplMap(tMetaData *pMetaData, IDX_TABLE memberForwardedToken) { - U32 i; - for (i=pMetaData->tables.numRows[MD_TABLE_IMPLMAP]; i >= 1; i--) { + for (U32 i=pMetaData->tables.numRows[MD_TABLE_IMPLMAP]; i >= 1; i--) { tMD_ImplMap *pImplMap = (tMD_ImplMap*)MetaData_GetTableRow(pMetaData, MAKE_TABLE_INDEX(MD_TABLE_IMPLMAP, i)); if (pImplMap->memberForwarded == memberForwardedToken) { return pImplMap; diff --git a/src/DNA/native/src/MethodState.c b/src/DNA/native/src/MethodState.c index 0ea8beeb..6c318dfd 100644 --- a/src/DNA/native/src/MethodState.c +++ b/src/DNA/native/src/MethodState.c @@ -117,35 +117,49 @@ static void AddCombinedJIT(tMD_MethodDef *pMethod) { #endif -tMethodState* MethodState_Direct(tThread *pThread, tMD_MethodDef *pMethod, tMethodState *pCaller, U32 isInternalNewObjCall) { +tMethodState* MethodState_Direct(tThread *pThread, tMD_MethodDef *pMethod, tMethodState *pCaller, U32 isInternalNewObjCall, U32 isTailCall) { tMethodState *pThis; - if (!pMethod->isFilled) { - tMD_TypeDef *pTypeDef; - - pTypeDef = MetaData_GetTypeDefFromMethodDef(pMethod); + tMD_TypeDef *pTypeDef = MetaData_GetTypeDefFromMethodDef(pMethod); MetaData_Fill_TypeDef(pTypeDef, NULL, NULL); } - - pThis = (tMethodState*)Thread_StackAlloc(pThread, sizeof(tMethodState)); - pThis->finalizerThis = NULL; - pThis->pCaller = pCaller; - pThis->pMetaData = pMethod->pMetaData; - pThis->pMethod = pMethod; if (pMethod->pJITted == NULL) { // If method has not already been JITted JIT_Prepare(pMethod, 0); } + U32 stackSize = pMethod->pJITted->maxStack + pMethod->parameterStackSize + pMethod->pJITted->localsStackSize; + + // check if tail call optimization is possible + if (isTailCall) { + U32 callerStackSize = pCaller->pMethod->pJITted->maxStack + pCaller->pMethod->parameterStackSize + pCaller->pMethod->pJITted->localsStackSize; + isTailCall = isTailCall && (stackSize <= callerStackSize) + && (pMethod->pReturnType == pCaller->pMethod->pReturnType) + && (pMethod->numberOfParameters == pCaller->pMethod->numberOfParameters); + //TODO: more tail call optimization checks if needed + //TODO: relax tail call optimization checks if possible + } + + if (isTailCall) { + pThis = pCaller; // reuse the stack + // keep the original pCaller + // keep the original pEvalStack + } else { + pThis = (tMethodState*)Thread_StackAlloc(pThread, sizeof(tMethodState)); + pThis->pCaller = pCaller; + pThis->pEvalStack = Thread_StackAlloc(pThread, stackSize); + memset(pThis->pEvalStack, 0, stackSize); + } + pThis->finalizerThis = NULL; + pThis->pMetaData = pMethod->pMetaData; + pThis->pMethod = pMethod; pThis->pJIT = pMethod->pJITted; pThis->ipOffset = 0; - pThis->pEvalStack = (PTR)Thread_StackAlloc(pThread, pThis->pMethod->pJITted->maxStack); pThis->stackOfs = 0; pThis->isInternalNewObjCall = isInternalNewObjCall; pThis->pNextDelegate = NULL; pThis->pDelegateParams = NULL; - pThis->pParamsLocals = (PTR)Thread_StackAlloc(pThread, pMethod->parameterStackSize + pMethod->pJITted->localsStackSize); - memset(pThis->pParamsLocals, 0, pMethod->parameterStackSize + pMethod->pJITted->localsStackSize); + pThis->pParamsLocals = pThis->pEvalStack + pMethod->pJITted->maxStack; #ifdef GEN_COMBINED_OPCODES AddCall(pMethod); @@ -189,7 +203,7 @@ tMethodState* MethodState_Direct(tThread *pThread, tMD_MethodDef *pMethod, tMeth #ifdef DIAG_METHOD_CALLS // Keep track of the number of times this method is called pMethod->callCount++; - pThis->startTime = microTime(); + pMethod->startTime = microTime(); #endif return pThis; @@ -199,7 +213,7 @@ tMethodState* MethodState(tThread *pThread, tMetaData *pMetaData, IDX_TABLE meth tMD_MethodDef *pMethod; pMethod = MetaData_GetMethodDefFromDefRefOrSpec(pMetaData, methodToken, NULL, NULL); - return MethodState_Direct(pThread, pMethod, pCaller, 0); + return MethodState_Direct(pThread, pMethod, pCaller, 0, 0); } void MethodState_Delete(tThread *pThread, tMethodState **ppMethodState) { @@ -220,7 +234,9 @@ void MethodState_Delete(tThread *pThread, tMethodState **ppMethodState) { #endif #ifdef DIAG_METHOD_CALLS - pThis->pMethod->totalTime += microTime() - pThis->startTime; + U64 elapsed = microTime() - pThis->pMethod->startTime; + pThis->pMethod->totalTime += elapsed; + if (pThis->pMethod->maxTime < elapsed) { pThis->pMethod->maxTime = elapsed; } #endif // If this MethodState is a Finalizer, then let the heap know this Finalizer has been run @@ -232,9 +248,9 @@ void MethodState_Delete(tThread *pThread, tMethodState **ppMethodState) { free(pThis->pDelegateParams); } - // Note that the way the stack free funtion works means that only the 1st allocated chunk + // Note that the way the stack free function works means that only the first allocated chunk // needs to be free'd, as this function just sets the current allocation offset to the address given. - Thread_StackFree(pThread, pThis); + Thread_StackFree(pThread, (PTR)pThis); *ppMethodState = NULL; } \ No newline at end of file diff --git a/src/DNA/native/src/MethodState.h b/src/DNA/native/src/MethodState.h index 96d8e4e1..78d8a84b 100644 --- a/src/DNA/native/src/MethodState.h +++ b/src/DNA/native/src/MethodState.h @@ -54,11 +54,6 @@ struct tMethodState_ { // When a leave instruction has to run a 'finally' bit of code, store the leave jump address here U32 *pOpEndFinally; -#ifdef DIAG_METHOD_CALLS - // For tracking execution time. - U64 startTime; -#endif - // Link to caller methodstate tMethodState *pCaller; @@ -69,7 +64,7 @@ struct tMethodState_ { }; //void MethodState_Init(); -tMethodState* MethodState_Direct(tThread *pThread, tMD_MethodDef *pMethod, tMethodState *pCaller, U32 isInternalNewObjCall); +tMethodState* MethodState_Direct(tThread *pThread, tMD_MethodDef *pMethod, tMethodState *pCaller, U32 isInternalNewObjCall, U32 isTailCall); tMethodState* MethodState(tThread *pThread, tMetaData *pMetaData, IDX_TABLE methodToken, tMethodState *pCaller); void MethodState_Delete(tThread *pThread, tMethodState **ppMethodState); diff --git a/src/DNA/native/src/PInvoke.c b/src/DNA/native/src/PInvoke.c index 011672ad..64447988 100644 --- a/src/DNA/native/src/PInvoke.c +++ b/src/DNA/native/src/PInvoke.c @@ -61,7 +61,7 @@ static tLoadedLib* GetLib(STRING name) { } // Not loaded, so load it sprintf(strchr(libName, 0), ".%s", LIB_SUFFIX); -#if _WIN32 +#ifdef _WIN32 pNativeLib = LoadLibraryA(libName); #else pNativeLib = dlopen(libName, RTLD_LAZY); //DL_LAZY); @@ -80,7 +80,7 @@ static tLoadedLib* GetLib(STRING name) { #endif return NULL; } - pLib = TMALLOCFOREVER(tLoadedLib); + pLib = TMALLOCFOREVER(1, tLoadedLib); pLib->pNext = pLoadedLibs; pLoadedLibs = pLib; pLib->name = name; @@ -89,26 +89,27 @@ static tLoadedLib* GetLib(STRING name) { } fnPInvoke PInvoke_GetFunction(tMetaData *pMetaData, tMD_ImplMap *pImplMap) { +#ifdef JS_INTEROP + return (fnPInvoke)invokeJsFunc; +#else tLoadedLib *pLib; STRING libName; void *pProc; libName = MetaData_GetModuleRefName(pMetaData, pImplMap->importScope); -#ifndef _WIN32 - return (fnPInvoke)invokeJsFunc; -#else - pLib = GetLib(libName); if (pLib == NULL) { // Library not found, so we can't find the function return NULL; } - +#ifdef _WIN32 pProc = GetProcAddress(pLib->pLib, pImplMap->importName); +#else + pProc = dlsym(pLib, pImplMap->importName); #endif return pProc; - +#endif } static void* ConvertStringToANSI(HEAP_PTR pHeapEntry) { @@ -174,9 +175,9 @@ U32 PInvoke_Call(tJITCallPInvoke *pCall, PTR pParams, PTR pReturnValue, tThread U32 _tempMemOfs = 0; U32 i; U32 funcParams = DEFAULT; - U64 u64Ret; - float fRet; - double dRet; + U64 u64Ret = 0; + float fRet = 0; + double dRet = 0; // [Steve edit] Before we issue the call into JS code, we need to set the calling .NET thread's state // to 'suspended' so that, if the JS code makes other calls into .NET, the DNA runtime doesn't try to diff --git a/src/DNA/native/src/PInvoke.h b/src/DNA/native/src/PInvoke.h index e02ed2d0..81e2e18e 100644 --- a/src/DNA/native/src/PInvoke.h +++ b/src/DNA/native/src/PInvoke.h @@ -23,7 +23,7 @@ #include "MetaData.h" #include "JIT.h" -#include "String.h" +#include "System.String.h" extern char* invokeJsFunc(STRING libName, STRING funcName, STRING arg0); fnPInvoke PInvoke_GetFunction(tMetaData *pMetaData, tMD_ImplMap *pImplMap); diff --git a/src/DNA/native/src/RVA.c b/src/DNA/native/src/RVA.c index fe218087..cb1bab79 100644 --- a/src/DNA/native/src/RVA.c +++ b/src/DNA/native/src/RVA.c @@ -20,12 +20,13 @@ #include "Compat.h" +#include "Sys.h" #include "RVA.h" tRVA* RVA() { tRVA *pRet; - pRet = TMALLOC(tRVA); + pRet = TMALLOCFOREVER(1, tRVA); return pRet; } @@ -34,11 +35,11 @@ tRVA_Item* RVA_Create(tRVA *pThis, void *pFile, void *pSectionHeader) { unsigned int rawOfs; unsigned int rawSize; - pRet = TMALLOC(tRVA_Item); + pRet = TMALLOCFOREVER(1, tRVA_Item); pRet->baseAddress = *(unsigned int*)&((char*)pSectionHeader)[12]; pRet->size = *(unsigned int*)&((char*)pSectionHeader)[8]; - pRet->pData = malloc(pRet->size); - memset(pRet->pData, 0, pRet->size); + pRet->pData = callocForever(1, pRet->size); + //memset(pRet->pData, 0, pRet->size); pRet->pNext = pThis->pFirstRVA; pThis->pFirstRVA = pRet; diff --git a/src/DNA/native/src/Reflection.c b/src/DNA/native/src/Reflection.c index 0bf8a60c..3c004235 100644 --- a/src/DNA/native/src/Reflection.c +++ b/src/DNA/native/src/Reflection.c @@ -7,6 +7,7 @@ #include "System.Reflection.PropertyInfo.h" #include "System.Reflection.MemberInfo.h" #include "System.Reflection.MethodBase.h" +#include "System.Reflection.MethodInfo.h" #include "System.RuntimeType.h" #include "System.String.h" @@ -16,20 +17,23 @@ tAsyncCall* Reflection_MemberInfo_GetCustomAttributes(PTR pThis_, PTR pParams, P tRuntimeType *pMemberOwnerRuntimeType = (tRuntimeType*)pMemberInfo->ownerType; tMD_TypeDef *pMemberOwnerTypeDef = pMemberOwnerRuntimeType->pTypeDef; - tMD_TypeDef* thisType = Heap_GetType((HEAP_PTR)pThis_); + tMD_TypeDef* pThisType = Heap_GetType((HEAP_PTR)pThis_); tMetaData *pMetaData = pMemberOwnerTypeDef->pMetaData; tTables tables = pMetaData->tables; U32 numCustomAttributeRows = tables.numRows[MD_TABLE_CUSTOMATTRIBUTE]; // Figure out what metadata entry we're looking for custom attributes on IDX_TABLE searchForAttributesOnMemberIndex; - if (strcmp(thisType->name, "TypeInfo") == 0) { + if (strcmp(pThisType->name, "TypeInfo") == 0) { searchForAttributesOnMemberIndex = pMemberOwnerTypeDef->tableIndex; - } else if (strcmp(thisType->name, "PropertyInfo") == 0) { + } else if (strcmp(pThisType->name, "PropertyInfo") == 0) { tPropertyInfo *pPropertyInfo = (tPropertyInfo *)pMemberInfo; searchForAttributesOnMemberIndex = pPropertyInfo->index; + } else if (strcmp(pThisType->name, "MethodInfo") == 0) { + tMethodInfo *pMethodInfo = (tMethodInfo *)pMemberInfo; + searchForAttributesOnMemberIndex = pMethodInfo->methodBase.methodDef->tableIndex; } else { - Crash("Not implemented: Getting custom attributes for a %s\n", thisType->name); + Crash("Not implemented: Getting custom attributes for a %s\n", pThisType->name); return NULL; } @@ -57,7 +61,12 @@ tAsyncCall* Reflection_MemberInfo_GetCustomAttributes(PTR pThis_, PTR pParams, P // The 'type' value references the constructor method tMD_MethodDef* pCtorMethodDef = MetaData_GetMethodDefFromDefRefOrSpec(pMetaData, pCustomAttribute->type, NULL, NULL); tMD_TypeDef* pCtorTypeDef = MetaData_GetTypeDefFromMethodDef(pCtorMethodDef); - + + MetaData_Fill_TypeDef(pCtorTypeDef, NULL, NULL); + //if (pCtorMethodDef->isFilled == 0) { + // MetaData_Fill_MethodDef(pCtorTypeDef, pCtorMethodDef, NULL, NULL); + //} + // Create a InternalCustomAttributeInfo PTR arrayEntryPtr = SystemArray_LoadElementAddress(ret, insertionIndex++); tInternalCustomAttributeInfo *pInternalCustomAttributeInfo = (tInternalCustomAttributeInfo*)arrayEntryPtr; @@ -75,8 +84,9 @@ tAsyncCall* Reflection_MemberInfo_GetCustomAttributes(PTR pThis_, PTR pParams, P pInternalCustomAttributeInfo->pConstructorMethodBase = customAttributeConstructorMethodBase; // Construct an array of constructor args + U32 numCtorArgs = pCtorMethodDef->numberOfParameters; tMD_TypeDef *pObjectArrayType = Type_GetArrayTypeDef(types[TYPE_SYSTEM_OBJECT], NULL, NULL); - HEAP_PTR pConstructorArgsArray = SystemArray_NewVector(pObjectArrayType, pCtorMethodDef->numberOfParameters - 1); + HEAP_PTR pConstructorArgsArray = SystemArray_NewVector(pObjectArrayType, numCtorArgs - 1); pInternalCustomAttributeInfo->pConstructorParams = pConstructorArgsArray; // The info is in the 'value' blob from metadata @@ -84,7 +94,6 @@ tAsyncCall* Reflection_MemberInfo_GetCustomAttributes(PTR pThis_, PTR pParams, P PTR blob = MetaData_GetBlob(pCustomAttribute->value, &blobLength); MetaData_DecodeSigEntry(&blob); - U32 numCtorArgs = pCtorMethodDef->numberOfParameters; for (U32 argIndex = 0; argIndex < numCtorArgs; argIndex++) { tParameter param = pCtorMethodDef->pParams[argIndex]; @@ -92,17 +101,12 @@ tAsyncCall* Reflection_MemberInfo_GetCustomAttributes(PTR pThis_, PTR pParams, P // Skip the 'this' param MetaData_DecodeSigEntry(&blob); } else { - if (param.pTypeDef == types[TYPE_SYSTEM_INT32]) { - unsigned int intValue = *((int*)blob); - blob += sizeof(int); - HEAP_PTR boxedInt = Heap_Box(types[TYPE_SYSTEM_INT32], (PTR)&intValue); - SystemArray_StoreElement(pConstructorArgsArray, argIndex - 1, (PTR)&boxedInt); - } else if (param.pTypeDef == types[TYPE_SYSTEM_BOOLEAN]) { - U32 boolVal = *((char*)blob); - blob += sizeof(char); - HEAP_PTR boxedBool = Heap_Box(types[TYPE_SYSTEM_BOOLEAN], (PTR)&boolVal); - SystemArray_StoreElement(pConstructorArgsArray, argIndex - 1, (PTR)&boxedBool); - } else if (param.pTypeDef == types[TYPE_SYSTEM_STRING]) { + if (param.pTypeDef->isValueType) { + HEAP_PTR boxed = Heap_Box(param.pTypeDef, blob); + blob += param.pTypeDef->instanceMemSize; + SystemArray_StoreElement(pConstructorArgsArray, argIndex - 1, (PTR)&boxed); + } + else if (param.pTypeDef == types[TYPE_SYSTEM_STRING]) { HEAP_PTR dotNetString; unsigned int numUtf8Bytes = MetaData_DecodeSigEntryExt(&blob, 0); if (numUtf8Bytes == 0xffffffff) { @@ -120,20 +124,93 @@ tAsyncCall* Reflection_MemberInfo_GetCustomAttributes(PTR pThis_, PTR pParams, P free(buf); } SystemArray_StoreElement(pConstructorArgsArray, argIndex - 1, (PTR)&dotNetString); - } else { - Crash("Unsupported: attribute parameter of type %s\n", param.pTypeDef->name); + } + else if (param.pTypeDef == types[TYPE_SYSTEM_TYPE]) { + unsigned int numUtf8Bytes = MetaData_DecodeSigEntryExt(&blob, 0); + // TODO: Handle non-ASCII UTF8 by converting the raw UTF8 data to UTF16 + char* buf = malloc(numUtf8Bytes + 1); + for (U32 byteIndex = 0; byteIndex < numUtf8Bytes; byteIndex++) { + buf[byteIndex] = *((char*)blob); + blob += sizeof(char); + } + buf[numUtf8Bytes] = 0; + + // separate the namespace + char *pLastDot = strrchr(buf, '.'); + STRING nameSpace = pLastDot ? buf : ""; + STRING className = pLastDot ? pLastDot + 1 : buf; + if (pLastDot) { *pLastDot = 0; } + + // remove debug type proxy + char* pDebugTypeProxy = strstr(className, "@DebugTypeProxy"); + if (pDebugTypeProxy) { *pDebugTypeProxy = 0; } + + // handle nested types + tMD_TypeDef *pInNested = NULL; + char *pNextPlus = strchr(className, '+'); + while (pNextPlus) { + *pNextPlus = 0; + pInNested = MetaData_GetTypeDefFromName(pMetaData, nameSpace, className, pInNested, /* assertExists */ 1); + className = pNextPlus + 1; + pNextPlus = strchr(className, '+'); + } + tMD_TypeDef *pTypeDef = MetaData_GetTypeDefFromName(pMetaData, nameSpace, className, pInNested, /* assertExists */ 1); + HEAP_PTR typeObject = Type_GetTypeObject(pTypeDef); + SystemArray_StoreElement(pConstructorArgsArray, argIndex - 1, (PTR)&typeObject); + free(buf); + } + // else if (param.pTypeDef == types[TYPE_SYSTEM_OBJECT]) { //TODO: implement + else { + Crash("GetCustomAttributes: Unsupported attribute parameter of type %s\n", param.pTypeDef->name); return NULL; } } } - unsigned int numNamedParams = MetaData_DecodeSigEntry(&blob); + MetaData_DecodeSigEntry(&blob); // something + U32 numNamedParams = MetaData_DecodeSigEntry(&blob); if (numNamedParams > 0) { - Crash("Unsupported: attributes with named params on attribute %s\n", pCtorTypeDef->name); + Crash("GetCustomAttributes: Unsupported attributes with named params on attribute %s\n", pCtorTypeDef->name); return NULL; } } } return NULL; -} \ No newline at end of file +} + +tAsyncCall* Reflection_MethodInfo_MakeGenericMethod(PTR pThis_, PTR pParams, PTR pReturnValue) +{ + // get type arguments + HEAP_PTR pTypeArgs = ((HEAP_PTR*)pParams)[0]; + U32 numTypeArgs = SystemArray_GetLength(pTypeArgs); + HEAP_PTR* pArray = (HEAP_PTR*)SystemArray_GetElements(pTypeArgs); + + // Get metadata for the 'this' type + tMethodInfo *pMethodInfoThis = (tMethodInfo*)pThis_; + tMD_MethodDef *pCoreMethod = pMethodInfoThis->methodBase.methodDef; + + // get arg types + tMD_TypeDef **ppTypeArgs = TMALLOC(numTypeArgs, tMD_TypeDef*); + for (U32 i = 0; i < numTypeArgs; i++) { + ppTypeArgs[i] = RuntimeType_DeRef(pArray[i]); + } + + // specialize generic method + tMD_MethodDef *pMethodDef = Generics_GetMethodDefFromCoreMethod(pCoreMethod, pCoreMethod->pParentType, numTypeArgs, ppTypeArgs); + free(ppTypeArgs); + + // Instantiate a MethodInfo + tMethodInfo *pMethodInfo = (tMethodInfo*)Heap_AllocType(types[TYPE_SYSTEM_REFLECTION_METHODINFO]); + + // Assign ownerType, name and flags + pMethodInfo->methodBase.ownerType = pThis_; + pMethodInfo->methodBase.name = SystemString_FromCharPtrASCII(pMethodDef->name); + pMethodInfo->methodBase.flags = pMethodDef->flags; + + // Assign method def + pMethodInfo->methodBase.methodDef = pMethodDef; + + *(HEAP_PTR*)pReturnValue = (HEAP_PTR)pMethodInfo; + return NULL; +} diff --git a/src/DNA/native/src/Reflection.h b/src/DNA/native/src/Reflection.h index 607bd8d1..21cadf47 100644 --- a/src/DNA/native/src/Reflection.h +++ b/src/DNA/native/src/Reflection.h @@ -1,8 +1,9 @@ #if !defined(__REFLECTION_H) -#define __REFLECTION +#define __REFLECTION_H #include "Types.h" tAsyncCall* Reflection_MemberInfo_GetCustomAttributes(PTR pThis_, PTR pParams, PTR pReturnValue); +tAsyncCall* Reflection_MethodInfo_MakeGenericMethod(PTR pThis_, PTR pParams, PTR pReturnValue); #endif \ No newline at end of file diff --git a/src/DNA/native/src/Sys.c b/src/DNA/native/src/Sys.c index 8ac46604..329b8839 100644 --- a/src/DNA/native/src/Sys.c +++ b/src/DNA/native/src/Sys.c @@ -43,6 +43,10 @@ void Crash(char *pMsg, ...) { printf("\n\n"); +#if defined(DIAG_METHOD_CALLS) || defined(DIAG_CALL_STACK) + abort(); +#endif + #ifdef _WIN32 { // Cause a delibrate exception, to get into debugger @@ -65,7 +69,7 @@ void log_f(U32 level, char *pMsg, ...) { } } -static char methodName[2048]; +static char methodName[8192]; // must be big enough to handle the biggest types char* Sys_GetMethodDesc(tMD_MethodDef *pMethod) { U32 i; @@ -74,18 +78,43 @@ char* Sys_GetMethodDesc(tMD_MethodDef *pMethod) { if (i > (U32)(METHOD_ISSTATIC(pMethod)?0:1)) { sprintf(strchr(methodName, 0), ","); } - sprintf(strchr(methodName, 0), pMethod->pParams[i].pTypeDef->name); + sprintf(strchr(methodName, 0), "%s", pMethod->pParams[i].pTypeDef->name); } sprintf(strchr(methodName, 0), ")"); return methodName; } -static U32 mallocForeverSize = 0; +static U32 allocForeverTotal = 0; +#ifdef DIAG_MEMORY_LEAKS +static U32 allocForeverIndex = 0; +#define allocForeverMax 50000 +static void* allocForeverPointers[allocForeverMax]; +#endif + // malloc() some memory that will never need to be resized or freed. +static void* allocForever(void* ptr, U32 size) { + allocForeverTotal += size; + log_f(3, "--- allocForever: Total Size %d\n", allocForeverTotal); +#ifdef DIAG_MEMORY_LEAKS + if (allocForeverIndex >= allocForeverMax) Crash("Too many allocForever()"); + allocForeverPointers[allocForeverIndex++] = ptr; +#endif + return ptr; +} + void* mallocForever(U32 size) { - mallocForeverSize += size; -log_f(3, "--- mallocForever: TotalSize %d\n", mallocForeverSize); - return malloc(size); + return allocForever(calloc(size, 1), size); +} +void* callocForever(U32 count, U32 size) { + return allocForever(calloc(count, size), count * size); +} + +void freeForever() { +#ifdef DIAG_MEMORY_LEAKS + for (U32 i=0; i < allocForeverIndex; i++) { + free(allocForeverPointers[i]); + } +#endif } /* @@ -98,27 +127,6 @@ void* mallocTrace(int s, char *pFile, int line) { #endif */ -U64 msTime() { -#ifdef _WIN32 - static LARGE_INTEGER freq = {0,0}; - LARGE_INTEGER time; - if (freq.QuadPart == 0) { - QueryPerformanceFrequency(&freq); - } - QueryPerformanceCounter(&time); - return (time.QuadPart * 1000) / freq.QuadPart; -#else - struct timeval tp; - U64 ms; - gettimeofday(&tp,NULL); - ms = tp.tv_sec; - ms *= 1000; - ms += ((U64)tp.tv_usec)/((U64)1000); - return ms; -#endif -} - -#if defined(DIAG_METHOD_CALLS) || defined(DIAG_OPCODE_TIMES) || defined(DIAG_GC) || defined(DIAG_TOTAL_TIME) U64 microTime() { #ifdef _WIN32 static LARGE_INTEGER freq = {0,0}; @@ -138,7 +146,10 @@ U64 microTime() { return ms; #endif } -#endif + +U64 msTime() { + return microTime() / 1000; +} void SleepMS(U32 ms) { #ifdef _WIN32 @@ -147,4 +158,703 @@ void SleepMS(U32 ms) { sleep(ms / 1000); usleep((ms % 1000) * 1000); #endif -} \ No newline at end of file +} + +#ifdef DEBUG_PRINT + +#define _CIL_OPDEF(str, op, action) case op: return str; + +char* Sys_CIL_OpCodeName(U32 op) { + switch (op) { + +_CIL_OPDEF("nop", 0x00, NEXT) +_CIL_OPDEF("break", 0x01, BREAK) +_CIL_OPDEF("ldarg.0", 0x02, NEXT) +_CIL_OPDEF("ldarg.1", 0x03, NEXT) +_CIL_OPDEF("ldarg.2", 0x04, NEXT) +_CIL_OPDEF("ldarg.3", 0x05, NEXT) +_CIL_OPDEF("ldloc.0", 0x06, NEXT) +_CIL_OPDEF("ldloc.1", 0x07, NEXT) +_CIL_OPDEF("ldloc.2", 0x08, NEXT) +_CIL_OPDEF("ldloc.3", 0x09, NEXT) +_CIL_OPDEF("stloc.0", 0x0A, NEXT) +_CIL_OPDEF("stloc.1", 0x0B, NEXT) +_CIL_OPDEF("stloc.2", 0x0C, NEXT) +_CIL_OPDEF("stloc.3", 0x0D, NEXT) +_CIL_OPDEF("ldarg.s", 0x0E, NEXT) +_CIL_OPDEF("ldarga.s", 0x0F, NEXT) +_CIL_OPDEF("starg.s", 0x10, NEXT) +_CIL_OPDEF("ldloc.s", 0x11, NEXT) +_CIL_OPDEF("ldloca.s", 0x12, NEXT) +_CIL_OPDEF("stloc.s", 0x13, NEXT) +_CIL_OPDEF("ldnull", 0x14, NEXT) +_CIL_OPDEF("ldc.i4.m1", 0x15, NEXT) +_CIL_OPDEF("ldc.i4.0", 0x16, NEXT) +_CIL_OPDEF("ldc.i4.1", 0x17, NEXT) +_CIL_OPDEF("ldc.i4.2", 0x18, NEXT) +_CIL_OPDEF("ldc.i4.3", 0x19, NEXT) +_CIL_OPDEF("ldc.i4.4", 0x1A, NEXT) +_CIL_OPDEF("ldc.i4.5", 0x1B, NEXT) +_CIL_OPDEF("ldc.i4.6", 0x1C, NEXT) +_CIL_OPDEF("ldc.i4.7", 0x1D, NEXT) +_CIL_OPDEF("ldc.i4.8", 0x1E, NEXT) +_CIL_OPDEF("ldc.i4.s", 0x1F, NEXT) +_CIL_OPDEF("ldc.i4", 0x20, NEXT) +_CIL_OPDEF("ldc.i8", 0x21, NEXT) +_CIL_OPDEF("ldc.r4", 0x22, NEXT) +_CIL_OPDEF("ldc.r8", 0x23, NEXT) +_CIL_OPDEF("unused", 0x24, NEXT) +_CIL_OPDEF("dup", 0x25, NEXT) +_CIL_OPDEF("pop", 0x26, NEXT) +_CIL_OPDEF("jmp", 0x27, CALL) +_CIL_OPDEF("call", 0x28, CALL) +_CIL_OPDEF("calli", 0x29, CALL) +_CIL_OPDEF("ret", 0x2A, RETURN) +_CIL_OPDEF("br.s", 0x2B, BRANCH) +_CIL_OPDEF("brfalse.s", 0x2C, COND_BRANCH) +_CIL_OPDEF("brtrue.s", 0x2D, COND_BRANCH) +_CIL_OPDEF("beq.s", 0x2E, COND_BRANCH) +_CIL_OPDEF("bge.s", 0x2F, COND_BRANCH) +_CIL_OPDEF("bgt.s", 0x30, COND_BRANCH) +_CIL_OPDEF("ble.s", 0x31, COND_BRANCH) +_CIL_OPDEF("blt.s", 0x32, COND_BRANCH) +_CIL_OPDEF("bne.un.s", 0x33, COND_BRANCH) +_CIL_OPDEF("bge.un.s", 0x34, COND_BRANCH) +_CIL_OPDEF("bgt.un.s", 0x35, COND_BRANCH) +_CIL_OPDEF("ble.un.s", 0x36, COND_BRANCH) +_CIL_OPDEF("blt.un.s", 0x37, COND_BRANCH) +_CIL_OPDEF("br", 0x38, BRANCH) +_CIL_OPDEF("brfalse", 0x39, COND_BRANCH) +_CIL_OPDEF("brtrue", 0x3A, COND_BRANCH) +_CIL_OPDEF("beq", 0x3B, COND_BRANCH) +_CIL_OPDEF("bge", 0x3C, COND_BRANCH) +_CIL_OPDEF("bgt", 0x3D, COND_BRANCH) +_CIL_OPDEF("ble", 0x3E, COND_BRANCH) +_CIL_OPDEF("blt", 0x3F, COND_BRANCH) +_CIL_OPDEF("bne.un", 0x40, COND_BRANCH) +_CIL_OPDEF("bge.un", 0x41, COND_BRANCH) +_CIL_OPDEF("bgt.un", 0x42, COND_BRANCH) +_CIL_OPDEF("ble.un", 0x43, COND_BRANCH) +_CIL_OPDEF("blt.un", 0x44, COND_BRANCH) +_CIL_OPDEF("switch", 0x45, COND_BRANCH) +_CIL_OPDEF("ldind.i1", 0x46, NEXT) +_CIL_OPDEF("ldind.u1", 0x47, NEXT) +_CIL_OPDEF("ldind.i2", 0x48, NEXT) +_CIL_OPDEF("ldind.u2", 0x49, NEXT) +_CIL_OPDEF("ldind.i4", 0x4A, NEXT) +_CIL_OPDEF("ldind.u4", 0x4B, NEXT) +_CIL_OPDEF("ldind.i8", 0x4C, NEXT) +_CIL_OPDEF("ldind.i", 0x4D, NEXT) +_CIL_OPDEF("ldind.r4", 0x4E, NEXT) +_CIL_OPDEF("ldind.r8", 0x4F, NEXT) +_CIL_OPDEF("ldind.ref", 0x50, NEXT) +_CIL_OPDEF("stind.ref", 0x51, NEXT) +_CIL_OPDEF("stind.i1", 0x52, NEXT) +_CIL_OPDEF("stind.i2", 0x53, NEXT) +_CIL_OPDEF("stind.i4", 0x54, NEXT) +_CIL_OPDEF("stind.i8", 0x55, NEXT) +_CIL_OPDEF("stind.r4", 0x56, NEXT) +_CIL_OPDEF("stind.r8", 0x57, NEXT) +_CIL_OPDEF("add", 0x58, NEXT) +_CIL_OPDEF("sub", 0x59, NEXT) +_CIL_OPDEF("mul", 0x5A, NEXT) +_CIL_OPDEF("div", 0x5B, NEXT) +_CIL_OPDEF("div.un", 0x5C, NEXT) +_CIL_OPDEF("rem", 0x5D, NEXT) +_CIL_OPDEF("rem.un", 0x5E, NEXT) +_CIL_OPDEF("and", 0x5F, NEXT) +_CIL_OPDEF("or", 0x60, NEXT) +_CIL_OPDEF("xor", 0x61, NEXT) +_CIL_OPDEF("shl", 0x62, NEXT) +_CIL_OPDEF("shr", 0x63, NEXT) +_CIL_OPDEF("shr.un", 0x64, NEXT) +_CIL_OPDEF("neg", 0x65, NEXT) +_CIL_OPDEF("not", 0x66, NEXT) +_CIL_OPDEF("conv.i1", 0x67, NEXT) +_CIL_OPDEF("conv.i2", 0x68, NEXT) +_CIL_OPDEF("conv.i4", 0x69, NEXT) +_CIL_OPDEF("conv.i8", 0x6A, NEXT) +_CIL_OPDEF("conv.r4", 0x6B, NEXT) +_CIL_OPDEF("conv.r8", 0x6C, NEXT) +_CIL_OPDEF("conv.u4", 0x6D, NEXT) +_CIL_OPDEF("conv.u8", 0x6E, NEXT) +_CIL_OPDEF("callvirt", 0x6F, CALL) +_CIL_OPDEF("cpobj", 0x70, NEXT) +_CIL_OPDEF("ldobj", 0x71, NEXT) +_CIL_OPDEF("ldstr", 0x72, NEXT) +_CIL_OPDEF("newobj", 0x73, CALL) +_CIL_OPDEF("castclass", 0x74, NEXT) +_CIL_OPDEF("isinst", 0x75, NEXT) +_CIL_OPDEF("conv.r.un", 0x76, NEXT) +_CIL_OPDEF("unused", 0x77, NEXT) +_CIL_OPDEF("unused", 0x78, NEXT) +_CIL_OPDEF("unbox", 0x79, NEXT) +_CIL_OPDEF("throw", 0x7A, THROW) +_CIL_OPDEF("ldfld", 0x7B, NEXT) +_CIL_OPDEF("ldflda", 0x7C, NEXT) +_CIL_OPDEF("stfld", 0x7D, NEXT) +_CIL_OPDEF("ldsfld", 0x7E, NEXT) +_CIL_OPDEF("ldsflda", 0x7F, NEXT) +_CIL_OPDEF("stsfld", 0x80, NEXT) +_CIL_OPDEF("stobj", 0x81, NEXT) +_CIL_OPDEF("conv.ovf.i1.un", 0x82, NEXT) +_CIL_OPDEF("conv.ovf.i2.un", 0x83, NEXT) +_CIL_OPDEF("conv.ovf.i4.un", 0x84, NEXT) +_CIL_OPDEF("conv.ovf.i8.un", 0x85, NEXT) +_CIL_OPDEF("conv.ovf.u1.un", 0x86, NEXT) +_CIL_OPDEF("conv.ovf.u2.un", 0x87, NEXT) +_CIL_OPDEF("conv.ovf.u4.un", 0x88, NEXT) +_CIL_OPDEF("conv.ovf.u8.un", 0x89, NEXT) +_CIL_OPDEF("conv.ovf.i.un", 0x8A, NEXT) +_CIL_OPDEF("conv.ovf.u.un", 0x8B, NEXT) +_CIL_OPDEF("box", 0x8C, NEXT) +_CIL_OPDEF("newarr", 0x8D, NEXT) +_CIL_OPDEF("ldlen", 0x8E, NEXT) +_CIL_OPDEF("ldelema", 0x8F, NEXT) +_CIL_OPDEF("ldelem.i1", 0x90, NEXT) +_CIL_OPDEF("ldelem.u1", 0x91, NEXT) +_CIL_OPDEF("ldelem.i2", 0x92, NEXT) +_CIL_OPDEF("ldelem.u2", 0x93, NEXT) +_CIL_OPDEF("ldelem.i4", 0x94, NEXT) +_CIL_OPDEF("ldelem.u4", 0x95, NEXT) +_CIL_OPDEF("ldelem.i8", 0x96, NEXT) +_CIL_OPDEF("ldelem.i", 0x97, NEXT) +_CIL_OPDEF("ldelem.r4", 0x98, NEXT) +_CIL_OPDEF("ldelem.r8", 0x99, NEXT) +_CIL_OPDEF("ldelem.ref", 0x9A, NEXT) +_CIL_OPDEF("stelem.i", 0x9B, NEXT) +_CIL_OPDEF("stelem.i1", 0x9C, NEXT) +_CIL_OPDEF("stelem.i2", 0x9D, NEXT) +_CIL_OPDEF("stelem.i4", 0x9E, NEXT) +_CIL_OPDEF("stelem.i8", 0x9F, NEXT) +_CIL_OPDEF("stelem.r4", 0xA0, NEXT) +_CIL_OPDEF("stelem.r8", 0xA1, NEXT) +_CIL_OPDEF("stelem.ref", 0xA2, NEXT) +_CIL_OPDEF("unused", 0xA3, NEXT) +_CIL_OPDEF("unused", 0xA4, NEXT) +_CIL_OPDEF("unused", 0xA5, NEXT) +_CIL_OPDEF("unused", 0xA6, NEXT) +_CIL_OPDEF("unused", 0xA7, NEXT) +_CIL_OPDEF("unused", 0xA8, NEXT) +_CIL_OPDEF("unused", 0xA9, NEXT) +_CIL_OPDEF("unused", 0xAA, NEXT) +_CIL_OPDEF("unused", 0xAB, NEXT) +_CIL_OPDEF("unused", 0xAC, NEXT) +_CIL_OPDEF("unused", 0xAD, NEXT) +_CIL_OPDEF("unused", 0xAE, NEXT) +_CIL_OPDEF("unused", 0xAF, NEXT) +_CIL_OPDEF("unused", 0xB0, NEXT) +_CIL_OPDEF("unused", 0xB1, NEXT) +_CIL_OPDEF("unused", 0xB2, NEXT) +_CIL_OPDEF("conv.ovf.i1", 0xB3, NEXT) +_CIL_OPDEF("conv.ovf.u1", 0xB4, NEXT) +_CIL_OPDEF("conv.ovf.i2", 0xB5, NEXT) +_CIL_OPDEF("conv.ovf.u2", 0xB6, NEXT) +_CIL_OPDEF("conv.ovf.i4", 0xB7, NEXT) +_CIL_OPDEF("conv.ovf.u4", 0xB8, NEXT) +_CIL_OPDEF("conv.ovf.i8", 0xB9, NEXT) +_CIL_OPDEF("conv.ovf.u8", 0xBA, NEXT) +_CIL_OPDEF("unused", 0xBB, NEXT) +_CIL_OPDEF("unused", 0xBC, NEXT) +_CIL_OPDEF("unused", 0xBD, NEXT) +_CIL_OPDEF("unused", 0xBE, NEXT) +_CIL_OPDEF("unused", 0xBF, NEXT) +_CIL_OPDEF("unused", 0xC0, NEXT) +_CIL_OPDEF("unused", 0xC1, NEXT) +_CIL_OPDEF("refanyval", 0xC2, NEXT) +_CIL_OPDEF("ckfinite", 0xC3, NEXT) +_CIL_OPDEF("unused", 0xC4, NEXT) +_CIL_OPDEF("unused", 0xC5, NEXT) +_CIL_OPDEF("mkrefany", 0xC6, NEXT) +_CIL_OPDEF("unused", 0xC7, NEXT) +_CIL_OPDEF("unused", 0xC8, NEXT) +_CIL_OPDEF("unused", 0xC9, NEXT) +_CIL_OPDEF("unused", 0xCA, NEXT) +_CIL_OPDEF("unused", 0xCB, NEXT) +_CIL_OPDEF("unused", 0xCC, NEXT) +_CIL_OPDEF("unused", 0xCD, NEXT) +_CIL_OPDEF("unused", 0xCE, NEXT) +_CIL_OPDEF("unused", 0xCF, NEXT) +_CIL_OPDEF("ldtoken", 0xD0, NEXT) +_CIL_OPDEF("conv.u2", 0xD1, NEXT) +_CIL_OPDEF("conv.u1", 0xD2, NEXT) +_CIL_OPDEF("conv.i", 0xD3, NEXT) +_CIL_OPDEF("conv.ovf.i", 0xD4, NEXT) +_CIL_OPDEF("conv.ovf.u", 0xD5, NEXT) +_CIL_OPDEF("add.ovf", 0xD6, NEXT) +_CIL_OPDEF("add.ovf.un", 0xD7, NEXT) +_CIL_OPDEF("mul.ovf", 0xD8, NEXT) +_CIL_OPDEF("mul.ovf.un", 0xD9, NEXT) +_CIL_OPDEF("sub.ovf", 0xDA, NEXT) +_CIL_OPDEF("sub.ovf.un", 0xDB, NEXT) +_CIL_OPDEF("endfinally", 0xDC, RETURN) +_CIL_OPDEF("leave", 0xDD, BRANCH) +_CIL_OPDEF("leave.s", 0xDE, BRANCH) +_CIL_OPDEF("stind.i", 0xDF, NEXT) +_CIL_OPDEF("conv.u", 0xE0, NEXT) +_CIL_OPDEF("unused", 0xE1, NEXT) +_CIL_OPDEF("unused", 0xE2, NEXT) +_CIL_OPDEF("unused", 0xE3, NEXT) +_CIL_OPDEF("unused", 0xE4, NEXT) +_CIL_OPDEF("unused", 0xE5, NEXT) +_CIL_OPDEF("unused", 0xE6, NEXT) +_CIL_OPDEF("unused", 0xE7, NEXT) +_CIL_OPDEF("unused", 0xE8, NEXT) +_CIL_OPDEF("unused", 0xE9, NEXT) +_CIL_OPDEF("unused", 0xEA, NEXT) +_CIL_OPDEF("unused", 0xEB, NEXT) +_CIL_OPDEF("unused", 0xEC, NEXT) +_CIL_OPDEF("unused", 0xED, NEXT) +_CIL_OPDEF("unused", 0xEE, NEXT) +_CIL_OPDEF("unused", 0xEF, NEXT) +_CIL_OPDEF("unused", 0xF0, NEXT) +_CIL_OPDEF("unused", 0xF1, NEXT) +_CIL_OPDEF("unused", 0xF2, NEXT) +_CIL_OPDEF("unused", 0xF3, NEXT) +_CIL_OPDEF("unused", 0xF4, NEXT) +_CIL_OPDEF("unused", 0xF5, NEXT) +_CIL_OPDEF("unused", 0xF6, NEXT) +_CIL_OPDEF("unused", 0xF7, NEXT) +_CIL_OPDEF("prefix7", 0xF8, META) +_CIL_OPDEF("prefix6", 0xF9, META) +_CIL_OPDEF("prefix5", 0xFA, META) +_CIL_OPDEF("prefix4", 0xFB, META) +_CIL_OPDEF("prefix3", 0xFC, META) +_CIL_OPDEF("prefix2", 0xFD, META) +_CIL_OPDEF("prefix1", 0xFE, META) +_CIL_OPDEF("prefixref", 0xFF, META) +_CIL_OPDEF("arglist", 0xFE00, NEXT) +_CIL_OPDEF("ceq", 0xFE01, NEXT) +_CIL_OPDEF("cgt", 0xFE02, NEXT) +_CIL_OPDEF("cgt.un", 0xFE03, NEXT) +_CIL_OPDEF("clt", 0xFE04, NEXT) +_CIL_OPDEF("clt.un", 0xFE05, NEXT) +_CIL_OPDEF("ldftn", 0xFE06, NEXT) +_CIL_OPDEF("ldvirtftn", 0xFE07, NEXT) +_CIL_OPDEF("unused", 0xFE08, NEXT) +_CIL_OPDEF("ldarg", 0xFE09, NEXT) +_CIL_OPDEF("ldarga", 0xFE0A, NEXT) +_CIL_OPDEF("starg", 0xFE0B, NEXT) +_CIL_OPDEF("ldloc", 0xFE0C, NEXT) +_CIL_OPDEF("ldloca", 0xFE0D, NEXT) +_CIL_OPDEF("stloc", 0xFE0E, NEXT) +_CIL_OPDEF("localloc", 0xFE0F, NEXT) +_CIL_OPDEF("unused", 0xFE10, NEXT) +_CIL_OPDEF("endfilter", 0xFE11, RETURN) +_CIL_OPDEF("unaligned.", 0xFE12, META) +_CIL_OPDEF("volatile.", 0xFE13, META) +_CIL_OPDEF("tail.", 0xFE14, META) +_CIL_OPDEF("initobj", 0xFE15, NEXT) +_CIL_OPDEF("unused", 0xFE16, NEXT) +_CIL_OPDEF("cpblk", 0xFE17, NEXT) +_CIL_OPDEF("initblk", 0xFE18, NEXT) +_CIL_OPDEF("unused", 0xFE19, NEXT) +_CIL_OPDEF("rethrow", 0xFE1A, THROW) +_CIL_OPDEF("unused", 0xFE1B, NEXT) +_CIL_OPDEF("sizeof", 0xFE1C, NEXT) +_CIL_OPDEF("refanytype", 0xFE1D, NEXT) +_CIL_OPDEF("unused", 0xFE1E, NEXT) + + default: return "undefined"; + } +} + + +#define _JIT_OPDEF(str, op) case op: return str; + +char* Sys_JIT_OpCodeName(U32 op) { + switch (op) { + +_JIT_OPDEF("NOP", 0x0) +_JIT_OPDEF("RETURN", 0x1) +_JIT_OPDEF("LOAD_I32", 0x2) +_JIT_OPDEF("BRANCH", 0x3) +_JIT_OPDEF("LOAD_STRING", 0x4) +_JIT_OPDEF("CALLVIRT_O", 0x5) +_JIT_OPDEF("CALL_NATIVE", 0x6) +_JIT_OPDEF("CALL_O", 0x7) +_JIT_OPDEF("NEWOBJECT", 0x8) +_JIT_OPDEF("LOAD_PARAMLOCAL_ADDR", 0x9) +_JIT_OPDEF("CALL_PTR", 0xa) +_JIT_OPDEF("BOX_CALLVIRT", 0xb) +_JIT_OPDEF("INIT_VALUETYPE", 0xc) +_JIT_OPDEF("NEW_VECTOR", 0xd) +_JIT_OPDEF("NEWOBJECT_VALUETYPE", 0xe) +_JIT_OPDEF("IS_INSTANCE", 0xf) +_JIT_OPDEF("LOAD_NULL", 0x10) +_JIT_OPDEF("UNBOX2VALUETYPE", 0x11) +_JIT_OPDEF("UNBOX2OBJECT", 0x12) +_JIT_OPDEF("LOAD_FIELD_ADDR", 0x13) +_JIT_OPDEF("DUP_GENERAL", 0x14) +_JIT_OPDEF("POP", 0x15) +_JIT_OPDEF("STORE_OBJECT_VALUETYPE", 0x16) +_JIT_OPDEF("DEREF_CALLVIRT", 0x17) +_JIT_OPDEF("STORE_ELEMENT", 0x18) +_JIT_OPDEF("LEAVE", 0x19) +_JIT_OPDEF("END_FINALLY", 0x1a) +_JIT_OPDEF("THROW", 0x1b) +_JIT_OPDEF("RETHROW", 0x1c) +_JIT_OPDEF("LOADOBJECT", 0x1d) +_JIT_OPDEF("LOAD_VECTOR_LEN", 0x1e) +_JIT_OPDEF("SWITCH", 0x1f) +_JIT_OPDEF("LOAD_ELEMENT_ADDR", 0x20) +_JIT_OPDEF("CALL_INTERFACE", 0x21) +_JIT_OPDEF("CAST_CLASS", 0x22) +_JIT_OPDEF("LOAD_ELEMENT", 0x23) +_JIT_OPDEF("LOADFIELD_VALUETYPE", 0x24) +_JIT_OPDEF("LOADFIELD", 0x25) +_JIT_OPDEF("LOADFUNCTION", 0x26) +_JIT_OPDEF("INVOKE_DELEGATE", 0x27) +_JIT_OPDEF("CALL_PINVOKE", 0x28) +_JIT_OPDEF("LOAD_I64", 0x29) +_JIT_OPDEF("INIT_OBJECT", 0x2a) +_JIT_OPDEF("DUP_4", 0x2b) +_JIT_OPDEF("DUP_8", 0x2c) +_JIT_OPDEF("LOADSTATICFIELDADDRESS_CHECKTYPEINIT", 0x2d) +_JIT_OPDEF("POP_4", 0x2e) +_JIT_OPDEF("LOAD_F32", 0x2f) + +_JIT_OPDEF("LOADPARAMLOCAL_INT64", 0x30) +_JIT_OPDEF("LOADPARAMLOCAL_INT32", 0x31) +_JIT_OPDEF("LOADPARAMLOCAL_INTNATIVE", 0x32) +_JIT_OPDEF("LOADPARAMLOCAL_F64", 0x33) +_JIT_OPDEF("LOADPARAMLOCAL_PTR", 0x34) +_JIT_OPDEF("LOADPARAMLOCAL_O", 0x35) +_JIT_OPDEF("LOADPARAMLOCAL_F32", 0x36) +_JIT_OPDEF("LOADPARAMLOCAL_VALUETYPE", 0x37) + +_JIT_OPDEF("STOREPARAMLOCAL_INT64", 0x38) +_JIT_OPDEF("STOREPARAMLOCAL_INT32", 0x39) +_JIT_OPDEF("STOREPARAMLOCAL_INTNATIVE", 0x3a) +_JIT_OPDEF("STOREPARAMLOCAL_F64", 0x3b) +_JIT_OPDEF("STOREPARAMLOCAL_PTR", 0x3c) +_JIT_OPDEF("STOREPARAMLOCAL_O", 0x3d) +_JIT_OPDEF("STOREPARAMLOCAL_F32", 0x3e) +_JIT_OPDEF("STOREPARAMLOCAL_VALUETYPE", 0x3f) + +_JIT_OPDEF("STOREFIELD_INT64", 0x48) +_JIT_OPDEF("STOREFIELD_INT32", 0x49) +_JIT_OPDEF("STOREFIELD_INTNATIVE", 0x4a) +_JIT_OPDEF("STOREFIELD_F64", 0x4b) +_JIT_OPDEF("STOREFIELD_PTR", 0x4c) +_JIT_OPDEF("STOREFIELD_O", 0x4d) +_JIT_OPDEF("STOREFIELD_F32", 0x4e) +_JIT_OPDEF("STOREFIELD_VALUETYPE", 0x4f) + +_JIT_OPDEF("LOADSTATICFIELD_CHECKTYPEINIT_INT64", 0x50) +_JIT_OPDEF("LOADSTATICFIELD_CHECKTYPEINIT_INT32", 0x51) +_JIT_OPDEF("LOADSTATICFIELD_CHECKTYPEINIT_INTNATIVE", 0x52) +_JIT_OPDEF("LOADSTATICFIELD_CHECKTYPEINIT_F64", 0x53) +_JIT_OPDEF("LOADSTATICFIELD_CHECKTYPEINIT_PTR", 0x54) +_JIT_OPDEF("LOADSTATICFIELD_CHECKTYPEINIT_O", 0x55) +_JIT_OPDEF("LOADSTATICFIELD_CHECKTYPEINIT_F32", 0x56) +_JIT_OPDEF("LOADSTATICFIELD_CHECKTYPEINIT_VALUETYPE", 0x57) + +_JIT_OPDEF("LOADSTATICFIELD_INT64", 0x58) +_JIT_OPDEF("LOADSTATICFIELD_INT32", 0x59) +_JIT_OPDEF("LOADSTATICFIELD_INTNATIVE", 0x5a) +_JIT_OPDEF("LOADSTATICFIELD_F64", 0x5b) +_JIT_OPDEF("LOADSTATICFIELD_PTR", 0x5c) +_JIT_OPDEF("LOADSTATICFIELD_O", 0x5d) +_JIT_OPDEF("LOADSTATICFIELD_F32", 0x5e) +_JIT_OPDEF("LOADSTATICFIELD_VALUETYPE", 0x5f) + +_JIT_OPDEF("STORESTATICFIELD_INT64", 0x60) +_JIT_OPDEF("STORESTATICFIELD_INT32", 0x61) +_JIT_OPDEF("STORESTATICFIELD_INTNATIVE", 0x62) +_JIT_OPDEF("STORESTATICFIELD_F64", 0x63) +_JIT_OPDEF("STORESTATICFIELD_PTR", 0x64) +_JIT_OPDEF("STORESTATICFIELD_O", 0x65) +_JIT_OPDEF("STORESTATICFIELD_F32", 0x66) +_JIT_OPDEF("STORESTATICFIELD_VALUETYPE", 0x67) + +_JIT_OPDEF("BOX_INT64", 0x68) +_JIT_OPDEF("BOX_INT32", 0x69) +_JIT_OPDEF("BOX_INTNATIVE", 0x6a) +_JIT_OPDEF("BOX_F64", 0x6b) +_JIT_OPDEF("BOX_PTR", 0x6c) +_JIT_OPDEF("BOX_O", 0x6d) +_JIT_OPDEF("BOX_F32", 0x6e) +_JIT_OPDEF("BOX_VALUETYPE", 0x6f) + +_JIT_OPDEF("CEQ_I32I32", 0x70) +_JIT_OPDEF("CGT_I32I32", 0x71) +_JIT_OPDEF("CGT_UN_I32I32", 0x72) +_JIT_OPDEF("CLT_I32I32", 0x73) +_JIT_OPDEF("CLT_UN_I32I32", 0x74) + +_JIT_OPDEF("CEQ_I64I64", 0x75) +_JIT_OPDEF("CGT_I64I64", 0x76) +_JIT_OPDEF("CGT_UN_I64I64", 0x77) +_JIT_OPDEF("CLT_I64I64", 0x78) +_JIT_OPDEF("CLT_UN_I64I64", 0x79) + +_JIT_OPDEF("ADD_OVF_I32I32", 0x7a) +_JIT_OPDEF("ADD_OVF_UN_I32I32", 0x7b) +_JIT_OPDEF("MUL_OVF_I32I32", 0x7c) +_JIT_OPDEF("MUL_OVF_UN_I32I32", 0x7d) +_JIT_OPDEF("SUB_OVF_I32I32", 0x7e) +_JIT_OPDEF("SUB_OVF_UN_I32I32", 0x7f) +_JIT_OPDEF("ADD_I32I32", 0x80) +_JIT_OPDEF("SUB_I32I32", 0x81) +_JIT_OPDEF("MUL_I32I32", 0x82) +_JIT_OPDEF("DIV_I32I32", 0x83) +_JIT_OPDEF("DIV_UN_I32I32", 0x84) +_JIT_OPDEF("REM_I32I32", 0x85) +_JIT_OPDEF("REM_UN_I32I32", 0x86) +_JIT_OPDEF("AND_I32I32", 0x87) +_JIT_OPDEF("OR_I32I32", 0x88) +_JIT_OPDEF("XOR_I32I32", 0x89) + +_JIT_OPDEF("NEG_I32", 0x8a) +_JIT_OPDEF("NOT_I32", 0x8b) +_JIT_OPDEF("NEG_I64", 0x8c) +_JIT_OPDEF("NOT_I64", 0x8d) +_JIT_OPDEF("NEG_F32", 0x8e) +_JIT_OPDEF("NEG_F64", 0x8f) + +_JIT_OPDEF("BEQ_I32I32", 0x90) +_JIT_OPDEF("BGE_I32I32", 0x91) +_JIT_OPDEF("BGT_I32I32", 0x92) +_JIT_OPDEF("BLE_I32I32", 0x93) +_JIT_OPDEF("BLT_I32I32", 0x94) +_JIT_OPDEF("BNE_UN_I32I32", 0x95) +_JIT_OPDEF("BGE_UN_I32I32", 0x96) +_JIT_OPDEF("BGT_UN_I32I32", 0x97) +_JIT_OPDEF("BLE_UN_I32I32", 0x98) +_JIT_OPDEF("BLT_UN_I32I32", 0x99) + +_JIT_OPDEF("BEQ_I64I64", 0x9a) +_JIT_OPDEF("BGE_I64I64", 0x9b) +_JIT_OPDEF("BGT_I64I64", 0x9c) +_JIT_OPDEF("BLE_I64I64", 0x9d) +_JIT_OPDEF("BLT_I64I64", 0x9e) +_JIT_OPDEF("BNE_UN_I64I64", 0x9f) +_JIT_OPDEF("BGE_UN_I64I64", 0xa0) +_JIT_OPDEF("BGT_UN_I64I64", 0xa1) +_JIT_OPDEF("BLE_UN_I64I64", 0xa2) +_JIT_OPDEF("BLT_UN_I64I64", 0xa3) + +_JIT_OPDEF("SHL_I32", 0xa4) +_JIT_OPDEF("SHR_I32", 0xa5) +_JIT_OPDEF("SHR_UN_I32", 0xa6) +_JIT_OPDEF("SHL_I64", 0xa7) +_JIT_OPDEF("SHR_I64", 0xa8) +_JIT_OPDEF("SHR_UN_I64", 0xa9) + +_JIT_OPDEF("BRANCH_FALSE", 0xaa) +_JIT_OPDEF("BRANCH_TRUE", 0xab) +_JIT_OPDEF("BRANCH64_FALSE", 0xac) +_JIT_OPDEF("BRANCH64_TRUE", 0xad) + +_JIT_OPDEF("BOX_NULLABLE", 0xae) +_JIT_OPDEF("LOAD_F64", 0xaf) + +_JIT_OPDEF("LOADTOKEN_TYPE", 0xb0) +_JIT_OPDEF("LOADTOKEN_METHOD", 0xb1) +_JIT_OPDEF("LOADTOKEN_FIELD", 0xb2) + +_JIT_OPDEF("LOADINDIRECT_I8", 0xb3) +_JIT_OPDEF("LOADINDIRECT_U8", 0xb4) +_JIT_OPDEF("LOADINDIRECT_I16", 0xb5) +_JIT_OPDEF("LOADINDIRECT_U16", 0xb6) +_JIT_OPDEF("LOADINDIRECT_I32", 0xb7) +_JIT_OPDEF("LOADINDIRECT_U32", 0xb8) +_JIT_OPDEF("LOADINDIRECT_I64", 0xb9) +_JIT_OPDEF("LOADINDIRECT_I", 0xba) +_JIT_OPDEF("LOADINDIRECT_R32", 0xbb) +_JIT_OPDEF("LOADINDIRECT_R64", 0xbc) +_JIT_OPDEF("LOADINDIRECT_REF", 0xbd) + +_JIT_OPDEF("STOREINDIRECT_REF", 0xbe) +_JIT_OPDEF("STOREINDIRECT_U8", 0xbf) +_JIT_OPDEF("STOREINDIRECT_U16", 0xc0) +_JIT_OPDEF("STOREINDIRECT_U32", 0xc1) +_JIT_OPDEF("STOREINDIRECT_U64", 0xc2) +_JIT_OPDEF("STOREINDIRECT_R32", 0xc3) +_JIT_OPDEF("STOREINDIRECT_R64", 0xc4) + +//_JIT_OPDEF("CONV_SIGNED32", 0xc5) +//_JIT_OPDEF("CONV_UNSIGNED32", 0xc6) +//_JIT_OPDEF("CONV_INT_I64", 0xc7) + +//_JIT_OPDEF("CONV_I1", 0xc5) +//_JIT_OPDEF("CONV_I2", 0xc6) +//_JIT_OPDEF("CONV_I4", 0xc7) +//_JIT_OPDEF("CONV_I8", 0xc8) +//_JIT_OPDEF("CONV_R4", 0xc9) +//_JIT_OPDEF("CONV_R8", 0xca) +//_JIT_OPDEF("CONV_U4", 0xcb) +//_JIT_OPDEF("CONV_U8", 0xcc) +//_JIT_OPDEF("CONV_U2", 0xcd) +//_JIT_OPDEF("CONV_U1", 0xce) +//_JIT_OPDEF("CONV_I_NATIVE", 0xcf) +//_JIT_OPDEF("CONV_U_NATIVE", 0xd0) + +//_JIT_OPDEF("CONV_OVF_I1", 0xd1) +//_JIT_OPDEF("CONV_OVF_U1", 0xd2) +//_JIT_OPDEF("CONV_OVF_I2", 0xd3) +//_JIT_OPDEF("CONV_OVF_U2", 0xd4) +//_JIT_OPDEF("CONV_OVF_I4", 0xd5) +//_JIT_OPDEF("CONV_OVF_U4", 0xd6) +//_JIT_OPDEF("CONV_OVF_I8", 0xd7) +//_JIT_OPDEF("CONV_OVF_U8", 0xd8) + +_JIT_OPDEF("UNBOX_NULLABLE", 0xda) + +_JIT_OPDEF("STORE_ELEMENT_32", 0xde) +_JIT_OPDEF("STORE_ELEMENT_64", 0xdf) + +_JIT_OPDEF("LOAD_ELEMENT_I8", 0xe0) +_JIT_OPDEF("LOAD_ELEMENT_U8", 0xe1) +_JIT_OPDEF("LOAD_ELEMENT_I16", 0xe2) +_JIT_OPDEF("LOAD_ELEMENT_U16", 0xe3) +_JIT_OPDEF("LOAD_ELEMENT_I32", 0xe4) +_JIT_OPDEF("LOAD_ELEMENT_U32", 0xe5) +_JIT_OPDEF("LOAD_ELEMENT_I64", 0xe6) +_JIT_OPDEF("LOAD_ELEMENT_R32", 0xe7) +_JIT_OPDEF("LOAD_ELEMENT_R64", 0xe8) + +_JIT_OPDEF("ADD_OVF_I64I64", 0xea) +_JIT_OPDEF("ADD_OVF_UN_I64I64", 0xeb) +_JIT_OPDEF("MUL_OVF_I64I64", 0xec) +_JIT_OPDEF("MUL_OVF_UN_I64I64", 0xed) +_JIT_OPDEF("SUB_OVF_I64I64", 0xee) +_JIT_OPDEF("SUB_OVF_UN_I64I64", 0xef) +_JIT_OPDEF("ADD_I64I64", 0xf0) +_JIT_OPDEF("SUB_I64I64", 0xf1) +_JIT_OPDEF("MUL_I64I64", 0xf2) +_JIT_OPDEF("DIV_I64I64", 0xf3) +_JIT_OPDEF("DIV_UN_I64I64", 0xf4) +_JIT_OPDEF("REM_I64I64", 0xf5) +_JIT_OPDEF("REM_UN_I64I64", 0xf6) +_JIT_OPDEF("AND_I64I64", 0xf7) +_JIT_OPDEF("OR_I64I64", 0xf8) +_JIT_OPDEF("XOR_I64I64", 0xf9) + +_JIT_OPDEF("CEQ_F32F32", 0xfa) +_JIT_OPDEF("CGT_F32F32", 0xfb) +_JIT_OPDEF("CGT_UN_F32F32", 0xfc) +_JIT_OPDEF("CLT_F32F32", 0xfd) +_JIT_OPDEF("CLT_UN_F32F32", 0xfe) + +_JIT_OPDEF("BEQ_F32F32", 0xff) +_JIT_OPDEF("BGE_F32F32", 0x100) +_JIT_OPDEF("BGT_F32F32", 0x101) +_JIT_OPDEF("BLE_F32F32", 0x102) +_JIT_OPDEF("BLT_F32F32", 0x103) +_JIT_OPDEF("BNE_UN_F32F32", 0x104) +_JIT_OPDEF("BGE_UN_F32F32", 0x105) +_JIT_OPDEF("BGT_UN_F32F32", 0x106) +_JIT_OPDEF("BLE_UN_F32F32", 0x107) +_JIT_OPDEF("BLT_UN_F32F32", 0x108) + +_JIT_OPDEF("ADD_F32F32", 0x109) +_JIT_OPDEF("SUB_F32F32", 0x10a) +_JIT_OPDEF("MUL_F32F32", 0x10b) +_JIT_OPDEF("DIV_F32F32", 0x10c) +_JIT_OPDEF("DIV_UN_F32F32", 0x10d) // Not used +_JIT_OPDEF("REM_F32F32", 0x10e) +_JIT_OPDEF("REM_UN_F32F32", 0x10f) // Not used + +_JIT_OPDEF("CEQ_F64F64", 0x110) +_JIT_OPDEF("CGT_F64F64", 0x111) +_JIT_OPDEF("CGT_UN_F64F64", 0x112) +_JIT_OPDEF("CLT_F64F64", 0x113) +_JIT_OPDEF("CLT_UN_F64F64", 0x114) + +_JIT_OPDEF("BEQ_F64F64", 0x115) +_JIT_OPDEF("BGE_F64F64", 0x116) +_JIT_OPDEF("BGT_F64F64", 0x117) +_JIT_OPDEF("BLE_F64F64", 0x118) +_JIT_OPDEF("BLT_F64F64", 0x119) +_JIT_OPDEF("BNE_UN_F64F64", 0x11a) +_JIT_OPDEF("BGE_UN_F64F64", 0x11b) +_JIT_OPDEF("BGT_UN_F64F64", 0x11c) +_JIT_OPDEF("BLE_UN_F64F64", 0x11d) +_JIT_OPDEF("BLT_UN_F64F64", 0x11e) + +_JIT_OPDEF("ADD_F64F64", 0x11f) +_JIT_OPDEF("SUB_F64F64", 0x120) +_JIT_OPDEF("MUL_F64F64", 0x121) +_JIT_OPDEF("DIV_F64F64", 0x122) +_JIT_OPDEF("DIV_UN_F64F64", 0x123) // Not used +_JIT_OPDEF("REM_F64F64", 0x124) +_JIT_OPDEF("REM_UN_F64F64", 0x125) // Not used + +_JIT_OPDEF("LOADPARAMLOCAL_0", 0x127) // Load 4-byte param/local at offset 0) +_JIT_OPDEF("LOADPARAMLOCAL_1", 0x128) // Load 4-byte param/local at offset 4) +_JIT_OPDEF("LOADPARAMLOCAL_2", 0x129) // Load 4-byte param/local at offset 8) +_JIT_OPDEF("LOADPARAMLOCAL_3", 0x12a) // Load 4-byte param/local at offset 12) +_JIT_OPDEF("LOADPARAMLOCAL_4", 0x12b) // Load 4-byte param/local at offset 16) +_JIT_OPDEF("LOADPARAMLOCAL_5", 0x12c) // Load 4-byte param/local at offset 20) +_JIT_OPDEF("LOADPARAMLOCAL_6", 0x12d) // Load 4-byte param/local at offset 24) +_JIT_OPDEF("LOADPARAMLOCAL_7", 0x12e) // Load 4-byte param/local at offset 28) + +_JIT_OPDEF("STOREPARAMLOCAL_0", 0x12f) // Store 4-byte param/local at offset 0) +_JIT_OPDEF("STOREPARAMLOCAL_1", 0x130) // Store 4-byte param/local at offset 4) +_JIT_OPDEF("STOREPARAMLOCAL_2", 0x131) // Store 4-byte param/local at offset 8) +_JIT_OPDEF("STOREPARAMLOCAL_3", 0x132) // Store 4-byte param/local at offset 12) +_JIT_OPDEF("STOREPARAMLOCAL_4", 0x133) // Store 4-byte param/local at offset 16) +_JIT_OPDEF("STOREPARAMLOCAL_5", 0x134) // Store 4-byte param/local at offset 20) +_JIT_OPDEF("STOREPARAMLOCAL_6", 0x135) // Store 4-byte param/local at offset 24) +_JIT_OPDEF("STOREPARAMLOCAL_7", 0x136) // Store 4-byte param/local at offset 28) + +_JIT_OPDEF("LOAD_I4_M1", 0x137) +_JIT_OPDEF("LOAD_I4_0", 0x138) +_JIT_OPDEF("LOAD_I4_1", 0x139) +_JIT_OPDEF("LOAD_I4_2", 0x13a) + +_JIT_OPDEF("LOADFIELD_4", 0x13b) + +_JIT_OPDEF("CONV_I32_I32", 0x140) +_JIT_OPDEF("CONV_I32_U32", 0x141) +_JIT_OPDEF("CONV_I32_I64", 0x142) +_JIT_OPDEF("CONV_I32_U64", 0x143) +_JIT_OPDEF("CONV_I32_R32", 0x144) +_JIT_OPDEF("CONV_I32_R64", 0x145) + +_JIT_OPDEF("CONV_U32_I32", 0x146) +_JIT_OPDEF("CONV_U32_U32", 0x147) +_JIT_OPDEF("CONV_U32_I64", 0x148) +_JIT_OPDEF("CONV_U32_U64", 0x149) +_JIT_OPDEF("CONV_U32_R32", 0x14a) +_JIT_OPDEF("CONV_U32_R64", 0x14b) + +_JIT_OPDEF("CONV_I64_I32", 0x14c) +_JIT_OPDEF("CONV_I64_U32", 0x14d) +_JIT_OPDEF("CONV_I64_I64", 0x14e) // Not used +_JIT_OPDEF("CONV_I64_U64", 0x14f) // Not used +_JIT_OPDEF("CONV_I64_R32", 0x150) +_JIT_OPDEF("CONV_I64_R64", 0x151) + +_JIT_OPDEF("CONV_U64_I32", 0x152) +_JIT_OPDEF("CONV_U64_U32", 0x153) +_JIT_OPDEF("CONV_U64_I64", 0x154) // Not used +_JIT_OPDEF("CONV_U64_U64", 0x155) // Not used +_JIT_OPDEF("CONV_U64_R32", 0x156) +_JIT_OPDEF("CONV_U64_R64", 0x157) + +_JIT_OPDEF("CONV_R32_I32", 0x158) +_JIT_OPDEF("CONV_R32_U32", 0x159) +_JIT_OPDEF("CONV_R32_I64", 0x15a) +_JIT_OPDEF("CONV_R32_U64", 0x15b) +_JIT_OPDEF("CONV_R32_R32", 0x15c) +_JIT_OPDEF("CONV_R32_R64", 0x15d) + +_JIT_OPDEF("CONV_R64_I32", 0x15e) +_JIT_OPDEF("CONV_R64_U32", 0x15f) +_JIT_OPDEF("CONV_R64_I64", 0x160) +_JIT_OPDEF("CONV_R64_U64", 0x161) +_JIT_OPDEF("CONV_R64_R32", 0x162) +_JIT_OPDEF("CONV_R64_R64", 0x163) + +_JIT_OPDEF("INVOKE_SYSTEM_REFLECTION_METHODBASE", 0x164) +_JIT_OPDEF("REFLECTION_DYNAMICALLY_BOX_RETURN_VALUE", 0x165) +_JIT_OPDEF("TAILCALL_PREFIX", 0x166) + + default: return "undefined"; + } +} + +#endif diff --git a/src/DNA/native/src/Sys.h b/src/DNA/native/src/Sys.h index 1c188d37..829a68d1 100644 --- a/src/DNA/native/src/Sys.h +++ b/src/DNA/native/src/Sys.h @@ -23,6 +23,13 @@ #include "Config.h" +#if defined(DIAG_MEMORY_LEAKS) && defined(_WIN32) +// looking for memory leaks +#define _CRTDBG_MAP_ALLOC +#include +#include +#endif + /*#ifdef _DEBUG void* mallocTrace(int s, char *pFile, int line); #define malloc(s) mallocTrace(s, __FILE__, __LINE__) @@ -34,6 +41,14 @@ void* mallocTrace(int s, char *pFile, int line); #define Assert(cond) #endif +#ifdef DEBUG_PRINT +#define dprintf(format, ...) printf(format, __VA_ARGS__) +#define dprintfn(format, ...) printf(format "\n", __VA_ARGS__) +#else +#define dprintf(format, ...) ((void) 0) +#define dprintfn(format, ...) ((void) 0) +#endif + #define FAKE_RETURN exit(101) #define INTERNALCALL_PARAM(ofs, type) *(type*)(pParams + ofs) @@ -48,11 +63,16 @@ void log_f(U32 level, char *pMsg, ...); char* Sys_GetMethodDesc(tMD_MethodDef *pMethod); void* mallocForever(U32 size); +void* callocForever(U32 count, U32 size); +void freeForever(); -U64 msTime(); -#if defined(DIAG_METHOD_CALLS) || defined(DIAG_OPCODE_TIMES) || defined(DIAG_GC) || defined(DIAG_TOTAL_TIME) U64 microTime(); -#endif +U64 msTime(); void SleepMS(U32 ms); +#ifdef DEBUG_PRINT +char* Sys_CIL_OpCodeName(U32 op); +char* Sys_JIT_OpCodeName(U32 op); +#endif + #endif diff --git a/src/DNA/native/src/System.Char.CaseConversion.h b/src/DNA/native/src/System.Char.CaseConversion.h index 7a853eb9..e70d90bc 100644 --- a/src/DNA/native/src/System.Char.CaseConversion.h +++ b/src/DNA/native/src/System.Char.CaseConversion.h @@ -18,7 +18,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -static unsigned short UC_CaseLower[] = { +static U16 UC_CaseLower[] = { 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, // 0000 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, 0x0070, // 0008 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, // 0010 @@ -106,7 +106,7 @@ static unsigned short UC_CaseLower[] = { 0xff5a, 0xffff }; -static unsigned short UC_CaseUpper[] = { +static U16 UC_CaseUpper[] = { 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, // 0000 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050, // 0008 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, // 0010 diff --git a/src/DNA/native/src/System.Char.c b/src/DNA/native/src/System.Char.c index e98e0935..88a97af7 100644 --- a/src/DNA/native/src/System.Char.c +++ b/src/DNA/native/src/System.Char.c @@ -67,11 +67,11 @@ tAsyncCall* System_Char_GetUnicodeCategory(PTR pThis_, PTR pParams, PTR pReturnV } // Return -1 if not found -static I32 SearchCaseArray(unsigned short *pCaseArray, unsigned short find) { +static I32 SearchCaseArray(U16 *pCaseArray, U16 find) { U32 lower = 0; U32 upper = sizeof(UC_CaseUpper) / 2; U32 curOfs = sizeof(UC_CaseUpper) / 4; - unsigned short val; + U16 val; if (find == 0xffff) { // Hande 0xffff specially, as the search below cannot handle it. @@ -99,22 +99,24 @@ static I32 SearchCaseArray(unsigned short *pCaseArray, unsigned short find) { } } -tAsyncCall* System_Char_ToLowerInvariant(PTR pThis_, PTR pParams, PTR pReturnValue) { - U32 paramCodePoint = ((U32*)pParams)[0]; - I32 pos; +U16 Char_ToLowerInvariant(U16 paramCodePoint) { + I32 pos = SearchCaseArray(UC_CaseUpper, paramCodePoint); + return (pos < 0) ? paramCodePoint : UC_CaseLower[pos]; +} - pos = SearchCaseArray(UC_CaseUpper, (unsigned short)paramCodePoint); - *(U32*)pReturnValue = (pos < 0)?paramCodePoint:UC_CaseLower[pos]; +U16 Char_ToUpperInvariant(U16 paramCodePoint) { + I32 pos = SearchCaseArray(UC_CaseLower, paramCodePoint); + return (pos < 0) ? paramCodePoint : UC_CaseUpper[pos]; +} +tAsyncCall* System_Char_ToLowerInvariant(PTR pThis_, PTR pParams, PTR pReturnValue) { + U32 paramCodePoint = ((U32*)pParams)[0]; + *(U32*)pReturnValue = Char_ToLowerInvariant((U16)paramCodePoint); return NULL; } tAsyncCall* System_Char_ToUpperInvariant(PTR pThis_, PTR pParams, PTR pReturnValue) { U32 paramCodePoint = ((U32*)pParams)[0]; - I32 pos; - - pos = SearchCaseArray(UC_CaseLower, (unsigned short)paramCodePoint); - *(U32*)pReturnValue = (pos < 0)?paramCodePoint:UC_CaseUpper[pos]; - + *(U32*)pReturnValue = Char_ToUpperInvariant((U16)paramCodePoint); return NULL; } diff --git a/src/DNA/native/src/System.Char.h b/src/DNA/native/src/System.Char.h index 25977f7e..b4551705 100644 --- a/src/DNA/native/src/System.Char.h +++ b/src/DNA/native/src/System.Char.h @@ -23,6 +23,9 @@ #include "Types.h" +U16 Char_ToLowerInvariant(U16 paramCodePoint); +U16 Char_ToUpperInvariant(U16 paramCodePoint); + tAsyncCall* System_Char_GetUnicodeCategory(PTR pThis_, PTR pParams, PTR pReturnValue); tAsyncCall* System_Char_ToLowerInvariant(PTR pThis_, PTR pParams, PTR pReturnValue); tAsyncCall* System_Char_ToUpperInvariant(PTR pThis_, PTR pParams, PTR pReturnValue); diff --git a/src/DNA/native/src/System.Console.c b/src/DNA/native/src/System.Console.c index 61de03a1..b431a8df 100644 --- a/src/DNA/native/src/System.Console.c +++ b/src/DNA/native/src/System.Console.c @@ -45,7 +45,7 @@ tAsyncCall* System_Console_Write(PTR pThis_, PTR pParams, PTR pReturnValue) { str8[i] = c?c:'?'; } str8[i] = 0; - printf(str8); + printf("%s", str8); strLen -= thisLen; start += thisLen; } @@ -97,7 +97,7 @@ static U32 Internal_ReadKey_Check(PTR pThis_, PTR pParams, PTR pReturnValue, tAs } tAsyncCall* System_Console_Internal_ReadKey(PTR pThis_, PTR pParams, PTR pReturnValue) { - tAsyncCall *pAsync = TMALLOC(tAsyncCall); + tAsyncCall *pAsync = TMALLOC(1, tAsyncCall); pAsync->sleepTime = -1; pAsync->checkFn = Internal_ReadKey_Check; diff --git a/src/DNA/native/src/System.Diagnostics.Debugger.c b/src/DNA/native/src/System.Diagnostics.Debugger.c index a798ff7e..d2c52286 100644 --- a/src/DNA/native/src/System.Diagnostics.Debugger.c +++ b/src/DNA/native/src/System.Diagnostics.Debugger.c @@ -43,6 +43,7 @@ struct tBreakPoint_ { static tBreakPoint* pBreakpoints; int Debugger_Reset() { + log_f(1, "Debugger_Reset called\n"); // Clear all break points pBreakpoints = NULL; @@ -55,14 +56,18 @@ int Debugger_Reset() { } int Debugger_Clear_BreakPoints() { + log_f(1, "Debugger_Clear_BreakPoints called\n"); + // Clear all break points pBreakpoints = NULL; return 0; } int Debugger_Continue() { + log_f(1, "Debugger_Continue called\n"); if (waitingOnBreakPoint) { releaseBreakPoint = 1; + printf("DEBUGGER_CONTINUE\n"); // Resume execution return Thread_Execute(); @@ -71,12 +76,14 @@ int Debugger_Continue() { } int Debugger_Step() { + log_f(1, "Debugger_Step called\n"); alwaysBreak = 1; return 0; } int Debugger_SetBreakPoint(char* pID, int sequencePoint) { + log_f(1, "Debugger_SetBreakPoint(%s, %d) called\n", pID, sequencePoint); tBreakPoint* pNode = pBreakpoints; tBreakPoint* pTail = NULL; @@ -91,7 +98,7 @@ int Debugger_SetBreakPoint(char* pID, int sequencePoint) // Didn't find the node if (pNode == NULL) { - pNode = TMALLOC(tBreakPoint); + pNode = TMALLOC(1, tBreakPoint); pNode->pID = mallocForever((U32)strlen(pID) + 1); strcpy(pNode->pID, pID); pNode->offset = 0; @@ -106,13 +113,24 @@ int Debugger_SetBreakPoint(char* pID, int sequencePoint) } if (pNode->offset < 100) { + log_f(1, "Breakpoint successfully set\n", pID, sequencePoint); pNode->breakOnSequencePoints[pNode->offset++] = sequencePoint; } + // Dump break points + tBreakPoint* pScan = pBreakpoints; + while (pScan != NULL) { + for (int i = 0; i < pScan->offset; i++) { + log_f(1, "Break point at (%s, %d) \n", pScan->pID, pScan->breakOnSequencePoints[i]); + } + pScan = pScan->next; + } + return 0; } tAsyncCall* System_Diagnostics_Debugger_Break(PTR pThis_, PTR pParams, PTR pReturnValue) { + printf("BREAK\n"); #if defined(_WIN32) && defined(_DEBUG) __debugbreak(); #endif @@ -127,6 +145,8 @@ int CheckIfSequencePointIsBreakpoint(tMethodState* pMethodState, I32 sequencePoi pDebugEntry = pMethodState->pMethod->pJITted->pDebugMetadataEntry; U32 ilOffset = pDebugEntry->sequencePoints[sequencePoint]; + // log_f(1, "(%s, %d, %04X) \n", pDebugEntry->pMethodName, sequencePoint, ilOffset); + if (!alwaysBreak) { doBreakpoint = 0; pHead = pBreakpoints; @@ -148,13 +168,15 @@ int CheckIfSequencePointIsBreakpoint(tMethodState* pMethodState, I32 sequencePoi } } + log_f(1, "BREAK_POINT hit (%s, %d, %04X) \n", pDebugEntry->pMethodName, sequencePoint, ilOffset); + waitingOnBreakPoint = 1; alwaysBreak = 0; // TODO: Handle overflow unsigned char payload[1024]; - sprintf(payload, "{\"command\":\"breakpoint\", \"ilOffset\":%d, \"sequencePoint\":%d,\"ID\":\"%s\"}", ilOffset, sequencePoint, pDebugEntry->pID); -#ifndef _WIN32 + snprintf(payload, sizeof(payload), "{\"command\":\"breakpoint\", \"ilOffset\":%d, \"sequencePoint\":%d,\"ID\":\"%s\"}", ilOffset, sequencePoint, pDebugEntry->pID); +#ifdef JS_INTEROP invokeJsFunc("browser.js", "SendDebuggerMessage", payload); #else printf("%s\n", payload); diff --git a/src/DNA/native/src/System.Environment.c b/src/DNA/native/src/System.Environment.c index 83860ea9..4f689e9d 100644 --- a/src/DNA/native/src/System.Environment.c +++ b/src/DNA/native/src/System.Environment.c @@ -62,7 +62,7 @@ tAsyncCall* System_Environment_get_Platform(PTR pThis_, PTR pParams, PTR pReturn OSVERSIONINFO osVer; osVer.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); GetVersionEx(&osVer); - *(U32*)pReturnValue = (osVer.dwPlatformId == VER_PLATFORM_WIN32_NT)?2:1; // _WIN32NT:_WIN32Windows + *(U32*)pReturnValue = (osVer.dwPlatformId == VER_PLATFORM_WIN32_NT)?2:1; // Win32NT:Win32Windows #else *(U32*)pReturnValue = 4; // UNIX #endif diff --git a/src/DNA/native/src/System.IO.FileInternal.c b/src/DNA/native/src/System.IO.FileInternal.c index 809a24f0..a40652a0 100644 --- a/src/DNA/native/src/System.IO.FileInternal.c +++ b/src/DNA/native/src/System.IO.FileInternal.c @@ -124,6 +124,37 @@ tAsyncCall* System_IO_FileInternal_Close(PTR pThis_, PTR pParams, PTR pReturnVal return NULL; } +tAsyncCall* System_IO_FileInternal_Length(PTR pThis_, PTR pParams, PTR pReturnValue) { + I32 ret = 0, error = 0; + I64 filesize = 0; + unsigned char filename[256]; + U32 i, filenameLen; + + STRING2 filename2 = SystemString_GetString(((HEAP_PTR*)pParams)[0], &filenameLen); + U32 *pError = ((U32**)pParams)[1]; + for (i = 0; isleepTime = -1; pAsync->checkFn = Accept_Check; pAsync->state = NULL; @@ -218,7 +218,7 @@ tAsyncCall* System_Net_Sockets_Internal_Connect(PTR pThis_, PTR pParams, PTR pRe if (ret) { return NULL; } else { - tAsyncCall *pAsync = TMALLOC(tAsyncCall); + tAsyncCall *pAsync = TMALLOC(1, tAsyncCall); pAsync->sleepTime = -1; pAsync->checkFn = Connect_Check; pAsync->state = NULL; @@ -284,8 +284,8 @@ static U32 Receive_Check(PTR pThis_, PTR pParams, PTR pReturnValue, tAsyncCall * tAsyncCall* System_Net_Sockets_Internal_Receive(PTR pThis_, PTR pParams, PTR pReturnValue) { U32 ok; - tAsyncCall *pAsync = TMALLOC(tAsyncCall); - tSendRecvState *pState = TMALLOC(tSendRecvState); + tAsyncCall *pAsync = TMALLOC(1, tAsyncCall); + tSendRecvState *pState = TMALLOC(1, tSendRecvState); pAsync->sleepTime = -1; pAsync->checkFn = Receive_Check; pAsync->state = (PTR)pState; @@ -347,8 +347,8 @@ printf("Send_Check: errno=%d\n", err); tAsyncCall* System_Net_Sockets_Internal_Send(PTR pThis_, PTR pParams, PTR pReturnValue) { U32 ok; - tAsyncCall *pAsync = TMALLOC(tAsyncCall); - tSendRecvState *pState = TMALLOC(tSendRecvState); + tAsyncCall *pAsync = TMALLOC(1, tAsyncCall); + tSendRecvState *pState = TMALLOC(1, tSendRecvState); pAsync->sleepTime = -1; pAsync->checkFn = Receive_Check; pAsync->state = (PTR)pState; diff --git a/src/DNA/native/src/System.Reflection.MethodBase.h b/src/DNA/native/src/System.Reflection.MethodBase.h index 0025073e..88799c9d 100644 --- a/src/DNA/native/src/System.Reflection.MethodBase.h +++ b/src/DNA/native/src/System.Reflection.MethodBase.h @@ -3,10 +3,11 @@ typedef struct tMethodBase_ tMethodBase; struct tMethodBase_ { - // Keep in sync with MethodBase class in .NET corlib code + // Keep in sync with System.Reflection.MethodBase.cs class in .NET corlib code HEAP_PTR ownerType; HEAP_PTR name; - tMD_MethodDef *methodDef; // Not accessed from .NET code + U32 flags; + tMD_MethodDef *methodDef; // Not accessed from .NET code }; #endif \ No newline at end of file diff --git a/src/DNA/native/src/System.Reflection.PropertyInfo.h b/src/DNA/native/src/System.Reflection.PropertyInfo.h index bd1dfb17..74e8c22e 100644 --- a/src/DNA/native/src/System.Reflection.PropertyInfo.h +++ b/src/DNA/native/src/System.Reflection.PropertyInfo.h @@ -3,7 +3,7 @@ typedef struct tPropertyInfo_ tPropertyInfo; struct tPropertyInfo_ { - // Keep in sync with System.Reflection.PropertyInfo.cs + // Keep in sync with System.Reflection.PropertyInfo.cs in .NET corlib code HEAP_PTR ownerType; HEAP_PTR name; HEAP_PTR propertyType; diff --git a/src/DNA/native/src/System.RuntimeType.c b/src/DNA/native/src/System.RuntimeType.c index 14c70aed..b73229de 100644 --- a/src/DNA/native/src/System.RuntimeType.c +++ b/src/DNA/native/src/System.RuntimeType.c @@ -30,6 +30,10 @@ #include "System.RuntimeType.h" #include "System.Array.h" +tMD_TypeDef* RuntimeType_DeRef(PTR type) { + return ((tRuntimeType*)type)->pTypeDef; +} + HEAP_PTR RuntimeType_New(tMD_TypeDef *pTypeDef) { tRuntimeType *pRuntimeType; @@ -41,30 +45,30 @@ HEAP_PTR RuntimeType_New(tMD_TypeDef *pTypeDef) { } tAsyncCall* System_RuntimeType_get_Name(PTR pThis_, PTR pParams, PTR pReturnValue) { - tRuntimeType *pRuntimeType = (tRuntimeType*)pThis_; + tMD_TypeDef *pThisType = RuntimeType_DeRef(pThis_); HEAP_PTR strResult; - strResult = SystemString_FromCharPtrASCII(pRuntimeType->pTypeDef->name); + strResult = SystemString_FromCharPtrASCII(pThisType->name); *(HEAP_PTR*)pReturnValue = strResult; return NULL; } tAsyncCall* System_RuntimeType_get_Namespace(PTR pThis_, PTR pParams, PTR pReturnValue) { - tRuntimeType *pRuntimeType = (tRuntimeType*)pThis_; + tMD_TypeDef *pThisType = RuntimeType_DeRef(pThis_); HEAP_PTR strResult; - strResult = SystemString_FromCharPtrASCII(pRuntimeType->pTypeDef->nameSpace); + strResult = SystemString_FromCharPtrASCII(pThisType->nameSpace); *(HEAP_PTR*)pReturnValue = strResult; return NULL; } tAsyncCall* System_RuntimeType_GetNestingParentType(PTR pThis_, PTR pParams, PTR pReturnValue) { - tRuntimeType *pRuntimeType = (tRuntimeType*)pThis_; + tMD_TypeDef *pThisType = RuntimeType_DeRef(pThis_); tMD_TypeDef *pNestingParentType; - pNestingParentType = pRuntimeType->pTypeDef->pNestedIn; + pNestingParentType = pThisType->pNestedIn; if (pNestingParentType == NULL) { *(HEAP_PTR*)pReturnValue = NULL; } else { @@ -75,8 +79,8 @@ tAsyncCall* System_RuntimeType_GetNestingParentType(PTR pThis_, PTR pParams, PTR } tAsyncCall* System_RuntimeType_get_BaseType(PTR pThis_, PTR pParams, PTR pReturnValue) { - tRuntimeType *pRuntimeType = (tRuntimeType*)pThis_; - tMD_TypeDef *pBaseType = pRuntimeType->pTypeDef->pParent; + tMD_TypeDef *pThisType = RuntimeType_DeRef(pThis_); + tMD_TypeDef *pBaseType = pThisType->pParent; if (pBaseType == NULL) { *(HEAP_PTR*)pReturnValue = NULL; @@ -88,45 +92,45 @@ tAsyncCall* System_RuntimeType_get_BaseType(PTR pThis_, PTR pParams, PTR pReturn } tAsyncCall* System_RuntimeType_get_IsEnum(PTR pThis_, PTR pParams, PTR pReturnValue) { - tMD_TypeDef *pType = ((tRuntimeType*)pThis_)->pTypeDef; + tMD_TypeDef *pThisType = RuntimeType_DeRef(pThis_); - U32 isEnum = pType->pParent == types[TYPE_SYSTEM_ENUM]; + U32 isEnum = pThisType->pParent == types[TYPE_SYSTEM_ENUM]; *(U32*)pReturnValue = isEnum; return NULL; } tAsyncCall* System_RuntimeType_get_IsGenericType(PTR pThis_, PTR pParams, PTR pReturnValue) { - tMD_TypeDef *pType = ((tRuntimeType*)pThis_)->pTypeDef; + tMD_TypeDef *pThisType = RuntimeType_DeRef(pThis_); - *(U32*)pReturnValue = TYPE_ISGENERICINSTANCE(pType) || pType->isGenericDefinition; + *(U32*)pReturnValue = TYPE_ISGENERICINSTANCE(pThisType) || pThisType->isGenericDefinition; return NULL; } tAsyncCall* System_RuntimeType_Internal_GetGenericTypeDefinition(PTR pThis_, PTR pParams, PTR pReturnValue) { - tMD_TypeDef *pType = ((tRuntimeType*)pThis_)->pTypeDef; + tMD_TypeDef *pThisType = RuntimeType_DeRef(pThis_); - if (TYPE_ISGENERICINSTANCE(pType)) { - pType = pType->pGenericDefinition; + if (TYPE_ISGENERICINSTANCE(pThisType)) { + pThisType = pThisType->pGenericDefinition; } - *(HEAP_PTR*)pReturnValue = Type_GetTypeObject(pType); + *(HEAP_PTR*)pReturnValue = Type_GetTypeObject(pThisType); return NULL; } tAsyncCall* System_RuntimeType_GetGenericArguments(PTR pThis_, PTR pParams, PTR pReturnValue) { - tMD_TypeDef *pType = ((tRuntimeType*)pThis_)->pTypeDef; + tMD_TypeDef *pThisType = RuntimeType_DeRef(pThis_); tMD_TypeDef *pCoreType; U32 i, argCount = 0; HEAP_PTR ret; - pCoreType = pType->pGenericDefinition; + pCoreType = pThisType->pGenericDefinition; if (pCoreType != NULL) { // Find the core instantiation of this type tGenericInstance *pInst = pCoreType->pGenericInstances; while (pInst != NULL) { - if (pInst->pInstanceTypeDef == pType) { + if (pInst->pInstanceTypeDef == pThisType) { // Found it! argCount = pInst->numTypeArgs; } @@ -139,20 +143,26 @@ tAsyncCall* System_RuntimeType_GetGenericArguments(PTR pThis_, PTR pParams, PTR *(HEAP_PTR*)pReturnValue = ret; for (i=0; ippClassTypeArgs[i]); + HEAP_PTR argType = Type_GetTypeObject(pThisType->ppClassTypeArgs[i]); SystemArray_StoreElement(ret, i, (PTR)&argType); } return NULL; } -tMD_TypeDef* RuntimeType_DeRef(PTR type) { - return ((tRuntimeType*)type)->pTypeDef; +tAsyncCall* System_RuntimeType_IsDefined(PTR pThis_, PTR pParams, PTR pReturnValue) { + tMD_TypeDef *pThisType = RuntimeType_DeRef(pThis_); + return NULL; +} + +tAsyncCall* System_RuntimeType_GetCustomAttributes(PTR pThis_, PTR pParams, PTR pReturnValue) { + tMD_TypeDef *pThisType = RuntimeType_DeRef(pThis_); + return NULL; } tAsyncCall* System_RuntimeType_GetElementType(PTR pThis_, PTR pParams, PTR pReturnValue) { - tMD_TypeDef *pType = ((tRuntimeType*)pThis_)->pTypeDef; - tMD_TypeDef *pElementTypeDef = pType->pArrayElementType; + tMD_TypeDef *pThisType = RuntimeType_DeRef(pThis_); + tMD_TypeDef *pElementTypeDef = pThisType->pArrayElementType; if (pElementTypeDef != NULL) { *(HEAP_PTR*)pReturnValue = Type_GetTypeObject(pElementTypeDef); diff --git a/src/DNA/native/src/System.RuntimeType.h b/src/DNA/native/src/System.RuntimeType.h index d99b5a26..7ef2cd67 100644 --- a/src/DNA/native/src/System.RuntimeType.h +++ b/src/DNA/native/src/System.RuntimeType.h @@ -30,6 +30,12 @@ struct tRuntimeType_ { tMD_TypeDef *pTypeDef; }; +// De-ref a runtime type pointer +tMD_TypeDef* RuntimeType_DeRef(PTR type); + +// Create a new heap object which is the RuntimeType object for the given type. +HEAP_PTR RuntimeType_New(tMD_TypeDef *pTypeDef); + tAsyncCall* System_RuntimeType_get_Name(PTR pThis_, PTR pParams, PTR pReturnValue); tAsyncCall* System_RuntimeType_get_Namespace(PTR pThis_, PTR pParams, PTR pReturnValue); tAsyncCall* System_RuntimeType_GetNestingParentType(PTR pThis_, PTR pParams, PTR pReturnValue); @@ -38,11 +44,8 @@ tAsyncCall* System_RuntimeType_get_IsEnum(PTR pThis_, PTR pParams, PTR pReturnVa tAsyncCall* System_RuntimeType_get_IsGenericType(PTR pThis_, PTR pParams, PTR pReturnValue); tAsyncCall* System_RuntimeType_Internal_GetGenericTypeDefinition(PTR pThis_, PTR pParams, PTR pReturnValue); tAsyncCall* System_RuntimeType_GetGenericArguments(PTR pThis_, PTR pParams, PTR pReturnValue); +tAsyncCall* System_RuntimeType_IsDefined(PTR pThis_, PTR pParams, PTR pReturnValue); +tAsyncCall* System_RuntimeType_GetCustomAttributes(PTR pThis_, PTR pParams, PTR pReturnValue); tAsyncCall* System_RuntimeType_GetElementType(PTR pThis_, PTR pParams, PTR pReturnValue); -// Create a new heap object which is the RuntimeType object for the given type. -HEAP_PTR RuntimeType_New(tMD_TypeDef *pTypeDef); -// De-ref a runtime type pointer -tMD_TypeDef* RuntimeType_DeRef(PTR type); - #endif \ No newline at end of file diff --git a/src/DNA/native/src/System.String.c b/src/DNA/native/src/System.String.c index 13952a9e..e4b332d3 100644 --- a/src/DNA/native/src/System.String.c +++ b/src/DNA/native/src/System.String.c @@ -19,10 +19,12 @@ // THE SOFTWARE. #include +#include #include "Compat.h" #include "Sys.h" +#include "System.Char.h" #include "System.String.h" #include "MetaData.h" @@ -31,13 +33,15 @@ #include "Type.h" #include "System.Array.h" +#include "errno.h" + typedef struct tSystemString_ tSystemString; // This structure must tie up with string.cs struct tSystemString_ { // Length in characters (not bytes) U32 length; // The characters - U16 chars[0]; + CHAR2 chars[0]; }; // length in characters, not bytes @@ -45,7 +49,7 @@ static tSystemString* CreateStringHeapObj(U32 len) { tSystemString *pSystemString; U32 totalSize; - totalSize = sizeof(tSystemString) + (len << 1); + totalSize = sizeof(tSystemString) + ((len + 1) << 1); pSystemString = (tSystemString*)Heap_Alloc(types[TYPE_SYSTEM_STRING], totalSize); pSystemString->length = len; return pSystemString; @@ -67,6 +71,22 @@ tAsyncCall* System_String_ctor_CharInt32(PTR pThis_, PTR pParams, PTR pReturnVal return NULL; } +tAsyncCall* System_String_ctor_CharA(PTR pThis_, PTR pParams, PTR pReturnValue) { + tSystemString *pSystemString; + HEAP_PTR charArray; + PTR charElements; + U32 startIndex = 0, length = SystemArray_GetLength(((HEAP_PTR*)pParams)[0]); + + charArray = ((HEAP_PTR*)pParams)[0]; + + charElements = SystemArray_GetElements(charArray); + pSystemString = CreateStringHeapObj(length); + memcpy(pSystemString->chars, charElements + (startIndex << 1), length << 1); + *(HEAP_PTR*)pReturnValue = (HEAP_PTR)pSystemString; + + return NULL; +} + tAsyncCall* System_String_ctor_CharAIntInt(PTR pThis_, PTR pParams, PTR pReturnValue) { tSystemString *pSystemString; HEAP_PTR charArray; @@ -86,16 +106,16 @@ tAsyncCall* System_String_ctor_CharAIntInt(PTR pThis_, PTR pParams, PTR pReturnV } tAsyncCall* System_String_ctor_StringIntInt(PTR pThis_, PTR pParams, PTR pReturnValue) { - tSystemString *pThis, *pStr; + tSystemString *pSystemString, *pStr; U32 startIndex, length; pStr = ((tSystemString**)pParams)[0]; startIndex = ((U32*)pParams)[1]; length = ((U32*)pParams)[2]; - pThis = CreateStringHeapObj(length); - memcpy(pThis->chars, &pStr->chars[startIndex], length << 1); - *(HEAP_PTR*)pReturnValue = (HEAP_PTR)pThis; + pSystemString = CreateStringHeapObj(length); + memcpy(pSystemString->chars, &pStr->chars[startIndex], length << 1); + *(HEAP_PTR*)pReturnValue = (HEAP_PTR)pSystemString; return NULL; } @@ -113,8 +133,8 @@ tAsyncCall* System_String_get_Chars(PTR pThis_, PTR pParams, PTR pReturnValue) { tAsyncCall* System_String_InternalConcat(PTR pThis_, PTR pParams, PTR pReturnValue) { tSystemString *s0, *s1, *ret; - s0 = (tSystemString*)(((HEAP_PTR*)pParams)[0]); - s1 = (tSystemString*)(((HEAP_PTR*)pParams)[1]); + s0 = ((tSystemString**)pParams)[0]; + s1 = ((tSystemString**)pParams)[1]; ret = CreateStringHeapObj(s0->length + s1->length); memcpy(ret->chars, s0->chars, s0->length << 1); memcpy(&ret->chars[s0->length], s1->chars, s1->length << 1); @@ -123,19 +143,33 @@ tAsyncCall* System_String_InternalConcat(PTR pThis_, PTR pParams, PTR pReturnVal return NULL; } +tAsyncCall* System_String_InternalCopyTo(PTR pThis_, PTR pParams, PTR pReturnValue) { + tSystemString *pThis = (tSystemString*)pThis_; + + I32 sourceIndex = ((I32*)pParams)[0]; + HEAP_PTR pCharArray = ((HEAP_PTR*)pParams)[1]; + I32 destIndex = ((I32*)pParams)[2]; + I32 count = ((I32*)pParams)[3]; + + CHAR2 *pDestChars = (CHAR2*)SystemArray_GetElements(pCharArray); + memcpy(&pDestChars[destIndex], &pThis->chars[sourceIndex], count << 1); + + return NULL; +} + tAsyncCall* System_String_InternalTrim(PTR pThis_, PTR pParams, PTR pReturnValue) { tSystemString *pThis = (tSystemString*)pThis_; HEAP_PTR pWhiteChars; U32 trimType, i, j, checkCharsLen; U32 ofsStart, ofsEnd; - U16 *pCheckChars; + CHAR2 *pCheckChars; U32 isWhiteSpace; tSystemString *pRet; - U16 c; + CHAR2 c; pWhiteChars = ((HEAP_PTR*)pParams)[0]; trimType = ((U32*)pParams)[1]; - pCheckChars = (U16*)SystemArray_GetElements(pWhiteChars); + pCheckChars = (CHAR2*)SystemArray_GetElements(pWhiteChars); checkCharsLen = SystemArray_GetLength(pWhiteChars); ofsStart = 0; @@ -184,6 +218,22 @@ tAsyncCall* System_String_InternalTrim(PTR pThis_, PTR pParams, PTR pReturnValue return NULL; } +tAsyncCall* System_String_CompareOrdinal(PTR pThis_, PTR pParams, PTR pReturnValue) { + tSystemString *a, *b; + I32 ret; + + a = ((tSystemString**)pParams)[0]; + b = ((tSystemString**)pParams)[1]; + + if (a == NULL && b == NULL) { ret = 0; } + else if (a == NULL) { ret = -1; } + else if (b == NULL) { ret = 1; } + else { ret = wcscmp((wchar_t *)a->chars, (wchar_t *)b->chars); } + *(I32*)pReturnValue = ret; + + return NULL; +} + tAsyncCall* System_String_Equals(PTR pThis_, PTR pParams, PTR pReturnValue) { tSystemString *a, *b; U32 ret; @@ -205,21 +255,18 @@ tAsyncCall* System_String_Equals(PTR pThis_, PTR pParams, PTR pReturnValue) { tAsyncCall* System_String_GetHashCode(PTR pThis_, PTR pParams, PTR pReturnValue) { tSystemString *pThis = (tSystemString*)pThis_; - U16 *pChar, *pEnd; - I32 hash; - - hash = 0; - pChar = pThis->chars; - pEnd = pChar + pThis->length - 1; + I32 hash1 = 5381; + I32 hash2 = hash1; + CHAR2 *pChar = pThis->chars; + CHAR2 *pEnd = pChar + pThis->length - 1; for (; pChar < pEnd; pChar += 2) { - hash = (hash << 5) - hash + pChar[0]; - hash = (hash << 5) - hash + pChar[1]; + hash1 = ((hash1 << 5) + hash1) ^ pChar[0]; + hash2 = ((hash2 << 5) + hash2) ^ pChar[1]; } if (pChar <= pEnd) { - hash = (hash << 5) - hash + pChar[0]; + hash1 = ((hash1 << 5) + hash1) ^ pChar[0]; } - *(I32*)pReturnValue = hash; - + *(I32*)pReturnValue = hash1 + (hash2 * 1566083941); return NULL; } @@ -229,7 +276,7 @@ tAsyncCall* System_String_InternalReplace(PTR pThis_, PTR pParams, PTR pReturnVa tSystemString *pNew = ((tSystemString**)pParams)[1]; tSystemString *pResult; U32 thisLen, oldLen, newLen; - U16 *pThisChar0, *pOldChar0, *pNewChar0, *pResultChar0; + CHAR2 *pThisChar0, *pOldChar0, *pNewChar0, *pResultChar0; U32 i, j, replacements, dstIndex; U32 resultLen; @@ -287,25 +334,15 @@ tAsyncCall* System_String_InternalReplace(PTR pThis_, PTR pParams, PTR pReturnVa tAsyncCall* System_String_InternalIndexOf(PTR pThis_, PTR pParams, PTR pReturnValue) { tSystemString *pThis = (tSystemString*)pThis_; - U16 value = ((U16*)pParams)[0]; + CHAR2 value = ((CHAR2*)pParams)[0]; I32 startIndex = ((I32*)pParams)[1]; I32 count = ((I32*)pParams)[2]; - U32 forwards = ((U32*)pParams)[3]; + U32 forward = ((U32*)pParams)[3]; - I32 lastIndex; - I32 inc; - I32 i; + I32 inc = forward ? 1 : -1; + I32 lastIndex = forward ? startIndex + count : startIndex - count; - if (forwards) { - lastIndex = startIndex + count; - inc = 1; - i = startIndex; - } else { - lastIndex = startIndex - 1; - inc = -1; - i = startIndex + count - 1; - } - for (; i != lastIndex; i += inc) { + for (I32 i = startIndex; i != lastIndex; i += inc) { if (pThis->chars[i] == value) { *(I32*)pReturnValue = i; return NULL; @@ -320,33 +357,61 @@ tAsyncCall* System_String_InternalIndexOfAny(PTR pThis_, PTR pParams, PTR pRetur HEAP_PTR valueArray = ((HEAP_PTR*)pParams)[0]; I32 startIndex = ((I32*)pParams)[1]; I32 count = ((I32*)pParams)[2]; - U32 forwards = ((U32*)pParams)[3]; + U32 forward = ((U32*)pParams)[3]; PTR valueChars = SystemArray_GetElements(valueArray); U32 numValueChars = SystemArray_GetLength(valueArray); - I32 lastIndex; - I32 inc; - I32 i, j; + I32 inc = forward ? 1 : -1; + I32 lastIndex = forward ? startIndex + count : startIndex - count; - if (forwards) { - lastIndex = startIndex + count; - inc = 1; - i = startIndex; - } else { - lastIndex = startIndex - 1; - inc = -1; - i = startIndex + count - 1; - } - for (; i != lastIndex; i += inc) { - U16 thisChar = pThis->chars[i]; - for (j=numValueChars - 1; j>=0; j--) { - if (thisChar == ((U16*)valueChars)[j]) { + for (I32 i = startIndex; i != lastIndex; i += inc) { + CHAR2 thisChar = pThis->chars[i]; + for (I32 j=numValueChars - 1; j >= 0; j--) { + if (thisChar == ((CHAR2*)valueChars)[j]) { *(I32*)pReturnValue = i; return NULL; } } } + + *(I32*)pReturnValue = -1; + return NULL; +} + +tAsyncCall* System_String_InternalIndexOfStr(PTR pThis_, PTR pParams, PTR pReturnValue) { + tSystemString *pThis = (tSystemString*)pThis_; + tSystemString *pValue = ((tSystemString**)pParams)[0]; + I32 startIndex = ((I32*)pParams)[1]; + I32 count = ((I32*)pParams)[2]; + U32 forward = ((U32*)pParams)[3]; + + if (pThis->length == 0) { + *(I32*)pReturnValue = (pValue->length == 0 ? 0 : -1); + return NULL; + } + if (pValue->length == 0) { + *(I32*)pReturnValue = (forward ? startIndex : min((I32)pThis->length - 1, startIndex)); + return NULL; + } + + if (!forward && startIndex == pThis->length) { + startIndex--; + if (count > 0) { count--; } + } + + I32 inc = forward ? 1 : -1; + I32 fromIndex = forward ? startIndex : startIndex - pValue->length + 1; + I32 lastIndex = forward ? startIndex + count - pValue->length + 1 : startIndex - count; + U32 byteLen = pValue->length << 1; + + for (I32 i = fromIndex; i != lastIndex; i += inc) { + if (memcmp(&pThis->chars[i], pValue->chars, byteLen) == 0) { + *(I32*)pReturnValue = i; + return NULL; + } + } + *(I32*)pReturnValue = -1; return NULL; } @@ -375,7 +440,7 @@ HEAP_PTR SystemString_FromCharPtrASCII(U8 *pStr) { return (HEAP_PTR)pSystemString; } -HEAP_PTR SystemString_FromCharPtrUTF16(U16 *pStr) { +HEAP_PTR SystemString_FromCharPtrUTF16(CHAR2 *pStr) { tSystemString *pSystemString; int strLen = 0; @@ -397,5 +462,138 @@ STRING2 SystemString_GetString(HEAP_PTR pThis_, U32 *pLength) { } U32 SystemString_GetNumBytes(HEAP_PTR pThis_) { - return (((tSystemString*)pThis_)->length << 1) + sizeof(tSystemString); -} \ No newline at end of file + tSystemString *pThis = (tSystemString*)pThis_; + return ((pThis->length + 1) << 1) + sizeof(tSystemString); +} + +tAsyncCall* System_String_InternalFromInt32(PTR pThis_, PTR pParams, PTR pReturnValue) { + CHAR2 buf[30]; + swprintf((wchar_t*)buf, sizeof(buf)/sizeof(buf[0]), L"%d", INTERNALCALL_PARAM(0, I32)); + *(HEAP_PTR*)pReturnValue = SystemString_FromCharPtrUTF16(buf); + return NULL; +} + +tAsyncCall* System_String_InternalFromInt64(PTR pThis_, PTR pParams, PTR pReturnValue) { + CHAR2 buf[30]; + swprintf((wchar_t*)buf, sizeof(buf) / sizeof(buf[0]), L"%lld", INTERNALCALL_PARAM(0, I64)); + *(HEAP_PTR*)pReturnValue = SystemString_FromCharPtrUTF16(buf); + return NULL; +} + +tAsyncCall* System_String_InternalFromUInt32(PTR pThis_, PTR pParams, PTR pReturnValue) { + CHAR2 buf[30]; + swprintf((wchar_t*)buf, sizeof(buf) / sizeof(buf[0]), L"%u", INTERNALCALL_PARAM(0, U32)); + *(HEAP_PTR*)pReturnValue = SystemString_FromCharPtrUTF16(buf); + return NULL; +} + +tAsyncCall* System_String_InternalFromUInt64(PTR pThis_, PTR pParams, PTR pReturnValue) { + CHAR2 buf[30]; + swprintf((wchar_t*)buf, sizeof(buf) / sizeof(buf[0]), L"%llu", INTERNALCALL_PARAM(0, U64)); + *(HEAP_PTR*)pReturnValue = SystemString_FromCharPtrUTF16(buf); + return NULL; +} + +tAsyncCall* System_String_InternalFromSingle(PTR pThis_, PTR pParams, PTR pReturnValue) { + CHAR2 buf[30]; + swprintf((wchar_t*)buf, sizeof(buf) / sizeof(buf[0]), L"%.7G", INTERNALCALL_PARAM(0, float)); + *(HEAP_PTR*)pReturnValue = SystemString_FromCharPtrUTF16(buf); + return NULL; +} + +tAsyncCall* System_String_InternalFromDouble(PTR pThis_, PTR pParams, PTR pReturnValue) { + CHAR2 buf[30]; + swprintf((wchar_t*)buf, sizeof(buf) / sizeof(buf[0]), L"%.15G", INTERNALCALL_PARAM(0, double)); + *(HEAP_PTR*)pReturnValue = SystemString_FromCharPtrUTF16(buf); + return NULL; +} + +tAsyncCall* System_String_InternalToInt32(PTR pThis_, PTR pParams, PTR pReturnValue) { + tSystemString *pThis = (tSystemString*)pThis_; + U32 *pError = ((U32**)pParams)[0]; + I32 radix = ((I32*)pParams)[1]; + wchar_t *end, *str = (wchar_t *)pThis->chars; + errno = 0; + I32 ret = wcstol(str, &end, radix); + *pError = end != (str + pThis->length) || (ret == 0 && errno != 0); + *(I32*)pReturnValue = ret; + return NULL; +} + +tAsyncCall* System_String_InternalToInt64(PTR pThis_, PTR pParams, PTR pReturnValue) { + tSystemString *pThis = (tSystemString*)pThis_; + U32 *pError = ((U32**)pParams)[0]; + I32 radix = ((I32*)pParams)[1]; + wchar_t *end, *str = (wchar_t *)pThis->chars; + errno = 0; + I64 ret = wcstoll(str, &end, radix); + *pError = end != (str + pThis->length) || (ret == 0 && errno != 0); + *(I64*)pReturnValue = ret; + return NULL; +} + +tAsyncCall* System_String_InternalToUInt32(PTR pThis_, PTR pParams, PTR pReturnValue) { + tSystemString *pThis = (tSystemString*)pThis_; + U32 *pError = ((U32**)pParams)[0]; + I32 radix = ((I32*)pParams)[1]; + wchar_t *end, *str = (wchar_t *)pThis->chars; + errno = 0; + U32 ret = wcstoul(str, &end, radix); + *pError = end != (str + pThis->length) || (ret == 0 && errno != 0); + *(U32*)pReturnValue = ret; + return NULL; +} + +tAsyncCall* System_String_InternalToUInt64(PTR pThis_, PTR pParams, PTR pReturnValue) { + tSystemString *pThis = (tSystemString*)pThis_; + U32 *pError = ((U32**)pParams)[0]; + I32 radix = ((I32*)pParams)[1]; + wchar_t *end, *str = (wchar_t *)pThis->chars; + errno = 0; + U64 ret = wcstoull(str, &end, radix); + *pError = end != (str + pThis->length) || (ret == 0 && errno != 0); + *(U64*)pReturnValue = ret; + return NULL; +} + +tAsyncCall* System_String_InternalToSingle(PTR pThis_, PTR pParams, PTR pReturnValue) { + tSystemString *pThis = (tSystemString*)pThis_; + U32 *pError = ((U32**)pParams)[0]; + wchar_t *end, *str = (wchar_t *)pThis->chars; + errno = 0; + float ret = wcstof(str, &end); + *pError = end != (str + pThis->length) || (ret == 0 && errno != 0); + *(float*)pReturnValue = ret; + return NULL; +} + +tAsyncCall* System_String_InternalToDouble(PTR pThis_, PTR pParams, PTR pReturnValue) { + tSystemString *pThis = (tSystemString*)pThis_; + U32 *pError = ((U32**)pParams)[0]; + wchar_t *end, *str = (wchar_t *)pThis->chars; + errno = 0; + double ret = wcstod(str, &end); + *pError = end != (str + pThis->length) || (ret == 0 && errno != 0); + *(double*)pReturnValue = ret; + return NULL; +} + +tAsyncCall* System_String_ToLowerInvariant(PTR pThis_, PTR pParams, PTR pReturnValue) { + tSystemString *pThis = (tSystemString*)pThis_; + tSystemString *pSystemString = CreateStringHeapObj(pThis->length); + for (U32 i = 0; i < pThis->length; i++) { + pSystemString->chars[i] = Char_ToLowerInvariant(pThis->chars[i]); + } + *(HEAP_PTR*)pReturnValue = (HEAP_PTR)pSystemString; + return NULL; +} + +tAsyncCall* System_String_ToUpperInvariant(PTR pThis_, PTR pParams, PTR pReturnValue) { + tSystemString *pThis = (tSystemString*)pThis_; + tSystemString *pSystemString = CreateStringHeapObj(pThis->length); + for (U32 i = 0; i < pThis->length; i++) { + pSystemString->chars[i] = Char_ToUpperInvariant(pThis->chars[i]); + } + *(HEAP_PTR*)pReturnValue = (HEAP_PTR)pSystemString; + return NULL; +} diff --git a/src/DNA/native/src/System.String.h b/src/DNA/native/src/System.String.h index d6689e5c..6b200777 100644 --- a/src/DNA/native/src/System.String.h +++ b/src/DNA/native/src/System.String.h @@ -25,21 +25,42 @@ #include "Types.h" tAsyncCall* System_String_ctor_CharInt32(PTR pThis_, PTR pParams, PTR pReturnValue); +tAsyncCall* System_String_ctor_CharA(PTR pThis_, PTR pParams, PTR pReturnValue); tAsyncCall* System_String_ctor_CharAIntInt(PTR pThis_, PTR pParams, PTR pReturnValue); tAsyncCall* System_String_ctor_StringIntInt(PTR pThis_, PTR pParams, PTR pReturnValue); tAsyncCall* System_String_get_Chars(PTR pThis_, PTR pParams, PTR pReturnValue); tAsyncCall* System_String_InternalConcat(PTR pThis_, PTR pParams, PTR pReturnValue); +tAsyncCall* System_String_InternalCopyTo(PTR pThis_, PTR pParams, PTR pReturnValue); tAsyncCall* System_String_InternalTrim(PTR pThis_, PTR pParams, PTR pReturnValue); +tAsyncCall* System_String_CompareOrdinal(PTR pThis_, PTR pParams, PTR pReturnValue); tAsyncCall* System_String_Equals(PTR pThis_, PTR pParams, PTR pReturnValue); tAsyncCall* System_String_GetHashCode(PTR pThis_, PTR pParams, PTR pReturnValue); tAsyncCall* System_String_InternalReplace(PTR pThis_, PTR pParams, PTR pReturnValue); tAsyncCall* System_String_InternalIndexOf(PTR pThis_, PTR pParams, PTR pReturnValue); tAsyncCall* System_String_InternalIndexOfAny(PTR pThis_, PTR pParams, PTR pReturnValue); +tAsyncCall* System_String_InternalIndexOfStr(PTR pThis_, PTR pParams, PTR pReturnValue); HEAP_PTR SystemString_FromUserStrings(tMetaData *pMetaData, IDX_USERSTRINGS index); HEAP_PTR SystemString_FromCharPtrASCII(U8 *pStr); -HEAP_PTR SystemString_FromCharPtrUTF16(U16 *pStr); +HEAP_PTR SystemString_FromCharPtrUTF16(CHAR2 *pStr); STRING2 SystemString_GetString(HEAP_PTR pThis_, U32 *pLength); U32 SystemString_GetNumBytes(HEAP_PTR pThis_); +tAsyncCall* System_String_InternalFromInt32(PTR pThis_, PTR pParams, PTR pReturnValue); +tAsyncCall* System_String_InternalFromInt64(PTR pThis_, PTR pParams, PTR pReturnValue); +tAsyncCall* System_String_InternalFromUInt32(PTR pThis_, PTR pParams, PTR pReturnValue); +tAsyncCall* System_String_InternalFromUInt64(PTR pThis_, PTR pParams, PTR pReturnValue); +tAsyncCall* System_String_InternalFromSingle(PTR pThis_, PTR pParams, PTR pReturnValue); +tAsyncCall* System_String_InternalFromDouble(PTR pThis_, PTR pParams, PTR pReturnValue); + +tAsyncCall* System_String_InternalToInt32(PTR pThis_, PTR pParams, PTR pReturnValue); +tAsyncCall* System_String_InternalToInt64(PTR pThis_, PTR pParams, PTR pReturnValue); +tAsyncCall* System_String_InternalToUInt32(PTR pThis_, PTR pParams, PTR pReturnValue); +tAsyncCall* System_String_InternalToUInt64(PTR pThis_, PTR pParams, PTR pReturnValue); +tAsyncCall* System_String_InternalToSingle(PTR pThis_, PTR pParams, PTR pReturnValue); +tAsyncCall* System_String_InternalToDouble(PTR pThis_, PTR pParams, PTR pReturnValue); + +tAsyncCall* System_String_ToLowerInvariant(PTR pThis_, PTR pParams, PTR pReturnValue); +tAsyncCall* System_String_ToUpperInvariant(PTR pThis_, PTR pParams, PTR pReturnValue); + #endif \ No newline at end of file diff --git a/src/DNA/native/src/System.Threading.Monitor.c b/src/DNA/native/src/System.Threading.Monitor.c index b3cb637a..93ffdab6 100644 --- a/src/DNA/native/src/System.Threading.Monitor.c +++ b/src/DNA/native/src/System.Threading.Monitor.c @@ -67,7 +67,7 @@ tAsyncCall* System_Threading_Monitor_Internal_TryEnter(PTR pThis_, PTR pParams, // Got lock already, so don't block thread return NULL; } - pAsync = TMALLOC(tAsyncCall); + pAsync = TMALLOC(1, tAsyncCall); pAsync->sleepTime = -1; pAsync->checkFn = Internal_TryEntry_Check; pAsync->state = NULL; diff --git a/src/DNA/native/src/System.Threading.Thread.c b/src/DNA/native/src/System.Threading.Thread.c index 469e9884..a44b544e 100644 --- a/src/DNA/native/src/System.Threading.Thread.c +++ b/src/DNA/native/src/System.Threading.Thread.c @@ -72,7 +72,7 @@ tAsyncCall* System_Threading_Thread_Start(PTR pThis_, PTR pParams, PTR pReturnVa } tAsyncCall* System_Threading_Thread_Sleep(PTR pThis_, PTR pParams, PTR pReturnValue) { - tAsyncCall *pAsync = TMALLOC(tAsyncCall); + tAsyncCall *pAsync = TMALLOC(1, tAsyncCall); pAsync->sleepTime = ((I32*)pParams)[0]; diff --git a/src/DNA/native/src/System.Type.c b/src/DNA/native/src/System.Type.c index 9701cc9f..8e072142 100644 --- a/src/DNA/native/src/System.Type.c +++ b/src/DNA/native/src/System.Type.c @@ -32,23 +32,7 @@ #include "Type.h" #include "CLIFile.h" -tAsyncCall* System_Type_GetTypeFromHandle(PTR pThis_, PTR pParams, PTR pReturnValue) { - tMD_TypeDef *pTypeDef = *(tMD_TypeDef**)pParams; - - *(HEAP_PTR*)pReturnValue = Type_GetTypeObject(pTypeDef); - - return NULL; -} - -tAsyncCall* System_Type_get_IsValueType(PTR pThis_, PTR pParams, PTR pReturnValue) { - tRuntimeType *pRuntimeType = (tRuntimeType*)pThis_; - - *(U32*)pReturnValue = pRuntimeType->pTypeDef->isValueType; - - return NULL; -} - -void DotNetStringToCString(unsigned char* buf, U32 bufLength, STRING dotnetString) { +static void DotNetStringToCString(unsigned char* buf, U32 bufLength, STRING dotnetString) { U32 stringLen; STRING2 dotnetString2 = SystemString_GetString(dotnetString, &stringLen); if (stringLen > bufLength) { @@ -71,6 +55,30 @@ tAsyncCall* System_Type_EnsureAssemblyLoaded(PTR pThis_, PTR pParams, PTR pRetur return NULL; } +tAsyncCall* System_Type_get_Attributes(PTR pThis_, PTR pParams, PTR pReturnValue) { + tMD_TypeDef *pThisType = RuntimeType_DeRef(pThis_); + + *(U32*)pReturnValue = pThisType->flags; + + return NULL; +} + +tAsyncCall* System_Type_get_IsValueType(PTR pThis_, PTR pParams, PTR pReturnValue) { + tMD_TypeDef *pThisType = RuntimeType_DeRef(pThis_); + + *(U32*)pReturnValue = pThisType->isValueType; + + return NULL; +} + +tAsyncCall* System_Type_GetTypeFromHandle(PTR pThis_, PTR pParams, PTR pReturnValue) { + tMD_TypeDef *pTypeDef = *(tMD_TypeDef**)pParams; + + *(HEAP_PTR*)pReturnValue = Type_GetTypeObject(pTypeDef); + + return NULL; +} + tAsyncCall* System_Type_GetTypeFromName(PTR pThis_, PTR pParams, PTR pReturnValue) { unsigned char namespaceName[256]; unsigned char className[256]; @@ -90,101 +98,231 @@ tAsyncCall* System_Type_GetTypeFromName(PTR pThis_, PTR pParams, PTR pReturnValu pTypeDef = MetaData_GetTypeDefFromName(pAssemblyMetadata, namespaceName, className, NULL, /* assertExists */ 1); } - MetaData_Fill_TypeDef(pTypeDef, NULL, NULL); - *(HEAP_PTR*)pReturnValue = Type_GetTypeObject(pTypeDef); + if (pTypeDef != NULL) { + MetaData_Fill_TypeDef(pTypeDef, NULL, NULL); + *(HEAP_PTR*)pReturnValue = Type_GetTypeObject(pTypeDef); + } else { + // Not found + *(HEAP_PTR*)pReturnValue = NULL; + } return NULL; } -tAsyncCall* System_Type_GetProperties(PTR pThis_, PTR pParams, PTR pReturnValue) { - tRuntimeType *pRuntimeType = (tRuntimeType*)pThis_; - tMD_TypeDef *pTypeDef = pRuntimeType->pTypeDef; - tMetaData *pMetaData = pTypeDef->pMetaData; +tAsyncCall* System_Type_GetNestedType(PTR pThis_, PTR pParams, PTR pReturnValue) { + tMD_TypeDef *pThisType = RuntimeType_DeRef(pThis_); + + unsigned char className[256]; + DotNetStringToCString(className, 256, ((HEAP_PTR*)pParams)[0]); + + tMD_TypeDef *pTypeDef = MetaData_GetTypeDefFromName(pThisType->pMetaData, pThisType->nameSpace, className, pThisType, /* assertExists */ 1); + if (pTypeDef != NULL) { + MetaData_Fill_TypeDef(pTypeDef, NULL, NULL); + *(HEAP_PTR*)pReturnValue = Type_GetTypeObject(pTypeDef); + } else { + // Not found + *(HEAP_PTR*)pReturnValue = NULL; + } + return NULL; +} + +tAsyncCall* System_Type_GetNestedTypes(PTR pThis_, PTR pParams, PTR pReturnValue) { + tMD_TypeDef *pThisType = RuntimeType_DeRef(pThis_); + + // get the number of nested types + tMD_TypeDef *pTypeDef; + U32 numNestedTypes = 0; + U32 numTypes = pThisType->pMetaData->tables.numRows[MD_TABLE_TYPEDEF]; + for (U32 i = 1; i <= numTypes; i++) { + pTypeDef = (tMD_TypeDef*)MetaData_GetTableRow(pThisType->pMetaData, MAKE_TABLE_INDEX(MD_TABLE_TYPEDEF, i)); + if (pThisType == pTypeDef->pNestedIn) { + numNestedTypes++; + } + } + + // Instantiate a Type array + tMD_TypeDef *pArrayType = Type_GetArrayTypeDef(types[TYPE_SYSTEM_TYPE], NULL, NULL); + HEAP_PTR ret = SystemArray_NewVector(pArrayType, numNestedTypes); + // Allocate to return value straight away, so it cannot be GCed + *(HEAP_PTR*)pReturnValue = ret; + + // Fill the Type array + for (U32 i = 1, iNested = 0; i <= numTypes; i++) { + pTypeDef = (tMD_TypeDef*)MetaData_GetTableRow(pThisType->pMetaData, MAKE_TABLE_INDEX(MD_TABLE_TYPEDEF, i)); + if (pThisType == pTypeDef->pNestedIn) { + HEAP_PTR typeObject = Type_GetTypeObject(pTypeDef); + SystemArray_StoreElement(ret, iNested++, (PTR)&typeObject); + } + } + + return NULL; +} + +tAsyncCall* System_Type_GetInterfaces(PTR pThis_, PTR pParams, PTR pReturnValue) { + tMD_TypeDef *pThisType = RuntimeType_DeRef(pThis_); + + // Instantiate a Type array + tMD_TypeDef *pArrayType = Type_GetArrayTypeDef(types[TYPE_SYSTEM_TYPE], NULL, NULL); + HEAP_PTR ret = SystemArray_NewVector(pArrayType, pThisType->numInterfaces); + // Allocate to return value straight away, so it cannot be GCed + *(HEAP_PTR*)pReturnValue = ret; + + // Fill the Type array + for (U32 i = 0; inumInterfaces; i++) { + HEAP_PTR typeObject = Type_GetTypeObject(pThisType->pInterfaceMaps[i].pInterface); + SystemArray_StoreElement(ret, i, (PTR)&typeObject); + } + + return NULL; +} + +static tPropertyInfo* GetPropertyInfo(PTR pThis_, IDX_TABLE index) { + tMD_TypeDef *pThisType = RuntimeType_DeRef(pThis_); + tMD_Property *pPropertyMetadata = (tMD_Property*)MetaData_GetTableRow(pThisType->pMetaData, index); + + // Instantiate PropertyInfo and put it in the array + tPropertyInfo *pPropertyInfo = (tPropertyInfo*)Heap_AllocType(types[TYPE_SYSTEM_REFLECTION_PROPERTYINFO]); + + // Assign ownerType and name + pPropertyInfo->ownerType = pThis_; + pPropertyInfo->name = SystemString_FromCharPtrASCII(pPropertyMetadata->name); + + // Assign propertyType + U32 sigLength; + PTR typeSig = MetaData_GetBlob(pPropertyMetadata->typeSig, &sigLength); + MetaData_DecodeSigEntry(&typeSig); // Ignored: prolog + MetaData_DecodeSigEntry(&typeSig); // Ignored: number of 'getter' parameters + tMD_TypeDef *propertyTypeDef = Type_GetTypeFromSig(pThisType->pMetaData, &typeSig, pThisType->ppClassTypeArgs, NULL); + MetaData_Fill_TypeDef(propertyTypeDef, NULL, NULL); + pPropertyInfo->propertyType = Type_GetTypeObject(propertyTypeDef); + + // Assign propertyMetadata + pPropertyInfo->index = index; + pPropertyInfo->pMetaData = pPropertyMetadata; + + return pPropertyInfo; +} + +static tMethodInfo* GetMethodInfo(PTR pThis_, U32 i) { + tMD_TypeDef *pThisType = RuntimeType_DeRef(pThis_); + tMD_MethodDef *pMethodDef = pThisType->ppMethods[i]; + + // Instantiate a MethodInfo and put it in the array + tMethodInfo *pMethodInfo = (tMethodInfo*)Heap_AllocType(types[TYPE_SYSTEM_REFLECTION_METHODINFO]); + + // Assign ownerType, name and flags + pMethodInfo->methodBase.ownerType = pThis_; + pMethodInfo->methodBase.name = SystemString_FromCharPtrASCII(pMethodDef->name); + pMethodInfo->methodBase.flags = pMethodDef->flags; + + // Assign method def + pMethodInfo->methodBase.methodDef = pMethodDef; + + return pMethodInfo; +} + +static U32 GetNumProperties(tMD_TypeDef *pThisType, IDX_TABLE *pFirstIdx) { + tMetaData *pMetaData = pThisType->pMetaData; // First we search through the table of propertymaps to find the propertymap for the requested type - U32 i; - IDX_TABLE firstIdx = 0, lastIdxExc = 0; + *pFirstIdx = 0; + IDX_TABLE lastIdxExc = 0; U32 numPropertyRows = pMetaData->tables.numRows[MD_TABLE_PROPERTY]; U32 numPropertymapRows = pMetaData->tables.numRows[MD_TABLE_PROPERTYMAP]; - for (i=1; i <= numPropertymapRows; i++) { + for (U32 i=1; i <= numPropertymapRows; i++) { tMD_PropertyMap *pPropertyMap = (tMD_PropertyMap*)MetaData_GetTableRow(pMetaData, MAKE_TABLE_INDEX(MD_TABLE_PROPERTYMAP, i)); - if (pPropertyMap->parent == pTypeDef->tableIndex) { - firstIdx = TABLE_OFS(pPropertyMap->propertyList); + if (pPropertyMap->parent == pThisType->tableIndex) { + *pFirstIdx = TABLE_OFS(pPropertyMap->propertyList); if (i < numPropertymapRows) { tMD_PropertyMap *pNextPropertyMap = (tMD_PropertyMap*)MetaData_GetTableRow(pMetaData, MAKE_TABLE_INDEX(MD_TABLE_PROPERTYMAP, i + 1)); lastIdxExc = TABLE_OFS(pNextPropertyMap->propertyList); - } else { + } + else { lastIdxExc = numPropertyRows + 1; } break; } } + U32 numProperties = lastIdxExc - *pFirstIdx; + return numProperties; +} - // Instantiate a PropertyInfo[] - U32 numProperties = lastIdxExc - firstIdx; +tAsyncCall* System_Type_GetProperties(PTR pThis_, PTR pParams, PTR pReturnValue) { + tMD_TypeDef *pThisType = RuntimeType_DeRef(pThis_); + + IDX_TABLE firstIdx = 0; + U32 numProperties = GetNumProperties(pThisType, &firstIdx); + + // Instantiate a PropertyInfo array tMD_TypeDef *pArrayType = Type_GetArrayTypeDef(types[TYPE_SYSTEM_REFLECTION_PROPERTYINFO], NULL, NULL); HEAP_PTR ret = SystemArray_NewVector(pArrayType, numProperties); // Allocate to return value straight away, so it cannot be GCed *(HEAP_PTR*)pReturnValue = ret; - // Now fill the PropertyInfo[] - for (i=0; iownerType = pThis_; +tAsyncCall* System_Type_GetProperty(PTR pThis_, PTR pParams, PTR pReturnValue) { + tMD_TypeDef *pThisType = RuntimeType_DeRef(pThis_); - // Assign name - pPropertyInfo->name = SystemString_FromCharPtrASCII(pPropertyMetadata->name); + // Get property name from param + unsigned char propertyName[256]; + DotNetStringToCString(propertyName, 256, ((HEAP_PTR*)pParams)[0]); - // Assign propertyType - U32 sigLength; - PTR typeSig = MetaData_GetBlob(pPropertyMetadata->typeSig, &sigLength); - MetaData_DecodeSigEntry(&typeSig); // Ignored: prolog - MetaData_DecodeSigEntry(&typeSig); // Ignored: number of 'getter' parameters - tMD_TypeDef *propertyTypeDef = Type_GetTypeFromSig(pMetaData, &typeSig, NULL, NULL); - MetaData_Fill_TypeDef(propertyTypeDef, NULL, NULL); - pPropertyInfo->propertyType = Type_GetTypeObject(propertyTypeDef); + IDX_TABLE firstIdx = 0; + U32 numProperties = GetNumProperties(pThisType, &firstIdx); - // Assign propertyMetadata - pPropertyInfo->index = index; - pPropertyInfo->pMetaData = pPropertyMetadata; + // Search for the property by name + for (U32 i = 0; ipMetaData, index); + if (strcmp(pPropertyMetadata->name, propertyName) == 0) { + tPropertyInfo *pPropertyInfo = GetPropertyInfo(pThis_, index); + *(HEAP_PTR*)pReturnValue = (HEAP_PTR)pPropertyInfo; + return NULL; + } } + // Not found + *(HEAP_PTR*)pReturnValue = NULL; return NULL; } -tAsyncCall* System_Type_GetMethod(PTR pThis_, PTR pParams, PTR pReturnValue) -{ - // Read param - unsigned char methodName[256]; - DotNetStringToCString(methodName, 256, ((HEAP_PTR*)pParams)[0]); - - // Get metadata for the 'this' type - tRuntimeType *pRuntimeType = (tRuntimeType*)pThis_; - tMD_TypeDef *pTypeDef = pRuntimeType->pTypeDef; +tAsyncCall* System_Type_GetMethods(PTR pThis_, PTR pParams, PTR pReturnValue) { + tMD_TypeDef *pThisType = RuntimeType_DeRef(pThis_); - // Search for the method by name - for (U32 i=0; inumMethods; i++) { - if (strcmp(pTypeDef->ppMethods[i]->name, methodName) == 0) { - tMD_MethodDef *pMethodDef = pTypeDef->ppMethods[i]; + // Instantiate a MethodInfo array + tMD_TypeDef *pArrayType = Type_GetArrayTypeDef(types[TYPE_SYSTEM_REFLECTION_METHODINFO], NULL, NULL); + HEAP_PTR ret = SystemArray_NewVector(pArrayType, pThisType->numMethods); + // Allocate to return value straight away, so it cannot be GCed + *(HEAP_PTR*)pReturnValue = ret; - // Instantiate a MethodInfo - tMethodInfo *pMethodInfo = (tMethodInfo*)Heap_AllocType(types[TYPE_SYSTEM_REFLECTION_METHODINFO]); + // Fill the MethodInfo array + for (U32 i = 0; inumMethods; i++) { + tMethodInfo *pMethodInfo = GetMethodInfo(pThis_, i); + SystemArray_StoreElement(ret, i, (PTR)&pMethodInfo); + } - // Assign ownerType - pMethodInfo->methodBase.ownerType = pThis_; + return NULL; +} - // Assign name - pMethodInfo->methodBase.name = SystemString_FromCharPtrASCII(pMethodDef->name); +tAsyncCall* System_Type_GetMethod(PTR pThis_, PTR pParams, PTR pReturnValue) { + tMD_TypeDef *pThisType = RuntimeType_DeRef(pThis_); - // Assign method def - pMethodInfo->methodBase.methodDef = pMethodDef; + // Get method name from param + unsigned char methodName[256]; + DotNetStringToCString(methodName, 256, ((HEAP_PTR*)pParams)[0]); + // Search for the method by name + for (U32 i=0; inumMethods; i++) { + if (strcmp(pThisType->ppMethods[i]->name, methodName) == 0) { + tMethodInfo *pMethodInfo = GetMethodInfo(pThis_, i); *(HEAP_PTR*)pReturnValue = (HEAP_PTR)pMethodInfo; return NULL; } @@ -194,3 +332,42 @@ tAsyncCall* System_Type_GetMethod(PTR pThis_, PTR pParams, PTR pReturnValue) *(HEAP_PTR*)pReturnValue = NULL; return NULL; } + +tAsyncCall* System_Type_IsAssignableFrom(PTR pThis_, PTR pParams, PTR pReturnValue) { + tMD_TypeDef *pThisType = RuntimeType_DeRef(pThis_); + tMD_TypeDef *pFromType = RuntimeType_DeRef((PTR)((tMD_TypeDef**)pParams)[0]); + + *(U32*)pReturnValue = Type_IsAssignableFrom(pThisType, pFromType); + return NULL; +} + +tAsyncCall* System_Type_IsSubclassOf(PTR pThis_, PTR pParams, PTR pReturnValue) { + tMD_TypeDef *pBaseType = RuntimeType_DeRef(pThis_); + tMD_TypeDef *pTestType = RuntimeType_DeRef((PTR)((tMD_TypeDef**)pParams)[0]); + + *(U32*)pReturnValue = Type_IsDerivedFromOrSame(pBaseType, pTestType); + return NULL; +} + +tAsyncCall* System_Type_MakeGenericType(PTR pThis_, PTR pParams, PTR pReturnValue) +{ + // get type arguments + tMD_TypeDef *pThisType = RuntimeType_DeRef(pThis_); + HEAP_PTR pTypeArgs = ((HEAP_PTR*)pParams)[0]; + U32 numTypeArgs = SystemArray_GetLength(pTypeArgs); + HEAP_PTR* pArray = (HEAP_PTR*)SystemArray_GetElements(pTypeArgs); + + // get arg types + tMD_TypeDef **ppTypeArgs = TMALLOC(numTypeArgs, tMD_TypeDef*); + for (U32 i = 0; i < numTypeArgs; i++) { + ppTypeArgs[i] = RuntimeType_DeRef(pArray[i]); + } + + // specialize generic type + tMD_TypeDef* pTypeDef = Generics_GetGenericTypeFromCoreType(pThisType, numTypeArgs, ppTypeArgs); + free(ppTypeArgs); + + *(HEAP_PTR*)pReturnValue = Type_GetTypeObject(pTypeDef); + + return NULL; +} diff --git a/src/DNA/native/src/System.Type.h b/src/DNA/native/src/System.Type.h index d75441dd..ccaf6c82 100644 --- a/src/DNA/native/src/System.Type.h +++ b/src/DNA/native/src/System.Type.h @@ -24,11 +24,20 @@ #include "Types.h" #include "MetaData.h" -tAsyncCall* System_Type_GetTypeFromHandle(PTR pThis_, PTR pParams, PTR pReturnValue); +tAsyncCall* System_Type_EnsureAssemblyLoaded(PTR pThis_, PTR pParams, PTR pReturnValue); +tAsyncCall* System_Type_get_Attributes(PTR pThis_, PTR pParams, PTR pReturnValue); tAsyncCall* System_Type_get_IsValueType(PTR pThis_, PTR pParams, PTR pReturnValue); +tAsyncCall* System_Type_GetTypeFromHandle(PTR pThis_, PTR pParams, PTR pReturnValue); tAsyncCall* System_Type_GetTypeFromName(PTR pThis_, PTR pParams, PTR pReturnValue); -tAsyncCall* System_Type_EnsureAssemblyLoaded(PTR pThis_, PTR pParams, PTR pReturnValue); +tAsyncCall* System_Type_GetNestedType(PTR pThis_, PTR pParams, PTR pReturnValue); +tAsyncCall* System_Type_GetNestedTypes(PTR pThis_, PTR pParams, PTR pReturnValue); +tAsyncCall* System_Type_GetInterfaces(PTR pThis_, PTR pParams, PTR pReturnValue); tAsyncCall* System_Type_GetProperties(PTR pThis_, PTR pParams, PTR pReturnValue); +tAsyncCall* System_Type_GetProperty(PTR pThis_, PTR pParams, PTR pReturnValue); +tAsyncCall* System_Type_GetMethods(PTR pThis_, PTR pParams, PTR pReturnValue); tAsyncCall* System_Type_GetMethod(PTR pThis_, PTR pParams, PTR pReturnValue); +tAsyncCall* System_Type_IsAssignableFrom(PTR pThis_, PTR pParams, PTR pReturnValue); +tAsyncCall* System_Type_IsSubclassOf(PTR pThis_, PTR pParams, PTR pReturnValue); +tAsyncCall* System_Type_MakeGenericType(PTR pThis_, PTR pParams, PTR pReturnValue); #endif \ No newline at end of file diff --git a/src/DNA/native/src/Thread.c b/src/DNA/native/src/Thread.c index d310269d..aa08bc47 100644 --- a/src/DNA/native/src/Thread.c +++ b/src/DNA/native/src/Thread.c @@ -36,6 +36,8 @@ static tThread *pCurrentThread; U32 Internal_Debugger_Resume_Check(PTR pThis_, PTR pParams, PTR pReturnValue, tAsyncCall *pAsync) { if (releaseBreakPoint) { + log_f(1, "Resetting breakpoint state.\n"); + releaseBreakPoint = 0; waitingOnBreakPoint = 0; return 1; @@ -47,6 +49,7 @@ U32 Internal_Debugger_Resume_Check(PTR pThis_, PTR pParams, PTR pReturnValue, tA tThread* Thread() { static U32 threadID = 0; tThread *pThis; + tThread *pThread; // Create thread and initial method state. This is allocated on the managed heap, and // mark as undeletable. When the thread exits, it was marked as deletable. @@ -64,44 +67,62 @@ tThread* Thread() { pThis->state = THREADSTATE_UNSTARTED; // Allocate the first chunk of thread-local stack - pThis->pThreadStack = TMALLOC(tThreadStack); + pThis->pThreadStack = TMALLOC(1, tThreadStack); pThis->pThreadStack->ofs = 0; pThis->pThreadStack->pNext = NULL; + pThread = pAllThreads; + + log_f(1, "Creating thread %d.\n", (int)pThis->threadID); + + // FIFO + /*if (pThread == NULL) { + pAllThreads = pThis; + } + else { + while (pThread->pNextThread != NULL) { + pThread = pThread->pNextThread; + } + pThread->pNextThread = pThis; + }*/ + + // LIFO // Add to list of all thread - pThis->pNextThread = pAllThreads; - pAllThreads = pThis; + pThis->pNextThread = pAllThreads; + pAllThreads = pThis; return pThis; } -void* Thread_StackAlloc(tThread *pThread, U32 size) { +PTR Thread_StackAlloc(tThread *pThread, U32 size) { tThreadStack *pStack = pThread->pThreadStack; - void *pAddr = pStack->memory + pStack->ofs; + PTR pAddr = pStack->memory + pStack->ofs; #if _DEBUG *(U32*)pAddr = 0xabababab; ((U32*)pAddr)++; - pStack->ofs += 4; + pStack->ofs += sizeof(U32); #endif pStack->ofs += size; if (pStack->ofs > THREADSTACK_CHUNK_SIZE) { - Crash("Thread-local stack is too large"); + Crash("Thread-local stack is too large: size = %u", pStack->ofs); } #if _DEBUG memset(pAddr, 0xcd, size); - *(U32*)(((char*)pAddr) + size) = 0xfbfbfbfb; - pStack->ofs += 4; + *(U32*)(pAddr + size) = 0xfbfbfbfb; + pStack->ofs += sizeof(U32); #endif return pAddr; } -void Thread_StackFree(tThread *pThread, void *pAddr) { +void Thread_StackFree(tThread *pThread, PTR pAddr) { tThreadStack *pStack = pThread->pThreadStack; #if _DEBUG ((U32*)pAddr)--; - memset(pAddr, 0xfe, pStack->ofs - (U32)(((unsigned char*)pAddr) - pStack->memory)); + Assert(pAddr >= pStack->memory); + Assert(pStack->ofs >= (U32)(pAddr - pStack->memory)); + memset(pAddr, 0xfe, pStack->ofs - (U32)(pAddr - pStack->memory)); #endif - pStack->ofs = (U32)(((unsigned char*)pAddr) - pStack->memory); + pStack->ofs = (U32)(pAddr - pStack->memory); } void Thread_SetEntryPoint(tThread *pThis, tMetaData *pMetaData, IDX_TABLE entryPointToken, PTR params, U32 paramBytes) { @@ -137,12 +158,13 @@ I32 Thread_Execute() { U32 minSleepTime = 0xffffffff; I32 threadExitValue; + log_f(1, "Executing thread %d.\n", (int)pThread->threadID); status = JIT_Execute(pThread, 100); switch (status) { case THREAD_STATUS_EXIT: threadExitValue = pThread->threadExitValue; - log_f(1, "Thread ID#%d exited. Return value: %d\n", (int)pThread->threadID, (int)threadExitValue); + log_f(1, "Thread ID#:%d exited. Return value: %d\n", (int)pThread->threadID, (int)threadExitValue); // Remove the current thread from the running threads list. // Note that this list may have changed since before the call to JIT_Execute(). { @@ -175,6 +197,7 @@ I32 Thread_Execute() { pThread = pThread->pNextThread; } if (canExit) { + log_f(1, "No more threads to run. Quitting.\n"); return threadExitValue; } } @@ -234,6 +257,8 @@ I32 Thread_Execute() { break; } + log_f(1, "Thread ID#%d is blocked on the debugger. Exiting the loop.\n", (int)pThread->threadID); + return 0; } else { @@ -267,8 +292,9 @@ I32 Thread_Execute() { break; } if (pThread == pPrevThread) { + log_f(1, "All threads blocked exiting exec loop.\n"); // When it gets here, it means that all threads are currently blocked. - //printf("All blocked; sleep(%d)\n", minSleepTime); + // printf("All blocked; sleep(%d)\n", minSleepTime); // Execution needs to unwind if everything is blocked in javascript or it will // hang the browser's main thread, we need to schedule a call back into this method at a later time return minSleepTime; diff --git a/src/DNA/native/src/Thread.h b/src/DNA/native/src/Thread.h index db22e9af..c0a5014e 100644 --- a/src/DNA/native/src/Thread.h +++ b/src/DNA/native/src/Thread.h @@ -29,7 +29,7 @@ typedef struct tThreadStack_ tThreadStack; #include "Heap.h" #include "Types.h" -#define THREADSTACK_CHUNK_SIZE 10000 +#define THREADSTACK_CHUNK_SIZE 50000 struct tThreadStack_ { // This chunk of stack memory @@ -107,8 +107,8 @@ tThread* Thread(); void Thread_SetEntryPoint(tThread *pThis, tMetaData *pMetaData, IDX_TABLE entryPointToken, PTR params, U32 paramBytes); I32 Thread_Execute(); tThread* Thread_GetCurrent(); -void* Thread_StackAlloc(tThread *pThread, U32 size); -void Thread_StackFree(tThread *pThread, void *pAddr); +PTR Thread_StackAlloc(tThread *pThread, U32 size); +void Thread_StackFree(tThread *pThread, PTR pAddr); void Thread_GetHeapRoots(tHeapRoots *pHeapRoots); diff --git a/src/DNA/native/src/Type.c b/src/DNA/native/src/Type.c index 37750ec6..099ee077 100644 --- a/src/DNA/native/src/Type.c +++ b/src/DNA/native/src/Type.c @@ -123,7 +123,7 @@ static void CreateNewArrayType(tMD_TypeDef *pNewArrayType, tMD_TypeDef *pElement orgNumInterfaces = pNewArrayType->numInterfaces; pNewArrayType->numInterfaces += 3; - pAllIMs = (tInterfaceMap*)mallocForever(pNewArrayType->numInterfaces * sizeof(tInterfaceMap)); + pAllIMs = TMALLOCFOREVER(pNewArrayType->numInterfaces, tInterfaceMap); memcpy(pAllIMs, pNewArrayType->pInterfaceMaps, orgNumInterfaces * sizeof(tInterfaceMap)); pNewArrayType->pInterfaceMaps = pAllIMs; @@ -132,7 +132,7 @@ static void CreateNewArrayType(tMD_TypeDef *pNewArrayType, tMD_TypeDef *pElement pInterfaceT = Generics_GetGenericTypeFromCoreType(types[TYPE_SYSTEM_COLLECTIONS_GENERIC_IENUMERABLE_T], 1, &pElementType); pInterfaceMap->pInterface = pInterfaceT; pInterfaceMap->pVTableLookup = NULL; - pInterfaceMap->ppMethodVLookup = mallocForever(pInterfaceT->numVirtualMethods * sizeof(tMD_MethodDef*)); + pInterfaceMap->ppMethodVLookup = TMALLOCFOREVER(pInterfaceT->numVirtualMethods, tMD_MethodDef*); pMethod = Generics_GetMethodDefFromCoreMethod(ppGenericArrayMethods[GENERICARRAYMETHODS_Internal_GetGenericEnumerator], pNewArrayType, 1, &pElementType); pInterfaceMap->ppMethodVLookup[0] = pMethod; @@ -141,7 +141,7 @@ static void CreateNewArrayType(tMD_TypeDef *pNewArrayType, tMD_TypeDef *pElement pInterfaceT = Generics_GetGenericTypeFromCoreType(types[TYPE_SYSTEM_COLLECTIONS_GENERIC_ICOLLECTION_T], 1, &pElementType); pInterfaceMap->pInterface = pInterfaceT; pInterfaceMap->pVTableLookup = NULL; - pInterfaceMap->ppMethodVLookup = mallocForever(pInterfaceT->numVirtualMethods * sizeof(tMD_MethodDef*)); + pInterfaceMap->ppMethodVLookup = TMALLOCFOREVER(pInterfaceT->numVirtualMethods, tMD_MethodDef*); pInterfaceMap->ppMethodVLookup[0] = ppGenericArrayMethods[GENERICARRAYMETHODS_get_Length]; pInterfaceMap->ppMethodVLookup[1] = ppGenericArrayMethods[GENERICARRAYMETHODS_get_IsReadOnly]; pInterfaceMap->ppMethodVLookup[2] = Generics_GetMethodDefFromCoreMethod(ppGenericArrayMethods[GENERICARRAYMETHODS_Internal_GenericAdd], pNewArrayType, 1, &pElementType); @@ -155,7 +155,7 @@ static void CreateNewArrayType(tMD_TypeDef *pNewArrayType, tMD_TypeDef *pElement pInterfaceT = Generics_GetGenericTypeFromCoreType(types[TYPE_SYSTEM_COLLECTIONS_GENERIC_ILIST_T], 1, &pElementType); //, ppClassTypeArgs, ppMethodTypeArgs); pInterfaceMap->pInterface = pInterfaceT; pInterfaceMap->pVTableLookup = NULL; - pInterfaceMap->ppMethodVLookup = mallocForever(pInterfaceT->numVirtualMethods * sizeof(tMD_MethodDef*)); + pInterfaceMap->ppMethodVLookup = TMALLOCFOREVER(pInterfaceT->numVirtualMethods, tMD_MethodDef*); pInterfaceMap->ppMethodVLookup[0] = Generics_GetMethodDefFromCoreMethod(ppGenericArrayMethods[GENERICARRAYMETHODS_Internal_GenericIndexOf], pNewArrayType, 1, &pElementType); pInterfaceMap->ppMethodVLookup[1] = Generics_GetMethodDefFromCoreMethod(ppGenericArrayMethods[GENERICARRAYMETHODS_Internal_GenericInsert], pNewArrayType, 1, &pElementType); pInterfaceMap->ppMethodVLookup[2] = ppGenericArrayMethods[GENERICARRAYMETHODS_Internal_GenericRemoveAt]; @@ -184,11 +184,11 @@ tMD_TypeDef* Type_GetArrayTypeDef(tMD_TypeDef *pElementType, tMD_TypeDef **ppCla // Must have this new array type in the linked-list of array types before it is initialised // (otherwise it can get stuck in an infinite loop) - pIterArrays = TMALLOCFOREVER(tArrayTypeDefs); + pIterArrays = TMALLOCFOREVER(1, tArrayTypeDefs); pIterArrays->pElementType = pElementType; pIterArrays->pNext = pArrays; pArrays = pIterArrays; - pIterArrays->pArrayType = TMALLOC(tMD_TypeDef); + pIterArrays->pArrayType = TMALLOCFOREVER(1, tMD_TypeDef); CreateNewArrayType(pIterArrays->pArrayType, pElementType, ppClassTypeArgs, ppMethodTypeArgs); return pIterArrays->pArrayType; @@ -321,11 +321,11 @@ tMD_TypeDef* Type_GetTypeFromSig(tMetaData *pMetaData, SIG *pSig, tMD_TypeDef ** case ELEMENT_TYPE_MVAR: entry = MetaData_DecodeSigEntry(pSig); // This is the argument number - if (ppMethodTypeArgs == NULL) { + if (ppMethodTypeArgs != NULL) { + return ppMethodTypeArgs[entry]; + } else { // Can't do anything sensible, as we don't have any type args return NULL; - } else { - return ppMethodTypeArgs[entry]; } default: @@ -346,6 +346,7 @@ struct tTypeInit_ { U8 stackSize; U8 arrayElementSize; U8 instanceMemSize; + U8 index; }; static char mscorlib[] = "mscorlib"; @@ -357,71 +358,72 @@ static char SystemIO[] = "System.IO"; static char SystemGlobalization[] = "System.Globalization"; static tTypeInit typeInit[] = { - {mscorlib, System, "Object", EVALSTACK_O, 4, 4, 0}, - {mscorlib, System, "Array", EVALSTACK_O, 4, 4, 0}, - {mscorlib, System, "Void", EVALSTACK_O, 4, 4, 0}, - {mscorlib, System, "Boolean", EVALSTACK_INT32, 4, 4, 4}, - {mscorlib, System, "Byte", EVALSTACK_INT32, 4, 1, 4}, - {mscorlib, System, "SByte", EVALSTACK_INT32, 4, 1, 4}, - {mscorlib, System, "Char", EVALSTACK_INT32, 4, 2, 4}, - {mscorlib, System, "Int16", EVALSTACK_INT32, 4, 2, 4}, - {mscorlib, System, "Int32", EVALSTACK_INT32, 4, 4, 4}, - {mscorlib, System, "String", EVALSTACK_O, 4, 4, 0}, - {mscorlib, System, "IntPtr", EVALSTACK_PTR, sizeof(void*), sizeof(void*), 0}, - {mscorlib, System, "RuntimeFieldHandle", EVALSTACK_O, 4, 4, 0}, - {mscorlib, System, "InvalidCastException", EVALSTACK_O, 0, 0, 0}, - {mscorlib, System, "UInt32", EVALSTACK_INT32, 4, 4, 4}, - {mscorlib, System, "UInt16", EVALSTACK_INT32, 4, 2, 4}, - {NULL, NULL, (char*)TYPE_SYSTEM_CHAR, 0, 0, 0, 0}, - {NULL, NULL, (char*)TYPE_SYSTEM_OBJECT, 0, 0, 0, 0}, - {mscorlib, SystemCollectionsGeneric, "IEnumerable`1", EVALSTACK_O, 4, 4, 0}, - {mscorlib, SystemCollectionsGeneric, "ICollection`1", EVALSTACK_O, 4, 4, 0}, - {mscorlib, SystemCollectionsGeneric, "IList`1", EVALSTACK_O, 4, 4, 0}, - {mscorlib, System, "MulticastDelegate", EVALSTACK_O, 0, 0, 0}, - {mscorlib, System, "NullReferenceException", EVALSTACK_O, 0, 0, 0}, - {mscorlib, System, "Single", EVALSTACK_F32, 4, 4, 4}, - {mscorlib, System, "Double", EVALSTACK_F64, 8, 8, 8}, - {mscorlib, System, "Int64", EVALSTACK_INT64, 8, 8, 8}, - {mscorlib, System, "UInt64", EVALSTACK_INT64, 8, 8, 8}, - {mscorlib, System, "RuntimeType", EVALSTACK_O, 4, 4, sizeof(tRuntimeType)}, - {mscorlib, System, "Type", EVALSTACK_O, 4, 4, 0}, - {mscorlib, System, "RuntimeTypeHandle", EVALSTACK_O, 4, 4, 0}, - {mscorlib, System, "RuntimeMethodHandle", EVALSTACK_O, 4, 4, 0}, - {mscorlib, System, "Enum", EVALSTACK_VALUETYPE, 0, 0, 0}, - {NULL, NULL, (char*)TYPE_SYSTEM_STRING, 0, 0, 0, 0}, - {NULL, NULL, (char*)TYPE_SYSTEM_INT32, 0, 0, 0, 0}, - {mscorlib, SystemThreading, "Thread", EVALSTACK_O, 4, 4, sizeof(tThread)}, - {mscorlib, SystemThreading, "ThreadStart", EVALSTACK_O, 0, 0, 0}, - {mscorlib, SystemThreading, "ParameterizedThreadStart", EVALSTACK_O, 0, 0, 0}, - {mscorlib, System, "WeakReference", EVALSTACK_O, 4, 4, 0}, - {mscorlib, SystemIO, "FileMode", EVALSTACK_O, 0, 0, 0}, - {mscorlib, SystemIO, "FileAccess", EVALSTACK_O, 0, 0, 0}, - {mscorlib, SystemIO, "FileShare", EVALSTACK_O, 0, 0, 0}, - {NULL, NULL, (char*)TYPE_SYSTEM_BYTE, 0, 0, 0, 0}, - {mscorlib, SystemGlobalization, "UnicodeCategory", EVALSTACK_INT32, 0, 0, 0}, - {mscorlib, System, "OverflowException", EVALSTACK_O, 0, 0, 0}, - {mscorlib, System, "PlatformID", EVALSTACK_INT32, 0, 0, 0}, - {mscorlib, SystemIO, "FileAttributes", EVALSTACK_O, 0, 0, 0}, - {mscorlib, System, "UIntPtr", EVALSTACK_PTR, sizeof(void*), sizeof(void*), 0}, - {mscorlib, System, "Nullable`1", EVALSTACK_VALUETYPE, 0, 0, 0}, - {NULL, NULL, (char*)TYPE_SYSTEM_TYPE, 0, 0, 0, 0}, - {mscorlib, SystemReflection, "PropertyInfo", EVALSTACK_O, 4, 4, sizeof(tPropertyInfo)}, - {mscorlib, SystemReflection, "MethodInfo", EVALSTACK_O, 4, 4, sizeof(tMethodInfo)}, - {mscorlib, SystemReflection, "MethodBase", EVALSTACK_O, 4, 4, sizeof(tMethodBase)}, - {mscorlib, SystemReflection, "MemberInfo", EVALSTACK_O, 4, 4, sizeof(tMemberInfo)}, - {mscorlib, System, "Attribute", EVALSTACK_O, 4, 4, sizeof(tSystemAttribute)}, - {mscorlib, SystemReflection, "InternalCustomAttributeInfo", EVALSTACK_VALUETYPE, sizeof(tInternalCustomAttributeInfo), sizeof(tInternalCustomAttributeInfo), sizeof(tInternalCustomAttributeInfo) }, + {mscorlib, System, "Object", EVALSTACK_O, 4, 4, 0 , TYPE_SYSTEM_OBJECT }, // 0 + {mscorlib, System, "Array", EVALSTACK_O, 4, 4, 0 , TYPE_SYSTEM_ARRAY_NO_TYPE }, // 1 + {mscorlib, System, "Void", EVALSTACK_O, 4, 4, 0 , TYPE_SYSTEM_VOID }, // 2 + {mscorlib, System, "Boolean", EVALSTACK_INT32, 4, 4, 4 , TYPE_SYSTEM_BOOLEAN }, // 3 + {mscorlib, System, "Byte", EVALSTACK_INT32, 4, 1, 4 , TYPE_SYSTEM_BYTE }, // 4 + {mscorlib, System, "SByte", EVALSTACK_INT32, 4, 1, 4 , TYPE_SYSTEM_SBYTE }, // 5 + {mscorlib, System, "Char", EVALSTACK_INT32, 4, 2, 4 , TYPE_SYSTEM_CHAR }, // 6 + {mscorlib, System, "Int16", EVALSTACK_INT32, 4, 2, 4 , TYPE_SYSTEM_INT16 }, // 7 + {mscorlib, System, "Int32", EVALSTACK_INT32, 4, 4, 4 , TYPE_SYSTEM_INT32 }, // 8 + {mscorlib, System, "String", EVALSTACK_O, 4, 4, 0 , TYPE_SYSTEM_STRING }, // 9 + {mscorlib, System, "IntPtr", EVALSTACK_PTR, sizeof(void*), sizeof(void*), 0 , TYPE_SYSTEM_INTPTR }, // 10 + {mscorlib, System, "RuntimeFieldHandle", EVALSTACK_O, 4, 4, 0 , TYPE_SYSTEM_RUNTIMEFIELDHANDLE }, // 11 + {mscorlib, System, "InvalidCastException", EVALSTACK_O, 0, 0, 0 , TYPE_SYSTEM_INVALIDCASTEXCEPTION }, // 12 + {mscorlib, System, "UInt32", EVALSTACK_INT32, 4, 4, 4 , TYPE_SYSTEM_UINT32 }, // 13 + {mscorlib, System, "UInt16", EVALSTACK_INT32, 4, 2, 4 , TYPE_SYSTEM_UINT16 }, // 14 + {NULL, NULL, (char*)TYPE_SYSTEM_CHAR, 0, 0, 0, 0 , TYPE_SYSTEM_ARRAY_CHAR }, // 15 + {NULL, NULL, (char*)TYPE_SYSTEM_OBJECT, 0, 0, 0, 0 , TYPE_SYSTEM_ARRAY_OBJECT }, // 16 + {mscorlib, SystemCollectionsGeneric, "IEnumerable`1", EVALSTACK_O, 4, 4, 0 , TYPE_SYSTEM_COLLECTIONS_GENERIC_IENUMERABLE_T }, // 17 + {mscorlib, SystemCollectionsGeneric, "ICollection`1", EVALSTACK_O, 4, 4, 0 , TYPE_SYSTEM_COLLECTIONS_GENERIC_ICOLLECTION_T }, // 18 + {mscorlib, SystemCollectionsGeneric, "IList`1", EVALSTACK_O, 4, 4, 0 , TYPE_SYSTEM_COLLECTIONS_GENERIC_ILIST_T }, // 19 + {mscorlib, System, "MulticastDelegate", EVALSTACK_O, 0, 0, 0 , TYPE_SYSTEM_MULTICASTDELEGATE }, // 20 + {mscorlib, System, "NullReferenceException", EVALSTACK_O, 0, 0, 0 , TYPE_SYSTEM_NULLREFERENCEEXCEPTION }, // 21 + {mscorlib, System, "Single", EVALSTACK_F32, 4, 4, 4 , TYPE_SYSTEM_SINGLE }, // 22 + {mscorlib, System, "Double", EVALSTACK_F64, 8, 8, 8 , TYPE_SYSTEM_DOUBLE }, // 23 + {mscorlib, System, "Int64", EVALSTACK_INT64, 8, 8, 8 , TYPE_SYSTEM_INT64 }, // 24 + {mscorlib, System, "UInt64", EVALSTACK_INT64, 8, 8, 8 , TYPE_SYSTEM_UINT64 }, // 25 + {mscorlib, System, "RuntimeType", EVALSTACK_O, 4, 4, sizeof(tRuntimeType) , TYPE_SYSTEM_RUNTIMETYPE }, // 26 + {mscorlib, System, "Type", EVALSTACK_O, 4, 4, 0 , TYPE_SYSTEM_TYPE }, // 27 + {mscorlib, System, "RuntimeTypeHandle", EVALSTACK_O, 4, 4, 0 , TYPE_SYSTEM_RUNTIMETYPEHANDLE }, // 28 + {mscorlib, System, "RuntimeMethodHandle", EVALSTACK_O, 4, 4, 0 , TYPE_SYSTEM_RUNTIMEMETHODHANDLE }, // 29 + {mscorlib, System, "Enum", EVALSTACK_VALUETYPE, 0, 0, 0 , TYPE_SYSTEM_ENUM }, // 30 + {NULL, NULL, (char*)TYPE_SYSTEM_STRING, 0, 0, 0, 0 , TYPE_SYSTEM_ARRAY_STRING }, // 31 + {NULL, NULL, (char*)TYPE_SYSTEM_INT32, 0, 0, 0, 0 , TYPE_SYSTEM_ARRAY_INT32 }, // 32 + {mscorlib, SystemThreading, "Thread", EVALSTACK_O, 4, 4, sizeof(tThread) , TYPE_SYSTEM_THREADING_THREAD }, // 33 + {mscorlib, SystemThreading, "ThreadStart", EVALSTACK_O, 0, 0, 0 , TYPE_SYSTEM_THREADING_THREADSTART }, // 34 + {mscorlib, SystemThreading, "ParameterizedThreadStart", EVALSTACK_O, 0, 0, 0 , TYPE_SYSTEM_THREADING_PARAMETERIZEDTHREADSTART }, // 35 + {mscorlib, System, "WeakReference", EVALSTACK_O, 4, 4, 0 , TYPE_SYSTEM_WEAKREFERENCE }, // 36 + {mscorlib, SystemIO, "FileMode", EVALSTACK_INT32, 4, 4, 4 , TYPE_SYSTEM_IO_FILEMODE }, // 37 + {mscorlib, SystemIO, "FileAccess", EVALSTACK_INT32, 4, 4, 4 , TYPE_SYSTEM_IO_FILEACCESS }, // 38 + {mscorlib, SystemIO, "FileShare", EVALSTACK_INT32, 4, 4, 4 , TYPE_SYSTEM_IO_FILESHARE }, // 39 + {NULL, NULL, (char*)TYPE_SYSTEM_BYTE, 0, 0, 0, 0 , TYPE_SYSTEM_ARRAY_BYTE }, // 40 + {mscorlib, SystemGlobalization, "UnicodeCategory", EVALSTACK_INT32, 4, 4, 4 , TYPE_SYSTEM_GLOBALIZATION_UNICODECATEGORY }, // 41 + {mscorlib, System, "OverflowException", EVALSTACK_O, 0, 0, 0 , TYPE_SYSTEM_OVERFLOWEXCEPTION }, // 42 + {mscorlib, System, "PlatformID", EVALSTACK_INT32, 4, 4, 4 , TYPE_SYSTEM_PLATFORMID }, // 43 + {mscorlib, SystemIO, "FileAttributes", EVALSTACK_INT32, 4, 4, 4 , TYPE_SYSTEM_IO_FILESYSTEMATTRIBUTES }, // 44 + {mscorlib, System, "UIntPtr", EVALSTACK_PTR, sizeof(void*), sizeof(void*), 0 , TYPE_SYSTEM_UINTPTR }, // 45 + {mscorlib, System, "Nullable`1", EVALSTACK_VALUETYPE, 0, 0, 0 , TYPE_SYSTEM_NULLABLE }, // 46 + {NULL, NULL, (char*)TYPE_SYSTEM_TYPE, 0, 0, 0, 0 , TYPE_SYSTEM_ARRAY_TYPE }, // 47 + {mscorlib, SystemReflection, "PropertyInfo", EVALSTACK_O, 4, 4, sizeof(tPropertyInfo) , TYPE_SYSTEM_REFLECTION_PROPERTYINFO }, // 48 + {mscorlib, SystemReflection, "MethodInfo", EVALSTACK_O, 4, 4, sizeof(tMethodInfo) , TYPE_SYSTEM_REFLECTION_METHODINFO }, // 49 + {mscorlib, SystemReflection, "MethodBase", EVALSTACK_O, 4, 4, sizeof(tMethodBase) , TYPE_SYSTEM_REFLECTION_METHODBASE }, // 50 + {mscorlib, SystemReflection, "MemberInfo", EVALSTACK_O, 4, 4, sizeof(tMemberInfo) , TYPE_SYSTEM_REFLECTION_MEMBERINFO }, // 51 + {mscorlib, System, "Attribute", EVALSTACK_O, 4, 4, sizeof(tSystemAttribute) , TYPE_SYSTEM_ATTRIBUTE }, // 52 + {mscorlib, SystemReflection, "InternalCustomAttributeInfo", EVALSTACK_VALUETYPE, sizeof(tInternalCustomAttributeInfo), + sizeof(tInternalCustomAttributeInfo), sizeof(tInternalCustomAttributeInfo) , TYPE_SYSTEM_REFLECTION_INTERNALCUSTOMATTRIBUTEINFO }, // 53 + {mscorlib, SystemGlobalization, "NumberStyles", EVALSTACK_INT32, 4, 4, 4 , TYPE_SYSTEM_GLOBALIZATION_NUMBERSTYLES }, // 54 }; int CorLibDone = 0; void Type_Init() { - U32 i; - // Build all the types needed by the interpreter. numInitTypes = sizeof(typeInit) / sizeof(typeInit[0]); - types = (tMD_TypeDef**)mallocForever(numInitTypes * sizeof(tMD_TypeDef*)); - for (i=0; iinstanceMemSize = typeInit[i].instanceMemSize; } } - for (i=0; isignature, &sigLen); i = MetaData_DecodeSigEntry(&sig); // Don't care about this - if (i & SIG_METHODDEF_GENERIC) { + if (i & SIG_CALLCONV_GENERIC) { MetaData_DecodeSigEntry(&sig); } numSigParams = MetaData_DecodeSigEntry(&sig); @@ -500,6 +502,9 @@ U32 Type_IsDerivedFromOrSame(tMD_TypeDef *pBaseType, tMD_TypeDef *pTestType) { return 1; } MetaData_Fill_TypeDef(pTestType, NULL, NULL); + if (pTestType->pTypeDef != NULL && pTestType->pTypeDef == pBaseType->pTypeDef) { + return 1; + } pTestType = pTestType->pParent; } return 0; @@ -527,4 +532,4 @@ HEAP_PTR Type_GetTypeObject(tMD_TypeDef *pTypeDef) { pTypeDef->typeObject = RuntimeType_New(pTypeDef); } return pTypeDef->typeObject; -} \ No newline at end of file +} diff --git a/src/DNA/native/src/Type.h b/src/DNA/native/src/Type.h index 868f06cc..46dc0cbb 100644 --- a/src/DNA/native/src/Type.h +++ b/src/DNA/native/src/Type.h @@ -109,6 +109,7 @@ extern tMD_TypeDef **types; #define TYPE_SYSTEM_REFLECTION_MEMBERINFO 51 #define TYPE_SYSTEM_ATTRIBUTE 52 #define TYPE_SYSTEM_REFLECTION_INTERNALCUSTOMATTRIBUTEINFO 53 +#define TYPE_SYSTEM_GLOBALIZATION_NUMBERSTYLES 54 //U32 Type_IsMethod(tMD_MethodDef *pMethod, STRING name, tMD_TypeDef *pReturnType, U32 numParams, ...); U32 Type_IsMethod(tMD_MethodDef *pMethod, STRING name, tMD_TypeDef *pReturnType, U32 numParams, U8 *pParamTypeIndexs); diff --git a/src/DNA/native/src/Types.h b/src/DNA/native/src/Types.h index d49fac9e..d6cd9675 100644 --- a/src/DNA/native/src/Types.h +++ b/src/DNA/native/src/Types.h @@ -21,15 +21,17 @@ #if !defined(__TYPES_H) #define __TYPES_H +#include + // Indexes into the user-string heap -typedef unsigned int IDX_USERSTRINGS; +typedef uint32_t IDX_USERSTRINGS; // Index into a table. most significant byte stores which table, other 3 bytes store index -typedef unsigned int IDX_TABLE; +typedef uint32_t IDX_TABLE; // Flag types -typedef unsigned int FLAGS32; -typedef unsigned short FLAGS16; +typedef uint32_t FLAGS32; +typedef uint16_t FLAGS16; // Pointers typedef unsigned char* HEAP_PTR; @@ -41,17 +43,17 @@ typedef unsigned char* BLOB_; typedef unsigned char* GUID_; // Int types -typedef long long I64; -typedef unsigned long long U64; +typedef int64_t I64; +typedef uint64_t U64; //#ifdef _WIN32 -typedef int I32; -typedef unsigned int U32; -typedef short I16; -typedef unsigned short U16; -typedef char I8; -typedef unsigned char U8; +typedef int32_t I32; +typedef uint32_t U32; +typedef int16_t I16; +typedef uint16_t U16; +typedef int8_t I8; // define as int8 and not as char (causing sign mismatch on different compilers) +typedef uint8_t U8; //#endif // _WIN32 @@ -72,7 +74,8 @@ union uConvFloat_ { }; // other types! -typedef unsigned short CHAR2; + +typedef uint16_t CHAR2; typedef struct tAsyncCall_ tAsyncCall; diff --git a/src/DNA/native/src/dna.c b/src/DNA/native/src/dna.c index a5a23ed1..f3409bf6 100644 --- a/src/DNA/native/src/dna.c +++ b/src/DNA/native/src/dna.c @@ -18,6 +18,8 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. +#include + #include "Compat.h" #include "Sys.h" @@ -30,57 +32,11 @@ #include "MethodState.h" #include "JSInterop.h" -static void ShowUsage() { - printf("Usage:\n"); - printf("\tdna [-v] <.Net executable to execute> [.Net executable arguments]\n"); - printf("\n"); - printf("\t-v : Verbose output of files loaded and GC statistics\n"); - printf("\t-vv : More verbose output, including methods JITted and types/arrays/generics use\n"); - printf("\n"); - exit(1); -} - -int main(int argc, char **argp) { - tCLIFile *pCLIFile; - char *pFileName; - U32 i; - I32 retValue; #ifdef DIAG_TOTAL_TIME - U64 startTime; +U64 startTime; #endif - if (argc < 2) { - ShowUsage(); - } - - // Read any flags passed in - for (i=1; i < (U32)argc; i++) { - if (argp[i][0] == '-') { - U32 j; - - for (j=1; ; j++) { - switch (argp[i][j]) { - case 0: - goto doneArgs; - case 'v': - logLevel++; - break; - default: - Crash("Invalid argument: -%c", argp[i][1]); - } - } -doneArgs:; - } else { - break; - } - } - - JIT_Execute_Init(); - MetaData_Init(); - Type_Init(); - Heap_Init(); - Finalizer_Init(); - Socket_Init(); +void Diag_Init() { #ifdef DIAG_OPCODE_TIMES #ifdef _WIN32 @@ -92,89 +48,106 @@ doneArgs:; memset(opcodeTimes, 0, sizeof(opcodeTimes)); #endif -#ifdef DIAG_OPCODE_USE +#ifdef DIAG_OPCODE_USES memset(opcodeNumUses, 0, sizeof(opcodeNumUses)); #endif - pFileName = argp[i]; - - pCLIFile = CLIFile_Load(pFileName); - #ifdef DIAG_TOTAL_TIME startTime = microTime(); #endif +} - if (pCLIFile->entryPoint) { - retValue = CLIFile_Execute(pCLIFile, argc - i, argp + i); - } else { - printf("File %s has no entry point, skipping execution\n", pFileName); - retValue = 0; - } +void Diag_Print() { + +#ifdef DIAG_CALL_STACK + printf("\nCall stack buffer:\n\n"); + PrintCallStackBuffer(); + printf("\n"); +#endif #ifdef DIAG_TOTAL_TIME - printf("Total execution time = %d ms\n", (int)((microTime() - startTime) / 1000)); + printf("Total execution time = %.3f sec\n", (microTime() - startTime) / 1000000.0); #endif #ifdef DIAG_GC - printf("Total GC time = %d ms\n", (int)(gcTotalTime / 1000)); + printf("Total GC time = %llu ms\n", gcTotalTime / 1000); #endif #ifdef DIAG_METHOD_CALLS +// The default sort is by method call counts, unless redefined below: +//#define SORT_BY_TOTAL_TIME // sort by method total time (inclusive) +//#define SORT_BY_START_TIME // sort by method start time (call order) +//#define SORT_BY_HEAP_ALLOC // sort by method heap alloc count +//#define SORT_BY_PARAMS_STACK // sort by method params stack size +//#define SORT_BY_LOCALS_STACK // sort by method locals stack size +//#define SORT_BY_EVAL_STACK // sort by method eval stack size { - U32 numMethods, i; - I32 howMany = 25; - tMetaData *pCorLib; + tMD_MethodDef* topMethods[50]; // increase if needed + U32 numTop = sizeof(topMethods) / sizeof(topMethods[0]); + for (U32 t = 0; t < numTop; t++) { topMethods[t] = NULL; } + // Report on most-used methods - pCorLib = CLIFile_GetMetaDataForAssembly("mscorlib"); - numMethods = pCorLib->tables.numRows[MD_TABLE_METHODDEF]; - printf("\nCorLib method usage:\n"); - for (; howMany > 0; howMany--) { - tMD_MethodDef *pMethod; - U32 maxCount = 0, maxIndex = 0; - for (i=1; i<=numMethods; i++) { - pMethod = (tMD_MethodDef*)MetaData_GetTableRow(pCorLib, MAKE_TABLE_INDEX(MD_TABLE_METHODDEF, i)); - if (pMethod->callCount > maxCount) { - maxCount = pMethod->callCount; - maxIndex = i; + printf("\nTop %d methods:\n\n", numTop); + + // enumerate and sort all methods in all assemblies + tFilesLoaded *pFiles = CLIFile_GetLoadedAssemblies(); + while (pFiles != NULL) { + tMetaData *pMetaData = pFiles->pCLIFile->pMetaData; + + U32 numMethods = pMetaData->tables.numRows[MD_TABLE_METHODDEF]; + for (U32 i = 1; i <= numMethods; i++) { + tMD_MethodDef *pMethod = (tMD_MethodDef*)MetaData_GetTableRow(pMetaData, MAKE_TABLE_INDEX(MD_TABLE_METHODDEF, i)); + + for (U32 t = 0; t < numTop; t++) { + if (topMethods[t] == NULL) { topMethods[t] = pMethod; } +#if defined(SORT_BY_TOTAL_TIME) + if (topMethods[t]->totalTime < pMethod->totalTime) { +#elif defined(SORT_BY_START_TIME) + if (topMethods[t]->startTime < pMethod->startTime) { +#elif defined(SORT_BY_HEAP_ALLOC) + if (topMethods[t]->heapAlloc < pMethod->heapAlloc) { +#elif defined(SORT_BY_PARAMS_STACK) + if (topMethods[t]->parameterStackSize < pMethod->parameterStackSize) { +#elif defined(SORT_BY_LOCALS_STACK) + if (pMethod->pJITted != NULL && (topMethods[t]->pJITted == NULL || topMethods[t]->pJITted->localsStackSize < pMethod->pJITted->localsStackSize)) { +#elif defined(SORT_BY_EVAL_STACK) + if (pMethod->pJITted != NULL && (topMethods[t]->pJITted == NULL || topMethods[t]->pJITted->maxStack < pMethod->pJITted->maxStack)) { +#else // DEFAULT SORT BY CALL COUNTS + if (topMethods[t]->callCount < pMethod->callCount) { +#endif + memmove(&topMethods[t + 1], &topMethods[t], (numTop - t - 1) * sizeof(topMethods[0])); + topMethods[t] = pMethod; + break; + } } } - pMethod = (tMD_MethodDef*)MetaData_GetTableRow(pCorLib, MAKE_TABLE_INDEX(MD_TABLE_METHODDEF, maxIndex)); - printf("%d: %s (%d)\n", (int)pMethod->callCount, Sys_GetMethodDesc(pMethod), (int)(pMethod->totalTime/1000)); - pMethod->callCount = 0; + + pFiles = pFiles->pNext; } - printf("\n"); - } - { - U32 numMethods, i; - I32 howMany = 25; - tMetaData *pCorLib; - // Report on most-used methods - pCorLib = CLIFile_GetMetaDataForAssembly("mscorlib"); - numMethods = pCorLib->tables.numRows[MD_TABLE_METHODDEF]; - printf("\nCorLib method execution time:\n"); - for (; howMany > 0; howMany--) { - tMD_MethodDef *pMethod; - U64 maxTime = 0; - U32 maxIndex = 0; - for (i=1; i<=numMethods; i++) { - pMethod = (tMD_MethodDef*)MetaData_GetTableRow(pCorLib, MAKE_TABLE_INDEX(MD_TABLE_METHODDEF, i)); - if (pMethod->totalTime > maxTime) { - maxTime = pMethod->totalTime; - maxIndex = i; - } - } - pMethod = (tMD_MethodDef*)MetaData_GetTableRow(pCorLib, MAKE_TABLE_INDEX(MD_TABLE_METHODDEF, maxIndex)); - printf("%d: %s (%d)\n", (int)pMethod->callCount, Sys_GetMethodDesc(pMethod), (int)(pMethod->totalTime/1000)); - pMethod->totalTime = 0; + + for (U32 t = 0; t < numTop; t++) { + tMD_MethodDef *pMethod = topMethods[t]; + char* methodName = pMethod->isFilled ? Sys_GetMethodDesc(pMethod) : (char*)pMethod->name; + printf("%02d: %s\n : calls: %llu", t+1, methodName, pMethod->callCount); + printf(", total: %.3f sec", pMethod->totalTime / 1000000.0); + printf(", max: %f sec", pMethod->maxTime / 1000000.0); + printf(", avg: %f sec", pMethod->totalTime / max(pMethod->callCount, 1) / 1000000.0); + printf(", alloc: %llu", pMethod->heapAlloc); + printf(", params: %u bytes", pMethod->parameterStackSize); + printf(", locals: %u bytes", pMethod->pJITted == NULL ? 0 : pMethod->pJITted->localsStackSize); + printf(", eval stack: %u bytes", pMethod->pJITted == NULL ? 0 : pMethod->pJITted->maxStack); + printf("\n"); } + printf("\n"); } #endif + #ifdef DIAG_OPCODE_TIMES { I32 howMany = 25; U32 i; - printf("\nOpCodes execution time:\n"); + printf("\nJIT OpCodes execution time:\n"); for (; howMany > 0; howMany--) { U64 maxTime = 0; U32 maxIndex = 0; @@ -184,13 +157,17 @@ doneArgs:; maxIndex = i; } } - printf("0x%03x: %dms (used %d times) (ave = %d)\n", - maxIndex, (int)(maxTime / 1000), (int)opcodeNumUses[maxIndex], (int)(maxTime / opcodeNumUses[maxIndex])); + printf("0x%03x: %llu ms", maxIndex, maxTime / 1000); +#ifdef DIAG_OPCODE_USES + printf(" (used %u times) (avg time = %llu)\n", opcodeNumUses[maxIndex], maxTime / opcodeNumUses[maxIndex]); +#endif + printf("\n"); opcodeTimes[maxIndex] = 0; } } #endif -#ifdef DIAG_OPCODE_USE + +#ifdef DIAG_OPCODE_USES { I32 howMany = 25; U32 i, j; @@ -209,8 +186,123 @@ doneArgs:; } } #endif +} + +static void ShowUsage() { + printf("Usage:\n"); + printf("\tdna [-v] <.Net executable to execute> [.Net executable arguments]\n"); + printf("\n"); + printf("\t-v : Verbose output of files loaded and GC statistics\n"); + printf("\t-vv : More verbose output, including methods JITted and types/arrays/generics use\n"); + printf("\n"); + exit(1); +} + +void almost_c99_signal_handler(int sig) { + switch (sig) { + case SIGABRT: + fputs("Caught SIGABRT: usually caused by an abort() or assert()\n", stderr); + break; + case SIGFPE: + fputs("Caught SIGFPE: arithmetic exception, such as divide by zero\n", stderr); + break; + case SIGILL: + fputs("Caught SIGILL: illegal instruction\n", stderr); + break; + case SIGINT: + fputs("Caught SIGINT: interactive attention signal, probably a ctrl+c\n", stderr); + break; + case SIGSEGV: + fputs("Caught SIGSEGV: segfault\n", stderr); + break; + case SIGTERM: + default: + fputs("Caught SIGTERM: a termination request was sent to the program\n", stderr); + break; + } + + Diag_Print(); +} + +void set_signal_handler() { + signal(SIGABRT, almost_c99_signal_handler); + signal(SIGFPE, almost_c99_signal_handler); + signal(SIGILL, almost_c99_signal_handler); + signal(SIGINT, almost_c99_signal_handler); + signal(SIGSEGV, almost_c99_signal_handler); + signal(SIGTERM, almost_c99_signal_handler); +} + +int main(int argc, char **argp) { + tCLIFile *pCLIFile; + char *pFileName; + U32 i; + I32 retValue; + +#ifdef _WIN32 + set_signal_handler(); +#endif + + if (argc < 2) { + ShowUsage(); + } + + // Read any flags passed in + for (i=1; i < (U32)argc; i++) { + if (argp[i][0] == '-') { + U32 j; + + for (j=1; ; j++) { + switch (argp[i][j]) { + case 0: + goto doneArgs; + case 'v': + logLevel++; + break; + default: + Crash("Invalid argument: -%c", argp[i][1]); + } + } +doneArgs:; + } else { + break; + } + } + + JIT_Execute_Init(); + MetaData_Init(); + Type_Init(); + Heap_Init(); + Finalizer_Init(); + Socket_Init(); + + Diag_Init(); + + pFileName = argp[i]; + pCLIFile = CLIFile_Load(pFileName); + + if (pCLIFile->entryPoint) { + retValue = CLIFile_Execute(pCLIFile, argc - i, argp + i); + } else { + printf("File %s has no entry point, skipping execution\n", pFileName); + retValue = 0; + } + + Diag_Print(); //Crash("FINISHED!!!"); +#ifdef DIAG_MEMORY_LEAKS + // cleanup memory + Heap_GarbageCollect(); + Finalizer_Free(); + freeForever(); + +#ifdef _WIN32 + // looking for memory leaks + _CrtDumpMemoryLeaks(); +#endif +#endif + return retValue; }