-Subproject commit 366b5e92d77e4e6e62a6965073097b48a59c1bdc
+Subproject commit bb16afac3deaa1cd8f798668b04b5510cfcd53ba
-Subproject commit c783777342f4d39b58f3c2e6a1659eedf504ac87
+Subproject commit 4f39b930ed66009c54f2326451644ca9d06e4d30
-Subproject commit 0b523fa7e0f2f83cc67e4c19f1f769e68d717562
+Subproject commit f64903c0e069224aaac7de243fa0a3b17684b4dd
-Subproject commit 5b7e0d739fa65bb7b1c2230df875d37a55b74d10
+Subproject commit e49886bd091487abfbf5de934a451c5a8fe7f4c5
[assembly: AssemblyCompany ("Xamarin, Inc.")]
[assembly: AssemblyProduct ("Mono Common Language Infrastructure")]
[assembly: AssemblyCopyright ("Copyright (c) 2015 Xamarin Inc. (http://www.xamarin.com)")]
-[assembly: AssemblyVersion ("4.1.0.0")]
+[assembly: AssemblyVersion ("4.2.1.0")]
[assembly: AssemblyInformationalVersion ("4.0.0.0")]
[assembly: AssemblyFileVersion ("4.0.0.0")]
//
[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.DBNull))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.AcceptRejectRule))]
[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.CommandBehavior))]
[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.CommandType))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.Common.CatalogLocation))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.Common.DataAdapter))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.Common.DataColumnMapping))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.Common.DataColumnMappingCollection))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.Common.DataTableMapping))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.Common.DataTableMappingCollection))]
[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.Common.DbColumn))]
[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.Common.DbCommand))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.Common.DbCommandBuilder))]
[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.Common.DbConnection))]
[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.Common.DbConnectionStringBuilder))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.Common.DbDataAdapter))]
[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.Common.DbDataReader))]
[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.Common.DbDataReaderExtensions))]
[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.Common.DbDataRecord))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.Common.DbDataSourceEnumerator))]
[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.Common.DbEnumerator))]
[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.Common.DbException))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.Common.DbMetaDataCollectionNames))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.Common.DbMetaDataColumnNames))]
[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.Common.DbParameter))]
[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.Common.DbParameterCollection))]
[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.Common.DbProviderFactory))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.Common.DbProviderSpecificTypePropertyAttribute))]
[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.Common.DbTransaction))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.Common.GroupByBehavior))]
[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.Common.IDbColumnSchemaGenerator))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.Common.IdentifierCase))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.Common.RowUpdatedEventArgs))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.Common.RowUpdatingEventArgs))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.Common.SchemaTableColumn))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.Common.SchemaTableOptionalColumn))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.Common.SupportedJoinOperators))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.ConflictOption))]
[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.ConnectionState))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.Constraint))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.ConstraintCollection))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.ConstraintException))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.DBConcurrencyException))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.DataColumn))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.DataColumnChangeEventArgs))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.DataColumnChangeEventHandler))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.DataColumnCollection))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.DataException))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.DataRelation))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.DataRelationCollection))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.DataRow))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.DataRowAction))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.DataRowBuilder))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.DataRowChangeEventArgs))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.DataRowChangeEventHandler))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.DataRowCollection))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.DataRowState))]
[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.DataRowVersion))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.DataRowView))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.DataSet))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.DataSetDateTime))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.DataSysDescriptionAttribute))]
[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.DataTable))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.DataTableClearEventArgs))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.DataTableClearEventHandler))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.DataTableCollection))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.DataTableNewRowEventArgs))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.DataTableNewRowEventHandler))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.DataTableReader))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.DataView))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.DataViewManager))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.DataViewRowState))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.DataViewSetting))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.DataViewSettingCollection))]
[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.DbType))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.DeletedRowInaccessibleException))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.DuplicateNameException))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.EvaluateException))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.FillErrorEventArgs))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.FillErrorEventHandler))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.ForeignKeyConstraint))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.IColumnMapping))]
[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.IColumnMappingCollection))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.IDataAdapter))]
[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.IDataParameter))]
[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.IDataParameterCollection))]
[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.IDataReader))]
[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.IDataRecord))]
[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.IDbCommand))]
[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.IDbConnection))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.IDbDataAdapter))]
[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.IDbDataParameter))]
[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.IDbTransaction))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.ITableMapping))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.ITableMappingCollection))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.InRowChangingEventException))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.InternalDataCollectionBase))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.InvalidConstraintException))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.InvalidExpressionException))]
[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.IsolationLevel))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.KeyRestrictionBehavior))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.LoadOption))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.MappingType))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.MergeFailedEventArgs))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.MergeFailedEventHandler))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.MissingMappingAction))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.MissingPrimaryKeyException))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.MissingSchemaAction))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.NoNullAllowedException))]
[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.ParameterDirection))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.PropertyCollection))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.ReadOnlyException))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.RowNotInTableException))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.Rule))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.SchemaSerializationMode))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.SchemaType))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.SerializationFormat))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.SqlDbType))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.SqlTypes.INullable))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.SqlTypes.SqlAlreadyFilledException))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.SqlTypes.SqlBinary))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.SqlTypes.SqlBoolean))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.SqlTypes.SqlByte))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.SqlTypes.SqlBytes))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.SqlTypes.SqlChars))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.SqlTypes.SqlCompareOptions))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.SqlTypes.SqlDateTime))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.SqlTypes.SqlDecimal))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.SqlTypes.SqlDouble))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.SqlTypes.SqlGuid))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.SqlTypes.SqlInt16))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.SqlTypes.SqlInt32))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.SqlTypes.SqlInt64))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.SqlTypes.SqlMoney))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.SqlTypes.SqlNotFilledException))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.SqlTypes.SqlNullValueException))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.SqlTypes.SqlSingle))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.SqlTypes.SqlString))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.SqlTypes.SqlTruncateException))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.SqlTypes.SqlTypeException))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.SqlTypes.SqlXml))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.SqlTypes.StorageState))]
[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.StateChangeEventArgs))]
[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.StateChangeEventHandler))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.StatementCompletedEventArgs))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.StatementCompletedEventHandler))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.StatementType))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.StrongTypingException))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.SyntaxErrorException))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.UniqueConstraint))]
[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.UpdateRowSource))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.UpdateStatus))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.VersionNotFoundException))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.XmlReadMode))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Data.XmlWriteMode))]
[assembly: AssemblyCompany ("Xamarin, Inc.")]
[assembly: AssemblyProduct ("Mono Common Language Infrastructure")]
[assembly: AssemblyCopyright ("Copyright (c) 2015 Xamarin Inc. (http://www.xamarin.com)")]
-[assembly: AssemblyVersion ("4.0.2.0")]
+[assembly: AssemblyVersion ("4.1.1.0")]
[assembly: AssemblyInformationalVersion ("4.0.0.0")]
[assembly: AssemblyFileVersion ("4.0.0.0")]
[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Diagnostics.StackFrame))]
[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Diagnostics.StackTrace))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Diagnostics.SymbolStore.ISymbolBinder))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Diagnostics.SymbolStore.ISymbolBinder1))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Diagnostics.SymbolStore.ISymbolDocument))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Diagnostics.SymbolStore.ISymbolDocumentWriter))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Diagnostics.SymbolStore.ISymbolMethod))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Diagnostics.SymbolStore.ISymbolNamespace))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Diagnostics.SymbolStore.ISymbolReader))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Diagnostics.SymbolStore.ISymbolScope))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Diagnostics.SymbolStore.ISymbolVariable))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Diagnostics.SymbolStore.ISymbolWriter))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Diagnostics.SymbolStore.SymAddressKind))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Diagnostics.SymbolStore.SymDocumentType))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Diagnostics.SymbolStore.SymLanguageType))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Diagnostics.SymbolStore.SymLanguageVendor))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Diagnostics.SymbolStore.SymbolToken))]
[assembly: AssemblyCompany ("Xamarin, Inc.")]
[assembly: AssemblyProduct ("Mono Common Language Infrastructure")]
[assembly: AssemblyCopyright ("Copyright (c) 2013 Xamarin Inc. (http://www.xamarin.com)")]
-[assembly: AssemblyVersion ("4.1.0.0")]
+[assembly: AssemblyVersion ("4.2.1.0")]
[assembly: AssemblyInformationalVersion ("4.0.0.0")]
[assembly: AssemblyFileVersion ("4.0.0.0")]
[assembly: AssemblyCompany ("Xamarin, Inc.")]
[assembly: AssemblyProduct ("Mono Common Language Infrastructure")]
[assembly: AssemblyCopyright ("Copyright (c) 2015 Xamarin Inc. (http://www.xamarin.com)")]
-[assembly: AssemblyVersion ("4.0.1.0")]
+[assembly: AssemblyVersion ("4.1.1.0")]
[assembly: AssemblyInformationalVersion ("4.0.0.0")]
[assembly: AssemblyFileVersion ("4.0.0.0")]
[assembly: AssemblyCompany ("Xamarin, Inc.")]
[assembly: AssemblyProduct ("Mono Common Language Infrastructure")]
[assembly: AssemblyCopyright ("Copyright (c) 2016 Xamarin Inc. (http://www.xamarin.com)")]
-[assembly: AssemblyVersion ("4.0.0.0")]
+[assembly: AssemblyVersion ("4.0.1.0")]
[assembly: AssemblyInformationalVersion ("4.0.0.0")]
[assembly: AssemblyFileVersion ("4.0.0.0")]
[assembly: AssemblyCompany ("Xamarin, Inc.")]
[assembly: AssemblyProduct ("Mono Common Language Infrastructure")]
[assembly: AssemblyCopyright ("Copyright (c) 2015 Xamarin Inc. (http://www.xamarin.com)")]
-[assembly: AssemblyVersion ("4.1.0.0")]
+[assembly: AssemblyVersion ("4.2.1.0")]
[assembly: AssemblyInformationalVersion ("4.0.0.0")]
[assembly: AssemblyFileVersion ("4.0.0.0")]
[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Net.Sockets.LingerOption))]
[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Net.Sockets.MulticastOption))]
[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Net.Sockets.NetworkStream))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Net.Sockets.ProtocolFamily))]
[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Net.Sockets.ProtocolType))]
[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Net.Sockets.SelectMode))]
[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Net.Sockets.SendPacketsElement))]
[assembly: AssemblyCompany ("Xamarin, Inc.")]
[assembly: AssemblyProduct ("Mono Common Language Infrastructure")]
[assembly: AssemblyCopyright ("Copyright (c) 2016 Xamarin Inc. (http://www.xamarin.com)")]
-[assembly: AssemblyVersion ("4.0.1.0")]
+[assembly: AssemblyVersion ("4.0.3.0")]
[assembly: AssemblyInformationalVersion ("4.0.0.0")]
[assembly: AssemblyFileVersion ("4.0.0.0")]
RESX_RESOURCE_STRING = ../../../../external/corefx/src/System.Runtime.InteropServices.RuntimeInformation/src/Resources/Strings.resx
KEY_FILE = ../../msfinal.pub
-SIGN_FLAGS = /delaysign /keyfile:$(KEY_FILE) /nowarn:1616,1699
+SIGN_FLAGS = /delaysign /keyfile:$(KEY_FILE) /nowarn:1616,1699,436
LIB_REFS = System
LIB_MCS_FLAGS = $(SIGN_FLAGS) /unsafe
{
public static class RuntimeInformation
{
- [DllImport ("__Internal")]
- extern static string mono_get_runtime_build_info ();
-
public static string FrameworkDescription {
get {
- return mono_get_runtime_build_info ();
+ return "Mono " + Mono.Runtime.GetDisplayName ();
}
}
[assembly: AssemblyCompany ("Xamarin, Inc.")]
[assembly: AssemblyProduct ("Mono Common Language Infrastructure")]
[assembly: AssemblyCopyright ("Copyright (c) 2013 Xamarin Inc. (http://www.xamarin.com)")]
-[assembly: AssemblyVersion ("4.1.1.0")]
+[assembly: AssemblyVersion ("4.2.1.0")]
[assembly: AssemblyInformationalVersion ("4.0.0.0")]
[assembly: AssemblyFileVersion ("4.0.0.0")]
[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Runtime.Serialization.DataContractAttribute))]
[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Runtime.Serialization.DataMemberAttribute))]
[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Runtime.Serialization.EnumMemberAttribute))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Runtime.Serialization.ExportOptions))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Runtime.Serialization.ExtensionDataObject))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Runtime.Serialization.IExtensibleDataObject))]
[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Runtime.Serialization.IgnoreDataMemberAttribute))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Runtime.Serialization.InvalidDataContractException))]
[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Runtime.Serialization.KnownTypeAttribute))]
[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Runtime.Serialization.OnDeserializedAttribute))]
[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Runtime.Serialization.OnDeserializingAttribute))]
[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Runtime.Serialization.OnSerializingAttribute))]
[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Runtime.Serialization.SerializationException))]
[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Runtime.Serialization.StreamingContext))]
-[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Runtime.Serialization.InvalidDataContractException))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Runtime.Serialization.StreamingContextStates))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Runtime.Serialization.XmlSerializableServices))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Runtime.Serialization.XPathQueryGenerator))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Runtime.Serialization.XsdDataContractExporter))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Xml.IFragmentCapableXmlDictionaryWriter))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Xml.IStreamProvider))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Xml.IXmlBinaryReaderInitializer))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Xml.IXmlBinaryWriterInitializer))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Xml.IXmlTextReaderInitializer))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Xml.IXmlTextWriterInitializer))]
[assembly: AssemblyCompany ("Xamarin, Inc.")]
[assembly: AssemblyProduct ("Mono Common Language Infrastructure")]
[assembly: AssemblyCopyright ("Copyright (c) 2016 Xamarin Inc. (http://www.xamarin.com)")]
-[assembly: AssemblyVersion ("4.2.0.0")]
+[assembly: AssemblyVersion ("4.3.1.0")]
[assembly: AssemblyInformationalVersion ("4.0.0.0")]
[assembly: AssemblyFileVersion ("4.0.0.0")]
//
[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.Aes))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.AesManaged))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.AsymmetricKeyExchangeDeformatter))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.AsymmetricKeyExchangeFormatter))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.AsymmetricSignatureDeformatter))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.AsymmetricSignatureFormatter))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.CryptoConfig))]
[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.DeriveBytes))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.DES))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.DSA))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.DSAParameters))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.DSASignatureDeformatter))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.DSASignatureFormatter))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.ECCurve))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.ECDiffieHellmanPublicKey))]
[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.ECDsa))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.ECParameters))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.ECPoint))]
[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.HMACMD5))]
[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.HMACSHA1))]
[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.HMACSHA256))]
[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.HMACSHA384))]
[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.HMACSHA512))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.MaskGenerationMethod))]
[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.MD5))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.PKCS1MaskGenerationMethod))]
[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.RandomNumberGenerator))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.RC2))]
[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.Rfc2898DeriveBytes))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.Rijndael))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.RijndaelManaged))]
[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.RSA))]
[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.RSAEncryptionPadding))]
[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.RSAEncryptionPaddingMode))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.RSAOAEPKeyExchangeDeformatter))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.RSAOAEPKeyExchangeFormatter))]
[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.RSAParameters))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.RSAPKCS1KeyExchangeDeformatter))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.RSAPKCS1KeyExchangeFormatter))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.RSAPKCS1SignatureDeformatter))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.RSAPKCS1SignatureFormatter))]
[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.RSASignaturePadding))]
[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.RSASignaturePaddingMode))]
[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.SHA1))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.SHA1Managed))]
[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.SHA256))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.SHA256Managed))]
[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.SHA384))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.SHA384Managed))]
[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.SHA512))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.SHA512Managed))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.SignatureDescription))]
[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.TripleDES))]
-[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.ECCurve))]
-[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.ECParameters))]
-[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.ECPoint))]
[assembly: AssemblyCompany ("Xamarin, Inc.")]
[assembly: AssemblyProduct ("Mono Common Language Infrastructure")]
[assembly: AssemblyCopyright ("Copyright (c) 2015 Xamarin Inc. (http://www.xamarin.com)")]
-[assembly: AssemblyVersion ("4.0.0.0")]
+[assembly: AssemblyVersion ("4.1.1.0")]
[assembly: AssemblyInformationalVersion ("4.0.0.0")]
[assembly: AssemblyFileVersion ("4.0.0.0")]
[assembly: AssemblyCompany ("Xamarin, Inc.")]
[assembly: AssemblyProduct ("Mono Common Language Infrastructure")]
[assembly: AssemblyCopyright ("Copyright (c) 2015 Xamarin Inc. (http://www.xamarin.com)")]
-[assembly: AssemblyVersion ("4.0.1.0")]
+[assembly: AssemblyVersion ("4.1.1.0")]
[assembly: AssemblyInformationalVersion ("4.0.0.0")]
[assembly: AssemblyFileVersion ("4.0.0.0")]
[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Threading.IOCompletionCallback))]
[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Threading.NativeOverlapped))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Threading.Overlapped))]
[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Threading.PreAllocatedOverlapped))]
[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Threading.ThreadPoolBoundHandle))]
[assembly: AssemblyCompany ("Xamarin, Inc.")]
[assembly: AssemblyProduct ("Mono Common Language Infrastructure")]
[assembly: AssemblyCopyright ("Copyright (c) 2016 Xamarin Inc. (http://www.xamarin.com)")]
-[assembly: AssemblyVersion ("4.0.1.0")]
+[assembly: AssemblyVersion ("4.0.3.0")]
[assembly: AssemblyInformationalVersion ("4.0.0.0")]
[assembly: AssemblyFileVersion ("4.0.0.0")]
[assembly: AssemblyCompany ("Xamarin, Inc.")]
[assembly: AssemblyProduct ("Mono Common Language Infrastructure")]
[assembly: AssemblyCopyright ("Copyright (c) 2015 Xamarin Inc. (http://www.xamarin.com)")]
-[assembly: AssemblyVersion ("4.0.1.0")]
+[assembly: AssemblyVersion ("4.1.1.0")]
[assembly: AssemblyInformationalVersion ("4.0.0.0")]
[assembly: AssemblyFileVersion ("4.0.0.0")]
../../../external/corefx/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Conversions.cs
../../../external/corefx/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/COperators.cs
../../../external/corefx/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Declarations/AggregateDeclaration.cs
-../../../external/corefx/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Declarations/Declaration.cs
-../../../external/corefx/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Declarations/GlobalAttributeDeclaration.cs
-../../../external/corefx/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Declarations/NamespaceDeclaration.cs
../../../external/corefx/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/ExplicitConversion.cs
../../../external/corefx/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/ExpressionBinder.cs
../../../external/corefx/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/ExpressionKind.cs
../../../external/corefx/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Symbols/EventSymbol.cs
../../../external/corefx/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Symbols/FieldSymbol.cs
../../../external/corefx/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Symbols/IndexerSymbol.cs
-../../../external/corefx/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Symbols/LabelSymbol.cs
../../../external/corefx/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Symbols/LocalVariableSymbol.cs
../../../external/corefx/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Symbols/MethodOrPropertySymbol.cs
../../../external/corefx/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Symbols/MethodSymbol.cs
../../../external/corefx/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Symbols/SymbolTable.cs
../../../external/corefx/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Symbols/SymFactory.cs
../../../external/corefx/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Symbols/SymFactoryBase.cs
-../../../external/corefx/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Symbols/TransparentIdentifierMemberSymbol.cs
../../../external/corefx/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Symbols/TypeParameterSymbol.cs
../../../external/corefx/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Symbols/UnresolvedAggregateSymbol.cs
../../../external/corefx/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Symbols/VariableSymbol.cs
../../../external/corefx/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/ArrayIndex.cs
../../../external/corefx/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/ArrayInitialization.cs
-../../../external/corefx/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/ArrayLength.cs
../../../external/corefx/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/Assignment.cs
../../../external/corefx/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/BinaryOperator.cs
../../../external/corefx/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/Block.cs
../../../external/corefx/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/Class.cs
../../../external/corefx/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/CompoundOperator.cs
../../../external/corefx/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/Concatenate.cs
-../../../external/corefx/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/ConditionalOperator.cs
../../../external/corefx/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/Constant.cs
../../../external/corefx/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/Event.cs
../../../external/corefx/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/EXPR.cs
using System.Runtime.InteropServices;
using System.Security.Permissions;
-[assembly: AssemblyVersion (Consts.FxVersion)]
+
+#if MONO_POSIX_NETSTANDARD_BUILD
+[assembly: AssemblyVersion ("1.0.0.0")]
+[assembly: AssemblyTitle("Mono.Posix.NETStandard.dll")]
+#else
+[assembly: AssemblyVersion (Consts.FxVersion)]
[assembly: AssemblyTitle("Mono.Posix.dll")]
+#endif
+
[assembly: AssemblyDescription("Unix Integration Classes")]
[assembly: CLSCompliant (true)]
*/
+#if !MONO_POSIX_NETSTANDARD_BUILD
+// We are using ../Open.snk for MONO_POSIX_NETSTANDARD_BUILD
[assembly: AssemblyDelaySign (true)]
[assembly: AssemblyKeyFile ("../mono.pub")]
-
+#endif
/*
* TODO:
*
--- /dev/null
+<Project Sdk="Microsoft.NET.Sdk">\r
+\r
+ <PropertyGroup>\r
+ <TargetFramework>netstandard2.0</TargetFramework>\r
+ <AllowUnsafeBlocks>true</AllowUnsafeBlocks>\r
+ <AssemblyName>Mono.Posix.NETStandard</AssemblyName>\r
+ <GenerateAssemblyDescriptionAttribute>false</GenerateAssemblyDescriptionAttribute>\r
+ <GenerateAssemblyTitleAttribute>false</GenerateAssemblyTitleAttribute>\r
+ <GenerateAssemblyVersionAttribute>false</GenerateAssemblyVersionAttribute>\r
+ <EnableDefaultItems>false</EnableDefaultItems>\r
+ <SignAssembly>true</SignAssembly>\r
+ <DelaySign>true</DelaySign>\r
+ <AssemblyOriginatorKeyFile>..\Open.snk</AssemblyOriginatorKeyFile>\r
+ <!--<BaseIntermediateOutputPath>obj-netstandard2.0</BaseIntermediateOutputPath>\r
+ <IntermediateOutputPath>obj-netstandard2.0</IntermediateOutputPath>-->\r
+ </PropertyGroup>\r
+\r
+ <PropertyGroup>\r
+ <DefineConstants>$(DefineConstants);MONO_POSIX_NETSTANDARD_BUILD</DefineConstants>\r
+ </PropertyGroup>\r
+\r
+ <PropertyGroup Condition="'$(ForceUseLibC)' == 'true'">\r
+ <DefineConstants>$(DefineConstants);FORCE_USE_LIBC_NOT_MSVC</DefineConstants>\r
+ </PropertyGroup>\r
+\r
+ <ItemGroup>\r
+ <Compile Include=".\Assembly\**\*.cs" />\r
+ <Compile Include=".\Mono.Posix\**\*.cs" />\r
+ <Compile Include=".\Mono.Unix\**\*.cs" />\r
+ <Compile Include=".\Mono.Unix.Native\**\*.cs" />\r
+ <Compile Include="..\..\build\common\Locale.cs" />\r
+ <Compile Remove=".\Mono.Unix.Native\CdeclFunction.cs" />\r
+ </ItemGroup>\r
+\r
+</Project>\r
public delegate void SignalHandler (int signal);
+#if !NETSTANDARD2_0
internal class XPrintfFunctions
{
internal delegate object XPrintf (object[] parameters);
syslog = new XPrintf (_syslog.Invoke);
}
}
+#endif
//
// Convention: Functions that are part of the C standard library go here.
//
public class Stdlib
{
+#if FORCE_USE_LIBC_NOT_MSVC
+ internal const string LIBC = "c";
+#else
internal const string LIBC = "msvcrt";
+#endif
internal const string MPH = "MonoPosixHelper";
// It is possible for Mono.Posix and MonoPosixHelper to get out of sync,
return sys_fprintf (stream, "%s", message);
}
+#if !NETSTANDARD2_0
[Obsolete ("Not necessarily portable due to cdecl restrictions.\n" +
"Use fprintf (IntPtr, string) instead.")]
public static int fprintf (IntPtr stream, string format, params object[] parameters)
Array.Copy (parameters, 0, _parameters, 2, parameters.Length);
return (int) XPrintfFunctions.fprintf (_parameters);
}
+#endif
/* SKIP: fscanf(3) */
return sys_printf ("%s", message);
}
+#if !NETSTANDARD2_0
[Obsolete ("Not necessarily portable due to cdecl restrictions.\n" +
"Use printf (string) instead.")]
public static int printf (string format, params object[] parameters)
Array.Copy (parameters, 0, _parameters, 1, parameters.Length);
return (int) XPrintfFunctions.printf (_parameters);
}
+#endif
/* SKIP: scanf(3) */
return sys_snprintf (s, (ulong) s.Capacity, "%s", message);
}
+#if !NETSTANDARD2_0
[CLSCompliant (false)]
[Obsolete ("Not necessarily portable due to cdecl restrictions.\n" +
"Use snprintf (StringBuilder, string) instead.")]
Array.Copy (parameters, 0, _parameters, 3, parameters.Length);
return (int) XPrintfFunctions.snprintf (_parameters);
}
+#endif
/*
* SKIP:
return UnixMarshal.EscapeFormatString (message, new char[]{'m'});
}
+#if !NETSTANDARD2_0
[Obsolete ("Not necessarily portable due to cdecl restrictions.\n" +
"Use syslog(SyslogFacility, SyslogLevel, string) instead.")]
public static int syslog (SyslogFacility facility, SyslogLevel level,
Array.Copy (parameters, 0, _parameters, 2, parameters.Length);
return (int) XPrintfFunctions.syslog (_parameters);
}
+#endif
[DllImport (MPH, SetLastError=true,
EntryPoint="Mono_Posix_Syscall_closelog")]
Assert.IsFalse (NativeConvert.ToSignum (st.signalReceived) == Signum.SIGURG,
"#IH: Signal Handler invoked when it should have been removed!");
}
-
+#if !NETCOREAPP2_0
[Test]
// MSVCRT.DLL doesn't export snprintf(3).
[Category ("NotDotNet")]
Assert.AreEqual (s.ToString(), expected,
"#SNPF: printf of many builtin types failed");
}
+#endif
}
}
properties = new ConfigurationPropertyCollection ();
properties.Add (bypassListProp);
+ properties.Add (enabledProp);
properties.Add (moduleProp);
properties.Add (proxyProp);
+ properties.Add (useDefaultCredentialsProp);
}
public DefaultProxySection ()
properties = new ConfigurationPropertyCollection ();
+ properties.Add (autoDetectProp);
properties.Add (bypassOnLocalProp);
properties.Add (proxyAddressProp);
properties.Add (scriptLocationProp);
return Send (addresses [0], timeout, buffer, options);
}
- static IPAddress GetNonLoopbackIPV4 ()
- {
-#pragma warning disable 618
- foreach (IPAddress addr in Dns.GetHostByName (Dns.GetHostName ()).AddressList)
- if (!IPAddress.IsLoopback (addr) && addr.AddressFamily == AddressFamily.InterNetwork)
- return addr;
-#pragma warning restore 618
-
- throw new InvalidOperationException ("Could not resolve non-loopback IP address for localhost");
- }
-
public PingReply Send (IPAddress address, int timeout, byte [] buffer, PingOptions options)
{
if (address == null)
private PingReply SendPrivileged (IPAddress address, int timeout, byte [] buffer, PingOptions options)
{
IPEndPoint target = new IPEndPoint (address, 0);
- IPEndPoint client = new IPEndPoint (GetNonLoopbackIPV4 (), 0);
-
+
// FIXME: support IPv6
using (Socket s = new Socket (AddressFamily.InterNetwork, SocketType.Raw, ProtocolType.Icmp)) {
if (options != null) {
// receive
bytes = new byte [100];
do {
- EndPoint endpoint = client;
+ EndPoint endpoint = target;
SocketError error = 0;
int rc = s.ReceiveFrom (bytes, 0, 100, SocketFlags.None,
ref endpoint, out error);
--- /dev/null
+//
+// HttpListenerWebSocketContext.platformnotsupported.cs
+//
+// Author:
+// Marek Safar <marek.safar@gmail.com>
+//
+// Copyright (c) 2017 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.Net.WebSockets
+{
+ public partial class HttpListenerWebSocketContext : System.Net.WebSockets.WebSocketContext
+ {
+ const string EXCEPTION_MESSAGE = "System.Net.WebSockets.HttpListenerWebSocketContext is not supported on the current platform.";
+
+ private HttpListenerWebSocketContext() { }
+ public override System.Net.CookieCollection CookieCollection { get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); } }
+ public override System.Collections.Specialized.NameValueCollection Headers { get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); } }
+ public override bool IsAuthenticated { get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); } }
+ public override bool IsLocal { get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); } }
+ public override bool IsSecureConnection { get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); } }
+ public override string Origin { get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); } }
+ public override System.Uri RequestUri { get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); } }
+ public override string SecWebSocketKey { get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); } }
+ public override System.Collections.Generic.IEnumerable<string> SecWebSocketProtocols { get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); } }
+ public override string SecWebSocketVersion { get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); } }
+ public override System.Security.Principal.IPrincipal User { get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); } }
+ public override System.Net.WebSockets.WebSocket WebSocket { get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); } }
+ }
+}
\ No newline at end of file
../../../external/corefx/src/System.Net.WebSockets.Client/src/System/Net/WebSockets/ClientWebSocketOptions.cs
../../../external/corefx/src/System.Net.WebSockets.Client/src/System/Net/WebSockets/WebSocketHandle.Managed.cs
-../../../external/corefx/src/System.Net.HttpListener/src/System/Net/WebSockets/HttpListenerWebSocketContext.cs
-
../../../external/corefx/src/System.Private.Uri/src/System/UriBuilder.cs
../../../external/corefx/src/System.Runtime.Extensions/src/System/CodeDom/Compiler/IndentedTextWriter.cs
../referencesource/System/net/System/Net/Sockets/TCPClient.cs
../referencesource/System/net/System/Net/Sockets/TCPListener.cs
../referencesource/System/net/System/Net/Sockets/UDPClient.cs
+
+../../../external/corefx/src/System.Net.HttpListener/src/System/Net/WebSockets/HttpListenerWebSocketContext.cs
System.Net/HttpWebResponse.platformnotsupported.cs
System.Net/ServicePoint.platformnotsupported.cs
System.Net/ServicePointManager.platformnotsupported.cs
+System.Net.WebSockets/HttpListenerWebSocketContext.platformnotsupported.cs
../Mono.Security/Mono.Security.X509.Extensions/AuthorityKeyIdentifierExtension.cs
include ../../build/rules.make
-the_libdir = $(topdir)/class/lib/$(PROFILE)/
+the_libdir = $(topdir)/class/lib/$(PROFILE_DIRECTORY)/
CSC_DIR = $(dir $(CSC_LOCATION))
# The directory where the AOT images are stored
images_dir = $(the_libdir)
PROGRAM_INSTALL_DIR = $(mono_libdir)/mono/$(FRAMEWORK_VERSION)
LIBRARY_INSTALL_DIR = $(mono_libdir)/mono/$(FRAMEWORK_VERSION)
+LOG_FILE = $(PROFILE_DIRECTORY)_aot.log
+
ifndef SKIP_AOT
profile_file:=$(wildcard $(topdir)/class/lib/build/csc.*.aotprofile)
ifdef PLATFORM_AOT_SUFFIX
$(mcs_aot_image): $(mcs_exe) $(mscorlib_dll) $(runtime_dep)
- $(Q_AOT) MONO_PATH='$(the_libdir)' > $(PROFILE)_aot.log 2>&1 $(RUNTIME) --aot=bind-to-runtime-version$(profile_arg),outfile=$(mcs_aot_image) --debug $(mcs_exe) || cat $(PROFILE)_aot.log || (cat $(PROFILE)_aot.log; exit 1)
+ $(Q_AOT) MONO_PATH='$(the_libdir)' > $(LOG_FILE) 2>&1 $(RUNTIME) --aot=bind-to-runtime-version$(profile_arg),outfile=$(mcs_aot_image) --debug $(mcs_exe) || cat $(LOG_FILE) || (cat $(LOG_FILE); exit 1)
$(csc_aot_image): $(csc_exe) $(mscorlib_dll) $(runtime_dep)
- $(Q_AOT) MONO_PATH='$(the_libdir)' > $(PROFILE)_aot.log 2>&1 $(RUNTIME) --aot=bind-to-runtime-version$(profile_arg),outfile=$(csc_aot_image) --debug $(csc_exe) || cat $(PROFILE)_aot.log || (cat $(PROFILE)_aot.log; exit 1)
+ $(Q_AOT) MONO_PATH='$(the_libdir)' > $(LOG_FILE) 2>&1 $(RUNTIME) --aot=bind-to-runtime-version$(profile_arg),outfile=$(csc_aot_image) --debug $(csc_exe) || cat $(LOG_FILE) || (cat $(LOG_FILE); exit 1)
$(mscorlib_aot_image): $(mscorlib_dll) $(runtime_dep)
- $(Q_AOT) MONO_PATH='$(the_libdir)' > $(PROFILE)_aot.log 2>&1 $(RUNTIME) --aot=bind-to-runtime-version$(profile_arg) --debug $(mscorlib_dll) || (cat $(PROFILE)_aot.log; exit 1)
+ $(Q_AOT) MONO_PATH='$(the_libdir)' > $(LOG_FILE) 2>&1 $(RUNTIME) --aot=bind-to-runtime-version$(profile_arg) --debug $(mscorlib_dll) || (cat $(LOG_FILE); exit 1)
$(csc_MC_image): $(csc_MC_dll) $(runtime_dep)
- $(Q_AOT) MONO_PATH='$(the_libdir)' > $(PROFILE)_aot.log 2>&1 $(RUNTIME) --aot=bind-to-runtime-version$(profile_arg),outfile=$(csc_MC_image) --debug $(csc_MC_dll) || (cat $(PROFILE)_aot.log; exit 1)
+ $(Q_AOT) MONO_PATH='$(the_libdir)' > $(LOG_FILE) 2>&1 $(RUNTIME) --aot=bind-to-runtime-version$(profile_arg),outfile=$(csc_MC_image) --debug $(csc_MC_dll) || (cat $(LOG_FILE); exit 1)
$(csc_MCS_image): $(csc_MCS_dll) $(runtime_dep)
- $(Q_AOT) MONO_PATH='$(the_libdir)' > $(PROFILE)_aot.log 2>&1 $(RUNTIME) --aot=bind-to-runtime-version$(profile_arg),outfile=$(csc_MCS_image) --debug $(csc_MCS_dll) || (cat $(PROFILE)_aot.log; exit 1)
+ $(Q_AOT) MONO_PATH='$(the_libdir)' > $(LOG_FILE) 2>&1 $(RUNTIME) --aot=bind-to-runtime-version$(profile_arg),outfile=$(csc_MCS_image) --debug $(csc_MCS_dll) || (cat $(LOG_FILE); exit 1)
$(csc_SRM_image): $(csc_SRM_dll) $(runtime_dep)
- $(Q_AOT) MONO_PATH='$(the_libdir)' > $(PROFILE)_aot.log 2>&1 $(RUNTIME) --aot=bind-to-runtime-version$(profile_arg),outfile=$(csc_SRM_image) --debug --apply-bindings=$(csc_exe).config $(csc_SRM_dll) || (cat $(PROFILE)_aot.log; exit 1)
+ $(Q_AOT) MONO_PATH='$(the_libdir)' > $(LOG_FILE) 2>&1 $(RUNTIME) --aot=bind-to-runtime-version$(profile_arg),outfile=$(csc_SRM_image) --debug --apply-bindings=$(csc_exe).config $(csc_SRM_dll) || (cat $(LOG_FILE); exit 1)
$(csc_SCI_image): $(csc_SCI_dll) $(runtime_dep)
- $(Q_AOT) MONO_PATH='$(the_libdir)' > $(PROFILE)_aot.log 2>&1 $(RUNTIME) --aot=bind-to-runtime-version$(profile_arg),outfile=$(csc_SCI_image) --debug $(csc_SCI_dll) || (cat $(PROFILE)_aot.log; exit 1)
+ $(Q_AOT) MONO_PATH='$(the_libdir)' > $(LOG_FILE) 2>&1 $(RUNTIME) --aot=bind-to-runtime-version$(profile_arg),outfile=$(csc_SCI_image) --debug $(csc_SCI_dll) || (cat $(LOG_FILE); exit 1)
ifdef ENABLE_AOT
CSC_IMAGES = $(csc_aot_image) $(csc_SRM_image) $(csc_SCI_image) $(csc_MC_image) $(csc_MCS_image)
clean-local:
- -rm -f $(mscorlib_aot_image) $(mcs_aot_image) $(CSC_IMAGES) $(PROFILE)_aot.log
+ -rm -f $(mscorlib_aot_image) $(mcs_aot_image) $(CSC_IMAGES) $(LOG_FILE)
# AOT build profile to speed up build
ifeq ($(PROFILE),build)
[assembly: InternalsVisibleTo ("System.Runtime.WindowsRuntime, PublicKey=00000000000000000400000000000000")]
[assembly: InternalsVisibleTo ("System.Runtime.WindowsRuntime.UI.Xaml, PublicKey=00000000000000000400000000000000")]
+[assembly: InternalsVisibleTo ("System.Runtime.InteropServices.RuntimeInformation, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293")]
+
#if MONOTOUCH
#if MONOTOUCH_TV
[assembly: InternalsVisibleTo ("Xamarin.TVOS, PublicKey=0024000004800000940000000602000000240000525341310004000011000000438ac2a5acfbf16cbd2b2b47a62762f273df9cb2795ceccdf77d10bf508e69e7a362ea7a45455bbf3ac955e1f2e2814f144e5d817efc4c6502cc012df310783348304e3ae38573c6d658c234025821fda87a0be8a0d504df564e2c93b2b878925f42503e9d54dfef9f9586d9e6f38a305769587b1de01f6c0410328b2c9733db")]
--- /dev/null
+// CS0535: `CC' does not implement interface member `IA.Coordinate.set'
+// Line: 33
+
+using System;
+
+public interface IA
+{
+ object Coordinate {
+ get;
+ set;
+ }
+}
+
+public abstract class CA : IA
+{
+ public abstract object Coordinate {
+ get;
+ set;
+ }
+}
+
+public partial class CB : CA
+{
+ public override object Coordinate {
+ get {
+ throw new NotImplementedException ();
+ }
+ set {
+ }
+ }
+}
+
+public class CC : CB, IA
+{
+ public new object Coordinate {
+ get {
+ throw new NotImplementedException ();
+ }
+ }
+}
--- /dev/null
+// CS0535: `CC' does not implement interface member `IA.this[int].set'
+// Line: 33
+
+using System;
+
+public interface IA
+{
+ object this[int arg] {
+ get;
+ set;
+ }
+}
+
+public abstract class CA : IA
+{
+ public abstract object this[int arg] {
+ get;
+ set;
+ }
+}
+
+public partial class CB : CA
+{
+ public override object this[int arg] {
+ get {
+ throw new NotImplementedException ();
+ }
+ set {
+ }
+ }
+}
+
+public class CC : CB, IA
+{
+ public new object this[int arg] {
+ get {
+ throw new NotImplementedException ();
+ }
+ }
+}
bool is_value_type = type.IsStructOrEnum;
VariableReference vr = target as VariableReference;
+ bool prepare_await = ec.HasSet (BuilderContext.Options.AsyncBody) && arguments?.ContainsEmitWithAwait () == true;
+
if (target != null && is_value_type && (vr != null || method == null)) {
+ if (prepare_await) {
+ arguments = arguments.Emit (ec, false, true);
+ prepare_await = false;
+ }
+
target.AddressOf (ec, AddressOp.Store);
} else if (vr != null && vr.IsRef) {
vr.EmitLoad (ec);
}
if (arguments != null) {
- if (ec.HasSet (BuilderContext.Options.AsyncBody) && (arguments.Count > (this is NewInitialize ? 0 : 1)) && arguments.ContainsEmitWithAwait ())
+ if (prepare_await)
arguments = arguments.Emit (ec, false, true);
arguments.Emit (ec);
kind = MemberKind.Constructor;
returnType = module.Compiler.BuiltinTypes.Void;
} else {
+ var mi = (MethodInfo)mb;
+ returnType = ImportType (mi.ReturnType, new DynamicTypeReader (mi.ReturnParameter), declaringType);
+
//
// Detect operators and destructors
//
kind = MemberKind.Operator;
}
}
- } else if (parameters.IsEmpty && name == Destructor.MetadataName) {
+ } else if (parameters.IsEmpty && name == Destructor.MetadataName && returnType.Kind == MemberKind.Void) {
kind = MemberKind.Destructor;
if (declaringType.BuiltinType == BuiltinTypeSpec.Type.Object) {
mod &= ~Modifiers.OVERRIDE;
}
}
- var mi = (MethodInfo) mb;
- returnType = ImportType (mi.ReturnType, new DynamicTypeReader (mi.ReturnParameter), declaringType);
-
// Cannot set to OVERRIDE without full hierarchy checks
// this flag indicates that the method could be override
// but further validation is needed
if (set_param_count == 0) {
set_based_param = ParametersCompiled.EmptyReadOnlyParameters;
} else {
- //
- // Create indexer parameters based on setter method parameters (the last parameter has to be removed)
- //
- var data = new IParameterData[set_param_count];
- var types = new TypeSpec[set_param_count];
- Array.Copy (set.Parameters.FixedParameters, data, set_param_count);
- Array.Copy (set.Parameters.Types, types, set_param_count);
- set_based_param = new ParametersImported (data, types, set.Parameters.HasParams);
+ set_based_param = IndexerSpec.CreateParametersFromSetter (set, set_param_count);
}
mod = set.Modifiers;
}
public class ParamsParameter : Parameter {
+
+ bool ParamsAttributeEmit;
+
public ParamsParameter (FullNamedExpression type, string name, Attributes attrs, Location loc):
base (type, name, Parameter.Modifier.PARAMS, attrs, loc)
{
return null;
}
+ var mc = ec as MemberCore;
+ ParamsAttributeEmit = mc == null || (mc.ModFlags & Modifiers.OVERRIDE) == 0;
+
return parameter_type;
}
public override void ApplyAttributes (MethodBuilder mb, ConstructorBuilder cb, int index, PredefinedAttributes pa)
{
base.ApplyAttributes (mb, cb, index, pa);
- pa.ParamArray.EmitAttribute (builder);
+
+ if (ParamsAttributeEmit)
+ pa.ParamArray.EmitAttribute (builder);
}
}
int i = 0;
if (abstract_methods != null) {
int count = abstract_methods.Length;
- pending_implementations [i].methods = new MethodSpec [count];
pending_implementations [i].need_proxy = new MethodSpec [count];
pending_implementations [i].methods = abstract_methods;
bool BaseImplements (TypeSpec iface_type, MethodSpec mi, out MethodSpec base_method)
{
base_method = null;
- var base_type = container.BaseType;
+ bool base_can_implement = true;
+ TypeSpec lookup_type;
+
+ //
+ // Special handling for properties/indexers which cannot have accessors
+ // implementing an interface found in different types (e.g. current and base)
+ //
+ if (mi.IsAccessor && container.Interfaces != null) {
+
+ bool new_implementation = false;
+ foreach (var iface in container.Interfaces) {
+ if (TypeSpecComparer.IsEqual (iface, iface_type)) {
+ new_implementation = true;
+ break;
+ }
+ }
+
+ if (new_implementation) {
+ MemberFilter filter;
+ if (mi.Parameters.Count > 1) {
+ var indexer_params = mi.Name [0] == 'g' ? mi.Parameters : IndexerSpec.CreateParametersFromSetter (mi, mi.Parameters.Count - 1);
+ filter = new MemberFilter (MemberCache.IndexerNameAlias, 0, MemberKind.Indexer, indexer_params, null);
+ } else {
+ var pname = mi.Name.Substring (4);
+ filter = MemberFilter.Property (pname, null);
+ }
+
+ var prop = MemberCache.FindMember (container.CurrentType, filter, BindingRestriction.DeclaredOnly | BindingRestriction.InstanceOnly);
+ if (prop != null && (prop.Modifiers & Modifiers.NEW) != 0)
+ base_can_implement = false;
+ }
+ }
+
+ if (base_can_implement) {
+ lookup_type = container.BaseType;
+
+ if (lookup_type.ImplementsInterface (iface_type, false))
+ return true;
+ } else {
+ lookup_type = container.CurrentType;
+ }
//
// Setup filter with no return type to give better error message
MethodSpec close_match = null;
while (true) {
- var candidates = MemberCache.FindMembers (base_type, mi.Name, false);
+ var candidates = MemberCache.FindMembers (lookup_type, mi.Name, !base_can_implement);
if (candidates == null) {
base_method = close_match;
return false;
break;
}
- base_type = candidates[0].DeclaringType.BaseType;
- if (base_type == null) {
+ if (!base_can_implement)
+ return false;
+
+ lookup_type = candidates[0].DeclaringType.BaseType;
+ if (lookup_type == null) {
base_method = close_match;
return false;
}
for (i = 0; i < top; i++){
TypeSpec type = pending_implementations [i].type;
- bool base_implements_type = type.IsInterface &&
- container.BaseType != null &&
- container.BaseType.ImplementsInterface (type, false);
-
for (int j = 0; j < pending_implementations [i].methods.Count; ++j) {
var mi = pending_implementations[i].methods[j];
if (mi == null)
continue;
}
- if (pending_implementations [i].optional)
- continue;
-
MethodSpec candidate;
- if (base_implements_type || BaseImplements (type, mi, out candidate))
+ if (BaseImplements (type, mi, out candidate))
continue;
if (candidate == null) {
}
#endregion
+ public static ParametersImported CreateParametersFromSetter (MethodSpec setter, int set_param_count)
+ {
+ //
+ // Creates indexer parameters based on setter method parameters (the last parameter has to be removed)
+ //
+ var data = new IParameterData [set_param_count];
+ var types = new TypeSpec [set_param_count];
+ Array.Copy (setter.Parameters.FixedParameters, data, set_param_count);
+ Array.Copy (setter.Parameters.Types, types, set_param_count);
+ return new ParametersImported (data, types, setter.Parameters.HasParams);
+ }
+
public override string GetSignatureForDocumentation ()
{
return base.GetSignatureForDocumentation () + parameters.GetSignatureForDocumentation ();
ec.Emit (OpCodes.Br, end);
ec.MarkLabel (labels [i + 1]);
+
+ ec.EmitInt (0);
+ ec.Emit (OpCodes.Stloc, state_variable);
+
c = catch_sm [i];
ec.AsyncThrowVariable = c.Variable;
c.Block.Emit (ec);
--- /dev/null
+// Compiler options: -t:library
+
+public class Class1
+{
+ public byte[] Finalize ()
+ {
+ return null;
+ }
+}
--- /dev/null
+// Compiler options: -r:test-944-lib.dll
+
+public class Class2
+{
+ public static void Main ()
+ {
+ var writer = new Class1();
+ byte[] bytes = writer.Finalize();
+ }
+}
\ No newline at end of file
--- /dev/null
+public abstract class A
+{
+ public abstract void Bind (string [] args);
+}
+
+public class B : A
+{
+ public override void Bind (params string [] args)
+ {
+ }
+
+ public static int Main ()
+ {
+ var m = typeof (B).GetMethod ("Bind");
+ var p = m.GetParameters ();
+ var ca = p[0].GetCustomAttributes (false);
+ if (ca.Length != 0)
+ return 1;
+
+ return 0;
+ }
+}
--- /dev/null
+using System.Threading.Tasks;
+
+public class A
+{
+ public async Task<ValueType> Test1 (int input2)
+ {
+ return new ValueType (await Task.FromResult (12345));
+ }
+
+ public static void Main ()
+ {
+ var a = new A ();
+ a.Test1 (1).Wait ();
+ }
+}
+
+public struct ValueType
+{
+ public ValueType (int field2)
+ {
+ }
+}
--- /dev/null
+using System;
+using System.Threading.Tasks;
+
+public class Test
+{
+ public static int Main()
+ {
+ var t = new Test ();
+ t.Entry().Wait();
+ if (t.caughtCounter != 1)
+ return 1;
+
+ return 0;
+ }
+
+ int caughtCounter;
+
+ async Task Entry()
+ {
+ for (int i = 0; i < 5; ++i) {
+ try {
+ var result = Func(i);
+ Console.WriteLine($"{i} result {result}");
+ } catch (Exception e) {
+ await Nothing();
+ Console.WriteLine($"{i} caught");
+ ++caughtCounter;
+ }
+ }
+ }
+
+ bool Func(int i)
+ {
+ if (i == 0) {
+ throw new Exception();
+ } else {
+ return true;
+ }
+ }
+
+ async Task Nothing()
+ {
+ }
+}
\ No newline at end of file
</method>
</type>
</test>
+ <test name="test-943.cs">
+ <type name="MyStruct">
+ <method name="Int32 get_X()" attrs="2182">
+ <size>14</size>
+ </method>
+ <method name="Void set_X(Int32)" attrs="2182">
+ <size>8</size>
+ </method>
+ </type>
+ <type name="X">
+ <method name="Int32 Main()" attrs="150">
+ <size>44</size>
+ </method>
+ <method name="Void .ctor()" attrs="6278">
+ <size>7</size>
+ </method>
+ </type>
+ </test>
+ <test name="test-944.cs">
+ <type name="Class2">
+ <method name="Void Main()" attrs="150">
+ <size>15</size>
+ </method>
+ <method name="Void .ctor()" attrs="6278">
+ <size>7</size>
+ </method>
+ </type>
+ </test>
+ <test name="test-945.cs">
+ <type name="A">
+ <method name="Void Bind(System.String[])" attrs="1478">
+ <size>0</size>
+ </method>
+ <method name="Void .ctor()" attrs="6276">
+ <size>7</size>
+ </method>
+ </type>
+ <type name="B">
+ <method name="Void Bind(System.String[])" attrs="198">
+ <size>2</size>
+ </method>
+ <method name="Int32 Main()" attrs="150">
+ <size>63</size>
+ </method>
+ <method name="Void .ctor()" attrs="6278">
+ <size>7</size>
+ </method>
+ </type>
+ </test>
<test name="test-95.cs">
<type name="X">
<method name="Int32 Main()" attrs="150">
</type>
<type name="C+<TestSingleAwait>c__async0">
<method name="Void MoveNext()" attrs="486">
- <size>274</size>
+ <size>276</size>
</method>
<method name="Void SetStateMachine(System.Runtime.CompilerServices.IAsyncStateMachine)" attrs="486">
<size>13</size>
</type>
<type name="C+<TestDoubleAwait>c__async1">
<method name="Void MoveNext()" attrs="486">
- <size>419</size>
+ <size>423</size>
</method>
<method name="Void SetStateMachine(System.Runtime.CompilerServices.IAsyncStateMachine)" attrs="486">
<size>13</size>
</type>
<type name="C+<TestRethrow>c__async0">
<method name="Void MoveNext()" attrs="486">
- <size>363</size>
+ <size>367</size>
</method>
<method name="Void SetStateMachine(System.Runtime.CompilerServices.IAsyncStateMachine)" attrs="486">
<size>13</size>
</type>
<type name="Test+<BreakTest>c__async1">
<method name="Void MoveNext()" attrs="486">
- <size>903</size>
+ <size>906</size>
</method>
<method name="Void SetStateMachine(System.Runtime.CompilerServices.IAsyncStateMachine)" attrs="486">
<size>13</size>
</type>
<type name="Test+<ContinueTest>c__async2">
<method name="Void MoveNext()" attrs="486">
- <size>903</size>
+ <size>906</size>
</method>
<method name="Void SetStateMachine(System.Runtime.CompilerServices.IAsyncStateMachine)" attrs="486">
<size>13</size>
</type>
<type name="Program+<Test>c__async0">
<method name="Void MoveNext()" attrs="486">
- <size>543</size>
+ <size>545</size>
</method>
<method name="Void SetStateMachine(System.Runtime.CompilerServices.IAsyncStateMachine)" attrs="486">
<size>13</size>
</type>
<type name="Program+<Test2>c__async1">
<method name="Void MoveNext()" attrs="486">
- <size>398</size>
+ <size>400</size>
</method>
<method name="Void SetStateMachine(System.Runtime.CompilerServices.IAsyncStateMachine)" attrs="486">
<size>13</size>
</type>
<type name="Test+<AsyncWithDeepTry>c__async0">
<method name="Void MoveNext()" attrs="486">
- <size>460</size>
+ <size>463</size>
</method>
<method name="Void SetStateMachine(System.Runtime.CompilerServices.IAsyncStateMachine)" attrs="486">
<size>13</size>
</method>
</type>
</test>
+ <test name="test-async-92.cs">
+ <type name="A">
+ <method name="System.Threading.Tasks.Task`1[ValueType] Test1(Int32)" attrs="134">
+ <size>33</size>
+ </method>
+ <method name="Void Main()" attrs="150">
+ <size>20</size>
+ </method>
+ <method name="Void .ctor()" attrs="6278">
+ <size>7</size>
+ </method>
+ </type>
+ <type name="ValueType">
+ <method name="Void .ctor(Int32)" attrs="6278">
+ <size>2</size>
+ </method>
+ </type>
+ <type name="A+<Test1>c__async0">
+ <method name="Void MoveNext()" attrs="486">
+ <size>174</size>
+ </method>
+ <method name="Void SetStateMachine(System.Runtime.CompilerServices.IAsyncStateMachine)" attrs="486">
+ <size>13</size>
+ </method>
+ </type>
+ </test>
+ <test name="test-async-93.cs">
+ <type name="Test">
+ <method name="Int32 Main()" attrs="150">
+ <size>46</size>
+ </method>
+ <method name="System.Threading.Tasks.Task Entry()" attrs="129">
+ <size>41</size>
+ </method>
+ <method name="Boolean Func(Int32)" attrs="129">
+ <size>24</size>
+ </method>
+ <method name="System.Threading.Tasks.Task Nothing()" attrs="129">
+ <size>33</size>
+ </method>
+ <method name="Void .ctor()" attrs="6278">
+ <size>7</size>
+ </method>
+ </type>
+ <type name="Test+<Entry>c__async0">
+ <method name="Void MoveNext()" attrs="486">
+ <size>344</size>
+ </method>
+ <method name="Void SetStateMachine(System.Runtime.CompilerServices.IAsyncStateMachine)" attrs="486">
+ <size>13</size>
+ </method>
+ </type>
+ <type name="Test+<Nothing>c__async1">
+ <method name="Void MoveNext()" attrs="486">
+ <size>61</size>
+ </method>
+ <method name="Void SetStateMachine(System.Runtime.CompilerServices.IAsyncStateMachine)" attrs="486">
+ <size>13</size>
+ </method>
+ </type>
+ </test>
<test name="test-cls-00.cs">
<type name="CLSCLass_6">
<method name="Void add_Disposed(Delegate)" attrs="2182">
</type>
<type name="X+<Test>c__async0">
<method name="Void MoveNext()" attrs="486">
- <size>281</size>
+ <size>283</size>
</method>
<method name="Void SetStateMachine(System.Runtime.CompilerServices.IAsyncStateMachine)" attrs="486">
<size>13</size>
</type>
<type name="X+<TestGeneric>c__async1">
<method name="Void MoveNext()" attrs="486">
- <size>250</size>
+ <size>252</size>
</method>
<method name="Void SetStateMachine(System.Runtime.CompilerServices.IAsyncStateMachine)" attrs="486">
<size>13</size>
</type>
<type name="Test+<TestCapturedException>c__async0">
<method name="Void MoveNext()" attrs="486">
- <size>491</size>
+ <size>495</size>
</method>
<method name="Void SetStateMachine(System.Runtime.CompilerServices.IAsyncStateMachine)" attrs="486">
<size>13</size>
mono-endian.c \
mono-endian.h \
mono-hash.h \
+ mono-conc-hash.h \
mono-mlist.c \
mono-mlist.h \
mono-perfcounters.c \
gc.c \
monitor.c \
mono-hash.c \
+ mono-conc-hash.c \
object.c \
dynamic-image.c \
sre.c \
static MonoMethod*
mono_class_get_virtual_methods (MonoClass* klass, gpointer *iter)
{
- MonoMethod** method;
+ gboolean static_iter = FALSE;
+
if (!iter)
return NULL;
- if (klass->methods || !MONO_CLASS_HAS_STATIC_METADATA (klass)) {
+
+ /*
+ * If the lowest bit of the iterator is 1, this is an iterator for static metadata,
+ * and the upper bits contain an index. Otherwise, the iterator is a pointer into
+ * klass->methods.
+ */
+ if ((gsize)(*iter) & 1)
+ static_iter = TRUE;
+ /* Use the static metadata only if klass->methods is not yet initialized */
+ if (!static_iter && !(klass->methods || !MONO_CLASS_HAS_STATIC_METADATA (klass)))
+ static_iter = TRUE;
+
+ if (!static_iter) {
+ MonoMethod** methodptr;
+
if (!*iter) {
mono_class_setup_methods (klass);
/*
if (!klass->methods)
return NULL;
/* start from the first */
- method = &klass->methods [0];
+ methodptr = &klass->methods [0];
} else {
- method = (MonoMethod **)*iter;
- method++;
+ methodptr = (MonoMethod **)*iter;
+ methodptr++;
}
+ if (*iter)
+ g_assert ((guint64)(*iter) > 0x100);
int mcount = mono_class_get_method_count (klass);
- while (method < &klass->methods [mcount]) {
- if (*method && ((*method)->flags & METHOD_ATTRIBUTE_VIRTUAL))
+ while (methodptr < &klass->methods [mcount]) {
+ if (*methodptr && ((*methodptr)->flags & METHOD_ATTRIBUTE_VIRTUAL))
break;
- method ++;
+ methodptr ++;
}
- if (method < &klass->methods [mcount]) {
- *iter = method;
- return *method;
+ if (methodptr < &klass->methods [mcount]) {
+ *iter = methodptr;
+ return *methodptr;
} else {
return NULL;
}
if (!*iter) {
start_index = 0;
} else {
- start_index = GPOINTER_TO_UINT (*iter);
+ start_index = GPOINTER_TO_UINT (*iter) >> 1;
}
int first_idx = mono_class_get_first_method_idx (klass);
mono_error_cleanup (&error); /* FIXME don't swallow the error */
/* Add 1 here so the if (*iter) check fails */
- *iter = GUINT_TO_POINTER (i + 1);
+ *iter = GUINT_TO_POINTER (((i + 1) << 1) | 1);
return res;
} else {
return NULL;
for (i = 1; i <= sig->param_count; i++)
mono_mb_emit_ldarg (mb, i);
- if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
+ if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) || mono_class_is_interface (method->klass)) {
MonoMethod * native_wrapper = mono_cominterop_get_native_wrapper(method);
mono_mb_emit_managed_call (mb, native_wrapper, NULL);
}
#include <mono/metadata/lock-tracer.h>
#include <mono/utils/mono-codeman.h>
#include <mono/metadata/mono-hash.h>
+#include <mono/metadata/mono-conc-hash.h>
#include <mono/utils/mono-compiler.h>
#include <mono/utils/mono-internal-hash.h>
#include <mono/metadata/mempool-internals.h>
{
MonoDomain *domain;
int num_chunks;
+ int num_valid;
MonoJitInfoTableChunk *chunks [MONO_ZERO_LEN_ARRAY];
};
* d.tramp_info contains additional data in this case.
*/
gboolean is_trampoline:1;
+ /* Whenever this jit info refers to an interpreter method */
+ gboolean is_interp:1;
/* FIXME: Embed this after the structure later*/
gpointer gc_info; /* Currently only used by SGen */
MonoGHashTable *ldstr_table;
/* hashtables for Reflection handles */
MonoGHashTable *type_hash;
- MonoGHashTable *refobject_hash;
+ MonoConcGHashTable *refobject_hash;
/* maps class -> type initialization exception object */
MonoGHashTable *type_init_exception_hash;
/* maps delegate trampoline addr -> delegate object */
mono_debug_domain_unload (domain);
- mono_appdomains_lock ();
- appdomains_list [domain->domain_id] = NULL;
- mono_appdomains_unlock ();
-
/* must do this early as it accesses fields and types */
if (domain->special_static_fields) {
mono_alloc_special_static_data_free (domain->special_static_fields);
mono_gc_deregister_root ((char*)&(domain->MONO_DOMAIN_FIRST_GC_TRACKED));
+ mono_appdomains_lock ();
+ appdomains_list [domain->domain_id] = NULL;
+ mono_appdomains_unlock ();
+
/* FIXME: anything else required ? */
mono_gc_free_fixed (domain);
static int
jit_info_table_num_elements (MonoJitInfoTable *table)
{
- int i;
- int num_elements = 0;
-
- for (i = 0; i < table->num_chunks; ++i) {
- MonoJitInfoTableChunk *chunk = table->chunks [i];
- int chunk_num_elements = chunk->num_elements;
- int j;
-
- for (j = 0; j < chunk_num_elements; ++j) {
- if (!IS_JIT_INFO_TOMBSTONE (chunk->data [j]))
- ++num_elements;
- }
- }
-
- return num_elements;
+ return table->num_valid;
}
static MonoJitInfoTableChunk*
table->domain = domain;
table->num_chunks = 1;
table->chunks [0] = jit_info_table_new_chunk ();
+ table->num_valid = 0;
return table;
}
result = (MonoJitInfoTable *)g_malloc (MONO_SIZEOF_JIT_INFO_TABLE + sizeof (MonoJitInfoTableChunk*) * num_chunks);
result->domain = old->domain;
result->num_chunks = num_chunks;
+ result->num_valid = old->num_valid;
for (i = 0; i < num_chunks; ++i)
result->chunks [i] = jit_info_table_new_chunk ();
new_table->domain = table->domain;
new_table->num_chunks = table->num_chunks + 1;
+ new_table->num_valid = table->num_valid;
j = 0;
for (i = 0; i < table->num_chunks; ++i) {
new_table->domain = table->domain;
new_table->num_chunks = table->num_chunks;
+ new_table->num_valid = table->num_valid;
j = 0;
for (i = 0; i < table->num_chunks; ++i) {
chunk->last_code_end = (gint8*)chunk->data [chunk->num_elements - 1]->code_start
+ chunk->data [chunk->num_elements - 1]->code_size;
+ ++table->num_valid;
+
/* Debugging code, should be removed. */
//jit_info_table_check (table);
}
g_assert (chunk->data [pos] == ji);
chunk->data [pos] = mono_jit_info_make_tombstone (chunk, ji);
+ --table->num_valid;
/* Debugging code, should be removed. */
//jit_info_table_check (table);
return new_list;
}
+static inline GList*
+g_list_append_mempool (MonoMemPool *mp, GList *list, gpointer data)
+{
+ GList *new_list;
+
+ new_list = (GList *) mono_mempool_alloc0 (mp, sizeof (GList));
+ new_list->data = data;
+ new_list->prev = g_list_last (list);
+ if (new_list->prev)
+ new_list->prev->next = new_list;
+
+ return list ? list : new_list;
+}
+
char*
mono_mempool_strdup_vprintf (MonoMemPool *pool, const char *format, va_list args);
--- /dev/null
+/**
+ * \file
+ * Conc GC aware Hashtable implementation
+ *
+ * Author:
+ * Rodrigo Kumpera (kumpera@gmail.com)
+ *
+ */
+#include <config.h>
+#include <stdio.h>
+#include <math.h>
+#include <glib.h>
+#include "mono-conc-hash.h"
+#include "metadata/gc-internals.h"
+#include <mono/utils/checked-build.h>
+#include <mono/utils/mono-threads-coop.h>
+
+#ifdef HAVE_BOEHM_GC
+#define mg_new0(type,n) ((type *) GC_MALLOC(sizeof(type) * (n)))
+#define mg_new(type,n) ((type *) GC_MALLOC(sizeof(type) * (n)))
+#define mg_free(x) do { } while (0)
+#else
+#define mg_new0(x,n) g_new0(x,n)
+#define mg_new(type,n) g_new(type,n)
+#define mg_free(x) g_free(x)
+#endif
+
+#define INITIAL_SIZE 32
+#define LOAD_FACTOR 0.75f
+#define PTR_TOMBSTONE ((gpointer)(ssize_t)-1)
+/* Expand ration must be a power of two */
+#define EXPAND_RATIO 2
+
+typedef struct {
+ int table_size;
+ MonoGHashGCType gc_type;
+ void **keys;
+ void **values;
+} conc_table;
+
+struct _MonoConcGHashTable {
+ volatile conc_table *table; /* goes to HP0 */
+ GHashFunc hash_func;
+ GEqualFunc equal_func;
+ int element_count;
+ int overflow_count;
+ GDestroyNotify key_destroy_func;
+ GDestroyNotify value_destroy_func;
+ MonoGHashGCType gc_type;
+ MonoGCRootSource source;
+ const char *msg;
+};
+
+
+static conc_table*
+conc_table_new (MonoConcGHashTable *hash, int size)
+{
+#ifdef HAVE_SGEN_GC
+ conc_table *table = mg_new0 (conc_table, 1);
+#else
+ conc_table *table = mono_gc_alloc_fixed (sizeof (conc_table), MONO_GC_ROOT_DESCR_FOR_FIXED (sizeof (conc_table)), hash->source, hash->msg);
+#endif
+
+ table->keys = mg_new0 (void*, size);
+ table->values = mg_new0 (void*, size);
+ table->table_size = size;
+ table->gc_type = hash->gc_type;
+
+#ifdef HAVE_SGEN_GC
+ if (hash->gc_type & MONO_HASH_KEY_GC)
+ mono_gc_register_root_wbarrier ((char*)table->keys, sizeof (MonoObject*) * size, mono_gc_make_vector_descr (), hash->source, hash->msg);
+ if (hash->gc_type & MONO_HASH_VALUE_GC)
+ mono_gc_register_root_wbarrier ((char*)table->values, sizeof (MonoObject*) * size, mono_gc_make_vector_descr (), hash->source, hash->msg);
+#endif
+
+ return table;
+}
+
+static void
+conc_table_free (gpointer ptr)
+{
+ conc_table *table = (conc_table *)ptr;
+#ifdef HAVE_SGEN_GC
+ if (table->gc_type & MONO_HASH_KEY_GC)
+ mono_gc_deregister_root ((char*)table->keys);
+ if (table->gc_type & MONO_HASH_VALUE_GC)
+ mono_gc_deregister_root ((char*)table->values);
+#endif
+
+ mg_free (table->keys);
+ mg_free (table->values);
+#ifdef HAVE_SGEN_GC
+ mg_free (table);
+#else
+ mono_gc_free_fixed (table);
+#endif
+}
+
+static void
+conc_table_lf_free (conc_table *table)
+{
+ mono_thread_hazardous_try_free (table, conc_table_free);
+}
+
+
+static gboolean
+key_is_tombstone (MonoConcGHashTable *hash, gpointer ptr)
+{
+ if (hash->gc_type & MONO_HASH_KEY_GC)
+ return ptr == mono_domain_get()->ephemeron_tombstone;
+ return ptr == PTR_TOMBSTONE;
+}
+
+/*
+A common problem with power of two hashtables is that it leads of bad clustering when dealing
+with aligned numbers.
+
+The solution here is to mix the bits from two primes plus the hash itself, it produces a better spread
+than just the numbers.
+*/
+
+static MONO_ALWAYS_INLINE int
+mix_hash (int hash)
+{
+ return ((hash * 215497) >> 16) ^ (hash * 1823231 + hash);
+}
+
+
+static inline void
+set_key (conc_table *table, int slot, gpointer key)
+{
+ gpointer *key_addr = &table->keys [slot];
+ if (table->gc_type & MONO_HASH_KEY_GC)
+ mono_gc_wbarrier_generic_store (key_addr, key);
+ else
+ *key_addr = key;
+}
+
+static inline void
+set_key_to_tombstone (conc_table *table, int slot)
+{
+ gpointer *key_addr = &table->keys [slot];
+ if (table->gc_type & MONO_HASH_KEY_GC)
+ mono_gc_wbarrier_generic_store (key_addr, mono_domain_get()->ephemeron_tombstone);
+ else
+ *key_addr = PTR_TOMBSTONE;
+}
+
+static inline void
+set_value (conc_table *table, int slot, gpointer value)
+{
+ gpointer *value_addr = &table->values [slot];
+ if (table->gc_type & MONO_HASH_VALUE_GC)
+ mono_gc_wbarrier_generic_store (value_addr, value);
+ else
+ *value_addr = value;
+}
+
+static MONO_ALWAYS_INLINE void
+insert_one_local (conc_table *table, GHashFunc hash_func, gpointer key, gpointer value)
+{
+ int table_mask = table->table_size - 1;
+ int hash = mix_hash (hash_func (key));
+ int i = hash & table_mask;
+
+ while (table->keys [i])
+ i = (i + 1) & table_mask;
+
+ set_key (table, i, key);
+ set_value (table, i, value);
+}
+
+static void
+expand_table (MonoConcGHashTable *hash_table)
+{
+ conc_table *old_table = (conc_table*)hash_table->table;
+ conc_table *new_table = conc_table_new (hash_table, old_table->table_size * EXPAND_RATIO);
+ int i;
+
+ for (i = 0; i < old_table->table_size; ++i) {
+ if (old_table->keys [i] && !key_is_tombstone (hash_table, old_table->keys [i]))
+ insert_one_local (new_table, hash_table->hash_func, old_table->keys [i], old_table->values [i]);
+ }
+
+ mono_memory_barrier ();
+ hash_table->table = new_table;
+ hash_table->overflow_count = (int)(new_table->table_size * LOAD_FACTOR);
+ conc_table_lf_free (old_table);
+}
+
+
+MonoConcGHashTable *
+mono_conc_g_hash_table_new_type (GHashFunc hash_func, GEqualFunc key_equal_func, MonoGHashGCType type, MonoGCRootSource source, const char *msg)
+{
+ MonoConcGHashTable *hash;
+
+ if (!hash_func)
+ hash_func = g_direct_hash;
+
+ hash = g_new0 (MonoConcGHashTable, 1);
+ hash->hash_func = hash_func;
+ hash->equal_func = key_equal_func;
+
+ hash->element_count = 0;
+ hash->overflow_count = (int)(INITIAL_SIZE * LOAD_FACTOR);
+ hash->gc_type = type;
+ hash->source = source;
+ hash->msg = msg;
+
+ hash->table = conc_table_new (hash, INITIAL_SIZE);
+
+ if (type > MONO_HASH_KEY_VALUE_GC)
+ g_error ("wrong type for gc hashtable");
+
+ return hash;
+}
+
+gpointer
+mono_conc_g_hash_table_lookup (MonoConcGHashTable *hash, gconstpointer key)
+{
+ gpointer orig_key, value;
+
+ if (mono_conc_g_hash_table_lookup_extended (hash, key, &orig_key, &value))
+ return value;
+ else
+ return NULL;
+}
+
+gboolean
+mono_conc_g_hash_table_lookup_extended (MonoConcGHashTable *hash_table, gconstpointer key, gpointer *orig_key_ptr, gpointer *value_ptr)
+{
+ MonoThreadHazardPointers* hp;
+ conc_table *table;
+ int hash, i, table_mask;
+ hash = mix_hash (hash_table->hash_func (key));
+ hp = mono_hazard_pointer_get ();
+
+retry:
+ table = (conc_table *)mono_get_hazardous_pointer ((gpointer volatile*)&hash_table->table, hp, 0);
+ table_mask = table->table_size - 1;
+ i = hash & table_mask;
+
+ if (G_LIKELY (!hash_table->equal_func)) {
+ while (table->keys [i]) {
+ gpointer orig_key = table->keys [i];
+ if (key == orig_key) {
+ gpointer value;
+ /* The read of keys must happen before the read of values */
+ mono_memory_barrier ();
+ value = table->values [i];
+
+ /* We just read a value been deleted, try again. */
+ if (G_UNLIKELY (!value))
+ goto retry;
+
+ mono_hazard_pointer_clear (hp, 0);
+
+ *orig_key_ptr = orig_key;
+ *value_ptr = value;
+ return TRUE;
+ }
+ i = (i + 1) & table_mask;
+ }
+ } else {
+ GEqualFunc equal = hash_table->equal_func;
+
+ while (table->keys [i]) {
+ gpointer orig_key = table->keys [i];
+ if (!key_is_tombstone (hash_table, orig_key) && equal (key, orig_key)) {
+ gpointer value;
+ /* The read of keys must happen before the read of values */
+ mono_memory_barrier ();
+ value = table->values [i];
+
+ /* We just read a value been deleted, try again. */
+ if (G_UNLIKELY (!value))
+ goto retry;
+
+ mono_hazard_pointer_clear (hp, 0);
+ *orig_key_ptr = orig_key;
+ *value_ptr = value;
+ return TRUE;
+
+ }
+ i = (i + 1) & table_mask;
+ }
+ }
+
+ /* The table might have expanded and the value is now on the newer table */
+ mono_memory_barrier ();
+ if (hash_table->table != table)
+ goto retry;
+
+ mono_hazard_pointer_clear (hp, 0);
+
+ *orig_key_ptr = NULL;
+ *value_ptr = NULL;
+ return FALSE;
+}
+
+void
+mono_conc_g_hash_table_foreach (MonoConcGHashTable *hash_table, GHFunc func, gpointer user_data)
+{
+ int i;
+ conc_table *table = (conc_table*)hash_table->table;
+
+ for (i = 0; i < table->table_size; ++i) {
+ if (table->keys [i] && !key_is_tombstone (hash_table, table->keys [i])) {
+ func (table->keys [i], table->values [i], user_data);
+ }
+ }
+}
+
+void
+mono_conc_g_hash_table_destroy (MonoConcGHashTable *hash_table)
+{
+ if (hash_table->key_destroy_func || hash_table->value_destroy_func) {
+ int i;
+ conc_table *table = (conc_table*)hash_table->table;
+
+ for (i = 0; i < table->table_size; ++i) {
+ if (table->keys [i] && !key_is_tombstone (hash_table, table->keys [i])) {
+ if (hash_table->key_destroy_func)
+ (hash_table->key_destroy_func) (table->keys [i]);
+ if (hash_table->value_destroy_func)
+ (hash_table->value_destroy_func) (table->values [i]);
+ }
+ }
+ }
+ conc_table_free ((gpointer)hash_table->table);
+ g_free (hash_table);
+}
+
+/* Return NULL on success or the old value in failure */
+gpointer
+mono_conc_g_hash_table_insert (MonoConcGHashTable *hash_table, gpointer key, gpointer value)
+{
+ conc_table *table;
+ int hash, i, table_mask;
+
+ g_assert (key != NULL);
+ g_assert (value != NULL);
+
+ hash = mix_hash (hash_table->hash_func (key));
+
+ if (hash_table->element_count >= hash_table->overflow_count)
+ expand_table (hash_table);
+
+ table = (conc_table*)hash_table->table;
+ table_mask = table->table_size - 1;
+ i = hash & table_mask;
+
+ if (!hash_table->equal_func) {
+ for (;;) {
+ gpointer cur_key = table->keys [i];
+ if (!cur_key || key_is_tombstone (hash_table, cur_key)) {
+ set_value (table, i, value);
+
+ /* The write to values must happen after the write to keys */
+ mono_memory_barrier ();
+ set_key (table, i, key);
+ ++hash_table->element_count;
+ return NULL;
+ }
+ if (key == cur_key) {
+ gpointer value = table->values [i];
+ return value;
+ }
+ i = (i + 1) & table_mask;
+ }
+ } else {
+ GEqualFunc equal = hash_table->equal_func;
+ for (;;) {
+ gpointer cur_key = table->keys [i];
+ if (!cur_key || key_is_tombstone (hash_table, cur_key)) {
+ set_value (table, i, value);
+ /* The write to values must happen after the write to keys */
+ mono_memory_barrier ();
+ set_key (table, i, key);
+ ++hash_table->element_count;
+ return NULL;
+ }
+ if (equal (key, cur_key)) {
+ gpointer value = table->values [i];
+ return value;
+ }
+ i = (i + 1) & table_mask;
+ }
+ }
+}
+
+gpointer
+mono_conc_g_hash_table_remove (MonoConcGHashTable *hash_table, gconstpointer key)
+{
+ conc_table *table;
+ int hash, i, table_mask;
+
+ g_assert (key != NULL);
+
+ hash = mix_hash (hash_table->hash_func (key));
+
+ table = (conc_table*)hash_table->table;
+ table_mask = table->table_size - 1;
+ i = hash & table_mask;
+
+ if (!hash_table->equal_func) {
+ for (;;) {
+ gpointer cur_key = table->keys [i];
+ if (!cur_key) {
+ return NULL; /*key not found*/
+ }
+
+ if (key == cur_key) {
+ gpointer value = table->values [i];
+ table->values [i] = NULL;
+ mono_memory_barrier ();
+ set_key_to_tombstone (table, i);
+
+ --hash_table->element_count;
+
+ if (hash_table->key_destroy_func != NULL)
+ (*hash_table->key_destroy_func) (cur_key);
+ if (hash_table->value_destroy_func != NULL)
+ (*hash_table->value_destroy_func) (value);
+
+ return value;
+ }
+ i = (i + 1) & table_mask;
+ }
+ } else {
+ GEqualFunc equal = hash_table->equal_func;
+ for (;;) {
+ gpointer cur_key = table->keys [i];
+ if (!cur_key) {
+ return NULL; /*key not found*/
+ }
+
+ if (!key_is_tombstone (hash_table, cur_key) && equal (key, cur_key)) {
+ gpointer value = table->values [i];
+ table->values [i] = NULL;
+ mono_memory_barrier ();
+ set_key_to_tombstone (table, i);
+
+ if (hash_table->key_destroy_func != NULL)
+ (*hash_table->key_destroy_func) (cur_key);
+ if (hash_table->value_destroy_func != NULL)
+ (*hash_table->value_destroy_func) (value);
+ return value;
+ }
+
+ i = (i + 1) & table_mask;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+/**
+ * \file
+ * GC-aware concurrent hashtable, based on utils/mono-conc-hashtable
+ */
+
+#ifndef __MONO_CONC_G_HASH_H__
+#define __MONO_CONC_G_HASH_H__
+
+#include <mono/metadata/mono-hash.h>
+
+
+typedef struct _MonoConcGHashTable MonoConcGHashTable;
+
+MonoConcGHashTable * mono_conc_g_hash_table_new_type (GHashFunc hash_func, GEqualFunc key_equal_func, MonoGHashGCType type, MonoGCRootSource source, const char *msg);
+gpointer mono_conc_g_hash_table_lookup (MonoConcGHashTable *hash, gconstpointer key);
+gboolean mono_conc_g_hash_table_lookup_extended (MonoConcGHashTable *hash, gconstpointer key, gpointer *orig_key, gpointer *value);
+void mono_conc_g_hash_table_foreach (MonoConcGHashTable *hash, GHFunc func, gpointer user_data);
+void mono_conc_g_hash_table_destroy (MonoConcGHashTable *hash);
+gpointer mono_conc_g_hash_table_insert (MonoConcGHashTable *h, gpointer k, gpointer v);
+gpointer mono_conc_g_hash_table_remove (MonoConcGHashTable *hash, gconstpointer key);
+
+#endif /* __MONO_CONC_G_HASH_H__ */
ReflectedEntry pe;
pe.item = item;
pe.refclass = klass;
+
mono_domain_lock (domain);
if (!domain->refobject_hash)
- domain->refobject_hash = mono_g_hash_table_new_type (reflected_hash, reflected_equal, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_DOMAIN, "domain reflection objects table");
+ domain->refobject_hash = mono_conc_g_hash_table_new_type (reflected_hash, reflected_equal, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_DOMAIN, "domain reflection objects table");
- obj = (MonoObject*) mono_g_hash_table_lookup (domain->refobject_hash, &pe);
+ obj = (MonoObject*) mono_conc_g_hash_table_lookup (domain->refobject_hash, &pe);
if (obj == NULL) {
ReflectedEntry *e = ALLOC_REFENTRY;
e->item = item;
e->refclass = klass;
- mono_g_hash_table_insert (domain->refobject_hash, e, o);
+ mono_conc_g_hash_table_insert (domain->refobject_hash, e, o);
obj = o;
}
mono_domain_unlock (domain);
ReflectedEntry pe;
pe.item = item;
pe.refclass = klass;
+
mono_domain_lock (domain);
if (!domain->refobject_hash)
- domain->refobject_hash = mono_g_hash_table_new_type (reflected_hash, reflected_equal, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_DOMAIN, "domain reflection objects table");
+ domain->refobject_hash = mono_conc_g_hash_table_new_type (reflected_hash, reflected_equal, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_DOMAIN, "domain reflection objects table");
- MonoObjectHandle obj = MONO_HANDLE_NEW (MonoObject, mono_g_hash_table_lookup (domain->refobject_hash, &pe));
+ MonoObjectHandle obj = MONO_HANDLE_NEW (MonoObject, mono_conc_g_hash_table_lookup (domain->refobject_hash, &pe));
if (MONO_HANDLE_IS_NULL (obj)) {
ReflectedEntry *e = ALLOC_REFENTRY;
e->item = item;
e->refclass = klass;
- mono_g_hash_table_insert (domain->refobject_hash, e, MONO_HANDLE_RAW (o));
+ mono_conc_g_hash_table_insert (domain->refobject_hash, e, MONO_HANDLE_RAW (o));
MONO_HANDLE_ASSIGN (obj, o);
}
mono_domain_unlock (domain);
ReflectedEntry e;
e.item = item;
e.refclass = klass;
- mono_domain_lock (domain);
- if (!domain->refobject_hash)
- domain->refobject_hash = mono_g_hash_table_new_type (reflected_hash, reflected_equal, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_DOMAIN, "domain reflection objects table");
- MonoObjectHandle obj = MONO_HANDLE_NEW (MonoObject, mono_g_hash_table_lookup (domain->refobject_hash, &e));
- mono_domain_unlock (domain);
+ MonoConcGHashTable *hash = domain->refobject_hash;
+ if (!hash)
+ return MONO_HANDLE_NEW (MonoObject, NULL);
+
+ MonoObjectHandle obj = MONO_HANDLE_NEW (MonoObject, mono_conc_g_hash_table_lookup (hash, &e));
return obj;
}
return obj;
MONO_HANDLE_ASSIGN (obj, construct (domain, klass, item, user_data, error));
return_val_if_nok (error, NULL);
+ if (MONO_HANDLE_IS_NULL (obj))
+ return obj;
/* note no caching if there was an error in construction */
return cache_object_handle (domain, klass, item, obj);
}
pe.item = o;
pe.refclass = klass;
- if (mono_g_hash_table_lookup_extended (domain->refobject_hash, &pe, &orig_pe, &orig_value)) {
- mono_g_hash_table_remove (domain->refobject_hash, &pe);
+
+ if (mono_conc_g_hash_table_lookup_extended (domain->refobject_hash, &pe, &orig_pe, &orig_value)) {
+ mono_conc_g_hash_table_remove (domain->refobject_hash, &pe);
FREE_REFENTRY (orig_pe);
}
}
if (domain->refobject_hash) {
/*let's avoid scanning the whole hashtable if not needed*/
#ifdef REFENTRY_REQUIRES_CLEANUP
- mono_g_hash_table_foreach (domain->refobject_hash, cleanup_refobject_hash, NULL);
+ mono_conc_g_hash_table_foreach (domain->refobject_hash, cleanup_refobject_hash, NULL);
#endif
- mono_g_hash_table_destroy (domain->refobject_hash);
+ mono_conc_g_hash_table_destroy (domain->refobject_hash);
domain->refobject_hash = NULL;
}
}
HANDLE_FUNCTION_RETURN_OBJ (result);
}
+/* WARNING: This method can return NULL on sucess */
static MonoReflectionMethodBodyHandle
method_body_object_construct (MonoDomain *domain, MonoClass *unused_class, MonoMethod *method, gpointer user_data, MonoError *error)
{
goto leave;
g_assert (base);
gint32 rank = MONO_HANDLE_GETVAL (sre_array, rank);
- if (rank == 0) //single dimentional array
- result = &mono_array_class_get (mono_class_from_mono_type (base), 1)->byval_arg;
- else
- result = &mono_bounded_array_class_get (mono_class_from_mono_type (base), rank, TRUE)->byval_arg;
+ MonoClass *eclass = mono_class_from_mono_type (base);
+ result = mono_image_new0 (eclass->image, MonoType, 1);
+ if (rank == 0) {
+ result->type = MONO_TYPE_SZARRAY;
+ result->data.klass = eclass;
+ } else {
+ MonoArrayType *at = (MonoArrayType *)mono_image_alloc0 (eclass->image, sizeof (MonoArrayType));
+ result->type = MONO_TYPE_ARRAY;
+ result->data.array = at;
+ at->eklass = eclass;
+ at->rank = rank;
+ }
MONO_HANDLE_SETVAL (ref, type, MonoType*, result);
} else if (is_sre_byref (klass)) {
MonoReflectionDerivedTypeHandle sre_byref = MONO_HANDLE_CAST (MonoReflectionDerivedType, ref);
interp/mintops.def \
interp/mintops.c \
interp/transform.c
+else
+interp_sources = \
+ interp/interp-stubs.c
endif
if ENABLE_LLVM
aot-tests.cs \
gc-test.cs \
gshared.cs \
+ unaligned.cs \
+ MemoryIntrinsics.il \
mixed.cs
if NACL_CODEGEN
devirtualization.exe \
generics.exe \
basic-simd.exe \
+ unaligned.exe \
basic-vectors.exe
if NACL_CODEGEN
generics.exe: generics.cs TestDriver.dll generics-variant-types.dll
$(MCS) -out:$@ $(CSFLAGS) $< -r:TestDriver.dll -r:generics-variant-types.dll -r:$(CLASS)/System.Core.dll
+unaligned.exe: unaligned.cs TestDriver.dll MemoryIntrinsics.dll
+ $(MCS) -out:$@ $(CSFLAGS) $< -r:TestDriver.dll -r:MemoryIntrinsics.dll
+
%.exe: %.cs TestDriver.dll
$(MCS) -out:$@ $(CSFLAGS) $< -r:TestDriver.dll
generics-variant-types.dll: generics-variant-types.il
$(ILASM) -dll -output=$@ $<
+MemoryIntrinsics.dll: MemoryIntrinsics.il
+ $(ILASM) -dll -output=$@ $<
+
if NACL_CODEGEN
GENMDESC_OPTS=--nacl
else !NACL_CODEGEN
$(MAKE) fullaotcheck GSHAREDVT=1
fullaot_regtests = $(regtests) aot-tests.exe $(if $(GSHAREDVT),gshared.exe)
+fullaot_testing_deps = generics-variant-types.dll TestDriver.dll MemoryIntrinsics.dll
FULLAOT_LIBS_UNIVERSAL = \
mscorlib.dll \
System.Configuration.dll
endif
+
FULLAOT_LIBS = $(filter-out $(FULLAOT_LIBS_DISABLED),$(FULLAOT_LIBS_UNIVERSAL))
FULLAOT_TMP_DIR=$(top_builddir)/mono/mini/fullaot-tmp
# This currently only works on amd64/arm
-fullaotcheck: $(mono) $(fullaot_regtests)
+fullaotcheck: $(mono) $(fullaot_regtests) $(fullaot_testing_deps)
rm -rf $(FULLAOT_TMP_DIR)
mkdir $(FULLAOT_TMP_DIR)
$(MAKE) fullaot-libs AOT_FLAGS="full,$(MONO_FULLAOT_ADDITIONAL_ARGS)$(INVARIANT_AOT_OPTIONS)" GSHAREDVT=$(GSHAREDVT)
- cp $(regtests) $(fullaot_regtests) generics-variant-types.dll TestDriver.dll $(FULLAOT_TMP_DIR)/
- MONO_PATH=$(FULLAOT_TMP_DIR) $(top_builddir)/runtime/mono-wrapper $(MOBILE_RUNTIME_ARG) $(LLVM_AOT_RUNTIME_OPTS) $(GSHAREDVT_RUNTIME_OPTS) --aot="full,$(MONO_FULLAOT_ADDITIONAL_ARGS)$(INVARIANT_AOT_OPTIONS)" $(FULLAOT_TMP_DIR)/{generics-variant-types.dll,TestDriver.dll,*.exe} || exit 1
+ cp $(regtests) $(fullaot_regtests) $(fullaot_testing_deps) $(FULLAOT_TMP_DIR)/
+ MONO_PATH=$(FULLAOT_TMP_DIR) $(top_builddir)/runtime/mono-wrapper $(MOBILE_RUNTIME_ARG) $(LLVM_AOT_RUNTIME_OPTS) $(GSHAREDVT_RUNTIME_OPTS) --aot="full,$(MONO_FULLAOT_ADDITIONAL_ARGS)$(INVARIANT_AOT_OPTIONS)" $(FULLAOT_TMP_DIR)/{*.dll,*.exe} || exit 1
ln -s $(if $(MONO_EXECUTABLE),$(MONO_EXECUTABLE),$$PWD/mono) $(FULLAOT_TMP_DIR)/
for i in $(fullaot_regtests); do echo $$i; MONO_PATH=$(FULLAOT_TMP_DIR) $(top_builddir)/runtime/mono-wrapper $(MOBILE_RUNTIME_ARG) --full-aot $(FULLAOT_TMP_DIR)/$$i --exclude '!FULLAOT' $(ARCH_FULLAOT_EXCLUDE) || exit 1; done
rm -rf fullaot-tmp
mkdir fullaot-tmp
$(MAKE) fullaot-libs AOT_FLAGS="llvmonly,$(MONO_FULLAOT_ADDITIONAL_ARGS)$(INVARIANT_AOT_OPTIONS)"
- cp $(llvmonly_regtests) generics-variant-types.dll TestDriver.dll fullaot-tmp/
- MONO_PATH=fullaot-tmp $(top_builddir)/runtime/mono-wrapper $(MOBILE_RUNTIME_ARG) --aot=llvmonly fullaot-tmp/{generics-variant-types.dll,TestDriver.dll,*.exe} || exit 1
+ cp $(llvmonly_regtests) $(fullaot_testing_deps) fullaot-tmp/
+ MONO_PATH=fullaot-tmp $(top_builddir)/runtime/mono-wrapper $(MOBILE_RUNTIME_ARG) --aot=llvmonly fullaot-tmp/{*.dll,*.exe} || exit 1
ln -s $$PWD/mono fullaot-tmp/
for i in $(llvmonly_regtests); do echo $$i; MONO_PATH=fullaot-tmp $(top_builddir)/runtime/mono-wrapper $(MOBILE_RUNTIME_ARG) --llvmonly fullaot-tmp/$$i --exclude '!BITCODE' || exit 1; done
--- /dev/null
+.assembly extern mscorlib
+{
+ .publickeytoken = (B7 7A 5C 56 19 34 E0 89 )
+ .ver 4:0:0:0
+}
+
+.assembly 'MemoryIntrinsics'
+{
+ .custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78 63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 )
+ .hash algorithm 0x00008004
+ .ver 0:0:0:0
+}
+.module 'instrics-lib.dll'
+.imagebase 0x00400000
+.file alignment 0x00000200
+.stackreserve 0x00100000
+.subsystem 0x0003
+.corflags 0x00000001
+
+.namespace Mono {
+ .class public abstract auto ansi sealed beforefieldinit Intrinsics extends [mscorlib]System.Object
+ {
+ .method public hidebysig static void Cpobj<T>(void* 'to', void* from) cil managed
+ {
+ ldarg.0
+ ldarg.1
+ cpobj !!T
+ ret
+ }
+
+ .method public hidebysig static !!T Ldobj<T>(void* 'from') cil managed
+ {
+ ldarg.0
+ ldobj !!T
+ ret
+ }
+
+ .method public hidebysig static void Stobj<T>(void* 'to', !!T 'value') cil managed
+ {
+ ldarg.0
+ ldarg.1
+ stobj !!T
+ ret
+ }
+
+ .method public hidebysig static void LdobjStObjPair<T>(void* 'to', void* 'from') cil managed
+ {
+ ldarg.0
+ ldarg.1
+ ldobj !!T
+ stobj !!T
+ ret
+ }
+
+ .method public hidebysig static void Cpblk(void* 'to', void* 'from', int32 size) cil managed
+ {
+ ldarg.0
+ ldarg.1
+ ldarg.2
+ cpblk
+ ret
+ }
+
+ .method public hidebysig static void Initblk<T>(void* 'to', int32 'value', int32 'size') cil managed
+ {
+ ldarg.0
+ ldarg.1
+ ldarg.2
+ initblk
+ ret
+ }
+
+ //Unaligned intrinsics
+ .method public hidebysig static void UnalignedCpobj<T>(void* 'to', void* from) cil managed
+ {
+ ldarg.0
+ ldarg.1
+ unaligned. 1
+ cpobj !!T
+ ret
+ }
+
+ .method public hidebysig static !!T UnalignedLdobj<T>(void* 'from') cil managed
+ {
+ ldarg.0
+ unaligned. 1
+ ldobj !!T
+ ret
+ }
+
+ .method public hidebysig static void UnalignedStobj<T>(void* 'to', !!T 'value') cil managed
+ {
+ ldarg.0
+ ldarg.1
+ unaligned. 1
+ stobj !!T
+ ret
+ }
+
+ .method public hidebysig static void UnalignedLdobjStObjPair<T>(void* 'to', void* 'from') cil managed
+ {
+ ldarg.0
+ ldarg.1
+ unaligned. 1
+ ldobj !!T
+ stobj !!T
+ ret
+ }
+
+ .method public hidebysig static void UnalignedCpblk(void* 'to', void* 'from', int32 size) cil managed
+ {
+ ldarg.0
+ ldarg.1
+ ldarg.2
+ unaligned. 1
+ cpblk
+ ret
+ }
+
+ .method public hidebysig static void UnalignedInit(void* 'to', int32 'value', int32 'size') cil managed
+ {
+ ldarg.0
+ ldarg.1
+ ldarg.2
+ unaligned. 1
+ initblk
+ ret
+ }
+
+ //Unaligned ldind
+ .method public hidebysig static int16 UnalignedLdInd2(void* 'from') cil managed
+ {
+ ldarg.0
+ unaligned. 1
+ ldind.i2
+ ret
+ }
+
+ .method public hidebysig static int32 UnalignedLdInd4(void* 'from') cil managed
+ {
+ ldarg.0
+ unaligned. 1
+ ldind.i4
+ ret
+ }
+
+ .method public hidebysig static int64 UnalignedLdInd8(void* 'from') cil managed
+ {
+ ldarg.0
+ unaligned. 1
+ ldind.i8
+ ret
+ }
+
+ .method public hidebysig static float32 UnalignedLdIndR4(void* 'from') cil managed
+ {
+ ldarg.0
+ unaligned. 1
+ ldind.r4
+ ret
+ }
+
+ .method public hidebysig static float64 UnalignedLdIndR8(void* 'from') cil managed
+ {
+ ldarg.0
+ unaligned. 1
+ ldind.r8
+ ret
+ }
+
+ .method public hidebysig static native int UnalignedLdIndI(void* 'from') cil managed
+ {
+ ldarg.0
+ unaligned. 1
+ ldind.i
+ ret
+ }
+
+ }
+}
if (!method)
return NULL;
}
- full_name = mono_method_full_name (method, TRUE);
- mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT, "AOT: NOT FOUND: %s.", full_name);
- g_free (full_name);
+ if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL)) {
+ full_name = mono_method_full_name (method, TRUE);
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT, "AOT: NOT FOUND: %s.", full_name);
+ g_free (full_name);
+ }
}
return NULL;
}
#include <mono/utils/mono-threads.h>
#include <mono/utils/networking.h>
#include <mono/utils/mono-proclib.h>
+#include <mono/utils/w32api.h>
#include "debugger-agent.h"
#include "mini.h"
#include "seq-points.h"
-#include <mono/utils/w32api.h>
+#include "interp/interp.h"
/*
* On iOS we can't use System.Environment.Exit () as it will do the wrong
MonoContext ctx;
MonoDebugMethodJitInfo *jit;
MonoJitInfo *ji;
+ MonoInterpFrameHandle interp_frame;
int flags;
mgreg_t *reg_locations [MONO_MAX_IREGS];
/*
* SUSPEND/RESUME
*/
+static MonoJitInfo*
+get_top_method_ji (gpointer ip, MonoDomain **domain, gpointer *out_ip)
+{
+ MonoJitInfo *ji;
+
+ if (out_ip)
+ *out_ip = ip;
+
+ ji = mini_jit_info_table_find (mono_domain_get (), (char*)ip, domain);
+ if (!ji) {
+ /* Could be an interpreter method */
+
+ MonoLMF *lmf = mono_get_lmf ();
+ MonoInterpFrameHandle *frame;
+
+ g_assert (((guint64)lmf->previous_lmf) & 2);
+ MonoLMFExt *ext = (MonoLMFExt*)lmf;
+
+ g_assert (ext->interp_exit);
+ frame = ext->interp_exit_data;
+ ji = mono_interp_frame_get_jit_info (frame);
+ if (domain)
+ *domain = mono_domain_get ();
+ if (out_ip)
+ *out_ip = mono_interp_frame_get_ip (frame);
+ }
+ return ji;
+}
+
/*
* save_thread_context:
*
* suspended when it returns to managed code, so the parent's ctx should
* remain valid.
*/
+ MonoThreadUnwindState *state = mono_thread_info_get_suspend_state (info);
+
data.last_frame_set = FALSE;
- mono_get_eh_callbacks ()->mono_walk_stack_with_state (get_last_frame, mono_thread_info_get_suspend_state (info), MONO_UNWIND_SIGNAL_SAFE, &data);
+ mono_get_eh_callbacks ()->mono_walk_stack_with_state (get_last_frame, state, MONO_UNWIND_SIGNAL_SAFE, &data);
if (data.last_frame_set) {
gpointer jit_tls = ((MonoThreadInfo*)tls->thread->thread_info)->jit_data;
memcpy (&tls->async_last_frame, &data.last_frame, sizeof (StackFrameInfo));
+ if (data.last_frame.type == FRAME_TYPE_INTERP_TO_MANAGED) {
+ /*
+ * Store the current lmf instead of the parent one, since that
+ * contains the interp exit data.
+ */
+ data.lmf = state->unwind_data [MONO_UNWIND_DATA_LMF];
+ }
+
copy_unwind_state_from_frame_data (&tls->async_state, &data, jit_tls);
copy_unwind_state_from_frame_data (&tls->context, &data, jit_tls);
} else {
return;
}
- ji = mini_jit_info_table_find (mono_domain_get (), (char*)ip, NULL);
-
+ ji = get_top_method_ji (ip, NULL, NULL);
+ g_assert (ji);
/* Can't suspend in these methods */
method = jinfo_get_method (ji);
if (method->klass == mono_defaults.string_class && (!strcmp (method->name, "memset") || strstr (method->name, "memcpy")))
SeqPoint sp;
int flags = 0;
- if (info->type != FRAME_TYPE_MANAGED) {
+ if (info->type != FRAME_TYPE_MANAGED && info->type != FRAME_TYPE_INTERP) {
if (info->type == FRAME_TYPE_DEBUGGER_INVOKE) {
/* Mark the last frame as an invoke frame */
if (ud->frames)
frame->native_offset = info->native_offset;
frame->flags = flags;
frame->ji = info->ji;
+ frame->interp_frame = info->interp_frame;
if (info->reg_locations)
memcpy (frame->reg_locations, info->reg_locations, MONO_MAX_IREGS * sizeof (mgreg_t*));
if (ctx) {
send_type_load (method->klass);
- if (!result)
+ if (!result && jinfo)
add_pending_breakpoints (method, jinfo);
}
if (it.seq_point.native_offset == SEQ_POINT_NATIVE_OFFSET_DEAD_CODE) {
DEBUG_PRINTF (1, "[dbg] Attempting to insert seq point at dead IL offset %d, ignoring.\n", (int)bp->il_offset);
} else if (count == 0) {
+ if (ji->is_interp) {
+ mono_interp_set_breakpoint (ji, inst->ip);
+ } else {
#ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
- mono_arch_set_breakpoint (ji, inst->ip);
+ mono_arch_set_breakpoint (ji, inst->ip);
#else
- NOT_IMPLEMENTED;
+ NOT_IMPLEMENTED;
#endif
+ }
}
DEBUG_PRINTF (1, "[dbg] Inserted breakpoint at %s:[il=0x%x,native=0x%x] [%p](%d).\n", mono_method_full_name (jinfo_get_method (ji), TRUE), (int)it.seq_point.il_offset, (int)it.seq_point.native_offset, inst->ip, count);
g_assert (count > 0);
if (count == 1 && inst->native_offset != SEQ_POINT_NATIVE_OFFSET_DEAD_CODE) {
- mono_arch_clear_breakpoint (ji, ip);
+ if (ji->is_interp)
+ mono_interp_clear_breakpoint (ji, ip);
+ else
+ mono_arch_clear_breakpoint (ji, ip);
DEBUG_PRINTF (1, "[dbg] Clear breakpoint at %s [%p].\n", mono_method_full_name (jinfo_get_method (ji), TRUE), ip);
}
#else
/* Might be AOTed code */
mono_class_init (method->klass);
code = mono_aot_get_method_checked (domain, method, &oerror);
- g_assert (code);
- mono_error_assert_ok (&oerror);
- ji = mono_jit_info_table_find (domain, (char *)code);
+ if (code) {
+ mono_error_assert_ok (&oerror);
+ ji = mono_jit_info_table_find (domain, (char *)code);
+ } else {
+ /* Might be interpreted */
+ ji = mono_interp_find_jit_info (domain, method);
+ }
g_assert (ji);
}
- g_assert (code);
insert_breakpoint (seq_points, domain, ji, bp, error);
}
}
}
- MonoDebugMethodAsyncInfo* asyncMethod = mono_debug_lookup_method_async_debug_info (method);
- if (asyncMethod) {
- for (int i = 0; i < asyncMethod->num_awaits; i++)
- {
- if (asyncMethod->yield_offsets[i] == sp->il_offset || asyncMethod->resume_offsets[i] == sp->il_offset) {
- mono_debug_free_method_async_debug_info (asyncMethod);
+ MonoDebugMethodAsyncInfo* async_method = mono_debug_lookup_method_async_debug_info (method);
+ if (async_method) {
+ for (int i = 0; i < async_method->num_awaits; i++) {
+ if (async_method->yield_offsets[i] == sp->il_offset || async_method->resume_offsets[i] == sp->il_offset) {
+ mono_debug_free_method_async_debug_info (async_method);
return FALSE;
}
}
- mono_debug_free_method_async_debug_info (asyncMethod);
+ mono_debug_free_method_async_debug_info (async_method);
}
if (req->size != STEP_SIZE_LINE)
}
static void
-process_breakpoint_inner (DebuggerTlsData *tls, gboolean from_signal)
+process_breakpoint (DebuggerTlsData *tls, gboolean from_signal)
{
MonoJitInfo *ji;
guint8 *ip;
ip = (guint8 *)MONO_CONTEXT_GET_IP (ctx);
ji = mini_jit_info_table_find (mono_domain_get (), (char*)ip, NULL);
+
+ if (!ji) {
+ /* Interpreter */
+ // FIXME: Pass a flag instead to detect this
+ MonoLMF *lmf = mono_get_lmf ();
+ MonoInterpFrameHandle *frame;
+
+ g_assert (((guint64)lmf->previous_lmf) & 2);
+ MonoLMFExt *ext = (MonoLMFExt*)lmf;
+
+ g_assert (ext->interp_exit);
+ frame = ext->interp_exit_data;
+ ji = mono_interp_frame_get_jit_info (frame);
+ ip = mono_interp_frame_get_ip (frame);
+ }
+
g_assert (ji && !ji->is_trampoline);
method = jinfo_get_method (ji);
/* Compute the native offset of the breakpoint from the ip */
- native_offset = ip - (guint8*)ji->code_start;
+ native_offset = ip - (guint8*)ji->code_start;
/*
* Skip the instruction causing the breakpoint signal.
}
static void
-process_breakpoint (void)
+process_breakpoint_from_signal (void)
{
- process_signal_event (process_breakpoint_inner);
+ process_signal_event (process_breakpoint);
}
static void
* problems, like the original signal is disabled, libgc can't handle altstack, etc.
* So set up the signal context to return to the real breakpoint handler function.
*/
- resume_from_signal_handler (sigctx, process_breakpoint);
+ resume_from_signal_handler (sigctx, process_breakpoint_from_signal);
}
+typedef struct {
+ gboolean found;
+ MonoContext *ctx;
+} UserBreakCbData;
+
static gboolean
-user_break_cb (StackFrameInfo *frame, MonoContext *ctx, gpointer data)
+user_break_cb (StackFrameInfo *frame, MonoContext *ctx, gpointer user_data)
{
+ UserBreakCbData *data = user_data;
+
+ if (frame->type == FRAME_TYPE_INTERP_TO_MANAGED) {
+ data->found = TRUE;
+ return TRUE;
+ }
if (frame->managed) {
- *(MonoContext*)data = *ctx;
+ data->found = TRUE;
+ *data->ctx = *ctx;
return TRUE;
- } else {
- return FALSE;
}
+ return FALSE;
}
/*
MonoContext ctx;
int suspend_policy;
GSList *events;
+ UserBreakCbData data;
+
+ memset (&data, 0, sizeof (UserBreakCbData));
+ data.ctx = &ctx;
/* Obtain a context */
MONO_CONTEXT_SET_IP (&ctx, NULL);
- mono_walk_stack_with_ctx (user_break_cb, NULL, (MonoUnwindOptions)0, &ctx);
- g_assert (MONO_CONTEXT_GET_IP (&ctx) != NULL);
+ mono_walk_stack_with_ctx (user_break_cb, NULL, (MonoUnwindOptions)0, &data);
+ g_assert (data.found);
mono_loader_lock ();
events = create_event_list (EVENT_KIND_USER_BREAK, NULL, NULL, NULL, &suspend_policy);
SeqPoint sp;
MonoSeqPointInfo *info;
- ip = (guint8 *)MONO_CONTEXT_GET_IP (ctx);
-
/* Skip the instruction causing the single step */
if (from_signal)
mono_arch_skip_single_step (ctx);
if (mono_thread_internal_current () != ss_req->thread)
return;
- if (log_level > 0) {
- ji = mini_jit_info_table_find (mono_domain_get (), (char*)ip, &domain);
+ ip = (guint8 *)MONO_CONTEXT_GET_IP (ctx);
+
+ ji = get_top_method_ji (ip, &domain, (gpointer*)&ip);
+ g_assert (ji && !ji->is_trampoline);
+ if (log_level > 0) {
DEBUG_PRINTF (1, "[%p] Single step event (depth=%s) at %s (%p)[0x%x], sp %p, last sp %p\n", (gpointer) (gsize) mono_native_thread_id_get (), ss_depth_to_string (ss_req->depth), mono_method_full_name (jinfo_get_method (ji), TRUE), MONO_CONTEXT_GET_IP (ctx), (int)((guint8*)MONO_CONTEXT_GET_IP (ctx) - (guint8*)ji->code_start), MONO_CONTEXT_GET_SP (ctx), ss_req->last_sp);
}
- ji = mini_jit_info_table_find (mono_domain_get (), (char*)ip, &domain);
- g_assert (ji && !ji->is_trampoline);
method = jinfo_get_method (ji);
g_assert (method);
* The ip points to the instruction causing the single step event, which is before
* the offset recorded in the seq point map, so find the next seq point after ip.
*/
- if (!mono_find_next_seq_point_for_native_offset (domain, method, (guint8*)ip - (guint8*)ji->code_start, &info, &sp))
+ if (!mono_find_next_seq_point_for_native_offset (domain, method, (guint8*)ip - (guint8*)ji->code_start, &info, &sp)) {
+ g_assert_not_reached ();
return;
+ }
il_offset = sp.il_offset;
mono_thread_state_init_from_monoctx (&tls->restore_state, ctx);
memcpy (&tls->handler_ctx, ctx, sizeof (MonoContext));
- process_breakpoint_inner (tls, FALSE);
+ process_breakpoint (tls, FALSE);
memcpy (ctx, &tls->restore_state.ctx, sizeof (MonoContext));
memcpy (&tls->restore_state, &orig_restore_state, sizeof (MonoThreadUnwindState));
#ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
int val = InterlockedIncrement (&ss_count);
- if (val == 1)
+ if (val == 1) {
mono_arch_start_single_stepping ();
+ mono_interp_start_single_stepping ();
+ }
#else
g_assert_not_reached ();
#endif
#ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
int val = InterlockedDecrement (&ss_count);
- if (val == 0)
+ if (val == 0) {
mono_arch_stop_single_stepping ();
+ mono_interp_stop_single_stepping ();
+ }
#else
g_assert_not_reached ();
#endif
}
}
+static void
+set_interp_var (MonoType *t, gpointer addr, guint8 *val_buf)
+{
+ int size;
+
+ if (t->byref) {
+ addr = *(gpointer*)addr;
+ g_assert (addr);
+ }
+
+ if (MONO_TYPE_IS_REFERENCE (t))
+ size = sizeof (gpointer);
+ else
+ size = mono_class_value_size (mono_class_from_mono_type (t), NULL);
+
+ memcpy (addr, val_buf, size);
+}
+
static void
clear_event_request (int req_id, int etype)
{
// FIXME: Check that the ip change is safe
DEBUG_PRINTF (1, "[dbg] Setting IP to %s:0x%0x(0x%0x)\n", tls->frames [0]->actual_method->name, (int)sp.il_offset, (int)sp.native_offset);
- MONO_CONTEXT_SET_IP (&tls->restore_state.ctx, (guint8*)tls->frames [0]->ji->code_start + sp.native_offset);
+
+ if (tls->frames [0]->ji->is_interp) {
+ MonoJitTlsData *jit_data = ((MonoThreadInfo*)thread->thread_info)->jit_data;
+ mono_interp_set_resume_state (jit_data, NULL, tls->frames [0]->interp_frame, (guint8*)tls->frames [0]->ji->code_start + sp.native_offset);
+ } else {
+ MONO_CONTEXT_SET_IP (&tls->restore_state.ctx, (guint8*)tls->frames [0]->ji->code_start + sp.native_offset);
+ }
break;
}
default:
sig = mono_method_signature (frame->actual_method);
- if (!jit->has_var_info || !mono_get_seq_points (frame->domain, frame->actual_method))
+ if (!(jit->has_var_info || frame->ji->is_interp) || !mono_get_seq_points (frame->domain, frame->actual_method))
/*
* The method is probably from an aot image compiled without soft-debug, variables might be dead, etc.
*/
DEBUG_PRINTF (4, "[dbg] send arg %d.\n", pos);
- g_assert (pos >= 0 && pos < jit->num_params);
+ if (frame->ji->is_interp) {
+ guint8 *addr;
+
+ addr = mono_interp_frame_get_arg (frame->interp_frame, pos);
+
+ buffer_add_value_full (buf, sig->params [pos], addr, frame->domain, FALSE, NULL);
+ } else {
+ g_assert (pos >= 0 && pos < jit->num_params);
- add_var (buf, jit, sig->params [pos], &jit->params [pos], &frame->ctx, frame->domain, FALSE);
+ add_var (buf, jit, sig->params [pos], &jit->params [pos], &frame->ctx, frame->domain, FALSE);
+ }
} else {
MonoDebugLocalsInfo *locals;
pos = locals->locals [pos].index;
mono_debug_free_locals (locals);
}
- g_assert (pos >= 0 && pos < jit->num_locals);
DEBUG_PRINTF (4, "[dbg] send local %d.\n", pos);
- add_var (buf, jit, header->locals [pos], &jit->locals [pos], &frame->ctx, frame->domain, FALSE);
+ if (frame->ji->is_interp) {
+ guint8 *addr;
+
+ addr = mono_interp_frame_get_local (frame->interp_frame, pos);
+
+ buffer_add_value_full (buf, header->locals [pos], addr, frame->domain, FALSE, NULL);
+ } else {
+ g_assert (pos >= 0 && pos < jit->num_locals);
+
+ add_var (buf, jit, header->locals [pos], &jit->locals [pos], &frame->ctx, frame->domain, FALSE);
+ }
}
}
mono_metadata_free_mh (header);
break;
}
case CMD_STACK_FRAME_GET_THIS: {
+ if (frame->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
+ return ERR_ABSENT_INFORMATION;
if (frame->api_method->klass->valuetype) {
if (!sig->hasthis) {
MonoObject *p = NULL;
buffer_add_value (buf, &mono_defaults.object_class->byval_arg, &p, frame->domain);
} else {
- add_var (buf, jit, &frame->actual_method->klass->this_arg, jit->this_var, &frame->ctx, frame->domain, TRUE);
+ if (frame->ji->is_interp) {
+ guint8 *addr;
+
+ addr = mono_interp_frame_get_this (frame->interp_frame);
+
+ buffer_add_value_full (buf, &frame->actual_method->klass->this_arg, addr, frame->domain, FALSE, NULL);
+ } else {
+ add_var (buf, jit, &frame->actual_method->klass->this_arg, jit->this_var, &frame->ctx, frame->domain, TRUE);
+ }
}
} else {
if (!sig->hasthis) {
MonoObject *p = NULL;
buffer_add_value (buf, &frame->actual_method->klass->byval_arg, &p, frame->domain);
} else {
- add_var (buf, jit, &frame->api_method->klass->byval_arg, jit->this_var, &frame->ctx, frame->domain, TRUE);
+ if (frame->ji->is_interp) {
+ guint8 *addr;
+
+ addr = mono_interp_frame_get_this (frame->interp_frame);
+
+ buffer_add_value_full (buf, &frame->api_method->klass->byval_arg, addr, frame->domain, FALSE, NULL);
+ } else {
+ add_var (buf, jit, &frame->api_method->klass->byval_arg, jit->this_var, &frame->ctx, frame->domain, TRUE);
+ }
}
}
break;
MonoError error;
guint8 *val_buf;
MonoType *t;
- MonoDebugVarInfo *var;
+ MonoDebugVarInfo *var = NULL;
+ gboolean is_arg = FALSE;
len = decode_int (p, &p, end);
header = mono_method_get_header_checked (frame->actual_method, &error);
t = sig->params [pos];
var = &jit->params [pos];
+ is_arg = TRUE;
} else {
MonoDebugLocalsInfo *locals;
if (err != ERR_NONE)
return err;
- set_var (t, var, &frame->ctx, frame->domain, val_buf, frame->reg_locations, &tls->restore_state.ctx);
+ if (frame->ji->is_interp) {
+ guint8 *addr;
+
+ if (is_arg)
+ addr = mono_interp_frame_get_arg (frame->interp_frame, pos);
+ else
+ addr = mono_interp_frame_get_local (frame->interp_frame, pos);
+ set_interp_var (t, addr, val_buf);
+ } else {
+ set_var (t, var, &frame->ctx, frame->domain, val_buf, frame->reg_locations, &tls->restore_state.ctx);
+ }
}
mono_metadata_free_mh (header);
break;
t = &frame->actual_method->klass->byval_arg;
/* Checked by the sender */
g_assert (MONO_TYPE_ISSTRUCT (t));
- var = jit->this_var;
- g_assert (var);
val_buf = (guint8 *)g_alloca (mono_class_instance_size (mono_class_from_mono_type (t)));
err = decode_value (t, frame->domain, val_buf, p, &p, end);
if (err != ERR_NONE)
return err;
- set_var (&frame->actual_method->klass->this_arg, var, &frame->ctx, frame->domain, val_buf, frame->reg_locations, &tls->restore_state.ctx);
+ if (frame->ji->is_interp) {
+ guint8 *addr;
+
+ addr = mono_interp_frame_get_this (frame->interp_frame);
+ set_interp_var (&frame->actual_method->klass->this_arg, addr, val_buf);
+ } else {
+ var = jit->this_var;
+ g_assert (var);
+
+ set_var (&frame->actual_method->klass->this_arg, var, &frame->ctx, frame->domain, val_buf, frame->reg_locations, &tls->restore_state.ctx);
+ }
break;
}
default:
EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
EMIT_NEW_VARLOADA ((cfg), (dest), dest_var, dest_var->inst_vtype);
+ mini_emit_memory_copy (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke, 0);
- mini_emit_stobj (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke);
break;
}
case OP_VZERO:
dreg = alloc_preg (cfg);
EMIT_NEW_BIALU_IMM (cfg, dest, OP_ADD_IMM, dreg, ins->inst_destbasereg, ins->inst_offset);
- mini_emit_stobj (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke);
+ mini_emit_memory_copy (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke, 0);
break;
}
case OP_LOADV_MEMBASE: {
dreg = alloc_preg (cfg);
EMIT_NEW_BIALU_IMM (cfg, src, OP_ADD_IMM, dreg, ins->inst_basereg, ins->inst_offset);
EMIT_NEW_VARLOADA (cfg, dest, dest_var, dest_var->inst_vtype);
- mini_emit_stobj (cfg, dest, src, dest_var->klass, dest_var->backend.is_pinvoke);
+ mini_emit_memory_copy (cfg, dest, src, dest_var->klass, dest_var->backend.is_pinvoke, 0);
break;
}
case OP_OUTARG_VT: {
stackval *stack_args; /* parent */
stackval *stack;
stackval *sp; /* For GC stack marking */
+ unsigned char *locals;
/* exception info */
unsigned char invoke_trap;
const unsigned short *ip;
--- /dev/null
+#include <config.h>
+
+#ifndef ENABLE_INTERPRETER
+
+#include "interp.h"
+
+/* Dummy versions of interpreter functions to avoid ifdefs at call sites */
+
+MonoJitInfo*
+mono_interp_find_jit_info (MonoDomain *domain, MonoMethod *method)
+{
+ return NULL;
+}
+
+void
+mono_interp_set_breakpoint (MonoJitInfo *jinfo, gpointer ip)
+{
+ g_assert_not_reached ();
+}
+
+void
+mono_interp_clear_breakpoint (MonoJitInfo *jinfo, gpointer ip)
+{
+ g_assert_not_reached ();
+}
+
+MonoJitInfo*
+mono_interp_frame_get_jit_info (MonoInterpFrameHandle frame)
+{
+ g_assert_not_reached ();
+ return NULL;
+}
+
+gpointer
+mono_interp_frame_get_ip (MonoInterpFrameHandle frame)
+{
+ g_assert_not_reached ();
+ return NULL;
+}
+
+gpointer
+mono_interp_frame_get_arg (MonoInterpFrameHandle frame, int pos)
+{
+ g_assert_not_reached ();
+ return NULL;
+}
+
+gpointer
+mono_interp_frame_get_local (MonoInterpFrameHandle frame, int pos)
+{
+ g_assert_not_reached ();
+ return NULL;
+}
+
+gpointer
+mono_interp_frame_get_this (MonoInterpFrameHandle frame)
+{
+ g_assert_not_reached ();
+ return NULL;
+}
+
+void
+mono_interp_start_single_stepping (void)
+{
+}
+
+void
+mono_interp_stop_single_stepping (void)
+{
+}
+
+void
+mono_interp_set_resume_state (MonoJitTlsData *jit_tls, MonoException *ex, MonoInterpFrameHandle interp_frame, gpointer handler_ip)
+{
+ g_assert_not_reached ();
+}
+
+void
+mono_interp_run_finally (StackFrameInfo *frame, int clause_index, gpointer handler_ip)
+{
+ g_assert_not_reached ();
+}
+
+void
+mono_interp_frame_iter_init (MonoInterpStackIter *iter, gpointer interp_exit_data)
+{
+ g_assert_not_reached ();
+}
+
+gboolean
+mono_interp_frame_iter_next (MonoInterpStackIter *iter, StackFrameInfo *frame)
+{
+ g_assert_not_reached ();
+ return FALSE;
+}
+
+#endif
+
#include <mono/mini/mini.h>
#include <mono/mini/jit-icalls.h>
+#include <mono/mini/debugger-agent.h>
#ifdef TARGET_ARM
#include <mono/mini/mini-arm.h>
* Used for testing.
*/
GSList *jit_classes;
+/* If TRUE, interpreted code will be interrupted at function entry/backward branches */
+static gboolean ss_enabled;
void ves_exec_method (MonoInvocation *frame);
/* Set the current execution state to the resume state in context */
#define SET_RESUME_STATE(context) do { \
ip = (context)->handler_ip; \
+ if (frame->ex) { \
sp->data.p = frame->ex; \
++sp; \
+ } \
frame->ex = NULL; \
(context)->has_resume_state = 0; \
(context)->handler_frame = NULL; \
goto main_loop; \
} while (0)
+static void
+set_context (ThreadContext *context)
+{
+ MonoJitTlsData *jit_tls;
+
+ mono_native_tls_set_value (thread_context_id, context);
+ jit_tls = mono_tls_get_jit_tls ();
+ if (jit_tls)
+ jit_tls->interp_context = context;
+}
+
static void
ves_real_abort (int line, MonoMethod *mh,
const unsigned short *ip, stackval *stack, stackval *sp)
THROW_EX (mono_get_exception_execution_engine (NULL), ip); \
} while (0);
+static RuntimeMethod*
+lookup_runtime_method (MonoDomain *domain, MonoMethod *method)
+{
+ RuntimeMethod *rtm;
+ MonoJitDomainInfo *info;
+
+ info = domain_jit_info (domain);
+ mono_domain_jit_code_hash_lock (domain);
+ rtm = mono_internal_hash_table_lookup (&info->interp_code_hash, method);
+ mono_domain_jit_code_hash_unlock (domain);
+ return rtm;
+}
+
RuntimeMethod*
mono_interp_get_runtime_method (MonoDomain *domain, MonoMethod *method, MonoError *error)
{
return mono_interp_get_runtime_method (domain, method, error);
}
+/*
+ * interp_push_lmf:
+ *
+ * Push an LMF frame on the LMF stack
+ * to mark the transition to native code.
+ * This is needed for the native code to
+ * be able to do stack walks.
+ */
+static void
+interp_push_lmf (MonoLMFExt *ext, MonoInvocation *frame)
+{
+ memset (ext, 0, sizeof (MonoLMFExt));
+ ext->interp_exit = TRUE;
+ ext->interp_exit_data = frame;
+
+ mono_push_lmf (ext);
+}
+
+static void
+interp_pop_lmf (MonoLMFExt *ext)
+{
+ mono_pop_lmf (&ext->lmf);
+}
+
static inline RuntimeMethod*
get_virtual_method (MonoDomain *domain, RuntimeMethod *runtime_method, MonoObject *obj)
{
case MONO_TYPE_U4:
result->data.i = *(guint32*)data;
return;
- case MONO_TYPE_R4:
- result->data.f = *(float*)data;
+ case MONO_TYPE_R4: {
+ float tmp;
+ /* memmove handles unaligned case */
+ memmove (&tmp, data, sizeof (float));
+ result->data.f = tmp;
return;
+ }
case MONO_TYPE_I8:
case MONO_TYPE_U8:
- result->data.l = *(gint64*)data;
+ memmove (&result->data.l, data, sizeof (gint64));
return;
case MONO_TYPE_R8:
- result->data.f = *(double*)data;
+ memmove (&result->data.f, data, sizeof (double));
return;
case MONO_TYPE_STRING:
case MONO_TYPE_SZARRAY:
context->current_frame = frame;
context->managed_code = 0;
- /*
- * Push an LMF frame on the LMF stack
- * to mark the transition to native code.
- */
- memset (&ext, 0, sizeof (ext));
- ext.interp_exit = TRUE;
- ext.interp_exit_data = frame;
-
- mono_push_lmf (&ext);
+ interp_push_lmf (&ext, frame);
mono_interp_enter_icall_trampoline (addr, margs);
- mono_pop_lmf (&ext.lmf);
+ interp_pop_lmf (&ext);
context->managed_code = 1;
/* domain can only be changed by native code */
int i, type, isobject = 0;
void *ret = NULL;
stackval result;
- stackval *args = alloca (sizeof (stackval) * (sig->param_count + !!sig->hasthis));
+ stackval *args;
ThreadContext context_struct;
MonoInvocation *old_frame = NULL;
jmp_buf env;
context->domain = mono_domain_get ();
context->current_frame = old_frame;
context->managed_code = 0;
- } else
- mono_native_tls_set_value (thread_context_id, NULL);
+ } else
+ set_context (NULL);
if (exc != NULL)
*exc = (MonoObject *)frame.ex;
return retval;
context_struct.base_frame = &frame;
context_struct.env_frame = &frame;
context_struct.current_env = &env;
- mono_native_tls_set_value (thread_context_id, context);
+ set_context (context);
}
else
old_frame = context->current_frame;
break;
}
+ args = alloca (sizeof (stackval) * (sig->param_count + !!sig->hasthis));
if (sig->hasthis)
args [0].data.p = obj;
if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
method = mono_marshal_get_native_wrapper (method, FALSE, FALSE);
INIT_FRAME (&frame,context->current_frame,args,&result,mono_get_root_domain (),method,error);
+
if (exc)
frame.invoke_trap = 1;
context->managed_code = 1;
ves_exec_method_with_context (&frame, context, NULL, NULL, -1);
context->managed_code = 0;
if (context == &context_struct)
- mono_native_tls_set_value (thread_context_id, NULL);
+ set_context (NULL);
else
context->current_frame = old_frame;
if (frame.ex != NULL) {
memset (context, 0, sizeof (ThreadContext));
context_struct.base_frame = &frame;
context_struct.env_frame = &frame;
- mono_native_tls_set_value (thread_context_id, context);
- }
- else
+ set_context (context);
+ } else {
old_frame = context->current_frame;
+ }
context->domain = mono_domain_get ();
args = alloca (sizeof (stackval) * (sig->param_count + (sig->hasthis ? 1 : 0)));
ves_exec_method_with_context (&frame, context, NULL, NULL, -1);
context->managed_code = 0;
if (context == &context_struct)
- mono_native_tls_set_value (thread_context_id, NULL);
+ set_context (NULL);
else
context->current_frame = old_frame;
g_print ("(%p) Transforming %s\n", mono_thread_internal_current (), mn);
g_free (mn);
#endif
+
+ MonoLMFExt ext;
+
+ /* Use the parent frame as the current frame is not complete yet */
+ interp_push_lmf (&ext, frame->parent);
+
frame->ex = mono_interp_transform_method (frame->runtime_method, context);
context->managed_code = 1;
+
+ interp_pop_lmf (&ext);
+
if (frame->ex) {
rtm = NULL;
ip = NULL;
vtalloc = vt_sp;
#endif
locals = (unsigned char *) vt_sp + rtm->vt_stack_size;
+ frame->locals = locals;
child_frame.parent = frame;
if (filter_exception) {
MINT_IN_CASE(MINT_NOP)
++ip;
MINT_IN_BREAK;
- MINT_IN_CASE(MINT_BREAK)
+ MINT_IN_CASE(MINT_BREAK) {
++ip;
- G_BREAKPOINT (); /* this is not portable... */
+
+ MonoLMFExt ext;
+
+ interp_push_lmf (&ext, frame);
+
+ mono_debugger_agent_user_break ();
+
+ interp_pop_lmf (&ext);
MINT_IN_BREAK;
+ }
MINT_IN_CASE(MINT_LDNULL)
sp->data.p = NULL;
++ip;
vtalloc = vt_sp;
#endif
locals = vt_sp + rtm->vt_stack_size;
+ frame->locals = locals;
ip = rtm->new_body_start; /* bypass storing input args from callers frame */
MINT_IN_BREAK;
}
}
}
- /*
- * Push an LMF frame on the LMF stack
- * to mark the transition to compiled code.
- */
- memset (&ext, 0, sizeof (ext));
- ext.interp_exit = TRUE;
- ext.interp_exit_data = frame;
-
- mono_push_lmf (&ext);
+ interp_push_lmf (&ext, frame);
switch (pindex) {
case 0: {
break;
}
- mono_pop_lmf (&ext.lmf);
+ interp_pop_lmf (&ext);
if (context->has_resume_state) {
/*
goto exit_frame;
MINT_IN_CASE(MINT_RET_VOID)
if (sp > frame->stack)
- g_warning ("ret.void: more values on stack: %d", sp-frame->stack);
+ g_warning ("ret.void: more values on stack: %d %s", sp-frame->stack, mono_method_full_name (frame->runtime_method->method, TRUE));
goto exit_frame;
MINT_IN_CASE(MINT_RET_VT)
i32 = READ32(ip + 1);
gint offset;
ip += 2 * (guint32)sp->data.i;
offset = READ32 (ip);
- ip = st + offset;
+ ip = ip + offset;
} else {
ip = st;
}
MINT_IN_BREAK;
MINT_IN_CASE(MINT_LDIND_I8)
++ip;
- sp[-1].data.l = *(gint64*)sp[-1].data.p;
+ /* memmove handles unaligned case */
+ memmove (&sp [-1].data.l, sp [-1].data.p, sizeof (gint64));
MINT_IN_BREAK;
MINT_IN_CASE(MINT_LDIND_I) {
guint16 offset = * (guint16 *)(ip + 1);
MINT_IN_BREAK;
MINT_IN_CASE(MINT_CPOBJ) {
c = rtm->data_items[* (guint16 *)(ip + 1)];
- g_assert (c->byval_arg.type == MONO_TYPE_VALUETYPE);
+ g_assert (c->valuetype);
/* if this assertion fails, we need to add a write barrier */
g_assert (!MONO_TYPE_IS_REFERENCE (&c->byval_arg));
- stackval_from_data (&c->byval_arg, &sp [-2], sp [-1].data.p, FALSE);
+ if (c->byval_arg.type == MONO_TYPE_VALUETYPE)
+ stackval_from_data (&c->byval_arg, &sp [-2], sp [-1].data.p, FALSE);
+ else
+ stackval_from_data (&c->byval_arg, sp [-2].data.p, sp [-1].data.p, FALSE);
ip += 2;
sp -= 2;
MINT_IN_BREAK;
frame->ex_handler = NULL;
if (!sp->data.p)
sp->data.p = mono_get_exception_null_reference ();
+
THROW_EX ((MonoException *)sp->data.p, ip);
MINT_IN_BREAK;
MINT_IN_CASE(MINT_LDFLDA_UNSAFE)
++ip;
mono_jit_set_domain (context->original_domain);
MINT_IN_BREAK;
+ MINT_IN_CASE(MINT_SDB_INTR_LOC)
+ if (G_UNLIKELY (ss_enabled)) {
+ MonoLMFExt ext;
+ static void (*ss_tramp) (void);
+
+ if (!ss_tramp) {
+ void *tramp = mini_get_single_step_trampoline ();
+ mono_memory_barrier ();
+ ss_tramp = tramp;
+ }
+
+ /*
+ * Make this point to the MINT_SDB_SEQ_POINT instruction which follows this since
+ * the address of that instruction is stored as the seq point address.
+ */
+ frame->ip = ip + 1;
+
+ interp_push_lmf (&ext, frame);
+ /*
+ * Use the same trampoline as the JIT. This ensures that
+ * the debugger has the context for the last interpreter
+ * native frame.
+ */
+ ss_tramp ();
+ interp_pop_lmf (&ext);
+
+ if (context->has_resume_state) {
+ if (frame == context->handler_frame)
+ SET_RESUME_STATE (context);
+ else
+ goto exit_frame;
+ }
+ }
+ ++ip;
+ MINT_IN_BREAK;
+ MINT_IN_CASE(MINT_SDB_SEQ_POINT)
+ /* Just a placeholder for a breakpoint */
+ ++ip;
+ MINT_IN_BREAK;
+ MINT_IN_CASE(MINT_SDB_BREAKPOINT) {
+ MonoLMFExt ext;
+
+ static void (*bp_tramp) (void);
+ if (!bp_tramp) {
+ void *tramp = mini_get_breakpoint_trampoline ();
+ mono_memory_barrier ();
+ bp_tramp = tramp;
+ }
+
+ frame->ip = ip;
+
+ interp_push_lmf (&ext, frame);
+ /* Use the same trampoline as the JIT */
+ bp_tramp ();
+ interp_pop_lmf (&ext);
+
+ if (context->has_resume_state) {
+ if (frame == context->handler_frame)
+ SET_RESUME_STATE (context);
+ else
+ goto exit_frame;
+ }
+
+ ++ip;
+ MINT_IN_BREAK;
+ }
#define RELOP(datamem, op) \
--sp; \
context_struct.current_env = &env;
context_struct.search_for_handler = 0;
context_struct.managed_code = 0;
- mono_native_tls_set_value (thread_context_id, context);
+ set_context (context);
}
frame->ip = NULL;
frame->parent = context->current_frame;
mono_unhandled_exception ((MonoObject*)frame->ex);
}
if (context->base_frame == frame)
- mono_native_tls_set_value (thread_context_id, NULL);
+ set_context (NULL);
else
context->current_frame = frame->parent;
}
mono_interp_init ()
{
mono_native_tls_alloc (&thread_context_id, NULL);
- mono_native_tls_set_value (thread_context_id, NULL);
+ set_context (NULL);
mono_interp_transform_init ();
}
* Set the state the interpeter will continue to execute from after execution returns to the interpreter.
*/
void
-mono_interp_set_resume_state (MonoException *ex, StackFrameInfo *frame, gpointer handler_ip)
+mono_interp_set_resume_state (MonoJitTlsData *jit_tls, MonoException *ex, MonoInterpFrameHandle interp_frame, gpointer handler_ip)
{
- ThreadContext *context = mono_native_tls_get_value (thread_context_id);
+ ThreadContext *context;
+
+ g_assert (jit_tls);
+ context = jit_tls->interp_context;
+ g_assert (context);
context->has_resume_state = TRUE;
- context->handler_frame = frame->interp_frame;
+ context->handler_frame = interp_frame;
/* This is on the stack, so it doesn't need a wbarrier */
context->handler_frame->ex = ex;
context->handler_ip = handler_ip;
memset (frame, 0, sizeof (StackFrameInfo));
/* pinvoke frames doesn't have runtime_method set */
- while (iframe && !iframe->runtime_method)
+ while (iframe && !(iframe->runtime_method && iframe->runtime_method->code))
iframe = iframe->parent;
if (!iframe)
return FALSE;
frame->type = FRAME_TYPE_INTERP;
+ // FIXME:
+ frame->domain = mono_domain_get ();
frame->interp_frame = iframe;
frame->method = iframe->runtime_method->method;
frame->actual_method = frame->method;
/* This is the offset in the interpreter IR */
- frame->native_offset = iframe->ip - iframe->runtime_method->code;
+ frame->native_offset = (guint8*)iframe->ip - (guint8*)iframe->runtime_method->code;
frame->ji = iframe->runtime_method->jinfo;
stack_iter->current = iframe->parent;
return TRUE;
}
+
+MonoJitInfo*
+mono_interp_find_jit_info (MonoDomain *domain, MonoMethod *method)
+{
+ RuntimeMethod* rtm;
+
+ rtm = lookup_runtime_method (domain, method);
+ if (rtm)
+ return rtm->jinfo;
+ else
+ return NULL;
+}
+
+void
+mono_interp_set_breakpoint (MonoJitInfo *jinfo, gpointer ip)
+{
+ guint16 *code = (guint16*)ip;
+ g_assert (*code == MINT_SDB_SEQ_POINT);
+ *code = MINT_SDB_BREAKPOINT;
+}
+
+void
+mono_interp_clear_breakpoint (MonoJitInfo *jinfo, gpointer ip)
+{
+ guint16 *code = (guint16*)ip;
+ g_assert (*code == MINT_SDB_BREAKPOINT);
+ *code = MINT_SDB_SEQ_POINT;
+}
+
+MonoJitInfo*
+mono_interp_frame_get_jit_info (MonoInterpFrameHandle frame)
+{
+ MonoInvocation *iframe = (MonoInvocation*)frame;
+
+ g_assert (iframe->runtime_method);
+ return iframe->runtime_method->jinfo;
+}
+
+gpointer
+mono_interp_frame_get_ip (MonoInterpFrameHandle frame)
+{
+ MonoInvocation *iframe = (MonoInvocation*)frame;
+
+ g_assert (iframe->runtime_method);
+ return (gpointer)iframe->ip;
+}
+
+gpointer
+mono_interp_frame_get_arg (MonoInterpFrameHandle frame, int pos)
+{
+ MonoInvocation *iframe = (MonoInvocation*)frame;
+
+ g_assert (iframe->runtime_method);
+
+ int arg_offset = iframe->runtime_method->arg_offsets [pos + (iframe->runtime_method->hasthis ? 1 : 0)];
+
+ return iframe->args + arg_offset;
+}
+
+gpointer
+mono_interp_frame_get_local (MonoInterpFrameHandle frame, int pos)
+{
+ MonoInvocation *iframe = (MonoInvocation*)frame;
+
+ g_assert (iframe->runtime_method);
+
+ return iframe->locals + iframe->runtime_method->local_offsets [pos];
+}
+
+gpointer
+mono_interp_frame_get_this (MonoInterpFrameHandle frame)
+{
+ MonoInvocation *iframe = (MonoInvocation*)frame;
+
+ g_assert (iframe->runtime_method);
+ g_assert (iframe->runtime_method->hasthis);
+
+ int arg_offset = iframe->runtime_method->arg_offsets [0];
+
+ return iframe->args + arg_offset;
+}
+
+void
+mono_interp_start_single_stepping (void)
+{
+ ss_enabled = TRUE;
+}
+
+void
+mono_interp_stop_single_stepping (void)
+{
+ ss_enabled = FALSE;
+}
gpointer dummy [8];
};
+typedef gpointer MonoInterpFrameHandle;
+
int
mono_interp_regression_list (int verbose, int count, char *images []);
interp_walk_stack_with_ctx (MonoInternalStackWalk func, MonoContext *ctx, MonoUnwindOptions options, void *user_data);
void
-mono_interp_set_resume_state (MonoException *ex, StackFrameInfo *frame, gpointer handler_ip);
+mono_interp_set_resume_state (MonoJitTlsData *jit_tls, MonoException *ex, MonoInterpFrameHandle interp_frame, gpointer handler_ip);
void
mono_interp_run_finally (StackFrameInfo *frame, int clause_index, gpointer handler_ip);
gboolean
mono_interp_frame_iter_next (MonoInterpStackIter *iter, StackFrameInfo *frame);
+MonoJitInfo*
+mono_interp_find_jit_info (MonoDomain *domain, MonoMethod *method);
+
+void
+mono_interp_set_breakpoint (MonoJitInfo *jinfo, gpointer ip);
+
+void
+mono_interp_clear_breakpoint (MonoJitInfo *jinfo, gpointer ip);
+
+MonoJitInfo*
+mono_interp_frame_get_jit_info (MonoInterpFrameHandle frame);
+
+gpointer
+mono_interp_frame_get_ip (MonoInterpFrameHandle frame);
+
+gpointer
+mono_interp_frame_get_arg (MonoInterpFrameHandle frame, int pos);
+
+gpointer
+mono_interp_frame_get_local (MonoInterpFrameHandle frame, int pos);
+
+gpointer
+mono_interp_frame_get_this (MonoInterpFrameHandle frame);
+
+void
+mono_interp_start_single_stepping (void);
+
+void
+mono_interp_stop_single_stepping (void);
+
#endif /* __MONO_MINI_INTERPRETER_H__ */
if (i > 0)
g_print (", ");
offset = (gint32)READ32 (p);
- g_print ("IL_%04x", ip - base + 3 + 2 * sval + offset);
+ g_print ("IL_%04x", p + offset);
p += 2;
}
g_print (")");
// FIXME: MintOp
OPDEF(MINT_JIT_CALL, "mono_jit_call", 2, MintOpNoArgs)
+OPDEF(MINT_SDB_INTR_LOC, "sdb_intr_loc", 1, MintOpNoArgs)
+OPDEF(MINT_SDB_SEQ_POINT, "sdb_seq_point", 1, MintOpNoArgs)
+OPDEF(MINT_SDB_BREAKPOINT, "sdb_breakpoint", 1, MintOpNoArgs)
#include <mono/metadata/marshal.h>
#include <mono/metadata/profiler-private.h>
#include <mono/metadata/tabledefs.h>
+#include <mono/metadata/seq-points-data.h>
#include <mono/mini/mini.h>
unsigned char flags;
} StackInfo;
+typedef struct {
+ guint8 *ip;
+ GSList *preds;
+ GSList *seq_points;
+ SeqPoint *last_seq_point;
+
+ // This will hold a list of last sequence points of incoming basic blocks
+ SeqPoint **pred_seq_points;
+ guint num_pred_seq_points;
+} InterpBasicBlock;
+
+typedef enum {
+ RELOC_SHORT_BRANCH,
+ RELOC_LONG_BRANCH,
+ RELOC_SWITCH
+} RelocType;
+
+typedef struct {
+ RelocType type;
+ /* In the interpreter IR */
+ int offset;
+ /* In the IL code */
+ int target;
+} Reloc;
+
typedef struct
{
MonoMethod *method;
const unsigned char *in_start;
int code_size;
int *in_offsets;
- int *forward_refs;
StackInfo **stack_state;
int *stack_height;
int *vt_stack_size;
void **data_items;
GHashTable *data_hash;
int *clause_indexes;
+ gboolean gen_sdb_seq_points;
+ GPtrArray *seq_points;
+ InterpBasicBlock **offset_to_bb;
+ InterpBasicBlock *entry_bb;
+ MonoMemPool *mempool;
+ GList *basic_blocks;
+ GPtrArray *relocs;
+ gboolean verbose_level;
} TransformData;
#define MINT_TYPE_I1 0
} while (0)
static void
-handle_branch(TransformData *td, int short_op, int long_op, int offset)
+handle_branch (TransformData *td, int short_op, int long_op, int offset)
{
int shorten_branch = 0;
int target = td->ip + offset - td->il_code;
shorten_branch = 1;
}
} else {
- int prev = td->forward_refs [target];
- td->forward_refs [td->ip - td->il_code] = prev;
- td->forward_refs [target] = td->ip - td->il_code;
- offset = 0;
if (td->header->code_size <= 25000) /* FIX to be precise somehow? */
shorten_branch = 1;
+
+ Reloc *reloc = mono_mempool_alloc0 (td->mempool, sizeof (Reloc));
+ if (shorten_branch) {
+ offset = 0xffff;
+ reloc->type = RELOC_SHORT_BRANCH;
+ } else {
+ offset = 0xdeadbeef;
+ reloc->type = RELOC_LONG_BRANCH;
+ }
+ reloc->offset = td->new_ip - td->new_code;
+ reloc->target = target;
+ g_ptr_array_add (td->relocs, reloc);
}
if (shorten_branch) {
ADD_CODE(td, short_op);
WRITE32(td, &size);
} else {
g_assert (mt < MINT_TYPE_VT);
- if (mt == MINT_TYPE_I4 && !td->is_bb_start [td->in_start - td->il_code] && td->last_new_ip != NULL &&
+ if (!td->gen_sdb_seq_points &&
+ mt == MINT_TYPE_I4 && !td->is_bb_start [td->in_start - td->il_code] && td->last_new_ip != NULL &&
td->last_new_ip [0] == MINT_STLOC_I4 && td->last_new_ip [1] == offset) {
td->last_new_ip [0] = MINT_STLOC_NP_I4;
- } else if (mt == MINT_TYPE_O && !td->is_bb_start [td->in_start - td->il_code] && td->last_new_ip != NULL &&
- td->last_new_ip [0] == MINT_STLOC_O && td->last_new_ip [1] == offset) {
+ } else if (!td->gen_sdb_seq_points &&
+ mt == MINT_TYPE_O && !td->is_bb_start [td->in_start - td->il_code] && td->last_new_ip != NULL &&
+ td->last_new_ip [0] == MINT_STLOC_O && td->last_new_ip [1] == offset) {
td->last_new_ip [0] = MINT_STLOC_NP_O;
} else {
ADD_CODE(td, MINT_LDLOC_I1 + (mt - MINT_TYPE_I1));
else
target_method = (MonoMethod *)mono_method_get_wrapper_data (method, token);
csignature = mono_method_signature (target_method);
- if (target_method->klass == mono_defaults.string_class) {
- if (target_method->name [0] == 'g') {
- if (strcmp (target_method->name, "get_Chars") == 0)
- op = MINT_GETCHR;
- else if (strcmp (target_method->name, "get_Length") == 0)
- op = MINT_STRLEN;
- }
- } else if (mono_class_is_subclass_of (target_method->klass, mono_defaults.array_class, FALSE)) {
- if (!strcmp (target_method->name, "get_Rank")) {
- op = MINT_ARRAY_RANK;
- } else if (!strcmp (target_method->name, "get_Length")) {
- op = MINT_LDLEN;
- } else if (!strcmp (target_method->name, "Address")) {
- op = readonly ? MINT_LDELEMA : MINT_LDELEMA_TC;
- }
- } else if (target_method && generic_context) {
+
+ if (generic_context) {
csignature = mono_inflate_generic_signature (csignature, generic_context, &error);
mono_error_cleanup (&error); /* FIXME: don't swallow the error */
target_method = mono_class_inflate_generic_method_checked (target_method, generic_context, &error);
csignature = mono_method_signature (target_method);
}
+ /* Intrinsics */
+ if (target_method) {
+ if (target_method->klass == mono_defaults.string_class) {
+ if (target_method->name [0] == 'g') {
+ if (strcmp (target_method->name, "get_Chars") == 0)
+ op = MINT_GETCHR;
+ else if (strcmp (target_method->name, "get_Length") == 0)
+ op = MINT_STRLEN;
+ }
+ } else if (mono_class_is_subclass_of (target_method->klass, mono_defaults.array_class, FALSE)) {
+ if (!strcmp (target_method->name, "get_Rank")) {
+ op = MINT_ARRAY_RANK;
+ } else if (!strcmp (target_method->name, "get_Length")) {
+ op = MINT_LDLEN;
+ } else if (!strcmp (target_method->name, "Address")) {
+ op = readonly ? MINT_LDELEMA : MINT_LDELEMA_TC;
+ }
+ } else if (target_method->klass->image == mono_defaults.corlib &&
+ (strcmp (target_method->klass->name_space, "System.Diagnostics") == 0) &&
+ (strcmp (target_method->klass->name, "Debugger") == 0)) {
+ if (!strcmp (target_method->name, "Break") && csignature->param_count == 0) {
+ if (mini_should_insert_breakpoint (method))
+ op = MINT_BREAK;
+ }
+ }
+ }
+
if (constrained_class) {
if (constrained_class->enumtype && !strcmp (target_method->name, "GetHashCode")) {
/* Use the corresponding method from the base type to avoid boxing */
mono_class_init (target_method->klass);
CHECK_STACK (td, csignature->param_count + csignature->hasthis);
- if (!calli && (!virtual || (target_method->flags & METHOD_ATTRIBUTE_VIRTUAL) == 0) &&
+ if (!calli && op == -1 && (!virtual || (target_method->flags & METHOD_ATTRIBUTE_VIRTUAL) == 0) &&
(target_method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) == 0 &&
(target_method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) == 0 &&
!(target_method->iflags & METHOD_IMPL_ATTRIBUTE_NOINLINING)) {
if (/*mono_metadata_signature_equal (method->signature, target_method->signature) */ method == target_method && *(td->ip + 5) == CEE_RET) {
int offset;
- if (mono_interp_traceopt)
+ if (td->verbose_level)
g_print ("Optimize tail call of %s.%s\n", target_method->klass->name, target_method->name);
for (i = csignature->param_count - 1 + !!csignature->hasthis; i >= 0; --i)
} else {
/* mheader might not exist if this is a delegate invoc, etc */
if (mheader && *mheader->code == CEE_RET && called_inited) {
- if (mono_interp_traceopt)
+ if (td->verbose_level)
g_print ("Inline (empty) call of %s.%s\n", target_method->klass->name, target_method->name);
for (i = 0; i < csignature->param_count; i++) {
ADD_CODE (td, MINT_POP); /*FIX: vt */
return field;
}
+static InterpBasicBlock*
+get_bb (TransformData *td, InterpBasicBlock *cbb, unsigned char *ip)
+{
+ int offset = ip - td->il_code;
+ InterpBasicBlock *bb = td->offset_to_bb [offset];
+
+ if (!bb) {
+ bb = mono_mempool_alloc0 (td->mempool, sizeof (InterpBasicBlock));
+ bb->ip = ip;
+ td->offset_to_bb [offset] = bb;
+
+ td->basic_blocks = g_list_append_mempool (td->mempool, td->basic_blocks, bb);
+ }
+
+ if (cbb)
+ bb->preds = g_slist_prepend_mempool (td->mempool, bb->preds, cbb);
+ return bb;
+}
+
+/*
+ * get_basic_blocks:
+ *
+ * Compute the set of IL level basic blocks.
+ */
+static void
+get_basic_blocks (TransformData *td)
+{
+ guint8 *start = (guint8*)td->il_code;
+ guint8 *end = (guint8*)td->il_code + td->code_size;
+ guint8 *ip = start;
+ unsigned char *target;
+ int i;
+ guint cli_addr;
+ const MonoOpcode *opcode;
+ InterpBasicBlock *cbb;
+
+ td->offset_to_bb = mono_mempool_alloc0 (td->mempool, sizeof (InterpBasicBlock*) * (end - start + 1));
+ td->entry_bb = cbb = get_bb (td, NULL, start);
+
+ while (ip < end) {
+ cli_addr = ip - start;
+ td->offset_to_bb [cli_addr] = cbb;
+ i = mono_opcode_value ((const guint8 **)&ip, end);
+ opcode = &mono_opcodes [i];
+ switch (opcode->argument) {
+ case MonoInlineNone:
+ ip++;
+ break;
+ case MonoInlineString:
+ case MonoInlineType:
+ case MonoInlineField:
+ case MonoInlineMethod:
+ case MonoInlineTok:
+ case MonoInlineSig:
+ case MonoShortInlineR:
+ case MonoInlineI:
+ ip += 5;
+ break;
+ case MonoInlineVar:
+ ip += 3;
+ break;
+ case MonoShortInlineVar:
+ case MonoShortInlineI:
+ ip += 2;
+ break;
+ case MonoShortInlineBrTarget:
+ target = start + cli_addr + 2 + (signed char)ip [1];
+ get_bb (td, cbb, target);
+ ip += 2;
+ cbb = get_bb (td, cbb, ip);
+ break;
+ case MonoInlineBrTarget:
+ target = start + cli_addr + 5 + (gint32)read32 (ip + 1);
+ get_bb (td, cbb, target);
+ ip += 5;
+ cbb = get_bb (td, cbb, ip);
+ break;
+ case MonoInlineSwitch: {
+ guint32 n = read32 (ip + 1);
+ guint32 j;
+ ip += 5;
+ cli_addr += 5 + 4 * n;
+ target = start + cli_addr;
+ get_bb (td, cbb, target);
+
+ for (j = 0; j < n; ++j) {
+ target = start + cli_addr + (gint32)read32 (ip);
+ get_bb (td, cbb, target);
+ ip += 4;
+ }
+ cbb = get_bb (td, cbb, ip);
+ break;
+ }
+ case MonoInlineR:
+ case MonoInlineI8:
+ ip += 9;
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+ }
+}
+
static void
interp_save_debug_info (RuntimeMethod *rtm, MonoMethodHeader *header, TransformData *td, GArray *line_numbers)
{
*/
dinfo = g_new0 (MonoDebugMethodJitInfo, 1);
+ dinfo->num_params = rtm->param_count;
+ dinfo->params = g_new0 (MonoDebugVarInfo, dinfo->num_params);
dinfo->num_locals = header->num_locals;
dinfo->locals = g_new0 (MonoDebugVarInfo, header->num_locals);
dinfo->code_start = (guint8*)rtm->code;
dinfo->code_size = td->new_ip - td->new_code;
dinfo->epilogue_begin = 0;
- dinfo->has_var_info = FALSE;
+ dinfo->has_var_info = TRUE;
dinfo->num_line_numbers = line_numbers->len;
dinfo->line_numbers = g_new0 (MonoDebugLineNumberEntry, dinfo->num_line_numbers);
+
+ for (i = 0; i < dinfo->num_params; i++) {
+ MonoDebugVarInfo *var = &dinfo->params [i];
+ var->type = rtm->param_types [i];
+ }
+ for (i = 0; i < dinfo->num_locals; i++) {
+ MonoDebugVarInfo *var = &dinfo->locals [i];
+ var->type = header->locals [i];
+ }
+
for (i = 0; i < dinfo->num_line_numbers; i++)
dinfo->line_numbers [i] = g_array_index (line_numbers, MonoDebugLineNumberEntry, i);
mono_debug_add_method (rtm->method, dinfo, mono_domain_get ());
mono_debug_free_method_jit_info (dinfo);
}
+/* Same as the code in seq-points.c */
+static void
+insert_pred_seq_point (SeqPoint *last_sp, SeqPoint *sp, GSList **next)
+{
+ GSList *l;
+ int src_index = last_sp->next_offset;
+ int dst_index = sp->next_offset;
+
+ /* bb->in_bb might contain duplicates */
+ for (l = next [src_index]; l; l = l->next)
+ if (GPOINTER_TO_UINT (l->data) == dst_index)
+ break;
+ if (!l)
+ next [src_index] = g_slist_append (next [src_index], GUINT_TO_POINTER (dst_index));
+}
+
+static void
+recursively_make_pred_seq_points (TransformData *td, InterpBasicBlock *bb)
+{
+ const gpointer MONO_SEQ_SEEN_LOOP = GINT_TO_POINTER(-1);
+ GSList *l;
+
+ GArray *predecessors = g_array_new (FALSE, TRUE, sizeof (gpointer));
+ GHashTable *seen = g_hash_table_new_full (g_direct_hash, NULL, NULL, NULL);
+
+ // Insert/remove sentinel into the memoize table to detect loops containing bb
+ bb->pred_seq_points = MONO_SEQ_SEEN_LOOP;
+
+ for (l = bb->preds; l; l = l->next) {
+ InterpBasicBlock *in_bb = l->data;
+
+ // This bb has the last seq point, append it and continue
+ if (in_bb->last_seq_point != NULL) {
+ predecessors = g_array_append_val (predecessors, in_bb->last_seq_point);
+ continue;
+ }
+
+ // We've looped or handled this before, exit early.
+ // No last sequence points to find.
+ if (in_bb->pred_seq_points == MONO_SEQ_SEEN_LOOP)
+ continue;
+
+ // Take sequence points from incoming basic blocks
+
+ if (in_bb == td->entry_bb)
+ continue;
+
+ if (in_bb->pred_seq_points == NULL)
+ recursively_make_pred_seq_points (td, in_bb);
+
+ // Union sequence points with incoming bb's
+ for (int i=0; i < in_bb->num_pred_seq_points; i++) {
+ if (!g_hash_table_lookup (seen, in_bb->pred_seq_points [i])) {
+ g_array_append_val (predecessors, in_bb->pred_seq_points [i]);
+ g_hash_table_insert (seen, in_bb->pred_seq_points [i], (gpointer)&MONO_SEQ_SEEN_LOOP);
+ }
+ }
+ // predecessors = g_array_append_vals (predecessors, in_bb->pred_seq_points, in_bb->num_pred_seq_points);
+ }
+
+ g_hash_table_destroy (seen);
+
+ if (predecessors->len != 0) {
+ bb->pred_seq_points = mono_mempool_alloc0 (td->mempool, sizeof (SeqPoint *) * predecessors->len);
+ bb->num_pred_seq_points = predecessors->len;
+
+ for (int newer = 0; newer < bb->num_pred_seq_points; newer++) {
+ bb->pred_seq_points [newer] = g_array_index (predecessors, gpointer, newer);
+ }
+ }
+
+ g_array_free (predecessors, TRUE);
+}
+
+static void
+collect_pred_seq_points (TransformData *td, InterpBasicBlock *bb, SeqPoint *seqp, GSList **next)
+{
+ // Doesn't have a last sequence point, must find from incoming basic blocks
+ if (bb->pred_seq_points == NULL && bb != td->entry_bb)
+ recursively_make_pred_seq_points (td, bb);
+
+ for (int i = 0; i < bb->num_pred_seq_points; i++)
+ insert_pred_seq_point (bb->pred_seq_points [i], seqp, next);
+
+ return;
+}
+
+static void
+save_seq_points (TransformData *td)
+{
+ RuntimeMethod *rtm = td->rtm;
+ GByteArray *array;
+ int i, seq_info_size;
+ MonoSeqPointInfo *info;
+ MonoDomain *domain = mono_domain_get ();
+ GSList **next = NULL;
+ GList *bblist;
+
+ if (!td->gen_sdb_seq_points)
+ return;
+
+ /*
+ * For each sequence point, compute the list of sequence points immediately
+ * following it, this is needed to implement 'step over' in the debugger agent.
+ * Similar to the code in mono_save_seq_point_info ().
+ */
+ for (i = 0; i < td->seq_points->len; ++i) {
+ SeqPoint *sp = g_ptr_array_index (td->seq_points, i);
+
+ /* Store the seq point index here temporarily */
+ sp->next_offset = i;
+ }
+ next = mono_mempool_alloc0 (td->mempool, sizeof (GList*) * td->seq_points->len);
+ for (bblist = td->basic_blocks; bblist; bblist = bblist->next) {
+ InterpBasicBlock *bb = bblist->data;
+
+ GSList *bb_seq_points = g_slist_reverse (bb->seq_points);
+ SeqPoint *last = NULL;
+ for (GSList *l = bb_seq_points; l; l = l->next) {
+ SeqPoint *sp = l->data;
+
+ if (sp->il_offset == METHOD_ENTRY_IL_OFFSET || sp->il_offset == METHOD_EXIT_IL_OFFSET)
+ /* Used to implement method entry/exit events */
+ continue;
+
+ if (last != NULL) {
+ /* Link with the previous seq point in the same bb */
+ next [last->next_offset] = g_slist_append_mempool (td->mempool, next [last->next_offset], GINT_TO_POINTER (sp->next_offset));
+ } else {
+ /* Link with the last bb in the previous bblocks */
+ collect_pred_seq_points (td, bb, sp, next);
+ }
+ last = sp;
+ }
+ }
+
+ /* Serialize the seq points into a byte array */
+ array = g_byte_array_new ();
+ SeqPoint zero_seq_point = {0};
+ SeqPoint* last_seq_point = &zero_seq_point;
+ for (i = 0; i < td->seq_points->len; ++i) {
+ SeqPoint *sp = (SeqPoint*)g_ptr_array_index (td->seq_points, i);
+
+ sp->next_offset = 0;
+ if (mono_seq_point_info_add_seq_point (array, sp, last_seq_point, next [i], TRUE))
+ last_seq_point = sp;
+ }
+
+ if (td->verbose_level) {
+ g_print ("\nSEQ POINT MAP FOR %s: \n", td->method->name);
+
+ for (i = 0; i < td->seq_points->len; ++i) {
+ SeqPoint *sp = (SeqPoint*)g_ptr_array_index (td->seq_points, i);
+ GSList *l;
+
+ if (!next [i])
+ continue;
+
+ g_print ("\tIL0x%x[0x%0x] ->", sp->il_offset, sp->native_offset);
+ for (l = next [i]; l; l = l->next) {
+ int next_index = GPOINTER_TO_UINT (l->data);
+ g_print (" IL0x%x", ((SeqPoint*)g_ptr_array_index (td->seq_points, next_index))->il_offset);
+ }
+ g_print ("\n");
+ }
+ }
+
+ info = mono_seq_point_info_new (array->len, TRUE, array->data, TRUE, &seq_info_size);
+ mono_jit_stats.allocated_seq_points_size += seq_info_size;
+
+ g_byte_array_free (array, TRUE);
+
+ mono_domain_lock (domain);
+ g_hash_table_insert (domain_jit_info (domain)->seq_points, rtm->method, info);
+ mono_domain_unlock (domain);
+}
+
+static void
+emit_seq_point (TransformData *td, int il_offset, InterpBasicBlock *cbb, gboolean nonempty_stack)
+{
+ SeqPoint *seqp;
+
+ seqp = mono_mempool_alloc0 (td->mempool, sizeof (SeqPoint));
+ seqp->il_offset = il_offset;
+ seqp->native_offset = (guint8*)td->new_ip - (guint8*)td->new_code;
+ if (nonempty_stack)
+ seqp->flags |= MONO_SEQ_POINT_FLAG_NONEMPTY_STACK;
+
+ ADD_CODE (td, MINT_SDB_SEQ_POINT);
+ g_ptr_array_add (td->seq_points, seqp);
+
+ cbb->seq_points = g_slist_prepend_mempool (td->mempool, cbb->seq_points, seqp);
+ cbb->last_seq_point = seqp;
+}
+
static void
generate (MonoMethod *method, RuntimeMethod *rtm, unsigned char *is_bb_start, MonoGenericContext *generic_context)
{
TransformData td;
int generating_code = 1;
GArray *line_numbers;
+ MonoDebugMethodInfo *minfo;
+ MonoBitSet *seq_point_locs = NULL;
+ MonoBitSet *seq_point_set_locs = NULL;
+ gboolean sym_seq_points = FALSE;
+ InterpBasicBlock *bb_exit = NULL;
+ static gboolean verbose_method_inited;
+ static char* verbose_method_name;
+
+ if (!verbose_method_inited) {
+ verbose_method_name = getenv ("MONO_VERBOSE_METHOD");
+ verbose_method_inited = TRUE;
+ }
- memset(&td, 0, sizeof(td));
+ memset (&td, 0, sizeof(td));
td.method = method;
td.rtm = rtm;
td.is_bb_start = is_bb_start;
td.max_code_size = td.code_size;
td.new_code = (unsigned short *)g_malloc(td.max_code_size * sizeof(gushort));
td.new_code_end = td.new_code + td.max_code_size;
+ td.mempool = mono_mempool_new ();
td.in_offsets = g_malloc0(header->code_size * sizeof(int));
- td.forward_refs = g_malloc(header->code_size * sizeof(int));
td.stack_state = g_malloc0(header->code_size * sizeof(StackInfo *));
td.stack_height = g_malloc(header->code_size * sizeof(int));
td.vt_stack_size = g_malloc(header->code_size * sizeof(int));
td.data_items = NULL;
td.data_hash = g_hash_table_new (NULL, NULL);
td.clause_indexes = g_malloc (header->code_size * sizeof (int));
+ td.gen_sdb_seq_points = debug_options.gen_sdb_seq_points;
+ td.seq_points = g_ptr_array_new ();
+ td.relocs = g_ptr_array_new ();
+ td.verbose_level = mono_interp_traceopt;
rtm->data_items = td.data_items;
for (i = 0; i < header->code_size; i++) {
- td.forward_refs [i] = -1;
td.stack_height [i] = -1;
td.clause_indexes [i] = -1;
}
+
+ if (verbose_method_name) {
+ const char *name = verbose_method_name;
+
+ if ((strchr (name, '.') > name) || strchr (name, ':')) {
+ MonoMethodDesc *desc;
+
+ desc = mono_method_desc_new (name, TRUE);
+ if (mono_method_desc_full_match (desc, method)) {
+ td.verbose_level = 4;
+ }
+ mono_method_desc_free (desc);
+ } else {
+ if (strcmp (method->name, name) == 0)
+ td.verbose_level = 4;
+ }
+ }
+
+ if (td.gen_sdb_seq_points) {
+ get_basic_blocks (&td);
+
+ minfo = mono_debug_lookup_method (method);
+
+ if (minfo) {
+ MonoSymSeqPoint *sps;
+ int i, n_il_offsets;
+
+ mono_debug_get_seq_points (minfo, NULL, NULL, NULL, &sps, &n_il_offsets);
+ // FIXME: Free
+ seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (td.mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
+ seq_point_set_locs = mono_bitset_mem_new (mono_mempool_alloc0 (td.mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
+ sym_seq_points = TRUE;
+
+ for (i = 0; i < n_il_offsets; ++i) {
+ if (sps [i].il_offset < header->code_size)
+ mono_bitset_set_fast (seq_point_locs, sps [i].il_offset);
+ }
+ g_free (sps);
+ } else if (!method->wrapper_type && !method->dynamic && mono_debug_image_has_debug_info (method->klass->image)) {
+ /* Methods without line number info like auto-generated property accessors */
+ seq_point_locs = mono_bitset_new (header->code_size, 0);
+ seq_point_set_locs = mono_bitset_new (header->code_size, 0);
+ sym_seq_points = TRUE;
+ }
+ }
+
td.new_ip = td.new_code;
td.last_new_ip = NULL;
td.ip = header->code;
end = td.ip + header->code_size;
- if (mono_interp_traceopt) {
+ if (td.verbose_level) {
char *tmp = mono_disasm_code (NULL, method, td.ip, end);
char *name = mono_method_full_name (method, TRUE);
g_print ("Method %s, original code:\n", name);
}
}
+ if (sym_seq_points) {
+ InterpBasicBlock *cbb = td.offset_to_bb [0];
+ g_assert (cbb);
+ emit_seq_point (&td, METHOD_ENTRY_IL_OFFSET, cbb, FALSE);
+ }
+
while (td.ip < end) {
int in_offset;
td.in_start = td.ip;
MonoDebugLineNumberEntry lne;
- lne.native_offset = td.new_ip - td.new_code;
- lne.il_offset = td.ip - header->code;
+ lne.native_offset = (guint8*)td.new_ip - (guint8*)td.new_code;
+ lne.il_offset = in_offset;
g_array_append_val (line_numbers, lne);
- while (td.forward_refs [in_offset] >= 0) {
- int j = td.forward_refs [in_offset];
- int slot;
- td.forward_refs [in_offset] = td.forward_refs [j];
- if (td.in_offsets [j] < 0) {
- int old_switch_offset = -td.in_offsets [j];
- int new_switch_offset = td.in_offsets [old_switch_offset];
- int switch_case = (j - old_switch_offset - 5) / 4;
- int n_cases = read32 (header->code + old_switch_offset + 1);
- offset = (td.new_ip - td.new_code) - (new_switch_offset + 2 * n_cases + 3);
- slot = new_switch_offset + 3 + 2 * switch_case;
- td.new_code [slot] = * (unsigned short *)(&offset);
- td.new_code [slot + 1] = * ((unsigned short *)&offset + 1);
- } else {
- int op = td.new_code [td.in_offsets [j]];
- if (mono_interp_opargtype [op] == MintOpShortBranch) {
- offset = (td.new_ip - td.new_code) - td.in_offsets [j];
- g_assert (offset <= 32767);
- slot = td.in_offsets [j] + 1;
- td.new_code [slot] = offset;
- } else {
- offset = (td.new_ip - td.new_code) - td.in_offsets [j];
- slot = td.in_offsets [j] + 1;
- td.new_code [slot] = * (unsigned short *)(&offset);
- td.new_code [slot + 1] = * ((unsigned short *)&offset + 1);
- }
- }
- }
if (td.stack_height [in_offset] >= 0) {
g_assert (is_bb_start [in_offset]);
if (td.stack_height [in_offset] > 0)
++td.ip;
continue;
}
- if (mono_interp_traceopt > 1) {
+ if (td.verbose_level > 1) {
printf("IL_%04lx %s %-10s -> IL_%04lx, sp %ld, %s %-12s vt_sp %u (max %u)\n",
td.ip - td.il_code,
td.is_bb_start [td.ip - td.il_code] == 3 ? "<>" :
(td.sp > td.stack && (td.sp [-1].type == STACK_TYPE_O || td.sp [-1].type == STACK_TYPE_VT)) ? (td.sp [-1].klass == NULL ? "?" : td.sp [-1].klass->name) : "",
td.vt_sp, td.max_vt_sp);
}
+
+ if (sym_seq_points && mono_bitset_test_fast (seq_point_locs, td.ip - header->code)) {
+ InterpBasicBlock *cbb = td.offset_to_bb [td.ip - header->code];
+ g_assert (cbb);
+
+ /*
+ * Make methods interruptable at the beginning, and at the targets of
+ * backward branches.
+ */
+ if (in_offset == 0 || g_slist_length (cbb->preds) > 1)
+ ADD_CODE (&td, MINT_SDB_INTR_LOC);
+
+ emit_seq_point (&td, in_offset, cbb, FALSE);
+
+ mono_bitset_set_fast (seq_point_set_locs, td.ip - header->code);
+ }
+
+ if (sym_seq_points)
+ bb_exit = td.offset_to_bb [td.ip - header->code];
+
switch (*td.ip) {
case CEE_NOP:
/* lose it */
case CEE_CALLVIRT: /* Fall through */
case CEE_CALLI: /* Fall through */
case CEE_CALL: {
+ gboolean need_seq_point = FALSE;
+
+ if (sym_seq_points && !mono_bitset_test_fast (seq_point_locs, td.ip + 5 - header->code))
+ need_seq_point = TRUE;
+
interp_transform_call (&td, method, NULL, domain, generic_context, is_bb_start, body_start_offset, constrained_class, readonly);
+
+ if (need_seq_point) {
+ InterpBasicBlock *cbb = td.offset_to_bb [td.ip - header->code];
+ g_assert (cbb);
+
+ emit_seq_point (&td, td.ip - header->code, cbb, TRUE);
+ }
+
constrained_class = NULL;
readonly = FALSE;
break;
g_warning ("%s.%s: CEE_RET: more values on stack: %d", td.method->klass->name, td.method->name, td.sp - td.stack);
if (td.vt_sp != vt_size)
g_error ("%s.%s: CEE_RET: value type stack: %d vs. %d", td.method->klass->name, td.method->name, td.vt_sp, vt_size);
+
+ if (sym_seq_points) {
+ InterpBasicBlock *cbb = td.offset_to_bb [td.ip - header->code];
+ g_assert (cbb);
+ emit_seq_point (&td, METHOD_EXIT_IL_OFFSET, bb_exit, FALSE);
+ }
+
if (vt_size == 0)
SIMPLE_OP(td, signature->ret->type == MONO_TYPE_VOID ? MINT_RET_VOID : MINT_RET);
else {
case CEE_SWITCH: {
guint32 n;
const unsigned char *next_ip;
- const unsigned char *base_ip = td.ip;
- unsigned short *next_new_ip;
++td.ip;
n = read32 (td.ip);
ADD_CODE (&td, MINT_SWITCH);
WRITE32 (&td, &n);
td.ip += 4;
next_ip = td.ip + n * 4;
- next_new_ip = td.new_ip + n * 2;
--td.sp;
int stack_height = td.sp - td.stack;
for (i = 0; i < n; i++) {
if (stack_height > 0 && stack_height != td.stack_height [target])
g_warning ("SWITCH with back branch and non-empty stack");
#endif
- target = td.in_offsets [target] - (next_new_ip - td.new_code);
+ target = td.in_offsets [target] - (td.new_ip - td.new_code);
} else {
td.stack_height [target] = stack_height;
td.vt_stack_size [target] = td.vt_sp;
if (stack_height > 0)
td.stack_state [target] = g_memdup (td.stack, stack_height * sizeof (td.stack [0]));
- int prev = td.forward_refs [target];
- td.forward_refs [td.ip - td.il_code] = prev;
- td.forward_refs [target] = td.ip - td.il_code;
- td.in_offsets [td.ip - td.il_code] = - (base_ip - td.il_code);
+
+ Reloc *reloc = mono_mempool_alloc0 (td.mempool, sizeof (Reloc));
+ reloc->type = RELOC_SWITCH;
+ reloc->offset = td.new_ip - td.new_code;
+ reloc->target = target;
+ g_ptr_array_add (td.relocs, reloc);
+ target = 0xffff;
}
WRITE32 (&td, &target);
td.ip += 4;
MonoString *s;
token = mono_metadata_token_index (read32 (td.ip + 1));
td.ip += 5;
- if (method->wrapper_type != MONO_WRAPPER_NONE) {
- s = mono_string_new_wrapper(
- mono_method_get_wrapper_data (method, token));
- }
- else
+ if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
+ s = mono_method_get_wrapper_data (method, token);
+ } else if (method->wrapper_type != MONO_WRAPPER_NONE) {
+ s = mono_string_new_wrapper (mono_method_get_wrapper_data (method, token));
+ } else {
s = mono_ldstr (domain, image, token);
+ }
ADD_CODE(&td, MINT_LDSTR);
ADD_CODE(&td, get_data_item_index (&td, s));
PUSH_TYPE(&td, STACK_TYPE_O, mono_defaults.string_class);
++td.ip;
break;
case CEE_UNALIGNED_:
- ++td.ip;
- /* FIX: should do something? */;
+ td.ip += 2;
break;
case CEE_VOLATILE_:
++td.ip;
td.last_ip = td.in_start;
}
- if (mono_interp_traceopt) {
+ /* Handle relocations */
+ for (int i = 0; i < td.relocs->len; ++i) {
+ Reloc *reloc = g_ptr_array_index (td.relocs, i);
+
+ int offset = td.in_offsets [reloc->target] - reloc->offset;
+
+ switch (reloc->type) {
+ case RELOC_SHORT_BRANCH:
+ g_assert (td.new_code [reloc->offset + 1] == 0xffff);
+ td.new_code [reloc->offset + 1] = offset;
+ break;
+ case RELOC_LONG_BRANCH: {
+ guint16 *v = (guint16 *) &offset;
+ g_assert (td.new_code [reloc->offset + 1] == 0xbeef);
+ g_assert (td.new_code [reloc->offset + 2] == 0xdead);
+ td.new_code [reloc->offset + 1] = *(guint16 *) v;
+ td.new_code [reloc->offset + 2] = *(guint16 *) (v + 1);
+ break;
+ }
+ case RELOC_SWITCH: {
+ guint16 *v = (guint16*)&offset;
+ td.new_code [reloc->offset] = *(guint16*)v;
+ td.new_code [reloc->offset + 1] = *(guint16*)(v + 1);
+ break;
+ }
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+ }
+
+ if (td.verbose_level) {
const guint16 *p = td.new_code;
- printf("Runtime method: %p, VT stack size: %d\n", rtm, td.max_vt_sp);
+ printf("Runtime method: %s %p, VT stack size: %d\n", mono_method_full_name (method, TRUE), rtm, td.max_vt_sp);
printf("Calculated stack size: %d, stated size: %d\n", td.max_stack_height, header->max_stack);
while (p < td.new_ip) {
p = mono_interp_dis_mintop(td.new_code, p);
/* Create a MonoJitInfo for the interpreted method by creating the interpreter IR as the native code. */
int jinfo_len = mono_jit_info_size (0, header->num_clauses, 0);
MonoJitInfo *jinfo = (MonoJitInfo *)mono_domain_alloc0 (domain, jinfo_len);
+ jinfo->is_interp = 1;
rtm->jinfo = jinfo;
mono_jit_info_init (jinfo, method, (guint8*)rtm->code, code_len, 0, header->num_clauses, 0);
for (i = 0; i < jinfo->num_clauses; ++i) {
MonoExceptionClause *c = rtm->clauses + i;
ei->flags = c->flags;
- ei->try_start = rtm->code + c->try_offset;
- ei->try_end = rtm->code + c->try_offset + c->try_len;
- ei->handler_start = rtm->code + c->handler_offset;
+ ei->try_start = (guint8*)(rtm->code + c->try_offset);
+ ei->try_end = (guint8*)(rtm->code + c->try_offset + c->try_len);
+ ei->handler_start = (guint8*)(rtm->code + c->handler_offset);
if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER || ei->flags == MONO_EXCEPTION_CLAUSE_FINALLY) {
} else {
ei->data.catch_class = c->data.catch_class;
}
}
+ save_seq_points (&td);
+
g_free (td.in_offsets);
- g_free (td.forward_refs);
for (i = 0; i < header->code_size; ++i)
g_free (td.stack_state [i]);
g_free (td.stack_state);
g_free (td.stack);
g_hash_table_destroy (td.data_hash);
g_free (td.clause_indexes);
+ g_ptr_array_free (td.seq_points, TRUE);
g_array_free (line_numbers, TRUE);
+ g_ptr_array_free (td.relocs, TRUE);
+ mono_mempool_destroy (td.mempool);
}
static mono_mutex_t calc_section;
mono_os_mutex_lock(&calc_section);
if (runtime_method->transformed) {
mono_os_mutex_unlock(&calc_section);
- mono_profiler_method_end_jit (method, NULL, MONO_PROFILE_OK);
+ mono_profiler_method_end_jit (method, runtime_method->jinfo, MONO_PROFILE_OK);
return NULL;
}
if (runtime_method->transformed) {
mono_os_mutex_unlock(&calc_section);
g_free (is_bb_start);
- mono_profiler_method_end_jit (method, NULL, MONO_PROFILE_OK);
+ mono_profiler_method_end_jit (method, runtime_method->jinfo, MONO_PROFILE_OK);
return NULL;
}
g_free (is_bb_start);
- mono_profiler_method_end_jit (method, NULL, MONO_PROFILE_OK);
+ // FIXME: Add a different callback ?
+ mono_profiler_method_end_jit (method, runtime_method->jinfo, MONO_PROFILE_OK);
runtime_method->transformed = TRUE;
mono_os_mutex_unlock(&calc_section);
#ifndef DISABLE_JIT
+#include <mono/metadata/gc-internals.h>
#include <mono/utils/mono-memory-model.h>
#include "mini.h"
#include "ir-emit.h"
+#include "jit-icalls.h"
#define MAX_INLINE_COPIES 10
+#define MAX_INLINE_COPY_SIZE 10000
void
mini_emit_memset (MonoCompile *cfg, int destreg, int offset, int size, int val, int align)
{
int val_reg;
+ /*FIXME arbitrary hack to avoid unbound code expansion.*/
+ g_assert (size < MAX_INLINE_COPY_SIZE);
g_assert (val == 0);
-
- if (align == 0)
- align = 4;
+ g_assert (align > 0);
if ((size <= SIZEOF_REGISTER) && (size <= align)) {
switch (size) {
else
MONO_EMIT_NEW_ICONST (cfg, val_reg, val);
- if (align < 4) {
- /* This could be optimized further if neccesary */
- while (size >= 1) {
- MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
- offset += 1;
- size -= 1;
- }
- return;
- }
-
- if (!cfg->backend->no_unaligned_access && SIZEOF_REGISTER == 8) {
- if (offset % 8) {
- MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
- offset += 4;
- size -= 4;
- }
+ if (align < SIZEOF_VOID_P) {
+ if (align % 2 == 1)
+ goto set_1;
+ if (align % 4 == 2)
+ goto set_2;
+ if (SIZEOF_VOID_P == 8 && align % 8 == 4)
+ goto set_4;
+ }
+
+ //Unaligned offsets don't naturaly happen in the runtime, so it's ok to be conservative in how we copy
+ //We assume that input src and dest are be aligned to `align` so offset just worsen it
+ int offsets_mask = offset & 0x7; //we only care about the misalignment part
+ if (offsets_mask) {
+ if (offsets_mask % 2 == 1)
+ goto set_1;
+ if (offsets_mask % 4 == 2)
+ goto set_2;
+ if (SIZEOF_VOID_P == 8 && offsets_mask % 8 == 4)
+ goto set_4;
+ }
+
+ if (SIZEOF_REGISTER == 8) {
while (size >= 8) {
MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, offset, val_reg);
offset += 8;
size -= 8;
}
- }
+ }
+set_4:
while (size >= 4) {
MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
offset += 4;
size -= 4;
}
+
+
+set_2:
while (size >= 2) {
MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, val_reg);
offset += 2;
size -= 2;
}
+
+set_1:
while (size >= 1) {
MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
offset += 1;
{
int cur_reg;
- if (align == 0)
- align = 4;
-
/*FIXME arbitrary hack to avoid unbound code expansion.*/
- g_assert (size < 10000);
+ g_assert (size < MAX_INLINE_COPY_SIZE);
+ g_assert (align > 0);
+
+ if (align < SIZEOF_VOID_P) {
+ if (align == 4)
+ goto copy_4;
+ if (align == 2)
+ goto copy_2;
+ goto copy_1;
+ }
- if (align < 4) {
- /* This could be optimized further if neccesary */
- while (size >= 1) {
- cur_reg = alloc_preg (cfg);
- MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
- MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
- doffset += 1;
- soffset += 1;
- size -= 1;
- }
+ //Unaligned offsets don't naturaly happen in the runtime, so it's ok to be conservative in how we copy
+ //We assume that input src and dest are be aligned to `align` so offset just worsen it
+ int offsets_mask = (doffset | soffset) & 0x7; //we only care about the misalignment part
+ if (offsets_mask) {
+ if (offsets_mask % 2 == 1)
+ goto copy_1;
+ if (offsets_mask % 4 == 2)
+ goto copy_2;
+ if (SIZEOF_VOID_P == 8 && offsets_mask % 8 == 4)
+ goto copy_4;
}
- if (!cfg->backend->no_unaligned_access && SIZEOF_REGISTER == 8) {
+
+ if (SIZEOF_REGISTER == 8) {
while (size >= 8) {
cur_reg = alloc_preg (cfg);
MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI8_MEMBASE, cur_reg, srcreg, soffset);
soffset += 8;
size -= 8;
}
- }
+ }
+copy_4:
while (size >= 4) {
cur_reg = alloc_preg (cfg);
MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, cur_reg, srcreg, soffset);
soffset += 4;
size -= 4;
}
+
+copy_2:
while (size >= 2) {
cur_reg = alloc_preg (cfg);
MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, cur_reg, srcreg, soffset);
soffset += 2;
size -= 2;
}
+
+copy_1:
while (size >= 1) {
cur_reg = alloc_preg (cfg);
MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
/* FIXME: Optimize the case when src/dest is OP_LDADDR */
/* We can't do copies at a smaller granule than the provided alignment */
- if (size_ins || ((size / align > MAX_INLINE_COPIES) && !(cfg->opt & MONO_OPT_INTRINS))) {
+ if (size_ins || (size / align > MAX_INLINE_COPIES) || !(cfg->opt & MONO_OPT_INTRINS)) {
MonoInst *iargs [3];
iargs [0] = dest;
iargs [1] = src;
/* FIXME: Optimize the case when dest is OP_LDADDR */
/* We can't do copies at a smaller granule than the provided alignment */
- if (value_ins || size_ins || value != 0 || ((size / align > MAX_INLINE_COPIES) && !(cfg->opt & MONO_OPT_INTRINS))) {
+ if (value_ins || size_ins || value != 0 || (size / align > MAX_INLINE_COPIES) || !(cfg->opt & MONO_OPT_INTRINS)) {
MonoInst *iargs [3];
iargs [0] = dest;
mini_emit_memset_internal (cfg, dest, NULL, value, NULL, size, align);
}
+
+static void
+create_write_barrier_bitmap (MonoCompile *cfg, MonoClass *klass, unsigned *wb_bitmap, int offset)
+{
+ MonoClassField *field;
+ gpointer iter = NULL;
+
+ while ((field = mono_class_get_fields (klass, &iter))) {
+ int foffset;
+
+ if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
+ continue;
+ foffset = klass->valuetype ? field->offset - sizeof (MonoObject): field->offset;
+ if (mini_type_is_reference (mono_field_get_type (field))) {
+ g_assert ((foffset % SIZEOF_VOID_P) == 0);
+ *wb_bitmap |= 1 << ((offset + foffset) / SIZEOF_VOID_P);
+ } else {
+ MonoClass *field_class = mono_class_from_mono_type (field->type);
+ if (field_class->has_references)
+ create_write_barrier_bitmap (cfg, field_class, wb_bitmap, offset + foffset);
+ }
+ }
+}
+
+static gboolean
+mini_emit_wb_aware_memcpy (MonoCompile *cfg, MonoClass *klass, MonoInst *iargs[4], int size, int align)
+{
+ int dest_ptr_reg, tmp_reg, destreg, srcreg, offset;
+ unsigned need_wb = 0;
+
+ if (align == 0)
+ align = 4;
+
+ /*types with references can't have alignment smaller than sizeof(void*) */
+ if (align < SIZEOF_VOID_P)
+ return FALSE;
+
+ if (size > 5 * SIZEOF_VOID_P)
+ return FALSE;
+
+ create_write_barrier_bitmap (cfg, klass, &need_wb, 0);
+
+ destreg = iargs [0]->dreg;
+ srcreg = iargs [1]->dreg;
+ offset = 0;
+
+ dest_ptr_reg = alloc_preg (cfg);
+ tmp_reg = alloc_preg (cfg);
+
+ /*tmp = dreg*/
+ EMIT_NEW_UNALU (cfg, iargs [0], OP_MOVE, dest_ptr_reg, destreg);
+
+ while (size >= SIZEOF_VOID_P) {
+ MonoInst *load_inst;
+ MONO_INST_NEW (cfg, load_inst, OP_LOAD_MEMBASE);
+ load_inst->dreg = tmp_reg;
+ load_inst->inst_basereg = srcreg;
+ load_inst->inst_offset = offset;
+ MONO_ADD_INS (cfg->cbb, load_inst);
+
+ MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, dest_ptr_reg, 0, tmp_reg);
+
+ if (need_wb & 0x1)
+ mini_emit_write_barrier (cfg, iargs [0], load_inst);
+
+ offset += SIZEOF_VOID_P;
+ size -= SIZEOF_VOID_P;
+ need_wb >>= 1;
+
+ /*tmp += sizeof (void*)*/
+ if (size >= SIZEOF_VOID_P) {
+ NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, dest_ptr_reg, dest_ptr_reg, SIZEOF_VOID_P);
+ MONO_ADD_INS (cfg->cbb, iargs [0]);
+ }
+ }
+
+ /* Those cannot be references since size < sizeof (void*) */
+ while (size >= 4) {
+ MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tmp_reg, srcreg, offset);
+ MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, tmp_reg);
+ offset += 4;
+ size -= 4;
+ }
+
+ while (size >= 2) {
+ MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, tmp_reg, srcreg, offset);
+ MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, tmp_reg);
+ offset += 2;
+ size -= 2;
+ }
+
+ while (size >= 1) {
+ MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, tmp_reg, srcreg, offset);
+ MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, tmp_reg);
+ offset += 1;
+ size -= 1;
+ }
+
+ return TRUE;
+}
+
+static void
+mini_emit_memory_copy_internal (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *klass, int explicit_align, gboolean native)
+{
+ MonoInst *iargs [4];
+ int size;
+ guint32 align = 0;
+ MonoInst *size_ins = NULL;
+ MonoInst *memcpy_ins = NULL;
+
+ g_assert (klass);
+ /*
+ Fun fact about @native. It's false that @klass will have no ref when @native is true.
+ This happens in pinvoke2. What goes is that marshal.c uses CEE_MONO_LDOBJNATIVE and pass klass.
+ The actual stuff being copied will have no refs, but @klass might.
+ This means we can't assert !(klass->has_references && native).
+ */
+
+ if (cfg->gshared)
+ klass = mono_class_from_mono_type (mini_get_underlying_type (&klass->byval_arg));
+
+ /*
+ * This check breaks with spilled vars... need to handle it during verification anyway.
+ * g_assert (klass && klass == src->klass && klass == dest->klass);
+ */
+
+ if (mini_is_gsharedvt_klass (klass)) {
+ g_assert (!native);
+ size_ins = mini_emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
+ memcpy_ins = mini_emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_MEMCPY);
+ }
+
+ if (native)
+ size = mono_class_native_size (klass, &align);
+ else
+ size = mono_class_value_size (klass, &align);
+
+ if (!align)
+ align = SIZEOF_VOID_P;
+ if (explicit_align)
+ align = explicit_align;
+
+ if (mini_type_is_reference (&klass->byval_arg)) { // Refs *MUST* be naturally aligned
+ MonoInst *store, *load;
+ int dreg = alloc_ireg_ref (cfg);
+
+ NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, dreg, src->dreg, 0);
+ MONO_ADD_INS (cfg->cbb, load);
+
+ NEW_STORE_MEMBASE (cfg, store, OP_STORE_MEMBASE_REG, dest->dreg, 0, dreg);
+ MONO_ADD_INS (cfg->cbb, store);
+
+ mini_emit_write_barrier (cfg, dest, src);
+ } else if (cfg->gen_write_barriers && (klass->has_references || size_ins) && !native) { /* if native is true there should be no references in the struct */
+ /* Avoid barriers when storing to the stack */
+ if (!((dest->opcode == OP_ADD_IMM && dest->sreg1 == cfg->frame_reg) ||
+ (dest->opcode == OP_LDADDR))) {
+ int context_used;
+
+ iargs [0] = dest;
+ iargs [1] = src;
+
+ context_used = mini_class_check_context_used (cfg, klass);
+
+ /* It's ok to intrinsify under gsharing since shared code types are layout stable. */
+ if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && mini_emit_wb_aware_memcpy (cfg, klass, iargs, size, align)) {
+ } else if (size_ins || align < SIZEOF_VOID_P) {
+ if (context_used) {
+ iargs [2] = mini_emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
+ } else {
+ iargs [2] = mini_emit_runtime_constant (cfg, MONO_PATCH_INFO_CLASS, klass);
+ if (!cfg->compile_aot)
+ mono_class_compute_gc_descriptor (klass);
+ }
+ if (size_ins)
+ mono_emit_jit_icall (cfg, mono_gsharedvt_value_copy, iargs);
+ else
+ mono_emit_jit_icall (cfg, mono_value_copy, iargs);
+ } else {
+ /* We don't unroll more than 5 stores to avoid code bloat. */
+ /*This is harmless and simplify mono_gc_get_range_copy_func */
+ size += (SIZEOF_VOID_P - 1);
+ size &= ~(SIZEOF_VOID_P - 1);
+
+ EMIT_NEW_ICONST (cfg, iargs [2], size);
+ mono_emit_jit_icall (cfg, mono_gc_get_range_copy_func (), iargs);
+ }
+ return;
+ }
+ }
+
+ if (size_ins) {
+ iargs [0] = dest;
+ iargs [1] = src;
+ iargs [2] = size_ins;
+ mini_emit_calli (cfg, mono_method_signature (mini_get_memcpy_method ()), iargs, memcpy_ins, NULL, NULL);
+ } else {
+ mini_emit_memcpy_const_size (cfg, dest, src, size, align);
+ }
+}
+
MonoInst*
mini_emit_memory_load (MonoCompile *cfg, MonoType *type, MonoInst *src, int offset, int ins_flag)
{
MonoInst *ins;
- EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, type, src->dreg, offset);
+ if (ins_flag & MONO_INST_UNALIGNED) {
+ MonoInst *addr, *tmp_var;
+ int align;
+ int size = mono_type_size (type, &align);
+
+ if (offset) {
+ MonoInst *add_offset;
+ NEW_BIALU_IMM (cfg, add_offset, OP_PADD_IMM, alloc_preg (cfg), src->dreg, offset);
+ MONO_ADD_INS (cfg->cbb, add_offset);
+ src = add_offset;
+ }
+
+ tmp_var = mono_compile_create_var (cfg, type, OP_LOCAL);
+ EMIT_NEW_VARLOADA (cfg, addr, tmp_var, tmp_var->inst_vtype);
+
+ mini_emit_memcpy_const_size (cfg, addr, src, size, 1);
+ EMIT_NEW_TEMPLOAD (cfg, ins, tmp_var->inst_c0);
+ } else {
+ EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, type, src->dreg, offset);
+ }
ins->flags |= ins_flag;
if (ins_flag & MONO_INST_VOLATILE) {
/* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
mini_emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
}
+
+ if (ins_flag & MONO_INST_UNALIGNED) {
+ MonoInst *addr, *mov, *tmp_var;
+
+ tmp_var = mono_compile_create_var (cfg, type, OP_LOCAL);
+ EMIT_NEW_TEMPSTORE (cfg, mov, tmp_var->inst_c0, value);
+ EMIT_NEW_VARLOADA (cfg, addr, tmp_var, tmp_var->inst_vtype);
+ mini_emit_memory_copy_internal (cfg, dest, addr, mono_class_from_mono_type (type), 1, FALSE);
+ }
+
/* FIXME: should check item at sp [1] is compatible with the type of the store. */
EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, type, dest->dreg, 0, value->dreg);
void
mini_emit_memory_copy_bytes (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoInst *size, int ins_flag)
{
- int align = SIZEOF_VOID_P;
+ int align = (ins_flag & MONO_INST_UNALIGNED) ? 1 : SIZEOF_VOID_P;
/*
* FIXME: It's unclear whether we should be emitting both the acquire
mini_emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
}
- if ((cfg->opt & MONO_OPT_INTRINS) && (size->opcode == OP_ICONST) && size->inst_c0 < 10000) {
+ if ((cfg->opt & MONO_OPT_INTRINS) && (size->opcode == OP_ICONST)) {
mini_emit_memcpy_const_size (cfg, dest, src, size->inst_c0, align);
} else {
- if (cfg->verbose_level > 3)
- printf ("EMITING REGULAR COPY\n");
mini_emit_memcpy_internal (cfg, dest, src, size, 0, align);
}
void
mini_emit_memory_init_bytes (MonoCompile *cfg, MonoInst *dest, MonoInst *value, MonoInst *size, int ins_flag)
{
- int align = SIZEOF_VOID_P;
+ int align = (ins_flag & MONO_INST_UNALIGNED) ? 1 : SIZEOF_VOID_P;
if (ins_flag & MONO_INST_VOLATILE) {
/* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
}
+/*
+ * If @klass is a valuetype, emit code to copy a value with source address in @src and destination address in @dest.
+ * If @klass is a ref type, copy a pointer instead.
+ */
+
+void
+mini_emit_memory_copy (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *klass, gboolean native, int ins_flag)
+{
+ int explicit_align = 0;
+ if (ins_flag & MONO_INST_UNALIGNED)
+ explicit_align = 1;
+
+ /*
+ * FIXME: It's unclear whether we should be emitting both the acquire
+ * and release barriers for cpblk. It is technically both a load and
+ * store operation, so it seems like that's the sensible thing to do.
+ *
+ * FIXME: We emit full barriers on both sides of the operation for
+ * simplicity. We should have a separate atomic memcpy method instead.
+ */
+ if (ins_flag & MONO_INST_VOLATILE) {
+ /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
+ mini_emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
+ }
+
+ mini_emit_memory_copy_internal (cfg, dest, src, klass, explicit_align, native);
+
+ if (ins_flag & MONO_INST_VOLATILE) {
+ /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
+ mini_emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
+ }
+}
+
#endif
return memcpy_method;
}
-static void
-create_write_barrier_bitmap (MonoCompile *cfg, MonoClass *klass, unsigned *wb_bitmap, int offset)
-{
- MonoClassField *field;
- gpointer iter = NULL;
-
- while ((field = mono_class_get_fields (klass, &iter))) {
- int foffset;
-
- if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
- continue;
- foffset = klass->valuetype ? field->offset - sizeof (MonoObject): field->offset;
- if (mini_type_is_reference (mono_field_get_type (field))) {
- g_assert ((foffset % SIZEOF_VOID_P) == 0);
- *wb_bitmap |= 1 << ((offset + foffset) / SIZEOF_VOID_P);
- } else {
- MonoClass *field_class = mono_class_from_mono_type (field->type);
- if (field_class->has_references)
- create_write_barrier_bitmap (cfg, field_class, wb_bitmap, offset + foffset);
- }
- }
-}
-
void
mini_emit_write_barrier (MonoCompile *cfg, MonoInst *ptr, MonoInst *value)
{
if (!cfg->gen_write_barriers)
return;
+ //method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER && !MONO_INS_IS_PCONST_NULL (sp [1])
+
card_table = mono_gc_get_card_table (&card_table_shift_bits, &card_table_mask);
mono_gc_get_nursery (&nursery_shift_bits, &nursery_size);
EMIT_NEW_DUMMY_USE (cfg, dummy_use, value);
}
-gboolean
-mini_emit_wb_aware_memcpy (MonoCompile *cfg, MonoClass *klass, MonoInst *iargs[4], int size, int align)
-{
- int dest_ptr_reg, tmp_reg, destreg, srcreg, offset;
- unsigned need_wb = 0;
-
- if (align == 0)
- align = 4;
-
- /*types with references can't have alignment smaller than sizeof(void*) */
- if (align < SIZEOF_VOID_P)
- return FALSE;
-
- if (size > 5 * SIZEOF_VOID_P)
- return FALSE;
-
- create_write_barrier_bitmap (cfg, klass, &need_wb, 0);
-
- destreg = iargs [0]->dreg;
- srcreg = iargs [1]->dreg;
- offset = 0;
-
- dest_ptr_reg = alloc_preg (cfg);
- tmp_reg = alloc_preg (cfg);
-
- /*tmp = dreg*/
- EMIT_NEW_UNALU (cfg, iargs [0], OP_MOVE, dest_ptr_reg, destreg);
-
- while (size >= SIZEOF_VOID_P) {
- MonoInst *load_inst;
- MONO_INST_NEW (cfg, load_inst, OP_LOAD_MEMBASE);
- load_inst->dreg = tmp_reg;
- load_inst->inst_basereg = srcreg;
- load_inst->inst_offset = offset;
- MONO_ADD_INS (cfg->cbb, load_inst);
-
- MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, dest_ptr_reg, 0, tmp_reg);
-
- if (need_wb & 0x1)
- mini_emit_write_barrier (cfg, iargs [0], load_inst);
-
- offset += SIZEOF_VOID_P;
- size -= SIZEOF_VOID_P;
- need_wb >>= 1;
-
- /*tmp += sizeof (void*)*/
- if (size >= SIZEOF_VOID_P) {
- NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, dest_ptr_reg, dest_ptr_reg, SIZEOF_VOID_P);
- MONO_ADD_INS (cfg->cbb, iargs [0]);
- }
- }
-
- /* Those cannot be references since size < sizeof (void*) */
- while (size >= 4) {
- MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tmp_reg, srcreg, offset);
- MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, tmp_reg);
- offset += 4;
- size -= 4;
- }
-
- while (size >= 2) {
- MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, tmp_reg, srcreg, offset);
- MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, tmp_reg);
- offset += 2;
- size -= 2;
- }
-
- while (size >= 1) {
- MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, tmp_reg, srcreg, offset);
- MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, tmp_reg);
- offset += 1;
- size -= 1;
- }
-
- return TRUE;
-}
-
-/*
- * Emit code to copy a valuetype of type @klass whose address is stored in
- * @src->dreg to memory whose address is stored at @dest->dreg.
- */
-void
-mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *klass, gboolean native)
-{
- MonoInst *iargs [4];
- int n;
- guint32 align = 0;
- MonoMethod *memcpy_method;
- MonoInst *size_ins = NULL;
- MonoInst *memcpy_ins = NULL;
-
- g_assert (klass);
- if (cfg->gshared)
- klass = mono_class_from_mono_type (mini_get_underlying_type (&klass->byval_arg));
-
- /*
- * This check breaks with spilled vars... need to handle it during verification anyway.
- * g_assert (klass && klass == src->klass && klass == dest->klass);
- */
-
- if (mini_is_gsharedvt_klass (klass)) {
- g_assert (!native);
- size_ins = mini_emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
- memcpy_ins = mini_emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_MEMCPY);
- }
-
- if (native)
- n = mono_class_native_size (klass, &align);
- else
- n = mono_class_value_size (klass, &align);
-
- if (!align)
- align = SIZEOF_VOID_P;
- /* if native is true there should be no references in the struct */
- if (cfg->gen_write_barriers && (klass->has_references || size_ins) && !native) {
- /* Avoid barriers when storing to the stack */
- if (!((dest->opcode == OP_ADD_IMM && dest->sreg1 == cfg->frame_reg) ||
- (dest->opcode == OP_LDADDR))) {
- int context_used;
-
- iargs [0] = dest;
- iargs [1] = src;
-
- context_used = mini_class_check_context_used (cfg, klass);
-
- /* It's ok to intrinsify under gsharing since shared code types are layout stable. */
- if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && mini_emit_wb_aware_memcpy (cfg, klass, iargs, n, align)) {
- return;
- } else if (size_ins || align < SIZEOF_VOID_P) {
- if (context_used) {
- iargs [2] = mini_emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
- } else {
- iargs [2] = mini_emit_runtime_constant (cfg, MONO_PATCH_INFO_CLASS, klass);
- if (!cfg->compile_aot)
- mono_class_compute_gc_descriptor (klass);
- }
- if (size_ins)
- mono_emit_jit_icall (cfg, mono_gsharedvt_value_copy, iargs);
- else
- mono_emit_jit_icall (cfg, mono_value_copy, iargs);
- } else {
- /* We don't unroll more than 5 stores to avoid code bloat. */
- /*This is harmless and simplify mono_gc_get_range_copy_func */
- n += (SIZEOF_VOID_P - 1);
- n &= ~(SIZEOF_VOID_P - 1);
-
- EMIT_NEW_ICONST (cfg, iargs [2], n);
- mono_emit_jit_icall (cfg, mono_gc_get_range_copy_func (), iargs);
- }
- }
- }
-
- if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 8) {
- /* FIXME: Optimize the case when src/dest is OP_LDADDR */
- mini_emit_memcpy (cfg, dest->dreg, 0, src->dreg, 0, n, align);
- } else {
- iargs [0] = dest;
- iargs [1] = src;
- if (size_ins)
- iargs [2] = size_ins;
- else
- EMIT_NEW_ICONST (cfg, iargs [2], n);
-
- memcpy_method = mini_get_memcpy_method ();
- if (memcpy_ins)
- mini_emit_calli (cfg, mono_method_signature (memcpy_method), iargs, memcpy_ins, NULL, NULL);
- else
- mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
- }
-}
-
MonoMethod*
mini_get_memset_method (void)
{
return addr;
}
-static MonoBreakPolicy
-always_insert_breakpoint (MonoMethod *method)
-{
- return MONO_BREAK_POLICY_ALWAYS;
-}
-
-static MonoBreakPolicyFunc break_policy_func = always_insert_breakpoint;
-
-/**
- * mono_set_break_policy:
- * \param policy_callback the new callback function
- *
- * Allow embedders to decide wherther to actually obey breakpoint instructions
- * (both break IL instructions and \c Debugger.Break method calls), for example
- * to not allow an app to be aborted by a perfectly valid IL opcode when executing
- * untrusted or semi-trusted code.
- *
- * \p policy_callback will be called every time a break point instruction needs to
- * be inserted with the method argument being the method that calls \c Debugger.Break
- * or has the IL \c break instruction. The callback should return \c MONO_BREAK_POLICY_NEVER
- * if it wants the breakpoint to not be effective in the given method.
- * \c MONO_BREAK_POLICY_ALWAYS is the default.
- */
-void
-mono_set_break_policy (MonoBreakPolicyFunc policy_callback)
-{
- if (policy_callback)
- break_policy_func = policy_callback;
- else
- break_policy_func = always_insert_breakpoint;
-}
-
-static gboolean
-should_insert_brekpoint (MonoMethod *method) {
- switch (break_policy_func (method)) {
- case MONO_BREAK_POLICY_ALWAYS:
- return TRUE;
- case MONO_BREAK_POLICY_NEVER:
- return FALSE;
- case MONO_BREAK_POLICY_ON_DBG:
- g_warning ("mdb no longer supported");
- return FALSE;
- default:
- g_warning ("Incorrect value returned from break policy callback");
- return FALSE;
- }
-}
-
/* optimize the simple GetGenericValueImpl/SetGenericValueImpl generic icalls */
static MonoInst*
emit_array_generic_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
return NULL;
}
+
+static gboolean
+mono_type_is_native_blittable (MonoType *t)
+{
+ if (MONO_TYPE_IS_REFERENCE (t))
+ return FALSE;
+
+ if (MONO_TYPE_IS_PRIMITIVE_SCALAR (t))
+ return TRUE;
+
+ MonoClass *klass = mono_class_from_mono_type (t);
+
+ //MonoClass::blitable depends on mono_class_setup_fields being done.
+ mono_class_setup_fields (klass);
+ if (!klass->blittable)
+ return FALSE;
+
+ // If the native marshal size is different we can't convert PtrToStructure to a type load
+ if (mono_class_native_size (klass, NULL) != mono_class_value_size (klass, NULL))
+ return FALSE;
+
+ return TRUE;
+}
+
+
static MonoInst*
mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
{
(strcmp (cmethod->klass->name_space, "System.Diagnostics") == 0) &&
(strcmp (cmethod->klass->name, "Debugger") == 0)) {
if (!strcmp (cmethod->name, "Break") && fsig->param_count == 0) {
- if (should_insert_brekpoint (cfg->method)) {
+ if (mini_should_insert_breakpoint (cfg->method)) {
ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
} else {
MONO_INST_NEW (cfg, ins, OP_NOP);
MONO_ADD_INS (cfg->cbb, ins);
return ins;
}
+ } else if (cmethod->klass->image == mono_defaults.corlib &&
+ (strcmp (cmethod->klass->name_space, "System.Runtime.InteropServices") == 0) &&
+ (strcmp (cmethod->klass->name, "Marshal") == 0)) {
+ //Convert Marshal.PtrToStructure<T> of blittable T to direct loads
+ if (strcmp (cmethod->name, "PtrToStructure") == 0 &&
+ cmethod->is_inflated &&
+ fsig->param_count == 1 &&
+ !mini_method_check_context_used (cfg, cmethod)) {
+
+ MonoGenericContext *method_context = mono_method_get_context (cmethod);
+ MonoType *arg0 = method_context->method_inst->type_argv [0];
+ if (mono_type_is_native_blittable (arg0))
+ return mini_emit_memory_load (cfg, arg0, args [0], 0, 0);
+ }
}
#ifdef MONO_ARCH_SIMD_INTRINSICS
MONO_ADD_INS (cfg->cbb, ins);
break;
case CEE_BREAK:
- if (should_insert_brekpoint (cfg->method)) {
+ if (mini_should_insert_breakpoint (cfg->method)) {
ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
} else {
MONO_INST_NEW (cfg, ins, OP_NOP);
klass = mini_get_class (method, token, generic_context);
CHECK_TYPELOAD (klass);
sp -= 2;
- if (generic_class_is_reference_type (cfg, klass)) {
- MonoInst *store, *load;
- int dreg = alloc_ireg_ref (cfg);
-
- NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, dreg, sp [1]->dreg, 0);
- load->flags |= ins_flag;
- MONO_ADD_INS (cfg->cbb, load);
-
- NEW_STORE_MEMBASE (cfg, store, OP_STORE_MEMBASE_REG, sp [0]->dreg, 0, dreg);
- store->flags |= ins_flag;
- MONO_ADD_INS (cfg->cbb, store);
-
- if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER)
- mini_emit_write_barrier (cfg, sp [0], sp [1]);
- } else {
- mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
- }
+ mini_emit_memory_copy (cfg, sp [0], sp [1], klass, FALSE, ins_flag);
ins_flag = 0;
ip += 5;
break;
}
/* Optimize the ldobj+stobj combination */
- /* The reference case ends up being a load+store anyway */
- /* Skip this if the operation is volatile. */
- if (((ip [5] == CEE_STOBJ) && ip_in_bb (cfg, cfg->cbb, ip + 5) && read32 (ip + 6) == token) && !generic_class_is_reference_type (cfg, klass) && !(ins_flag & MONO_INST_VOLATILE)) {
+ if (((ip [5] == CEE_STOBJ) && ip_in_bb (cfg, cfg->cbb, ip + 5) && read32 (ip + 6) == token)) {
CHECK_STACK (1);
sp --;
- mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
+ mini_emit_memory_copy (cfg, sp [0], sp [1], klass, FALSE, ins_flag);
ip += 5 + 5;
ins_flag = 0;
dreg = alloc_ireg_mp (cfg);
EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
wbarrier_ptr_ins = ins;
- /* The decomposition will call mini_emit_stobj () which will emit a wbarrier if needed */
+ /* The decomposition will call mini_emit_memory_copy () which will emit a wbarrier if needed */
EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, dreg, 0, sp [1]->dreg);
} else {
EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, sp [0]->dreg, foffset, sp [1]->dreg);
temp = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
temp->backend.is_pinvoke = 1;
EMIT_NEW_TEMPLOADA (cfg, dest, temp->inst_c0);
- mini_emit_stobj (cfg, dest, src, klass, TRUE);
+ mini_emit_memory_copy (cfg, dest, src, klass, TRUE, 0);
EMIT_NEW_TEMPLOAD (cfg, dest, temp->inst_c0);
dest->type = STACK_VTYPE;
} else {
EMIT_NEW_RETLOADA (cfg, ins);
}
- mini_emit_stobj (cfg, ins, sp [0], klass, TRUE);
+ mini_emit_memory_copy (cfg, ins, sp [0], klass, TRUE, 0);
if (sp != stack_start)
UNVERIFIED;
the values on the stack before emitting the last instruction of the bb.
*/
-#else /* !DISABLE_JIT */
-
-void
-mono_set_break_policy (MonoBreakPolicyFunc policy_callback)
-{
-}
-
#endif /* !DISABLE_JIT */
return code;
}
-#if defined(__ARM_EABI__) && defined(__linux__) && !defined(PLATFORM_ANDROID) && !defined(__native_client__)
+#if defined(__ARM_EABI__) && defined(__linux__) && !defined(PLATFORM_ANDROID) && !defined(__native_client__) && !defined(MONO_CROSS_COMPILE)
#define HAVE_AEABI_READ_TP 1
#endif
mgreg_t *new_reg_locations [MONO_MAX_IREGS];
gboolean get_reg_locations = unwind_options & MONO_UNWIND_REG_LOCATIONS;
gboolean async = mono_thread_info_is_async_context ();
+ Unwinder unwinder;
if (mono_llvm_only) {
GSList *l, *ips;
memcpy (&ctx, start_ctx, sizeof (MonoContext));
memset (reg_locations, 0, sizeof (reg_locations));
+ unwinder_init (&unwinder);
+
while (MONO_CONTEXT_GET_SP (&ctx) < jit_tls->end_of_stack) {
frame.lmf = lmf;
- res = mono_find_jit_info_ext (domain, jit_tls, NULL, &ctx, &new_ctx, NULL, &lmf, get_reg_locations ? new_reg_locations : NULL, &frame);
+ res = unwinder_unwind_frame (&unwinder, domain, jit_tls, NULL, &ctx, &new_ctx, NULL, &lmf, get_reg_locations ? new_reg_locations : NULL, &frame);
if (!res)
return;
gpointer ip;
if (in_interp)
- ip = (guint16*)ji->code_start + frame.native_offset;
+ ip = (guint8*)ji->code_start + frame.native_offset;
else
ip = MONO_CONTEXT_GET_IP (ctx);
}
if (in_interp)
- ip = (guint16*)ji->code_start + frame.native_offset;
+ ip = (guint8*)ji->code_start + frame.native_offset;
else
ip = MONO_CONTEXT_GET_IP (ctx);
* like the call which transitioned to JITted code has succeeded, but the
* return value register etc. is not set, so we have to be careful.
*/
- mono_interp_set_resume_state (mono_ex, &frame, ei->handler_start);
+ mono_interp_set_resume_state (jit_tls, mono_ex, frame.interp_frame, ei->handler_start);
/* Undo the IP adjustment done by mono_arch_unwind_frame () */
#if defined(TARGET_AMD64)
ctx->gregs [AMD64_RIP] ++;
* mono_handle_exception:
* \param ctx saved processor state
* \param obj the exception object
+ *
+ * Handle the exception OBJ starting from the state CTX. Modify CTX to point to the handler clause if the exception is caught, and
+ * return TRUE.
*/
gboolean
mono_handle_exception (MonoContext *ctx, MonoObject *obj)
g_assert_not_reached ();
}
#endif
-
-#ifndef ENABLE_INTERPRETER
-/* Stubs of interpreter functions */
-void
-mono_interp_set_resume_state (MonoException *ex, StackFrameInfo *frame, gpointer handler_ip)
-{
- g_assert_not_reached ();
-}
-
-void
-mono_interp_run_finally (StackFrameInfo *frame, int clause_index, gpointer handler_ip)
-{
- g_assert_not_reached ();
-}
-
-void
-mono_interp_frame_iter_init (MonoInterpStackIter *iter, gpointer interp_exit_data)
-{
- g_assert_not_reached ();
-}
-
-gboolean
-mono_interp_frame_iter_next (MonoInterpStackIter *iter, StackFrameInfo *frame)
-{
- g_assert_not_reached ();
- return FALSE;
-}
-#endif
/*
* LOCKING: loader lock
*/
+#if defined(PLATFORM_ANDROID) && defined(TARGET_ARM)
+/* work around for HW bug on Nexus9 when running on armv7 */
+#ifdef __clang__
+static __attribute__ ((optnone)) void
+#else
+/* gcc */
+static __attribute__ ((optimize("O0"))) void
+#endif
+#else
static void
+#endif
rgctx_template_set_slot (MonoImage *image, MonoRuntimeGenericContextTemplate *template_, int type_argc,
int slot, gpointer data, MonoRgctxInfoType info_type)
{
G_GNUC_UNUSED gboolean
mono_debug_count (void)
{
- static int count = 0;
+ static int count = 0, int_val = 0;
static gboolean inited;
- static char *value;
count ++;
if (!inited) {
- value = g_getenv ("COUNT");
+ char *value = g_getenv ("COUNT");
+ if (value) {
+ int_val = atoi (value);
+ g_free (value);
+ }
inited = TRUE;
}
- if (!value)
+ if (!int_val)
return TRUE;
- int int_val = atoi (value);
- g_free (value);
-
if (count == int_val)
break_count ();
g_assert_not_reached ();
}
+
+static MonoBreakPolicy
+always_insert_breakpoint (MonoMethod *method)
+{
+ return MONO_BREAK_POLICY_ALWAYS;
+}
+
+static MonoBreakPolicyFunc break_policy_func = always_insert_breakpoint;
+
+/**
+ * mono_set_break_policy:
+ * \param policy_callback the new callback function
+ *
+ * Allow embedders to decide whether to actually obey breakpoint instructions
+ * (both break IL instructions and \c Debugger.Break method calls), for example
+ * to not allow an app to be aborted by a perfectly valid IL opcode when executing
+ * untrusted or semi-trusted code.
+ *
+ * \p policy_callback will be called every time a break point instruction needs to
+ * be inserted with the method argument being the method that calls \c Debugger.Break
+ * or has the IL \c break instruction. The callback should return \c MONO_BREAK_POLICY_NEVER
+ * if it wants the breakpoint to not be effective in the given method.
+ * \c MONO_BREAK_POLICY_ALWAYS is the default.
+ */
+void
+mono_set_break_policy (MonoBreakPolicyFunc policy_callback)
+{
+ if (policy_callback)
+ break_policy_func = policy_callback;
+ else
+ break_policy_func = always_insert_breakpoint;
+}
+
+gboolean
+mini_should_insert_breakpoint (MonoMethod *method)
+{
+ switch (break_policy_func (method)) {
+ case MONO_BREAK_POLICY_ALWAYS:
+ return TRUE;
+ case MONO_BREAK_POLICY_NEVER:
+ return FALSE;
+ case MONO_BREAK_POLICY_ON_DBG:
+ g_warning ("mdb no longer supported");
+ return FALSE;
+ default:
+ g_warning ("Incorrect value returned from break policy callback");
+ return FALSE;
+ }
+}
+
// Custom handlers currently only implemented by Windows.
#ifndef HOST_WIN32
gboolean
*/
gpointer abort_exc_stack_threshold;
-
/*
* List of methods being JIT'd in the current thread.
*/
int active_jit_methods;
+
+ gpointer interp_context;
} MonoJitTlsData;
/*
MonoInst* mono_emit_method_call (MonoCompile *cfg, MonoMethod *method, MonoInst **args, MonoInst *this_ins);
void mono_create_helper_signatures (void);
MonoInst* mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig, MonoInst **args);
+gboolean mini_should_insert_breakpoint (MonoMethod *method);
gboolean mini_class_is_system_array (MonoClass *klass);
MonoMethodSignature *mono_get_element_address_signature (int arity);
MonoInst* mini_emit_calli (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args, MonoInst *addr, MonoInst *imt_arg, MonoInst *rgctx_arg);
MonoInst* mini_emit_memory_barrier (MonoCompile *cfg, int kind);
void mini_emit_write_barrier (MonoCompile *cfg, MonoInst *ptr, MonoInst *value);
-gboolean mini_emit_wb_aware_memcpy (MonoCompile *cfg, MonoClass *klass, MonoInst *iargs[4], int size, int align);
MonoInst* mini_emit_memory_load (MonoCompile *cfg, MonoType *type, MonoInst *src, int offset, int ins_flag);
void mini_emit_memory_store (MonoCompile *cfg, MonoType *type, MonoInst *dest, MonoInst *value, int ins_flag);
void mini_emit_memory_copy_bytes (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoInst *size, int ins_flag);
void mini_emit_memory_init_bytes (MonoCompile *cfg, MonoInst *dest, MonoInst *value, MonoInst *size, int ins_flag);
+void mini_emit_memory_copy (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *klass, gboolean native, int ins_flag);
MonoMethod* mini_get_memcpy_method (void);
MonoMethod* mini_get_memset_method (void);
guint8 *start = NULL, *code, *label_gexits [gregs_num], *label_fexits [fregs_num], *label_leave_tramp [3], *label_is_float_ret;
MonoJumpInfo *ji = NULL;
GSList *unwind_ops = NULL;
- int buf_len, i, framesize = 0, off_methodargs, off_targetaddr;
+ int buf_len, i, framesize, off_methodargs, off_targetaddr;
const int fp_reg = ARMREG_R7;
buf_len = 512 + 1024;
start = code = (guint8 *) mono_global_codeman_reserve (buf_len);
- off_methodargs = framesize;
+ framesize = 5 * sizeof (mgreg_t); /* lr, r4, r8, r6 and plus one */
+
+ off_methodargs = -framesize;
framesize += sizeof (mgreg_t);
- off_targetaddr = framesize;
+ off_targetaddr = -framesize;
framesize += sizeof (mgreg_t);
- framesize = ALIGN_TO (framesize, MONO_ARCH_FRAME_ALIGNMENT);
+ framesize = ALIGN_TO (framesize + 4 * sizeof (mgreg_t), MONO_ARCH_FRAME_ALIGNMENT);
/* allocate space on stack for argument passing */
const int stack_space = ALIGN_TO (((gregs_num - ARMREG_R3) * sizeof (mgreg_t)), MONO_ARCH_FRAME_ALIGNMENT);
- /* use r4, r5 and r6 as scratch registers */
- ARM_PUSH (code, (1 << fp_reg) | (1 << ARMREG_LR) | (1 << ARMREG_R4) | (1 << ARMREG_R5) | (1 << ARMREG_R6));
+ /* iOS ABI */
+ ARM_PUSH (code, (1 << fp_reg) | (1 << ARMREG_LR));
ARM_MOV_REG_REG (code, fp_reg, ARMREG_SP);
+
+ /* use r4, r8 and r6 as scratch registers */
+ ARM_PUSH (code, (1 << ARMREG_R4) | (1 << ARMREG_R8) | (1 << ARMREG_R6));
ARM_SUB_REG_IMM8 (code, ARMREG_SP, ARMREG_SP, stack_space + framesize);
/* save InterpMethodArguments* onto stack */
/* load pointer to InterpMethodArguments* into r4 */
ARM_MOV_REG_REG (code, ARMREG_R4, ARMREG_R1);
- /* move flen into r5 */
- ARM_LDR_IMM (code, ARMREG_R5, ARMREG_R4, MONO_STRUCT_OFFSET (InterpMethodArguments, flen));
+ /* move flen into r8 */
+ ARM_LDR_IMM (code, ARMREG_R8, ARMREG_R4, MONO_STRUCT_OFFSET (InterpMethodArguments, flen));
/* load pointer to fargs into r6 */
ARM_LDR_IMM (code, ARMREG_R6, ARMREG_R4, MONO_STRUCT_OFFSET (InterpMethodArguments, fargs));
for (i = 0; i < fregs_num; ++i) {
- ARM_CMP_REG_IMM (code, ARMREG_R5, 0, 0);
+ ARM_CMP_REG_IMM (code, ARMREG_R8, 0, 0);
label_fexits [i] = code;
ARM_B_COND (code, ARMCOND_EQ, 0);
g_assert (i <= ARM_VFP_D7); /* otherwise, need to pass args on stack */
ARM_FLDD (code, i, ARMREG_R6, i * sizeof (double));
- ARM_SUB_REG_IMM8 (code, ARMREG_R5, ARMREG_R5, 1);
+ ARM_SUB_REG_IMM8 (code, ARMREG_R8, ARMREG_R8, 1);
}
for (i = 0; i < fregs_num; i++)
arm_patch (label_fexits [i], code);
- /* move ilen into r5 */
- ARM_LDR_IMM (code, ARMREG_R5, ARMREG_R4, MONO_STRUCT_OFFSET (InterpMethodArguments, ilen));
+ /* move ilen into r8 */
+ ARM_LDR_IMM (code, ARMREG_R8, ARMREG_R4, MONO_STRUCT_OFFSET (InterpMethodArguments, ilen));
/* load pointer to iargs into r6 */
ARM_LDR_IMM (code, ARMREG_R6, ARMREG_R4, MONO_STRUCT_OFFSET (InterpMethodArguments, iargs));
int stack_offset = 0;
for (i = 0; i < gregs_num; i++) {
- ARM_CMP_REG_IMM (code, ARMREG_R5, 0, 0);
+ ARM_CMP_REG_IMM (code, ARMREG_R8, 0, 0);
label_gexits [i] = code;
ARM_B_COND (code, ARMCOND_EQ, 0);
ARM_STR_IMM (code, ARMREG_R4, ARMREG_SP, stack_offset);
stack_offset += sizeof (mgreg_t);
}
- ARM_SUB_REG_IMM8 (code, ARMREG_R5, ARMREG_R5, 1);
+ ARM_SUB_REG_IMM8 (code, ARMREG_R8, ARMREG_R8, 1);
}
for (i = 0; i < gregs_num; i++)
ARM_LDR_IMM (code, ARMREG_R4, fp_reg, off_methodargs);
/* load is_float_ret */
- ARM_LDR_IMM (code, ARMREG_R5, ARMREG_R4, MONO_STRUCT_OFFSET (InterpMethodArguments, is_float_ret));
+ ARM_LDR_IMM (code, ARMREG_R8, ARMREG_R4, MONO_STRUCT_OFFSET (InterpMethodArguments, is_float_ret));
/* check if a float return value is expected */
- ARM_CMP_REG_IMM (code, ARMREG_R5, 0, 0);
+ ARM_CMP_REG_IMM (code, ARMREG_R8, 0, 0);
label_is_float_ret = code;
ARM_B_COND (code, ARMCOND_NE, 0);
/* greg return */
/* load retval */
- ARM_LDR_IMM (code, ARMREG_R5, ARMREG_R4, MONO_STRUCT_OFFSET (InterpMethodArguments, retval));
+ ARM_LDR_IMM (code, ARMREG_R8, ARMREG_R4, MONO_STRUCT_OFFSET (InterpMethodArguments, retval));
- ARM_CMP_REG_IMM (code, ARMREG_R5, 0, 0);
+ ARM_CMP_REG_IMM (code, ARMREG_R8, 0, 0);
label_leave_tramp [0] = code;
ARM_B_COND (code, ARMCOND_EQ, 0);
/* store greg result, always write back 64bit */
- ARM_STR_IMM (code, ARMREG_R0, ARMREG_R5, 0);
- ARM_STR_IMM (code, ARMREG_R1, ARMREG_R5, 4);
+ ARM_STR_IMM (code, ARMREG_R0, ARMREG_R8, 0);
+ ARM_STR_IMM (code, ARMREG_R1, ARMREG_R8, 4);
label_leave_tramp [1] = code;
ARM_B_COND (code, ARMCOND_AL, 0);
/* freg return */
arm_patch (label_is_float_ret, code);
/* load retval */
- ARM_LDR_IMM (code, ARMREG_R5, ARMREG_R4, MONO_STRUCT_OFFSET (InterpMethodArguments, retval));
+ ARM_LDR_IMM (code, ARMREG_R8, ARMREG_R4, MONO_STRUCT_OFFSET (InterpMethodArguments, retval));
- ARM_CMP_REG_IMM (code, ARMREG_R5, 0, 0);
+ ARM_CMP_REG_IMM (code, ARMREG_R8, 0, 0);
label_leave_tramp [2] = code;
ARM_B_COND (code, ARMCOND_EQ, 0);
/* store freg result */
- ARM_FSTD (code, ARM_VFP_F0, ARMREG_R5, 0);
+ ARM_FSTD (code, ARM_VFP_F0, ARMREG_R8, 0);
for (i = 0; i < 3; i++)
arm_patch (label_leave_tramp [i], code);
+ ARM_ADD_REG_IMM8 (code, ARMREG_SP, ARMREG_SP, stack_space + framesize);
+ ARM_POP (code, (1 << ARMREG_R4) | (1 << ARMREG_R8) | (1 << ARMREG_R6));
ARM_MOV_REG_REG (code, ARMREG_SP, fp_reg);
- ARM_POP (code, (1 << fp_reg) | (1 << ARMREG_PC) | (1 << ARMREG_R4) | (1 << ARMREG_R5) | (1 << ARMREG_R6));
+ ARM_POP (code, (1 << fp_reg) | (1 << ARMREG_PC));
g_assert (code - start < buf_len);
--- /dev/null
+using System;
+using System.Runtime.CompilerServices;
+using Mono;
+
+/*
+ * Regression tests for the mono JIT.
+ *
+ * Each test needs to be of the form:
+ *
+ * static int test_<result>_<name> ();
+ *
+ * where <result> is an integer (the value that needs to be returned by
+ * the method to make it pass.
+ * <name> is a user-displayed name used to identify the test.
+ *
+ * The tests can be driven in two ways:
+ * *) running the program directly: Main() uses reflection to find and invoke
+ * the test methods (this is useful mostly to check that the tests are correct)
+ * *) with the --regression switch of the jit (this is the preferred way since
+ * all the tests will be run with optimizations on and off)
+ *
+ * The reflection logic could be moved to a .dll since we need at least another
+ * regression test file written in IL code to have better control on how
+ * the IL code looks.
+ */
+
+#if __MOBILE__
+namespace UnalignedTests
+{
+#endif
+
+
+class Tests {
+
+#if !__MOBILE__
+ public static int Main (string[] args) {
+ return TestDriver.RunTests (typeof (Tests), args);
+ }
+#endif
+
+
+ public static unsafe int test_0_ldobj_r4 ()
+ {
+ byte *ptr = stackalloc byte [32];
+ float f = (float)123.44f;
+ *(float*)ptr = (float)f;
+
+ int expected = *(int*)ptr;
+
+ Intrinsics.UnalignedStobj<int> (ptr + 1, expected);
+ /* we can loose some precision due to r4<->r8 conversions */
+ if (Math.Abs (Intrinsics.UnalignedLdobj<float> (ptr + 1) - f) > 0.01f)
+ return 1;
+
+ return 0;
+ }
+
+ public static unsafe int test_0_ldobj_r8 ()
+ {
+ byte *ptr = stackalloc byte [32];
+ double f = 34423.44f;
+ *(double*)ptr = (double)f;
+
+ long expected = *(long*)ptr;
+
+ Intrinsics.UnalignedStobj<long> (ptr + 3, expected);
+ if (Intrinsics.UnalignedLdobj<double> (ptr + 3) != f)
+ return 1;
+
+ return 0;
+ }
+
+ public static unsafe int test_0_ldobj ()
+ {
+ byte *ptr = stackalloc byte [20];
+ for (int i = 0; i < 20; ++i)
+ ptr [i] = (byte)i;
+
+
+ if (Intrinsics.UnalignedLdobj<short> (ptr + 0) != 0x0100)
+ return 1;
+
+ if (Intrinsics.UnalignedLdobj<short> (ptr + 1) != 0x0201)
+ return 2;
+
+ if (Intrinsics.UnalignedLdobj<short> (ptr + 2) != 0x0302)
+ return 3;
+
+ if (Intrinsics.UnalignedLdobj<int> (ptr + 1) != 0x04030201)
+ return 4;
+
+ if (Intrinsics.UnalignedLdobj<int> (ptr + 2) != 0x05040302)
+ return 5;
+
+ if (Intrinsics.UnalignedLdobj<long> (ptr + 1) != 0x0807060504030201)
+ return 6;
+
+ if (Intrinsics.UnalignedLdobj<long> (ptr + 6) != 0xD0C0B0A09080706)
+ return 7;
+
+ return 0;
+ }
+
+ public static unsafe int test_0_ldind ()
+ {
+ byte *ptr = stackalloc byte [20];
+ for (int i = 0; i < 20; ++i)
+ ptr [i] = (byte)i;
+
+
+ if (Intrinsics.UnalignedLdInd2 (ptr + 0) != 0x0100)
+ return 1;
+
+ if (Intrinsics.UnalignedLdInd2 (ptr + 1) != 0x0201)
+ return 2;
+
+ if (Intrinsics.UnalignedLdInd2 (ptr + 2) != 0x0302)
+ return 3;
+
+ if (Intrinsics.UnalignedLdInd4 (ptr + 1) != 0x04030201)
+ return 4;
+
+ if (Intrinsics.UnalignedLdInd4 (ptr + 2) != 0x05040302)
+ return 5;
+
+ if (Intrinsics.UnalignedLdInd8 (ptr + 1) != 0x0807060504030201)
+ return 6;
+
+ if (Intrinsics.UnalignedLdInd8 (ptr + 6) != 0xD0C0B0A09080706)
+ return 7;
+
+ return 0;
+ }
+ public static unsafe int test_0_cpobj ()
+ {
+ byte *dest = stackalloc byte [20];
+ byte *src = stackalloc byte [20];
+ for (int i = 0; i < 20; ++i)
+ src [i] = (byte)i;
+
+ Intrinsics.UnalignedCpobj<short> (dest + 0, src + 0);
+ if (dest [0] != src [0] || dest [1] != src [1])
+ return 1;
+
+ Intrinsics.UnalignedCpobj<short> (dest + 1, src + 0);
+ if (dest [1] != src [0] || dest [2] != src [1])
+ return 2;
+
+ Intrinsics.UnalignedCpobj<short> (dest + 0, src + 1);
+ if (dest [0] != src [1] || dest [1] != src [2])
+ return 3;
+
+ Intrinsics.UnalignedCpobj<short> (dest + 1, src + 1);
+ if (dest [1] != src [1] || dest [2] != src [2])
+ return 3;
+
+ Intrinsics.UnalignedCpobj<int> (dest + 3, src);
+ for (int i = 0; i < 4; ++i) {
+ if (dest [i + 3] != src [i])
+ return 4;
+ }
+
+ Intrinsics.UnalignedCpobj<int> (dest + 1, src + 2);
+ for (int i = 0; i < 4; ++i) {
+ if (dest [i + 1] != src [i + 2])
+ return 5;
+ }
+
+ Intrinsics.UnalignedCpobj<long> (dest + 1, src + 2);
+ for (int i = 0; i < 8; ++i) {
+ if (dest [i + 1] != src [i + 2])
+ return 6;
+ }
+
+ Intrinsics.UnalignedCpobj<long> (dest + 7, src + 2);
+ for (int i = 0; i < 8; ++i) {
+ if (dest [i + 7] != src [i + 2])
+ return 7;
+ }
+
+ return 0;
+ }
+
+ public static unsafe int test_0_stobj ()
+ {
+ byte *ptr = stackalloc byte [20];
+
+ Intrinsics.UnalignedStobj <short> (ptr + 0, 0x6688);
+ if (ptr [0] != 0x88 || ptr [1] != 0x66)
+ return 1;
+
+ Intrinsics.UnalignedStobj <short> (ptr + 1, 0x6589);
+ if (ptr [1] != 0x89 || ptr [2] != 0x65)
+ return 2;
+
+ Intrinsics.UnalignedStobj <int> (ptr + 1, 0x60708090);
+ if (ptr [1] != 0x90 || ptr [2] != 0x80 || ptr [3] != 0x70 || ptr [4] != 0x60)
+ return 3;
+
+ Intrinsics.UnalignedStobj <long> (ptr + 1, 0x405060708090);
+ if (ptr [1] != 0x90 || ptr [2] != 0x80 || ptr [3] != 0x70 || ptr [4] != 0x60 || ptr [5] != 0x50 || ptr [6] != 0x40)
+ return 4;
+
+ return 0;
+ }
+
+ public static unsafe int test_0_ldobj_stobj ()
+ {
+ byte *dest = stackalloc byte [20];
+ byte *src = stackalloc byte [20];
+
+ for (int i = 0; i < 20; ++i)
+ src [i] = (byte)i;
+
+ Intrinsics.UnalignedLdobjStObjPair<short> (dest + 0, src + 0);
+ if (dest [0] != src [0] || dest [1] != src [1])
+ return 1;
+
+ Intrinsics.UnalignedLdobjStObjPair<short> (dest + 1, src + 0);
+ if (dest [1] != src [0] || dest [2] != src [1])
+ return 2;
+
+ Intrinsics.UnalignedLdobjStObjPair<short> (dest + 0, src + 1);
+ if (dest [0] != src [1] || dest [1] != src [2])
+ return 3;
+
+ Intrinsics.UnalignedLdobjStObjPair<short> (dest + 1, src + 1);
+ if (dest [1] != src [1] || dest [2] != src [2])
+ return 3;
+
+ Intrinsics.UnalignedLdobjStObjPair<int> (dest + 1, src + 1);
+ if (dest [1] != src [1] || dest [2] != src [2])
+ return 4;
+
+ Intrinsics.UnalignedLdobjStObjPair<long> (dest + 1, src + 1);
+ if (dest [1] != src [1] || dest [2] != src [2])
+ return 5;
+
+
+ return 0;
+ }
+
+
+ public static unsafe int test_0_cpblk ()
+ {
+ byte *dest = stackalloc byte [20];
+ byte *src = stackalloc byte [20];
+ for (int i = 0; i < 20; ++i)
+ src [i] = (byte)i;
+
+
+ Intrinsics.UnalignedCpblk (dest + 0, src + 0, 2);
+ if (dest [0] != src [0] || dest [1] != src [1])
+ return 1;
+
+ Intrinsics.UnalignedCpblk (dest + 1, src + 0, 2);
+ if (dest [1] != src [0] || dest [2] != src [1])
+ return 2;
+
+ Intrinsics.UnalignedCpblk (dest + 0, src + 1, 2);
+ if (dest [0] != src [1] || dest [1] != src [2])
+ return 3;
+
+ Intrinsics.UnalignedCpblk (dest + 1, src + 1, 2);
+ if (dest [1] != src [1] || dest [2] != src [2])
+ return 3;
+
+ Intrinsics.UnalignedCpblk (dest + 1, src + 1, 4);
+ for (int i = 0; i < 4; ++i) {
+ if (dest [i + 1] != src [i + 1])
+ return 4;
+ }
+
+ Intrinsics.UnalignedCpblk (dest + 1, src + 1, 8);
+ for (int i = 0; i < 8; ++i) {
+ if (dest [i + 1] != src [i + 1])
+ return 5;
+ }
+
+ return 0;
+ }
+
+
+ public static unsafe int test_0_initblk ()
+ {
+ byte *ptr = stackalloc byte [20];
+
+ for (int i = 0; i < 20; ++i)
+ ptr [i] = (byte)i;
+
+ Intrinsics.UnalignedInit (ptr, 30, 2);
+ if (ptr [0] != 30 || ptr [1] != 30)
+ return 1;
+
+ Intrinsics.UnalignedInit (ptr + 1, 31, 2);
+ if (ptr[0] != 30 || ptr [1] != 31 || ptr [2] != 31)
+ return 2;
+
+ return 0;
+ }
+}
+
+#if __MOBILE__
+}
+#endif
+
+
+
appdomain1.exe \
appdomain2.exe \
appdomain-exit.exe \
+ appdomain-unload-asmload.exe \
appdomain-unload-callback.exe \
appdomain-unload-doesnot-raise-pending-events.exe \
unload-appdomain-on-shutdown.exe \
appdomain-async-invoke.exe \
appdomain-exit.exe \
appdomain-serialize-exception.exe \
+ appdomain-unload-asmload.exe \
appdomain-unload-callback.exe \
appdomain-unload-doesnot-raise-pending-events.exe \
appdomain-unload.exe \
if (TestITestDelegate (itest) != 0)
return 174;
+ if (TestIfaceNoIcall (itest as ITestPresSig) != 0)
+ return 201;
+
itest = new TestClass ();
if (TestITest (itest) != 0)
if (TestITest (itest) != 0)
return 176;
+
#endif
#endregion // Runtime Callable Wrapper Tests
void ITestIn ([MarshalAs (UnmanagedType.Interface)]ITest val);
[MethodImplAttribute (MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void ITestOut ([MarshalAs (UnmanagedType.Interface)]out ITest val);
+ int Return22NoICall();
}
[ComImport ()]
[MethodImplAttribute (MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
[PreserveSig ()]
int ITestOut ([MarshalAs (UnmanagedType.Interface)]out ITestPresSig val);
+ [PreserveSig ()]
+ int Return22NoICall();
}
[System.Runtime.InteropServices.GuidAttribute ("00000000-0000-0000-0000-000000000002")]
public virtual extern void ITestIn ([MarshalAs (UnmanagedType.Interface)]ITest val);
[MethodImplAttribute (MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
public virtual extern void ITestOut ([MarshalAs (UnmanagedType.Interface)]out ITest val);
+
+ [MethodImplAttribute (MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
+ public virtual extern int Return22NoICall();
}
[System.Runtime.InteropServices.GuidAttribute ("00000000-0000-0000-0000-000000000002")]
val = new ManagedTestPresSig ();
return 0;
}
+
+ public int Return22NoICall()
+ {
+ return 88;
+ }
}
public class ManagedTest : ITest
return new ManagedTest ();
}
}
+
+ public int Return22NoICall()
+ {
+ return 99;
+ }
}
public static int mono_test_marshal_variant_in_callback (VarEnum vt, object obj)
}
return 0;
}
+
+ public static int TestIfaceNoIcall (ITestPresSig itest) {
+ return itest.Return22NoICall () == 22 ? 0 : 1;
+ }
}
public class TestVisible
int (STDCALL *DoubleIn)(MonoComObject* pUnk, double a);
int (STDCALL *ITestIn)(MonoComObject* pUnk, MonoComObject* pUnk2);
int (STDCALL *ITestOut)(MonoComObject* pUnk, MonoComObject* *ppUnk);
+ int (STDCALL *Return22NoICall)(MonoComObject* pUnk);
} MonoIUnknown;
struct MonoComObject
return S_OK;
}
+LIBTEST_API int STDCALL
+Return22NoICall(MonoComObject* pUnk)
+{
+ return 22;
+}
+
+
static void create_com_object (MonoComObject** pOut);
LIBTEST_API int STDCALL
(*pOut)->vtbl->ITestIn = ITestIn;
(*pOut)->vtbl->ITestOut = ITestOut;
(*pOut)->vtbl->get_ITest = get_ITest;
+ (*pOut)->vtbl->Return22NoICall = Return22NoICall;
}
static MonoComObject* same_object = NULL;
return 1;
return 0;
}
+
+ public static int test_0_generic_ptr_to_struct () {
+ int size = Marshal.SizeOf (typeof (SimpleStruct2));
+ IntPtr p = Marshal.AllocHGlobal (size);
+
+ Marshal.WriteInt32 (p, 0, 1); //a
+ Marshal.WriteInt32 (p, 4, 2); //a
+
+ var s = Marshal.PtrToStructure<SimpleStruct2> (p);
+
+ if (s.a != 1)
+ return 1;
+ if (s.b != 2)
+ return 2;
+ return 0;
+ }
}
<ClCompile Include="..\mono\mini\mini-native-types.c" />\r
<ClCompile Include="..\mono\mini\type-checking.c" />\r
<ClCompile Include="..\mono\mini\lldb.c" />\r
+ <ClCompile Include="..\mono\mini\interp\interp-stubs.c" />\r
</ItemGroup>\r
<PropertyGroup Label="Globals">\r
<ProjectGuid>{CB0D9E92-293C-439C-9AC7-C5F59B6E0772}</ProjectGuid>\r
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />\r
<ImportGroup Label="ExtensionTargets">\r
</ImportGroup>\r
-</Project>
\ No newline at end of file
+</Project>\r
<ClCompile Include="..\mono\mini\lldb.c">\r
<Filter>Source Files</Filter>\r
</ClCompile>\r
+ <ClCompile Include="..\mono\mini\interp\interp-stubs.c">\r
+ <Filter>Source Files</Filter>\r
+ </ClCompile>\r
</ItemGroup>\r
<ItemGroup>\r
<ClInclude Include="..\mono\mini\abcremoval.h">\r
<Filter>Resource Files</Filter>\r
</None>\r
</ItemGroup>\r
-</Project>
\ No newline at end of file
+</Project>\r
<ClCompile Include="..\mono\metadata\mono-debug.c" />\r
<ClCompile Include="..\mono\metadata\mono-endian.c" />\r
<ClCompile Include="..\mono\metadata\mono-hash.c" />\r
+ <ClCompile Include="..\mono\metadata\mono-conc-hash.c" />\r
<ClCompile Include="..\mono\metadata\mono-mlist.c" />\r
<ClCompile Include="..\mono\metadata\mono-perfcounters.c" />\r
<ClCompile Include="..\mono\metadata\nacl-stub.c" />\r
<ClInclude Include="..\mono\metadata\mono-debug.h" />\r
<ClInclude Include="..\mono\metadata\mono-endian.h" />\r
<ClInclude Include="..\mono\metadata\mono-hash.h" />\r
+ <ClInclude Include="..\mono\metadata\mono-conc-hash.h" />\r
<ClInclude Include="..\mono\metadata\mono-mlist.h" />\r
<ClInclude Include="..\mono\metadata\mono-perfcounters-def.h" />\r
<ClInclude Include="..\mono\metadata\mono-perfcounters.h" />\r
<ClCompile Include="..\mono\metadata\mono-hash.c">\r
<Filter>Source Files\gc</Filter>\r
</ClCompile>\r
+ <ClCompile Include="..\mono\metadata\mono-conc-hash.c">\r
+ <Filter>Source Files\gc</Filter>\r
+ </ClCompile>\r
<ClCompile Include="..\mono\metadata\object.c">\r
<Filter>Source Files\gc</Filter>\r
</ClCompile>\r
<ClInclude Include="..\mono\metadata\mono-hash.h">\r
<Filter>Header Files</Filter>\r
</ClInclude>\r
+ <ClInclude Include="..\mono\metadata\mono-conc-hash.h">\r
+ <Filter>Header Files</Filter>\r
+ </ClInclude>\r
<ClInclude Include="..\mono\metadata\mono-mlist.h">\r
<Filter>Header Files</Filter>\r
</ClInclude>\r
"LocalMachine")
ensure_dir(registry_dir)
- # Add ImportBefore/ImportAfter files from xbuild to the msbuild
- # directories
+ # Add ImportBefore files from xbuild 14.0 toolsVersion directory to msbuild's
+ # 15.0 directory
xbuild_dir = os.path.join(self.staged_prefix, 'lib/mono/xbuild')
- new_xbuild_tv_dir = os.path.join(xbuild_dir, self.version)
+ new_xbuild_tv_dir = os.path.join(xbuild_dir, '15.0')
os.makedirs(new_xbuild_tv_dir)
self.sh('cp -R %s/14.0/Imports %s' % (xbuild_dir, new_xbuild_tv_dir))
- self.sh(
- 'cp -R %s/14.0/Microsoft.Common.targets %s' %
- (xbuild_dir, new_xbuild_tv_dir))
+
+ for dep in glob.glob("%s/Microsoft/NuGet/*" % xbuild_dir):
+ self.sh('ln -s %s %s' % (dep, xbuild_dir))
def deploy(self):
if bockbuild.cmd_options.arch == 'darwin-universal':
Package.__init__(self, 'xamarin-gtk-theme',
sources=[
'git://github.com/mono/xamarin-gtk-theme.git'],
- revision='cc3fb66e56d494e968be3a529a0737a60e31c1f3')
+ revision='b7fe407d869dfeac4eacbcb82771f600e0bbaa83')
def build(self):
try: