summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/.nuget/Microsoft.NETCore.Jit/runtime.Windows_NT.Microsoft.NETCore.Jit.props1
-rw-r--r--src/.nuget/Microsoft.NETCore.Runtime.CoreCLR/runtime.Linux.Microsoft.NETCore.Runtime.CoreCLR.props11
-rw-r--r--src/.nuget/Microsoft.NETCore.Runtime.CoreCLR/runtime.OSX.Microsoft.NETCore.Runtime.CoreCLR.props3
-rw-r--r--src/.nuget/Microsoft.NETCore.Runtime.CoreCLR/runtime.Windows_NT.Microsoft.NETCore.Runtime.CoreCLR.props9
-rw-r--r--src/.nuget/ThirdPartyNotices.txt31
-rw-r--r--src/.nuget/dir.props41
-rw-r--r--src/.nuget/dir.targets18
-rw-r--r--src/.nuget/dotnet_library_license.txt127
-rw-r--r--src/.nuget/init/init.csproj24
-rw-r--r--src/.nuget/init/project.json10
-rw-r--r--src/.nuget/init/readme.txt1
-rw-r--r--src/.nuget/optdata/nuget.config6
-rw-r--r--src/.nuget/optdata/optdata.csproj24
-rw-r--r--src/.nuget/packages.builds4
-rw-r--r--src/CMakeLists.txt5
-rw-r--r--src/ToolBox/SOS/NETCore/SOS.NETCore.csproj27
-rw-r--r--src/ToolBox/SOS/NETCore/project.json15
-rw-r--r--src/ToolBox/SOS/Strike/sosdocsunix.txt1
-rw-r--r--src/ToolBox/SOS/Strike/strike.cpp8
-rw-r--r--src/ToolBox/SOS/lldbplugin/CMakeLists.txt31
-rw-r--r--src/binder/assemblybinder.cpp36
-rw-r--r--src/build.proj8
-rw-r--r--src/classlibnative/bcltype/arraynative.cpp24
-rw-r--r--src/corefx/System.Globalization.Native/icushim.h2
-rw-r--r--src/createVersionFile.proj13
-rw-r--r--src/debug/createdump/CMakeLists.txt11
-rw-r--r--src/debug/createdump/crashinfo.cpp244
-rw-r--r--src/debug/createdump/crashinfo.h4
-rw-r--r--src/debug/createdump/createdump.cpp8
-rw-r--r--src/debug/createdump/datatarget.cpp1
-rw-r--r--src/debug/createdump/dumpwriter.cpp2
-rw-r--r--src/debug/createdump/main.cpp5
-rw-r--r--src/debug/createdump/memoryregion.h39
-rw-r--r--src/debug/createdump/threadinfo.cpp2
-rw-r--r--src/debug/daccess/daccess.cpp2
-rw-r--r--src/debug/daccess/dacimpl.h1
-rw-r--r--src/debug/daccess/enummem.cpp8
-rw-r--r--src/debug/di/cordb.cpp11
-rw-r--r--src/debug/shared/amd64/primitives.cpp2
-rw-r--r--src/dlls/mscordac/mscordac_unixexports.src1
-rw-r--r--src/dlls/mscoree/CMakeLists.txt5
-rw-r--r--src/dlls/mscoree/coreclr/CMakeLists.txt6
-rw-r--r--src/dlls/mscoree/gdbjit_unixexports.src3
-rw-r--r--src/dlls/mscorpe/iceefilegen.cpp4
-rw-r--r--src/gc/handletablecore.cpp26
-rw-r--r--src/gc/objecthandle.cpp3
-rw-r--r--src/ilasm/asmman.cpp11
-rw-r--r--src/ilasm/asmman.hpp2
-rw-r--r--src/ilasm/assembler.cpp16
-rw-r--r--src/ilasm/prebuilt/asmparse.cpp35
-rw-r--r--src/inc/CrstTypes.def2
-rw-r--r--src/inc/clrconfigvalues.h14
-rw-r--r--src/inc/corcompile.h9
-rw-r--r--src/inc/corprof.idl18
-rw-r--r--src/inc/crsttypes.h3
-rw-r--r--src/inc/daccess.h6
-rw-r--r--src/inc/eventtracebase.h21
-rw-r--r--src/inc/profilepriv.inl15
-rw-r--r--src/inc/switches.h3
-rw-r--r--src/inc/winrt/paraminstanceapi.h7
-rw-r--r--src/jit/assertionprop.cpp2
-rw-r--r--src/jit/bitset.h11
-rw-r--r--src/jit/bitsetasshortlong.h32
-rw-r--r--src/jit/bitsetasuint64.h5
-rw-r--r--src/jit/bitsetasuint64inclass.h17
-rw-r--r--src/jit/bitsetops.h1
-rw-r--r--src/jit/codegenarm.cpp1313
-rw-r--r--src/jit/codegenarm64.cpp1773
-rw-r--r--src/jit/codegenarmarch.cpp834
-rw-r--r--src/jit/codegencommon.cpp26
-rw-r--r--src/jit/codegenlinear.cpp8
-rw-r--r--src/jit/codegenlinear.h63
-rw-r--r--src/jit/codegenxarch.cpp7
-rw-r--r--src/jit/compiler.h7
-rw-r--r--src/jit/copyprop.cpp2
-rw-r--r--src/jit/decomposelongs.cpp8
-rw-r--r--src/jit/ee_il_dll.cpp2
-rw-r--r--src/jit/emit.cpp6
-rw-r--r--src/jit/emit.h43
-rw-r--r--src/jit/emitarm64.cpp303
-rw-r--r--src/jit/emitarm64.h9
-rw-r--r--src/jit/emitxarch.cpp6
-rw-r--r--src/jit/flowgraph.cpp55
-rw-r--r--src/jit/gentree.cpp11
-rw-r--r--src/jit/gentree.h15
-rw-r--r--src/jit/importer.cpp67
-rw-r--r--src/jit/instrsarm64.h18
-rw-r--r--src/jit/lclvars.cpp5
-rw-r--r--src/jit/liveness.cpp3
-rw-r--r--src/jit/lower.cpp10
-rw-r--r--src/jit/lower.h16
-rw-r--r--src/jit/lowerarmarch.cpp7
-rw-r--r--src/jit/lsra.cpp255
-rw-r--r--src/jit/lsra.h6
-rw-r--r--src/jit/lsraarm.cpp2
-rw-r--r--src/jit/lsraarmarch.cpp22
-rw-r--r--src/jit/morph.cpp77
-rw-r--r--src/jit/nodeinfo.h4
-rw-r--r--src/jit/optimizer.cpp82
-rw-r--r--src/jit/regalloc.cpp4
-rw-r--r--src/jit/target.h15
-rw-r--r--src/md/ceefilegen/cceegen.cpp30
-rw-r--r--src/md/enc/mdinternalrw.cpp2
-rw-r--r--src/mscorlib/Resources/Strings.resx9
-rw-r--r--src/mscorlib/System.Private.CoreLib.csproj50
-rw-r--r--src/mscorlib/Tools/Signing/mscorlib.snkbin160 -> 0 bytes
-rw-r--r--src/mscorlib/shared/Interop/Unix/System.Globalization.Native/Interop.Collation.cs (renamed from src/mscorlib/src/Interop/Unix/System.Globalization.Native/Interop.Collation.cs)3
-rw-r--r--src/mscorlib/shared/Interop/Windows/Interop.Libraries.cs1
-rw-r--r--src/mscorlib/shared/Interop/Windows/Kernel32/Interop.Globalization.cs (renamed from src/mscorlib/src/Interop/Windows/kernel32/Interop.Globalization.cs)16
-rw-r--r--src/mscorlib/shared/Interop/Windows/Kernel32/Interop.SetThreadErrorMode.cs (renamed from src/mscorlib/shared/Interop/Windows/Kernel32/Interop.SetErrorMode.cs)4
-rw-r--r--src/mscorlib/shared/Interop/Windows/NtDll/Interop.ZeroMemory.cs16
-rw-r--r--src/mscorlib/shared/Microsoft/Win32/SafeHandles/SafeFileHandle.Unix.cs60
-rw-r--r--src/mscorlib/shared/Microsoft/Win32/SafeHandles/SafeHandleMinusOneIsInvalid.cs19
-rw-r--r--src/mscorlib/shared/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs19
-rw-r--r--src/mscorlib/shared/System.Private.CoreLib.Shared.projitems41
-rw-r--r--src/mscorlib/shared/System/ApplicationException.cs6
-rw-r--r--src/mscorlib/shared/System/ArgumentException.cs4
-rw-r--r--src/mscorlib/shared/System/ArgumentNullException.cs6
-rw-r--r--src/mscorlib/shared/System/ArgumentOutOfRangeException.cs (renamed from src/mscorlib/src/System/ArgumentOutOfRangeException.cs)61
-rw-r--r--src/mscorlib/shared/System/ArithmeticException.cs6
-rw-r--r--src/mscorlib/shared/System/ArrayTypeMismatchException.cs6
-rw-r--r--src/mscorlib/shared/System/AsyncCallback.cs1
-rw-r--r--src/mscorlib/shared/System/AttributeTargets.cs1
-rw-r--r--src/mscorlib/shared/System/AttributeUsageAttribute.cs1
-rw-r--r--src/mscorlib/shared/System/BadImageFormatException.cs (renamed from src/mscorlib/src/System/BadImageFormatException.cs)88
-rw-r--r--src/mscorlib/shared/System/CLSCompliantAttribute.cs1
-rw-r--r--src/mscorlib/shared/System/Char.cs2
-rw-r--r--src/mscorlib/shared/System/CharEnumerator.cs1
-rw-r--r--src/mscorlib/shared/System/Collections/Generic/KeyNotFoundException.cs6
-rw-r--r--src/mscorlib/shared/System/CurrentSystemTimeZone.cs1
-rw-r--r--src/mscorlib/shared/System/DBNull.cs10
-rw-r--r--src/mscorlib/shared/System/DataMisalignedException.cs3
-rw-r--r--src/mscorlib/shared/System/DateTimeKind.cs1
-rw-r--r--src/mscorlib/shared/System/DayOfWeek.cs1
-rw-r--r--src/mscorlib/shared/System/DefaultBinder.cs2
-rw-r--r--src/mscorlib/shared/System/Diagnostics/ConditionalAttribute.cs1
-rw-r--r--src/mscorlib/shared/System/Diagnostics/Debug.Unix.cs (renamed from src/mscorlib/src/System/Diagnostics/Debug.Unix.cs)0
-rw-r--r--src/mscorlib/shared/System/Diagnostics/Tracing/EventProvider.cs135
-rwxr-xr-x[-rw-r--r--]src/mscorlib/shared/System/Diagnostics/Tracing/EventSource.cs172
-rw-r--r--src/mscorlib/shared/System/Diagnostics/Tracing/EventSourceException.cs4
-rw-r--r--src/mscorlib/shared/System/Diagnostics/Tracing/IEventProvider.cs42
-rw-r--r--src/mscorlib/shared/System/DivideByZeroException.cs6
-rw-r--r--src/mscorlib/shared/System/DllNotFoundException.cs (renamed from src/mscorlib/src/System/DllNotFoundException.cs)5
-rw-r--r--src/mscorlib/shared/System/DuplicateWaitObjectException.cs9
-rw-r--r--src/mscorlib/shared/System/EntryPointNotFoundException.cs6
-rw-r--r--src/mscorlib/shared/System/EventArgs.cs1
-rw-r--r--src/mscorlib/shared/System/EventHandler.cs2
-rw-r--r--src/mscorlib/shared/System/ExecutionEngineException.cs3
-rw-r--r--src/mscorlib/shared/System/FieldAccessException.cs6
-rw-r--r--src/mscorlib/shared/System/FlagsAttribute.cs1
-rw-r--r--src/mscorlib/shared/System/FormatException.cs6
-rw-r--r--src/mscorlib/shared/System/Globalization/CalendarData.Unix.cs (renamed from src/mscorlib/src/System/Globalization/CalendarData.Unix.cs)27
-rw-r--r--src/mscorlib/shared/System/Globalization/CalendarWeekRule.cs1
-rw-r--r--src/mscorlib/shared/System/Globalization/ChineseLunisolarCalendar.cs1
-rw-r--r--src/mscorlib/shared/System/Globalization/CultureData.Unix.cs (renamed from src/mscorlib/src/System/Globalization/CultureData.Unix.cs)0
-rw-r--r--src/mscorlib/shared/System/Globalization/CultureNotFoundException.cs6
-rw-r--r--src/mscorlib/shared/System/Globalization/DateTimeFormatInfo.cs1
-rw-r--r--src/mscorlib/shared/System/Globalization/DaylightTime.cs1
-rw-r--r--src/mscorlib/shared/System/Globalization/EastAsianLunisolarCalendar.cs1
-rw-r--r--src/mscorlib/shared/System/Globalization/GregorianCalendarTypes.cs1
-rw-r--r--src/mscorlib/shared/System/Globalization/HebrewCalendar.cs1
-rw-r--r--src/mscorlib/shared/System/Globalization/HijriCalendar.Unix.cs (renamed from src/mscorlib/src/System/Globalization/HijriCalendar.Unix.cs)0
-rw-r--r--src/mscorlib/shared/System/Globalization/HijriCalendar.Win32.cs (renamed from src/mscorlib/src/System/Globalization/HijriCalendar.Win32.cs)0
-rw-r--r--src/mscorlib/shared/System/Globalization/HijriCalendar.WinRT.cs (renamed from src/mscorlib/src/System/Globalization/HijriCalendar.WinRT.cs)0
-rw-r--r--src/mscorlib/shared/System/Globalization/HijriCalendar.cs1
-rw-r--r--src/mscorlib/shared/System/Globalization/IdnMapping.Unix.cs (renamed from src/mscorlib/src/System/Globalization/IdnMapping.Unix.cs)4
-rw-r--r--src/mscorlib/shared/System/Globalization/JapaneseCalendar.Unix.cs (renamed from src/mscorlib/src/System/Globalization/JapaneseCalendar.Unix.cs)0
-rw-r--r--src/mscorlib/shared/System/Globalization/JapaneseCalendar.Win32.cs (renamed from src/mscorlib/src/System/Globalization/JapaneseCalendar.Win32.cs)0
-rw-r--r--src/mscorlib/shared/System/Globalization/JapaneseCalendar.WinRT.cs (renamed from src/mscorlib/src/System/Globalization/JapaneseCalendar.WinRT.cs)0
-rw-r--r--src/mscorlib/shared/System/Globalization/JapaneseCalendar.cs1
-rw-r--r--src/mscorlib/shared/System/Globalization/JapaneseLunisolarCalendar.cs1
-rw-r--r--src/mscorlib/shared/System/Globalization/JulianCalendar.cs1
-rw-r--r--src/mscorlib/shared/System/Globalization/KoreanCalendar.cs1
-rw-r--r--src/mscorlib/shared/System/Globalization/KoreanLunisolarCalendar.cs1
-rw-r--r--src/mscorlib/shared/System/Globalization/NumberFormatInfo.cs (renamed from src/mscorlib/src/System/Globalization/NumberFormatInfo.cs)25
-rw-r--r--src/mscorlib/shared/System/Globalization/PersianCalendar.cs1
-rw-r--r--src/mscorlib/shared/System/Globalization/SortKey.cs (renamed from src/mscorlib/src/System/Globalization/SortKey.cs)35
-rw-r--r--src/mscorlib/shared/System/Globalization/SortVersion.cs20
-rw-r--r--src/mscorlib/shared/System/Globalization/StringInfo.cs (renamed from src/mscorlib/src/System/Globalization/StringInfo.cs)11
-rw-r--r--src/mscorlib/shared/System/Globalization/TaiwanCalendar.cs1
-rw-r--r--src/mscorlib/shared/System/Globalization/TaiwanLunisolarCalendar.cs1
-rw-r--r--src/mscorlib/shared/System/Globalization/ThaiBuddhistCalendar.cs1
-rw-r--r--src/mscorlib/shared/System/Globalization/UmAlQuraCalendar.cs1
-rw-r--r--src/mscorlib/shared/System/IO/DirectoryNotFoundException.cs2
-rw-r--r--src/mscorlib/shared/System/IO/EncodingCache.cs (renamed from src/mscorlib/src/System/IO/EncodingCache.cs)0
-rw-r--r--src/mscorlib/shared/System/IO/EndOfStreamException.cs2
-rw-r--r--src/mscorlib/shared/System/IO/FileAccess.cs1
-rw-r--r--src/mscorlib/shared/System/IO/FileLoadException.cs11
-rw-r--r--src/mscorlib/shared/System/IO/FileNotFoundException.cs11
-rw-r--r--src/mscorlib/shared/System/IO/FileStream.Win32.cs13
-rw-r--r--src/mscorlib/shared/System/IO/FileStream.WinRT.cs20
-rw-r--r--src/mscorlib/shared/System/IO/FileStream.Windows.cs8
-rw-r--r--src/mscorlib/shared/System/IO/Path.Unix.cs9
-rw-r--r--src/mscorlib/shared/System/IO/Path.Windows.cs6
-rw-r--r--src/mscorlib/shared/System/IO/Path.cs24
-rw-r--r--src/mscorlib/shared/System/IO/PathInternal.Unix.cs5
-rw-r--r--src/mscorlib/shared/System/IO/PathInternal.Windows.cs5
-rw-r--r--src/mscorlib/shared/System/IO/PathTooLongException.cs2
-rw-r--r--src/mscorlib/shared/System/IO/PinnedBufferMemoryStream.cs (renamed from src/mscorlib/src/System/IO/PinnedBufferMemoryStream.cs)18
-rw-r--r--src/mscorlib/shared/System/IO/UnmanagedMemoryStream.cs (renamed from src/mscorlib/src/System/IO/UnmanagedMemoryStream.cs)254
-rw-r--r--src/mscorlib/shared/System/IO/UnmanagedMemoryStreamWrapper.cs (renamed from src/mscorlib/src/System/IO/UnmanagedMemoryStreamWrapper.cs)16
-rw-r--r--src/mscorlib/shared/System/IndexOutOfRangeException.cs3
-rw-r--r--src/mscorlib/shared/System/InsufficientExecutionStackException.cs3
-rw-r--r--src/mscorlib/shared/System/InvalidCastException.cs6
-rw-r--r--src/mscorlib/shared/System/InvalidOperationException.cs6
-rw-r--r--src/mscorlib/shared/System/InvalidProgramException.cs3
-rw-r--r--src/mscorlib/shared/System/InvalidTimeZoneException.cs6
-rw-r--r--src/mscorlib/shared/System/Lazy.cs15
-rw-r--r--src/mscorlib/shared/System/MarshalByRefObject.cs1
-rw-r--r--src/mscorlib/shared/System/MemberAccessException.cs6
-rw-r--r--src/mscorlib/shared/System/MethodAccessException.cs6
-rw-r--r--src/mscorlib/shared/System/MissingMethodException.cs2
-rw-r--r--src/mscorlib/shared/System/MulticastNotSupportedException.cs3
-rw-r--r--src/mscorlib/shared/System/NotFiniteNumberException.cs4
-rw-r--r--src/mscorlib/shared/System/NotImplementedException.cs6
-rw-r--r--src/mscorlib/shared/System/NotSupportedException.cs6
-rw-r--r--src/mscorlib/shared/System/NullReferenceException.cs6
-rw-r--r--src/mscorlib/shared/System/ObjectDisposedException.cs4
-rw-r--r--src/mscorlib/shared/System/ObsoleteAttribute.cs1
-rw-r--r--src/mscorlib/shared/System/OperationCanceledException.cs (renamed from src/mscorlib/src/System/OperationCanceledException.cs)2
-rw-r--r--src/mscorlib/shared/System/OverflowException.cs6
-rw-r--r--src/mscorlib/shared/System/PlatformNotSupportedException.cs6
-rw-r--r--src/mscorlib/shared/System/Random.cs1
-rw-r--r--src/mscorlib/shared/System/RankException.cs6
-rw-r--r--src/mscorlib/shared/System/Reflection/AmbiguousMatchException.cs6
-rw-r--r--src/mscorlib/shared/System/Reflection/Assembly.cs5
-rw-r--r--src/mscorlib/shared/System/Reflection/AssemblyNameFormatter.cs156
-rw-r--r--src/mscorlib/shared/System/Reflection/CustomAttributeFormatException.cs2
-rw-r--r--src/mscorlib/shared/System/Reflection/DefaultMemberAttribute.cs1
-rw-r--r--src/mscorlib/shared/System/Reflection/InvalidFilterCriteriaException.cs2
-rw-r--r--src/mscorlib/shared/System/Reflection/MemberInfoSerializationHolder.cs315
-rw-r--r--src/mscorlib/shared/System/Reflection/Missing.cs6
-rw-r--r--src/mscorlib/shared/System/Reflection/Module.cs5
-rw-r--r--src/mscorlib/shared/System/Reflection/ParameterInfo.cs41
-rw-r--r--src/mscorlib/shared/System/Reflection/ParameterModifier.cs1
-rw-r--r--src/mscorlib/shared/System/Reflection/Pointer.cs12
-rw-r--r--src/mscorlib/shared/System/Reflection/ReflectionTypeLoadException.cs10
-rw-r--r--src/mscorlib/shared/System/Reflection/StrongNameKeyPair.cs16
-rw-r--r--src/mscorlib/shared/System/Reflection/TargetException.cs2
-rw-r--r--src/mscorlib/shared/System/Reflection/TargetInvocationException.cs6
-rw-r--r--src/mscorlib/shared/System/Reflection/TargetParameterCountException.cs6
-rw-r--r--src/mscorlib/shared/System/Reflection/TypeDelegator.cs2
-rw-r--r--src/mscorlib/shared/System/Resources/MissingManifestResourceException.cs2
-rw-r--r--src/mscorlib/shared/System/Resources/MissingSatelliteAssemblyException.cs2
-rw-r--r--src/mscorlib/shared/System/Resources/ResourceFallbackManager.cs (renamed from src/mscorlib/src/System/Resources/ResourceFallbackManager.cs)9
-rw-r--r--src/mscorlib/shared/System/Resources/RuntimeResourceSet.cs (renamed from src/mscorlib/src/System/Resources/RuntimeResourceSet.cs)60
-rw-r--r--src/mscorlib/shared/System/Runtime/CompilerServices/AsyncStateMachineAttribute.cs1
-rw-r--r--src/mscorlib/shared/System/Runtime/CompilerServices/CompilationRelaxations.cs1
-rw-r--r--src/mscorlib/shared/System/Runtime/CompilerServices/CompilationRelaxationsAttribute.cs1
-rw-r--r--src/mscorlib/shared/System/Runtime/CompilerServices/CompilerGeneratedAttribute.cs1
-rw-r--r--src/mscorlib/shared/System/Runtime/CompilerServices/CompilerGlobalScopeAttribute.cs1
-rw-r--r--src/mscorlib/shared/System/Runtime/CompilerServices/DefaultDependencyAttribute.cs1
-rw-r--r--src/mscorlib/shared/System/Runtime/CompilerServices/DependencyAttribute.cs1
-rw-r--r--src/mscorlib/shared/System/Runtime/CompilerServices/FixedAddressValueTypeAttribute.cs1
-rw-r--r--src/mscorlib/shared/System/Runtime/CompilerServices/IndexerNameAttribute.cs1
-rw-r--r--src/mscorlib/shared/System/Runtime/CompilerServices/IsByRefLikeAttribute.cs21
-rw-r--r--src/mscorlib/shared/System/Runtime/CompilerServices/IteratorStateMachineAttribute.cs1
-rw-r--r--src/mscorlib/shared/System/Runtime/CompilerServices/LoadHint.cs1
-rw-r--r--src/mscorlib/shared/System/Runtime/CompilerServices/MethodCodeType.cs1
-rw-r--r--src/mscorlib/shared/System/Runtime/CompilerServices/ReferenceAssemblyAttribute.cs1
-rw-r--r--src/mscorlib/shared/System/Runtime/CompilerServices/RuntimeCompatibilityAttribute.cs1
-rw-r--r--src/mscorlib/shared/System/Runtime/CompilerServices/StateMachineAttribute.cs1
-rw-r--r--src/mscorlib/shared/System/Runtime/CompilerServices/StringFreezingAttribute.cs1
-rw-r--r--src/mscorlib/shared/System/Runtime/CompilerServices/UnsafeValueTypeAttribute.cs1
-rw-r--r--src/mscorlib/shared/System/Runtime/ConstrainedExecution/Cer.cs1
-rw-r--r--src/mscorlib/shared/System/Runtime/ConstrainedExecution/Consistency.cs1
-rw-r--r--src/mscorlib/shared/System/Runtime/InteropServices/ExternalException.cs2
-rw-r--r--src/mscorlib/shared/System/Runtime/Serialization/SerializationException.cs2
-rw-r--r--src/mscorlib/shared/System/Runtime/Serialization/StreamingContext.cs1
-rw-r--r--src/mscorlib/shared/System/Security/CryptographicException.cs2
-rw-r--r--src/mscorlib/shared/System/Security/SafeBSTRHandle.cs5
-rw-r--r--src/mscorlib/shared/System/Security/SecureString.Unix.cs46
-rw-r--r--src/mscorlib/shared/System/Security/SecureString.Windows.cs13
-rw-r--r--src/mscorlib/shared/System/Security/SecurityException.cs2
-rw-r--r--src/mscorlib/shared/System/Security/VerificationException.cs2
-rw-r--r--src/mscorlib/shared/System/StackOverflowException.cs3
-rw-r--r--src/mscorlib/shared/System/StringComparison.cs1
-rw-r--r--src/mscorlib/shared/System/SystemException.cs6
-rw-r--r--src/mscorlib/shared/System/Text/ASCIIEncoding.cs2
-rw-r--r--src/mscorlib/shared/System/Text/Decoder.cs1
-rw-r--r--src/mscorlib/shared/System/Text/Encoder.cs1
-rw-r--r--src/mscorlib/shared/System/Text/EncodingInfo.cs1
-rw-r--r--src/mscorlib/shared/System/Text/EncodingNLS.cs1
-rw-r--r--src/mscorlib/shared/System/Text/UTF32Encoding.cs2
-rw-r--r--src/mscorlib/shared/System/Text/UTF8Encoding.cs79
-rw-r--r--src/mscorlib/shared/System/Text/UnicodeEncoding.cs41
-rw-r--r--src/mscorlib/shared/System/ThreadStaticAttribute.cs1
-rw-r--r--src/mscorlib/shared/System/Threading/AbandonedMutexException.cs2
-rw-r--r--src/mscorlib/shared/System/Threading/ExecutionContext.cs11
-rw-r--r--src/mscorlib/shared/System/Threading/LockRecursionException.cs6
-rw-r--r--src/mscorlib/shared/System/Threading/SemaphoreFullException.cs2
-rw-r--r--src/mscorlib/shared/System/Threading/SynchronizationLockException.cs2
-rw-r--r--src/mscorlib/shared/System/Threading/Tasks/TaskCanceledException.cs2
-rw-r--r--src/mscorlib/shared/System/Threading/Tasks/TaskSchedulerException.cs2
-rw-r--r--src/mscorlib/shared/System/Threading/ThreadAbortException.cs6
-rw-r--r--src/mscorlib/shared/System/Threading/ThreadStartException.cs6
-rw-r--r--src/mscorlib/shared/System/Threading/ThreadStateException.cs2
-rw-r--r--src/mscorlib/shared/System/Threading/WaitHandleCannotBeOpenedException.cs2
-rw-r--r--src/mscorlib/shared/System/TimeZone.cs1
-rw-r--r--src/mscorlib/shared/System/TimeZoneNotFoundException.cs6
-rw-r--r--src/mscorlib/shared/System/TimeoutException.cs6
-rw-r--r--src/mscorlib/shared/System/Type.cs1
-rw-r--r--src/mscorlib/shared/System/TypeAccessException.cs6
-rw-r--r--src/mscorlib/shared/System/TypeCode.cs1
-rw-r--r--src/mscorlib/shared/System/TypeInitializationException.cs8
-rw-r--r--src/mscorlib/shared/System/TypeUnloadedException.cs7
-rw-r--r--src/mscorlib/shared/System/UnauthorizedAccessException.cs6
-rw-r--r--src/mscorlib/shared/System/UnhandledExceptionEventArgs.cs1
-rw-r--r--src/mscorlib/shared/System/UnhandledExceptionEventHandler.cs1
-rw-r--r--src/mscorlib/shared/System/UnitySerializationHolder.cs329
-rw-r--r--src/mscorlib/shared/System/Void.cs1
-rw-r--r--src/mscorlib/src/Microsoft/Win32/SafeHandles/Win32SafeHandles.cs60
-rw-r--r--src/mscorlib/src/Microsoft/Win32/Win32Native.cs24
-rw-r--r--src/mscorlib/src/System/AccessViolationException.cs6
-rw-r--r--src/mscorlib/src/System/Activator.cs258
-rw-r--r--src/mscorlib/src/System/AppDomain.cs178
-rw-r--r--src/mscorlib/src/System/AppDomainAttributes.cs1
-rw-r--r--src/mscorlib/src/System/AppDomainSetup.cs14
-rw-r--r--src/mscorlib/src/System/AppDomainUnloadedException.cs2
-rw-r--r--src/mscorlib/src/System/Array.cs3
-rw-r--r--src/mscorlib/src/System/ArraySegment.cs1
-rw-r--r--src/mscorlib/src/System/BCLDebug.cs2
-rw-r--r--src/mscorlib/src/System/BadImageFormatException.CoreCLR.cs19
-rw-r--r--src/mscorlib/src/System/Boolean.cs6
-rw-r--r--src/mscorlib/src/System/Byte.cs2
-rw-r--r--src/mscorlib/src/System/Collections/ArrayList.cs626
-rw-r--r--src/mscorlib/src/System/Collections/Comparer.cs27
-rw-r--r--src/mscorlib/src/System/Collections/CompatibleComparer.cs1
-rw-r--r--src/mscorlib/src/System/Collections/Concurrent/ConcurrentQueue.cs1
-rw-r--r--src/mscorlib/src/System/Collections/EmptyReadOnlyDictionaryInternal.cs1
-rw-r--r--src/mscorlib/src/System/Collections/Generic/ArraySortHelper.cs1
-rw-r--r--src/mscorlib/src/System/Collections/Generic/Comparer.cs3
-rw-r--r--src/mscorlib/src/System/Collections/Generic/Dictionary.cs44
-rw-r--r--src/mscorlib/src/System/Collections/Generic/EqualityComparer.cs34
-rw-r--r--src/mscorlib/src/System/Collections/Generic/List.cs1
-rw-r--r--src/mscorlib/src/System/Collections/Hashtable.cs72
-rw-r--r--src/mscorlib/src/System/Collections/ObjectModel/ReadOnlyDictionary.cs4
-rw-r--r--src/mscorlib/src/System/Currency.cs1
-rw-r--r--src/mscorlib/src/System/Delegate.cs4
-rw-r--r--src/mscorlib/src/System/DelegateSerializationHolder.cs287
-rw-r--r--src/mscorlib/src/System/Diagnostics/AssertFilter.cs1
-rw-r--r--src/mscorlib/src/System/Diagnostics/AssertFilters.cs1
-rw-r--r--src/mscorlib/src/System/Diagnostics/Contracts/ContractsBCL.cs13
-rw-r--r--src/mscorlib/src/System/Diagnostics/Debugger.cs114
-rw-r--r--src/mscorlib/src/System/Diagnostics/DebuggerAttributes.cs3
-rw-r--r--src/mscorlib/src/System/Diagnostics/EditAndContinueHelper.cs1
-rw-r--r--src/mscorlib/src/System/Diagnostics/Eventing/EventPipe.cs175
-rw-r--r--src/mscorlib/src/System/Diagnostics/Eventing/EventPipeEventProvider.cs116
-rw-r--r--src/mscorlib/src/System/Diagnostics/Eventing/EventSource_CoreCLR.cs20
-rw-r--r--src/mscorlib/src/System/Diagnostics/LogSwitch.cs1
-rw-r--r--src/mscorlib/src/System/Diagnostics/LoggingLevels.cs1
-rw-r--r--src/mscorlib/src/System/Diagnostics/Stackframe.cs1
-rw-r--r--src/mscorlib/src/System/Diagnostics/Stacktrace.cs2
-rw-r--r--src/mscorlib/src/System/Diagnostics/SymbolStore/SymAddressKind.cs1
-rw-r--r--src/mscorlib/src/System/Diagnostics/log.cs2
-rw-r--r--src/mscorlib/src/System/Double.cs2
-rw-r--r--src/mscorlib/src/System/Empty.cs9
-rw-r--r--src/mscorlib/src/System/Environment.cs3
-rw-r--r--src/mscorlib/src/System/Exception.cs102
-rw-r--r--src/mscorlib/src/System/GC.cs3
-rw-r--r--src/mscorlib/src/System/Globalization/BidiCategory.cs1
-rw-r--r--src/mscorlib/src/System/Globalization/Calendar.cs1
-rw-r--r--src/mscorlib/src/System/Globalization/CalendarData.Windows.cs49
-rw-r--r--src/mscorlib/src/System/Globalization/CompareInfo.Windows.cs4
-rw-r--r--src/mscorlib/src/System/Globalization/CompareInfo.cs34
-rw-r--r--src/mscorlib/src/System/Globalization/CultureData.Windows.cs98
-rw-r--r--src/mscorlib/src/System/Globalization/CultureInfo.cs1
-rw-r--r--src/mscorlib/src/System/Globalization/EncodingDataItem.Unix.cs1
-rw-r--r--src/mscorlib/src/System/Globalization/EncodingDataItem.cs2
-rw-r--r--src/mscorlib/src/System/Globalization/GregorianCalendar.cs3
-rw-r--r--src/mscorlib/src/System/Globalization/GregorianCalendarHelper.cs2
-rw-r--r--src/mscorlib/src/System/Globalization/RegionInfo.cs1
-rw-r--r--src/mscorlib/src/System/Globalization/TextElementEnumerator.cs1
-rw-r--r--src/mscorlib/src/System/Globalization/TextInfo.cs32
-rw-r--r--src/mscorlib/src/System/IO/BinaryWriter.cs1
-rw-r--r--src/mscorlib/src/System/IO/DriveNotFoundException.cs2
-rw-r--r--src/mscorlib/src/System/IO/File.cs27
-rw-r--r--src/mscorlib/src/System/IO/FileLoadException.CoreCLR.cs5
-rw-r--r--src/mscorlib/src/System/IO/FileSystemEnumerable.cs19
-rw-r--r--src/mscorlib/src/System/IO/IOException.cs2
-rw-r--r--src/mscorlib/src/System/IO/MemoryStream.cs1
-rw-r--r--src/mscorlib/src/System/IO/SearchOption.cs1
-rw-r--r--src/mscorlib/src/System/IO/Stream.cs3
-rw-r--r--src/mscorlib/src/System/IO/StreamReader.cs1
-rw-r--r--src/mscorlib/src/System/IO/TextReader.cs3
-rw-r--r--src/mscorlib/src/System/IO/__Error.cs6
-rw-r--r--src/mscorlib/src/System/InsufficientMemoryException.cs5
-rw-r--r--src/mscorlib/src/System/Int16.cs2
-rw-r--r--src/mscorlib/src/System/Int32.cs2
-rw-r--r--src/mscorlib/src/System/Int64.cs2
-rw-r--r--src/mscorlib/src/System/IntPtr.cs60
-rw-r--r--src/mscorlib/src/System/MissingFieldException.cs3
-rw-r--r--src/mscorlib/src/System/MissingMemberException.cs14
-rw-r--r--src/mscorlib/src/System/MulticastDelegate.cs45
-rw-r--r--src/mscorlib/src/System/Object.cs1
-rw-r--r--src/mscorlib/src/System/OleAutBinder.cs1
-rw-r--r--src/mscorlib/src/System/OperatingSystem.cs154
-rw-r--r--src/mscorlib/src/System/OutOfMemoryException.cs2
-rw-r--r--src/mscorlib/src/System/PlatformID.cs27
-rw-r--r--src/mscorlib/src/System/Reflection/Assembly.CoreCLR.cs80
-rw-r--r--src/mscorlib/src/System/Reflection/AssemblyName.cs67
-rw-r--r--src/mscorlib/src/System/Reflection/CustomAttribute.cs31
-rw-r--r--src/mscorlib/src/System/Reflection/Emit/AssemblyBuilderAccess.cs1
-rw-r--r--src/mscorlib/src/System/Reflection/Emit/EnumBuilder.cs2
-rw-r--r--src/mscorlib/src/System/Reflection/Emit/EventToken.cs1
-rw-r--r--src/mscorlib/src/System/Reflection/Emit/FieldToken.cs1
-rw-r--r--src/mscorlib/src/System/Reflection/Emit/FlowControl.cs1
-rw-r--r--src/mscorlib/src/System/Reflection/Emit/GenericTypeParameterBuilder.cs2
-rw-r--r--src/mscorlib/src/System/Reflection/Emit/ILGenerator.cs1
-rw-r--r--src/mscorlib/src/System/Reflection/Emit/Label.cs1
-rw-r--r--src/mscorlib/src/System/Reflection/Emit/MethodToken.cs1
-rw-r--r--src/mscorlib/src/System/Reflection/Emit/ModuleBuilderData.cs1
-rw-r--r--src/mscorlib/src/System/Reflection/Emit/OpcodeType.cs1
-rw-r--r--src/mscorlib/src/System/Reflection/Emit/OperandType.cs1
-rw-r--r--src/mscorlib/src/System/Reflection/Emit/PEFileKinds.cs1
-rw-r--r--src/mscorlib/src/System/Reflection/Emit/ParameterToken.cs1
-rw-r--r--src/mscorlib/src/System/Reflection/Emit/PropertyToken.cs1
-rw-r--r--src/mscorlib/src/System/Reflection/Emit/StackBehaviour.cs1
-rw-r--r--src/mscorlib/src/System/Reflection/Emit/StringToken.cs1
-rw-r--r--src/mscorlib/src/System/Reflection/Emit/SymbolType.cs4
-rw-r--r--src/mscorlib/src/System/Reflection/Emit/TypeBuilder.cs3
-rw-r--r--src/mscorlib/src/System/Reflection/Emit/TypeBuilderInstantiation.cs1
-rw-r--r--src/mscorlib/src/System/Reflection/Emit/TypeToken.cs1
-rw-r--r--src/mscorlib/src/System/Reflection/MdFieldInfo.cs1
-rw-r--r--src/mscorlib/src/System/Reflection/MdImport.cs7
-rw-r--r--src/mscorlib/src/System/Reflection/MemberSerializationStringGenerator.cs39
-rw-r--r--src/mscorlib/src/System/Reflection/RtFieldInfo.cs1
-rw-r--r--src/mscorlib/src/System/Reflection/RuntimeAssembly.cs31
-rw-r--r--src/mscorlib/src/System/Reflection/RuntimeConstructorInfo.cs6
-rw-r--r--src/mscorlib/src/System/Reflection/RuntimeEventInfo.cs7
-rw-r--r--src/mscorlib/src/System/Reflection/RuntimeFieldInfo.cs7
-rw-r--r--src/mscorlib/src/System/Reflection/RuntimeMethodInfo.cs10
-rw-r--r--src/mscorlib/src/System/Reflection/RuntimeModule.cs8
-rw-r--r--src/mscorlib/src/System/Reflection/RuntimeParameterInfo.cs31
-rw-r--r--src/mscorlib/src/System/Reflection/RuntimePropertyInfo.cs7
-rw-r--r--src/mscorlib/src/System/Resources/ResourceManager.cs1
-rw-r--r--src/mscorlib/src/System/Resources/ResourceSet.cs84
-rw-r--r--src/mscorlib/src/System/RtType.cs22
-rw-r--r--src/mscorlib/src/System/Runtime/CompilerServices/ConditionalWeakTable.cs38
-rw-r--r--src/mscorlib/src/System/Runtime/CompilerServices/CustomConstantAttribute.cs1
-rw-r--r--src/mscorlib/src/System/Runtime/CompilerServices/DateTimeConstantAttribute.cs1
-rw-r--r--src/mscorlib/src/System/Runtime/CompilerServices/DecimalConstantAttribute.cs1
-rw-r--r--src/mscorlib/src/System/Runtime/CompilerServices/MethodImplAttribute.cs1
-rw-r--r--src/mscorlib/src/System/Runtime/CompilerServices/RuntimeWrappedException.cs14
-rw-r--r--src/mscorlib/src/System/Runtime/GcSettings.cs2
-rw-r--r--src/mscorlib/src/System/Runtime/InteropServices/ArrayWithOffset.cs1
-rw-r--r--src/mscorlib/src/System/Runtime/InteropServices/Attributes.cs2
-rw-r--r--src/mscorlib/src/System/Runtime/InteropServices/BStrWrapper.cs1
-rw-r--r--src/mscorlib/src/System/Runtime/InteropServices/COMException.cs2
-rw-r--r--src/mscorlib/src/System/Runtime/InteropServices/ComEventsHelper.cs1
-rw-r--r--src/mscorlib/src/System/Runtime/InteropServices/ComMemberType.cs1
-rw-r--r--src/mscorlib/src/System/Runtime/InteropServices/ComTypes/ITypeComp.cs1
-rw-r--r--src/mscorlib/src/System/Runtime/InteropServices/ComTypes/ITypeInfo.cs11
-rw-r--r--src/mscorlib/src/System/Runtime/InteropServices/ComTypes/ITypeLib.cs3
-rw-r--r--src/mscorlib/src/System/Runtime/InteropServices/CurrencyWrapper.cs1
-rw-r--r--src/mscorlib/src/System/Runtime/InteropServices/DispatchWrapper.cs1
-rw-r--r--src/mscorlib/src/System/Runtime/InteropServices/ErrorWrapper.cs1
-rw-r--r--src/mscorlib/src/System/Runtime/InteropServices/GcHandle.cs1
-rw-r--r--src/mscorlib/src/System/Runtime/InteropServices/ICustomQueryInterface.cs1
-rw-r--r--src/mscorlib/src/System/Runtime/InteropServices/InvalidComObjectException.cs2
-rw-r--r--src/mscorlib/src/System/Runtime/InteropServices/InvalidOleVariantTypeException.cs2
-rw-r--r--src/mscorlib/src/System/Runtime/InteropServices/Marshal.cs128
-rw-r--r--src/mscorlib/src/System/Runtime/InteropServices/MarshalDirectiveException.cs2
-rw-r--r--src/mscorlib/src/System/Runtime/InteropServices/NonPortable.cs5
-rw-r--r--src/mscorlib/src/System/Runtime/InteropServices/PInvokeMap.cs1
-rw-r--r--src/mscorlib/src/System/Runtime/InteropServices/PInvokeMarshal.cs24
-rw-r--r--src/mscorlib/src/System/Runtime/InteropServices/SEHException.cs2
-rw-r--r--src/mscorlib/src/System/Runtime/InteropServices/SafeArrayRankMismatchException.cs2
-rw-r--r--src/mscorlib/src/System/Runtime/InteropServices/SafeArrayTypeMismatchException.cs2
-rw-r--r--src/mscorlib/src/System/Runtime/InteropServices/UnknownWrapper.cs1
-rw-r--r--src/mscorlib/src/System/Runtime/InteropServices/VariantWrapper.cs2
-rw-r--r--src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/ConstantSplittableMap.cs2
-rw-r--r--src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/DictionaryKeyCollection.cs2
-rw-r--r--src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/DictionaryValueCollection.cs2
-rw-r--r--src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/IMapViewToIReadOnlyDictionaryAdapter.cs4
-rw-r--r--src/mscorlib/src/System/Runtime/Loader/AssemblyLoadContext.cs8
-rw-r--r--src/mscorlib/src/System/Runtime/Remoting/ObjectHandle.cs40
-rw-r--r--src/mscorlib/src/System/Runtime/RuntimeImports.cs9
-rw-r--r--src/mscorlib/src/System/Runtime/Serialization/FormatterServices.cs1
-rw-r--r--src/mscorlib/src/System/Runtime/Serialization/SerializationInfo.cs1
-rw-r--r--src/mscorlib/src/System/RuntimeHandles.cs98
-rw-r--r--src/mscorlib/src/System/SByte.cs2
-rw-r--r--src/mscorlib/src/System/SharedStatics.cs1
-rw-r--r--src/mscorlib/src/System/Single.cs2
-rw-r--r--src/mscorlib/src/System/StubHelpers.cs31
-rw-r--r--src/mscorlib/src/System/Text/DecoderBestFitFallback.cs1
-rw-r--r--src/mscorlib/src/System/Text/DecoderExceptionFallback.cs3
-rw-r--r--src/mscorlib/src/System/Text/DecoderFallback.cs1
-rw-r--r--src/mscorlib/src/System/Text/DecoderNLS.cs16
-rw-r--r--src/mscorlib/src/System/Text/DecoderReplacementFallback.cs1
-rw-r--r--src/mscorlib/src/System/Text/EncoderBestFitFallback.cs1
-rw-r--r--src/mscorlib/src/System/Text/EncoderExceptionFallback.cs6
-rw-r--r--src/mscorlib/src/System/Text/EncoderFallback.cs1
-rw-r--r--src/mscorlib/src/System/Text/EncoderNLS.cs17
-rw-r--r--src/mscorlib/src/System/Text/EncoderReplacementFallback.cs1
-rw-r--r--src/mscorlib/src/System/Text/Encoding.cs100
-rw-r--r--src/mscorlib/src/System/Text/Latin1Encoding.cs25
-rw-r--r--src/mscorlib/src/System/Text/UTF7Encoding.cs52
-rw-r--r--src/mscorlib/src/System/Threading/ClrThreadPoolBoundHandle.Unix.cs21
-rw-r--r--src/mscorlib/src/System/Threading/ClrThreadPoolBoundHandle.Windows.cs42
-rw-r--r--src/mscorlib/src/System/Threading/ClrThreadPoolBoundHandle.cs23
-rw-r--r--src/mscorlib/src/System/Threading/Monitor.cs1
-rw-r--r--src/mscorlib/src/System/Threading/PinnableBufferCache.cs (renamed from src/mscorlib/Common/PinnableBufferCache.cs)0
-rw-r--r--src/mscorlib/src/System/Threading/Tasks/Task.cs3
-rw-r--r--src/mscorlib/src/System/Threading/Thread.cs1
-rw-r--r--src/mscorlib/src/System/Threading/ThreadInterruptedException.cs2
-rw-r--r--src/mscorlib/src/System/Threading/Timer.cs14
-rw-r--r--src/mscorlib/src/System/Threading/WaitHandle.cs1
-rw-r--r--src/mscorlib/src/System/TypeLoadException.cs21
-rw-r--r--src/mscorlib/src/System/UInt16.cs2
-rw-r--r--src/mscorlib/src/System/UInt32.cs2
-rw-r--r--src/mscorlib/src/System/UInt64.cs2
-rw-r--r--src/mscorlib/src/System/UIntPtr.cs46
-rw-r--r--src/mscorlib/src/System/Variant.cs1
-rw-r--r--src/mscorlib/src/System/__HResults.cs1
-rw-r--r--src/pal/inc/pal.h8
-rw-r--r--src/pal/prebuilt/idl/corprof_i.cpp9
-rw-r--r--src/pal/prebuilt/inc/corprof.h804
-rw-r--r--src/pal/src/CMakeLists.txt4
-rw-r--r--src/pal/src/config.h.in3
-rw-r--r--src/pal/src/configure.cmake20
-rw-r--r--src/pal/src/file/file.cpp6
-rw-r--r--src/pal/src/include/pal/context.h10
-rw-r--r--src/pal/src/include/pal/virtual.h20
-rw-r--r--src/pal/src/map/map.cpp21
-rw-r--r--src/pal/src/map/virtual.cpp229
-rw-r--r--src/pal/src/synchmgr/synchmanager.cpp12
-rw-r--r--src/pal/src/thread/process.cpp4
-rw-r--r--src/pal/src/thread/threadsusp.cpp12
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/MapViewOfFile/test1/MapViewOfFile.cpp26
-rw-r--r--src/pal/tests/palsuite/paltestlist.txt1
-rwxr-xr-xsrc/pal/tools/gen-buildsys-clang.sh2
-rw-r--r--src/scripts/genEventPipe.py495
-rw-r--r--src/scripts/genXplatEventing.py89
-rw-r--r--src/scripts/genXplatLttng.py11
-rw-r--r--src/sign.builds53
-rw-r--r--src/syncAzure.proj1
-rw-r--r--src/tools/crossgen/crossgen.cpp27
-rw-r--r--src/utilcode/util.cpp25
-rw-r--r--src/vm/CMakeLists.txt13
-rw-r--r--src/vm/arm/asmhelpers.S18
-rw-r--r--src/vm/arm/asmhelpers.asm21
-rw-r--r--src/vm/arm/cgencpu.h55
-rw-r--r--src/vm/arm/stubs.cpp7
-rw-r--r--src/vm/arm64/asmhelpers.S33
-rw-r--r--src/vm/arm64/crthelpers.S420
-rw-r--r--src/vm/arm64/stubs.cpp13
-rw-r--r--src/vm/assemblyname.cpp19
-rw-r--r--src/vm/assemblynative.cpp140
-rw-r--r--src/vm/assemblynative.hpp8
-rw-r--r--src/vm/assemblyspec.cpp14
-rw-r--r--src/vm/ceeload.cpp10
-rw-r--r--src/vm/ceemain.cpp18
-rw-r--r--src/vm/class.h11
-rw-r--r--src/vm/clrex.cpp13
-rw-r--r--src/vm/codeman.cpp79
-rw-r--r--src/vm/codeman.h6
-rw-r--r--src/vm/comdependenthandle.cpp30
-rw-r--r--src/vm/comdependenthandle.h12
-rw-r--r--src/vm/compile.cpp24
-rw-r--r--src/vm/coreassemblyspec.cpp28
-rw-r--r--src/vm/corhost.cpp2
-rw-r--r--src/vm/coverage.cpp55
-rw-r--r--src/vm/coverage.h19
-rw-r--r--src/vm/dllimport.cpp14
-rw-r--r--src/vm/dwreport.cpp42
-rw-r--r--src/vm/ecalllist.h26
-rw-r--r--src/vm/eeconfig.cpp31
-rw-r--r--src/vm/eeconfig.h15
-rw-r--r--src/vm/eepolicy.cpp98
-rw-r--r--src/vm/eetoprofinterfaceimpl.cpp93
-rw-r--r--src/vm/eetoprofinterfaceimpl.h9
-rw-r--r--src/vm/eventpipe.cpp448
-rw-r--r--src/vm/eventpipe.h200
-rw-r--r--src/vm/eventpipebuffer.cpp281
-rw-r--r--src/vm/eventpipebuffer.h109
-rw-r--r--src/vm/eventpipebuffermanager.cpp808
-rw-r--r--src/vm/eventpipebuffermanager.h161
-rw-r--r--src/vm/eventpipeconfiguration.cpp594
-rw-r--r--src/vm/eventpipeconfiguration.h164
-rw-r--r--src/vm/eventpipeevent.cpp120
-rw-r--r--src/vm/eventpipeevent.h87
-rw-r--r--src/vm/eventpipeeventinstance.cpp238
-rw-r--r--src/vm/eventpipeeventinstance.h90
-rw-r--r--src/vm/eventpipefile.cpp164
-rw-r--r--src/vm/eventpipefile.h85
-rw-r--r--src/vm/eventpipejsonfile.cpp22
-rw-r--r--src/vm/eventpipejsonfile.h12
-rw-r--r--src/vm/eventpipeprovider.cpp244
-rw-r--r--src/vm/eventpipeprovider.h117
-rw-r--r--src/vm/eventtrace.cpp22
-rw-r--r--src/vm/exceptionhandling.cpp6
-rw-r--r--src/vm/fastserializableobject.h32
-rw-r--r--src/vm/fastserializer.cpp337
-rw-r--r--src/vm/fastserializer.h74
-rw-r--r--src/vm/field.cpp9
-rw-r--r--src/vm/field.h6
-rw-r--r--src/vm/i386/cgenx86.cpp24
-rw-r--r--src/vm/i386/excepcpu.h4
-rw-r--r--src/vm/i386/excepx86.cpp54
-rw-r--r--src/vm/i386/gmsx86.cpp2
-rw-r--r--src/vm/i386/unixstubs.cpp6
-rw-r--r--src/vm/jitinterface.cpp14
-rw-r--r--src/vm/method.cpp221
-rw-r--r--src/vm/method.hpp17
-rw-r--r--src/vm/methodtable.h2
-rw-r--r--src/vm/mscorlib.cpp3
-rw-r--r--src/vm/mscorlib.h6
-rw-r--r--src/vm/pefile.cpp14
-rw-r--r--src/vm/pefile.h6
-rw-r--r--src/vm/peimage.cpp6
-rw-r--r--src/vm/peimagelayout.cpp13
-rw-r--r--src/vm/precode.cpp10
-rw-r--r--src/vm/precode.h5
-rw-r--r--src/vm/prestub.cpp22
-rw-r--r--src/vm/runtimehandles.cpp4
-rw-r--r--src/vm/sampleprofiler.cpp79
-rw-r--r--src/vm/sampleprofiler.h35
-rw-r--r--src/vm/threads.cpp29
-rw-r--r--src/vm/threads.h59
-rw-r--r--src/vm/threadsuspend.cpp5
-rw-r--r--src/vm/tieredcompilation.cpp4
-rw-r--r--src/vm/typedesc.cpp20
-rw-r--r--src/vm/win32threadpool.cpp25
-rw-r--r--src/zap/zapheaders.cpp2
-rw-r--r--src/zap/zapimage.cpp6
-rw-r--r--src/zap/zapinfo.cpp39
627 files changed, 13118 insertions, 8605 deletions
diff --git a/src/.nuget/Microsoft.NETCore.Jit/runtime.Windows_NT.Microsoft.NETCore.Jit.props b/src/.nuget/Microsoft.NETCore.Jit/runtime.Windows_NT.Microsoft.NETCore.Jit.props
index c45358d..f31b152 100644
--- a/src/.nuget/Microsoft.NETCore.Jit/runtime.Windows_NT.Microsoft.NETCore.Jit.props
+++ b/src/.nuget/Microsoft.NETCore.Jit/runtime.Windows_NT.Microsoft.NETCore.Jit.props
@@ -2,7 +2,6 @@
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<NativeBinary Include="$(BinDir)clrjit.dll" />
- <NativeBinary Condition="'$(Platform)' == 'x86' and '$(PackageCompatJit)' != ''" Include="$(BinDir)compatjit.dll" />
<CrossArchitectureSpecificNativeFileAndSymbol Include="$(BinDir)$(CrossTargetComponentFolder)\clrjit.dll" />
<!-- prevent accidental inclusion in AOT projects. -->
diff --git a/src/.nuget/Microsoft.NETCore.Runtime.CoreCLR/runtime.Linux.Microsoft.NETCore.Runtime.CoreCLR.props b/src/.nuget/Microsoft.NETCore.Runtime.CoreCLR/runtime.Linux.Microsoft.NETCore.Runtime.CoreCLR.props
index 4ad2538..5f244a9 100644
--- a/src/.nuget/Microsoft.NETCore.Runtime.CoreCLR/runtime.Linux.Microsoft.NETCore.Runtime.CoreCLR.props
+++ b/src/.nuget/Microsoft.NETCore.Runtime.CoreCLR/runtime.Linux.Microsoft.NETCore.Runtime.CoreCLR.props
@@ -1,9 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
- <_PlatformDoesNotSupportNiFiles Condition="'$(Platform)' == 'arm'">true</_PlatformDoesNotSupportNiFiles>
- <_PlatformDoesNotSupportNiFiles Condition="'$(Platform)' == 'armel'">true</_PlatformDoesNotSupportNiFiles>
- <_PlatformDoesNotSupportNiFiles Condition="'$(Platform)' == 'x86'">true</_PlatformDoesNotSupportNiFiles>
+ <_PlatformDoesNotSupportCreatedump Condition="'$(Platform)' == 'arm'">true</_PlatformDoesNotSupportCreatedump>
+ <_PlatformDoesNotSupportCreatedump Condition="'$(Platform)' == 'armel'">true</_PlatformDoesNotSupportCreatedump>
+ <_PlatformDoesNotSupportCreatedump Condition="'$(Platform)' == 'x86'">true</_PlatformDoesNotSupportCreatedump>
+ <_PlatformDoesNotSupportCreatedump Condition="'$(_runtimeOSFamily)' == 'tizen'">true</_PlatformDoesNotSupportCreatedump>
<_PlatformDoesNotSupportEventTrace Condition="'$(_runtimeOSFamily)' == 'tizen'">true</_PlatformDoesNotSupportEventTrace>
<_PlatformDoesNotSupportEventTrace Condition="'$(Platform)' == 'x86'">true</_PlatformDoesNotSupportEventTrace>
</PropertyGroup>
@@ -17,8 +18,8 @@
<NativeBinary Include="$(BinDir)libsosplugin.so" />
<NativeBinary Include="$(BinDir)System.Globalization.Native.so" />
<NativeBinary Include="$(BinDir)sosdocsunix.txt" />
- <NativeBinary Condition="'$(_PlatformDoesNotSupportNiFiles)' != 'true'" Include="$(BinDir)System.Private.CoreLib.ni.dll" />
- <ArchitectureSpecificLibFile Include="$(BinDir)System.Private.CoreLib.dll" />
+ <NativeBinary Include="$(BinDir)System.Private.CoreLib.dll" />
+ <NativeBinary Condition="'$(_PlatformDoesNotSupportCreatedump)' != 'true'" Include="$(BinDir)createdump" />
<ArchitectureSpecificLibFile Include="$(BinDir)SOS.NETCore.dll" />
<ArchitectureSpecificToolFile Include="$(BinDir)crossgen" />
</ItemGroup>
diff --git a/src/.nuget/Microsoft.NETCore.Runtime.CoreCLR/runtime.OSX.Microsoft.NETCore.Runtime.CoreCLR.props b/src/.nuget/Microsoft.NETCore.Runtime.CoreCLR/runtime.OSX.Microsoft.NETCore.Runtime.CoreCLR.props
index b988a40..ffb1c2d 100644
--- a/src/.nuget/Microsoft.NETCore.Runtime.CoreCLR/runtime.OSX.Microsoft.NETCore.Runtime.CoreCLR.props
+++ b/src/.nuget/Microsoft.NETCore.Runtime.CoreCLR/runtime.OSX.Microsoft.NETCore.Runtime.CoreCLR.props
@@ -8,8 +8,7 @@
<NativeBinary Include="$(BinDir)libsos.dylib" />
<NativeBinary Include="$(BinDir)System.Globalization.Native.dylib" />
<NativeBinary Include="$(BinDir)sosdocsunix.txt" />
- <NativeBinary Include="$(BinDir)System.Private.CoreLib.ni.dll" />
- <ArchitectureSpecificLibFile Include="$(BinDir)System.Private.CoreLib.dll" />
+ <NativeBinary Include="$(BinDir)System.Private.CoreLib.dll" />
<ArchitectureSpecificLibFile Include="$(BinDir)SOS.NETCore.dll" />
<ArchitectureSpecificToolFile Include="$(BinDir)crossgen" />
</ItemGroup>
diff --git a/src/.nuget/Microsoft.NETCore.Runtime.CoreCLR/runtime.Windows_NT.Microsoft.NETCore.Runtime.CoreCLR.props b/src/.nuget/Microsoft.NETCore.Runtime.CoreCLR/runtime.Windows_NT.Microsoft.NETCore.Runtime.CoreCLR.props
index 436901e..57cc46f 100644
--- a/src/.nuget/Microsoft.NETCore.Runtime.CoreCLR/runtime.Windows_NT.Microsoft.NETCore.Runtime.CoreCLR.props
+++ b/src/.nuget/Microsoft.NETCore.Runtime.CoreCLR/runtime.Windows_NT.Microsoft.NETCore.Runtime.CoreCLR.props
@@ -2,8 +2,8 @@
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<PackageTargetRuntime>$(MinOSForArch)-$(PackagePlatform)</PackageTargetRuntime>
- <LongNamePlatform>$(PackagePlatform)</LongNamePlatform>
- <LongNamePlatform Condition="'$(LongNamePlatform)'=='x64'">amd64</LongNamePlatform>
+ <LongNamePlatform>$(Platform)</LongNamePlatform>
+ <LongNamePlatform Condition="'$(Platform)'=='x64'">amd64</LongNamePlatform>
<CrossTargetPlatform>$(CrossTargetComponentFolder)</CrossTargetPlatform>
<CrossTargetPlatform Condition="'$(CrossTargetPlatform)'=='x64'">amd64</CrossTargetPlatform>
<LongNameSuffix>_$(LongNamePlatform)_$(LongNamePlatform)_$(MajorVersion).$(MinorVersion).$(BuildNumberMajor).0$(BuildNumberMinor)</LongNameSuffix>
@@ -19,9 +19,8 @@
<NativeBinary Include="$(BinDir)mscorrc.debug.dll" />
<NativeBinary Include="$(BinDir)mscorrc.dll" />
<NativeBinary Include="$(BinDir)sos.dll" />
- <NativeBinary Include="$(BinDir)System.Private.CoreLib.ni.dll" />
<NativeBinary Include="$(UniversalCRTSDKDir)Redist\ucrt\DLLs\$(BuildArch)\*.dll" Condition="'$(BuildType)'=='Release' AND '$(BuildArch)' != 'arm64'" />
- <ArchitectureSpecificLibFile Include="$(BinDir)System.Private.CoreLib.dll" />
+ <NativeBinary Include="$(BinDir)System.Private.CoreLib.dll" />
<ArchitectureSpecificLibFile Include="$(BinDir)SOS.NETCore.dll" />
<ArchitectureSpecificToolFile Include="$(BinDir)crossgen.exe" />
<CrossArchitectureSpecificToolFile Include="$(BinDir)$(CrossTargetComponentFolder)\crossgen.exe" />
@@ -45,7 +44,7 @@
<LongNameFile Include="$(BinDir)$(CrossTargetComponentFolder)\mscordaccore.dll;
$(BinDir)$(CrossTargetComponentFolder)\sos.dll"
Condition="'$(HasCrossTargetComponents)'=='true'">
- <TargetPath>tools\$(CrossTargetComponentFolder)_$(PackagePlatform)\%(FileName)$(CrossTargetLongNameSuffix)%(Extension)</TargetPath>
+ <TargetPath>tools\$(CrossTargetComponentFolder)_$(Platform)\%(FileName)$(CrossTargetLongNameSuffix)%(Extension)</TargetPath>
</LongNameFile>
</ItemGroup>
</Project>
diff --git a/src/.nuget/ThirdPartyNotices.txt b/src/.nuget/ThirdPartyNotices.txt
deleted file mode 100644
index 55cfb20..0000000
--- a/src/.nuget/ThirdPartyNotices.txt
+++ /dev/null
@@ -1,31 +0,0 @@
-This Microsoft .NET Library may incorporate components from the projects listed
-below. Microsoft licenses these components under the Microsoft .NET Library
-software license terms. The original copyright notices and the licenses under
-which Microsoft received such components are set forth below for informational
-purposes only. Microsoft reserves all rights not expressly granted herein,
-whether by implication, estoppel or otherwise.
-
-1. .NET Core (https://github.com/dotnet/core/)
-
-.NET Core
-Copyright (c) .NET Foundation and Contributors
-
-The MIT License (MIT)
-
-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. \ No newline at end of file
diff --git a/src/.nuget/dir.props b/src/.nuget/dir.props
index 59b94f7..2ff88d9 100644
--- a/src/.nuget/dir.props
+++ b/src/.nuget/dir.props
@@ -26,8 +26,12 @@
<SupportedPackageOSGroups Condition="'$(SupportedPackageOSGroups)' == ''">Windows_NT;OSX;Linux</SupportedPackageOSGroups>
<SupportedPackageOSGroups>;$(SupportedPackageOSGroups);</SupportedPackageOSGroups>
+ <!-- Identify OS family based upon the RuntimeOS, which could be distro specific (e.g. osx.10.12) or
+ portable (e.g. osx).
+ -->
<_runtimeOSVersionIndex>$(RuntimeOS.IndexOfAny(".-0123456789"))</_runtimeOSVersionIndex>
<_runtimeOSFamily Condition="'$(_runtimeOSVersionIndex)' != '-1'">$(RuntimeOS.SubString(0, $(_runtimeOSVersionIndex)))</_runtimeOSFamily>
+ <_runtimeOSFamily Condition="'$(_runtimeOSVersionIndex)' == '-1'">$(RuntimeOS)</_runtimeOSFamily>
<_isSupportedOSGroup>true</_isSupportedOSGroup>
</PropertyGroup>
@@ -66,7 +70,7 @@
<RIDPlatform Condition="'$(ArchGroup)' == 'arm64'">win10</RIDPlatform>
<!-- Set the platform part of the RID if we are doing a portable build -->
- <RIDPlatform Condition="'$(PortableBuild)' == '1'">win</RIDPlatform>
+ <RIDPlatform Condition="'$(PortableBuild)' == 'true'">win</RIDPlatform>
<PackageRID>$(RIDPlatform)-$(ArchGroup)</PackageRID>
</PropertyGroup>
</When>
@@ -74,21 +78,21 @@
<PropertyGroup>
<PackageRID>osx.10.12-$(ArchGroup)</PackageRID>
<!-- Set the platform part of the RID if we are doing a portable build -->
- <PackageRID Condition="'$(PortableBuild)' == '1'">osx-$(ArchGroup)</PackageRID>
+ <PackageRID Condition="'$(PortableBuild)' == 'true'">osx-$(ArchGroup)</PackageRID>
</PropertyGroup>
</When>
<When Condition="'$(_runtimeOSFamily)' == 'rhel'">
<PropertyGroup>
<PackageRID>rhel.7-$(ArchGroup)</PackageRID>
<!-- Set the platform part of the RID if we are doing a portable build -->
- <PackageRID Condition="'$(PortableBuild)' == '1'">linux-$(ArchGroup)</PackageRID>
+ <PackageRID Condition="'$(PortableBuild)' == 'true'">linux-$(ArchGroup)</PackageRID>
</PropertyGroup>
</When>
<Otherwise>
<PropertyGroup>
<PackageRID>$(RuntimeOS)-$(ArchGroup)</PackageRID>
<!-- Set the platform part of the RID if we are doing a portable build -->
- <PackageRID Condition="'$(PortableBuild)' == '1'">linux-$(ArchGroup)</PackageRID>
+ <PackageRID Condition="'$(PortableBuild)' == 'true'">linux-$(ArchGroup)</PackageRID>
</PropertyGroup>
</Otherwise>
</Choose>
@@ -111,51 +115,22 @@
</Choose>
<ItemGroup Condition="$(SupportedPackageOSGroups.Contains(';Linux;'))">
- <OfficialBuildRID Include="alpine.3.4.3-x64" />
- <OfficialBuildRID Include="debian.8-armel">
- <Platform>armel</Platform>
- </OfficialBuildRID>
- <OfficialBuildRID Include="debian.8-x64" />
- <OfficialBuildRID Include="fedora.23-x64" />
- <OfficialBuildRID Include="fedora.24-x64" />
<OfficialBuildRID Include="linux-x64" />
<OfficialBuildRID Include="linux-arm">
<Platform>arm</Platform>
</OfficialBuildRID>
- <OfficialBuildRID Include="opensuse.42.1-x64" />
- <OfficialBuildRID Include="rhel.7-x64" />
<OfficialBuildRID Include="tizen.4.0.0-armel">
<Platform>armel</Platform>
</OfficialBuildRID>
- <OfficialBuildRID Include="ubuntu.14.04-arm">
- <Platform>arm</Platform>
- </OfficialBuildRID>
- <OfficialBuildRID Include="ubuntu.14.04-x64" />
- <OfficialBuildRID Include="ubuntu.16.04-arm">
- <Platform>arm</Platform>
- </OfficialBuildRID>
- <OfficialBuildRID Include="ubuntu.16.04-x64" />
- <OfficialBuildRID Include="ubuntu.16.10-x64" />
</ItemGroup>
<ItemGroup Condition="$(SupportedPackageOSGroups.Contains(';OSX;'))">
- <OfficialBuildRID Include="osx.10.12-x64" />
<OfficialBuildRID Include="osx-x64" />
</ItemGroup>
<ItemGroup Condition="$(SupportedPackageOSGroups.Contains(';Windows_NT;'))">
- <OfficialBuildRID Include="win7-x86">
- <Platform>x86</Platform>
- </OfficialBuildRID>
<OfficialBuildRID Include="win-x86">
<Platform>x86</Platform>
</OfficialBuildRID>
- <OfficialBuildRID Include="win7-x64" />
<OfficialBuildRID Include="win-x64" />
- <OfficialBuildRID Include="win8-arm">
- <Platform>arm</Platform>
- </OfficialBuildRID>
- <OfficialBuildRID Include="win10-arm64">
- <Platform>arm64</Platform>
- </OfficialBuildRID>
<OfficialBuildRID Include="win-arm">
<Platform>arm</Platform>
</OfficialBuildRID>
diff --git a/src/.nuget/dir.targets b/src/.nuget/dir.targets
index 49e550a..447b071 100644
--- a/src/.nuget/dir.targets
+++ b/src/.nuget/dir.targets
@@ -32,10 +32,10 @@
<ItemGroup Condition="'$(HasCrossTargetComponents)'=='true'">
<NativeWithSymbolFile Include="@(CrossArchitectureSpecificNativeFileAndSymbol)">
- <TargetPath>runtimes/$(CrossTargetComponentFolder)_$(PackagePlatform)/native</TargetPath>
+ <TargetPath>runtimes/$(CrossTargetComponentFolder)_$(Platform)/native</TargetPath>
</NativeWithSymbolFile>
<NativeWithSymbolFile Include="@(CrossArchitectureSpecificToolFile)">
- <TargetPath>tools/$(CrossTargetComponentFolder)_$(PackagePlatform)</TargetPath>
+ <TargetPath>tools/$(CrossTargetComponentFolder)_$(Platform)</TargetPath>
</NativeWithSymbolFile>
</ItemGroup>
@@ -84,5 +84,19 @@
</ItemGroup>
</Target>
+ <!-- OverrideLicenseUrl is temporary till we update the buildtools to v2 -->
+ <Target Name="OverrideLicenseUrl" BeforeTargets="GenerateNuSpec">
+ <PropertyGroup>
+ <LicenseUrl>https://github.com/dotnet/coreclr/blob/master/LICENSE.TXT</LicenseUrl>
+ </PropertyGroup>
+ </Target>
+
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory)\.., dir.targets))\dir.targets" />
+ <ItemGroup>
+ <!-- Add version file to packages -->
+ <File Condition="Exists('$(SyncInfoFile)')"
+ Include="$(SyncInfoFile)">
+ <SkipPackageFileCheck>true</SkipPackageFileCheck>
+ </File>
+ </ItemGroup>
</Project>
diff --git a/src/.nuget/dotnet_library_license.txt b/src/.nuget/dotnet_library_license.txt
deleted file mode 100644
index 9953cbb..0000000
--- a/src/.nuget/dotnet_library_license.txt
+++ /dev/null
@@ -1,127 +0,0 @@
-MICROSOFT SOFTWARE LICENSE TERMS
-
-
-MICROSOFT .NET LIBRARY
-
-These license terms are an agreement between Microsoft Corporation (or based on where you live, one of its affiliates) and you. Please read them. They apply to the software named above, which includes the media on which you received it, if any. The terms also apply to any Microsoft
-
-- updates,
-
-- supplements,
-
-- Internet-based services, and
-
-- support services
-
-for this software, unless other terms accompany those items. If so, those terms apply.
-
-BY USING THE SOFTWARE, YOU ACCEPT THESE TERMS. IF YOU DO NOT ACCEPT THEM, DO NOT USE THE SOFTWARE.
-
-
-IF YOU COMPLY WITH THESE LICENSE TERMS, YOU HAVE THE PERPETUAL RIGHTS BELOW.
-
-1. INSTALLATION AND USE RIGHTS.
-
-a. Installation and Use. You may install and use any number of copies of the software to design, develop and test your programs.
-
-b. Third Party Programs. The software may include third party programs that Microsoft, not the third party, licenses to you under this agreement. Notices, if any, for the third party program are included for your information only.
-
-2. ADDITIONAL LICENSING REQUIREMENTS AND/OR USE RIGHTS.
-
-a. DISTRIBUTABLE CODE. The software is comprised of Distributable Code. "Distributable Code" is code that you are permitted to distribute in programs you develop if you comply with the terms below.
-
-i. Right to Use and Distribute.
-
-- You may copy and distribute the object code form of the software.
-
-- Third Party Distribution. You may permit distributors of your programs to copy and distribute the Distributable Code as part of those programs.
-
-ii. Distribution Requirements. For any Distributable Code you distribute, you must
-
-- add significant primary functionality to it in your programs;
-
-- require distributors and external end users to agree to terms that protect it at least as much as this agreement;
-
-- display your valid copyright notice on your programs; and
-
-- indemnify, defend, and hold harmless Microsoft from any claims, including attorneys' fees, related to the distribution or use of your programs.
-
-iii. Distribution Restrictions. You may not
-
-- alter any copyright, trademark or patent notice in the Distributable Code;
-
-- use Microsoft's trademarks in your programs' names or in a way that suggests your programs come from or are endorsed by Microsoft;
-
-- include Distributable Code in malicious, deceptive or unlawful programs; or
-
-- modify or distribute the source code of any Distributable Code so that any part of it becomes subject to an Excluded License. An Excluded License is one that requires, as a condition of use, modification or distribution, that
-
-- the code be disclosed or distributed in source code form; or
-
-- others have the right to modify it.
-
-3. SCOPE OF LICENSE. The software is licensed, not sold. This agreement only gives you some rights to use the software. Microsoft reserves all other rights. Unless applicable law gives you more rights despite this limitation, you may use the software only as expressly permitted in this agreement. In doing so, you must comply with any technical limitations in the software that only allow you to use it in certain ways. You may not
-
-- work around any technical limitations in the software;
-
-- reverse engineer, decompile or disassemble the software, except and only to the extent that applicable law expressly permits, despite this limitation;
-
-- publish the software for others to copy;
-
-- rent, lease or lend the software;
-
-- transfer the software or this agreement to any third party; or
-
-- use the software for commercial software hosting services.
-
-4. BACKUP COPY. You may make one backup copy of the software. You may use it only to reinstall the software.
-
-5. DOCUMENTATION. Any person that has valid access to your computer or internal network may copy and use the documentation for your internal, reference purposes.
-
-6. EXPORT RESTRICTIONS. The software is subject to United States export laws and regulations. You must comply with all domestic and international export laws and regulations that apply to the software. These laws include restrictions on destinations, end users and end use. For additional information, see www.microsoft.com/exporting.
-
-7. SUPPORT SERVICES. Because this software is "as is," we may not provide support services for it.
-
-8. ENTIRE AGREEMENT. This agreement, and the terms for supplements, updates, Internet-based services and support services that you use, are the entire agreement for the software and support services.
-
-9. APPLICABLE LAW.
-
-a. United States. If you acquired the software in the United States, Washington state law governs the interpretation of this agreement and applies to claims for breach of it, regardless of conflict of laws principles. The laws of the state where you live govern all other claims, including claims under state consumer protection laws, unfair competition laws, and in tort.
-
-b. Outside the United States. If you acquired the software in any other country, the laws of that country apply.
-
-10. LEGAL EFFECT. This agreement describes certain legal rights. You may have other rights under the laws of your country. You may also have rights with respect to the party from whom you acquired the software. This agreement does not change your rights under the laws of your country if the laws of your country do not permit it to do so.
-
-11. DISCLAIMER OF WARRANTY. THE SOFTWARE IS LICENSED "AS-IS." YOU BEAR THE RISK OF USING IT. MICROSOFT GIVES NO EXPRESS WARRANTIES, GUARANTEES OR CONDITIONS. YOU MAY HAVE ADDITIONAL CONSUMER RIGHTS OR STATUTORY GUARANTEES UNDER YOUR LOCAL LAWS WHICH THIS AGREEMENT CANNOT CHANGE. TO THE EXTENT PERMITTED UNDER YOUR LOCAL LAWS, MICROSOFT EXCLUDES THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
-
-FOR AUSTRALIA - YOU HAVE STATUTORY GUARANTEES UNDER THE AUSTRALIAN CONSUMER LAW AND NOTHING IN THESE TERMS IS INTENDED TO AFFECT THOSE RIGHTS.
-
-12. LIMITATION ON AND EXCLUSION OF REMEDIES AND DAMAGES. YOU CAN RECOVER FROM MICROSOFT AND ITS SUPPLIERS ONLY DIRECT DAMAGES UP TO U.S. $5.00. YOU CANNOT RECOVER ANY OTHER DAMAGES, INCLUDING CONSEQUENTIAL, LOST PROFITS, SPECIAL, INDIRECT OR INCIDENTAL DAMAGES.
-
-This limitation applies to
-
-- anything related to the software, services, content (including code) on third party Internet sites, or third party programs; and
-
-- claims for breach of contract, breach of warranty, guarantee or condition, strict liability, negligence, or other tort to the extent permitted by applicable law.
-
-It also applies even if Microsoft knew or should have known about the possibility of the damages. The above limitation or exclusion may not apply to you because your country may not allow the exclusion or limitation of incidental, consequential or other damages.
-
-Please note: As this software is distributed in Quebec, Canada, some of the clauses in this agreement are provided below in French.
-
-Remarque : Ce logiciel etant distribue au Quebec, Canada, certaines des clauses dans ce contrat sont fournies ci-dessous en francais.
-
-EXONERATION DE GARANTIE. Le logiciel vise par une licence est offert << tel quel >>. Toute utilisation de ce logiciel est a votre seule risque et peril. Microsoft n'accorde aucune autre garantie expresse. Vous pouvez beneficier de droits additionnels en vertu du droit local sur la protection des consommateurs, que ce contrat ne peut modifier. La ou elles sont permises par le droit locale, les garanties implicites de qualite marchande, d'adequation a un usage particulier et d'absence de contrefacon sont exclues.
-
-LIMITATION DES DOMMAGES-INTERETS ET EXCLUSION DE RESPONSABILITE POUR LES DOMMAGES. Vous pouvez obtenir de Microsoft et de ses fournisseurs une indemnisation en cas de dommages directs uniquement a hauteur de 5,00 $ US. Vous ne pouvez pretendre a aucune indemnisation pour les autres dommages, y compris les dommages speciaux, indirects ou accessoires et pertes de benefices.
-
-Cette limitation concerne :
-
-- tout ce qui est relie au logiciel, aux services ou au contenu (y compris le code) figurant sur des sites Internet tiers ou dans des programmes tiers ; et
-
-- les reclamations au titre de violation de contrat ou de garantie, ou au titre de responsabilite stricte, de negligence ou d'une autre faute dans la limite autorisee par la loi en vigueur.
-
-Elle s'applique egalement, meme si Microsoft connaissait ou devrait connaitre l'eventualite d'un tel dommage. Si votre pays n'autorise pas l'exclusion ou la limitation de responsabilite pour les dommages indirects, accessoires ou de quelque nature que ce soit, il se peut que la limitation ou l'exclusion ci-dessus ne s'appliquera pas a votre egard.
-
-EFFET JURIDIQUE. Le present contrat decrit certains droits juridiques. Vous pourriez avoir d'autres droits prevus par les lois de votre pays. Le present contrat ne modifie pas les droits que vous conferent les lois de votre pays si celles-ci ne le permettent pas.
-
-
diff --git a/src/.nuget/init/init.csproj b/src/.nuget/init/init.csproj
new file mode 100644
index 0000000..115090d
--- /dev/null
+++ b/src/.nuget/init/init.csproj
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <CLRTestKind>BuildOnly</CLRTestKind>
+ </PropertyGroup>
+ <ItemGroup>
+ <PackageReference Include="Microsoft.NETCore.Platforms">
+ <Version>$(RuntimeIdGraphDefinitionVersion)</Version>
+ </PackageReference>
+ </ItemGroup>
+ <PropertyGroup>
+ <TargetFramework>netcoreapp1.0</TargetFramework>
+ <TargetFrameworkIdentifier>.NETCoreApp</TargetFrameworkIdentifier>
+ <PackageTargetFallback>$(PackageTargetFallback);portable-net45+win8</PackageTargetFallback>
+ <ContainsPackageReferences>true</ContainsPackageReferences>
+ <PrereleaseResolveNuGetPackages>false</PrereleaseResolveNuGetPackages>
+ </PropertyGroup>
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+ <Target Name="Build"
+ DependsOnTargets="ResolveReferences" />
+</Project>
diff --git a/src/.nuget/init/project.json b/src/.nuget/init/project.json
deleted file mode 100644
index 5908fcc..0000000
--- a/src/.nuget/init/project.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "dependencies": {
- "Microsoft.NETCore.Platforms": "1.0.2-beta-24224-02"
- },
- "frameworks": {
- "dnxcore50": {
- "imports": "portable-net45+win8"
- }
- },
-} \ No newline at end of file
diff --git a/src/.nuget/init/readme.txt b/src/.nuget/init/readme.txt
deleted file mode 100644
index 6792dd5..0000000
--- a/src/.nuget/init/readme.txt
+++ /dev/null
@@ -1 +0,0 @@
-Please keep the package details listed in project.json in sync with <repo_root>/dir.props. \ No newline at end of file
diff --git a/src/.nuget/optdata/nuget.config b/src/.nuget/optdata/nuget.config
new file mode 100644
index 0000000..e747f7e
--- /dev/null
+++ b/src/.nuget/optdata/nuget.config
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<configuration>
+ <packageSources>
+ <add key="myget.org dotnet-core-optimization-data" value="https://dotnet.myget.org/F/dotnet-core-optimization-data/api/v3/index.json" />
+ </packageSources>
+</configuration>
diff --git a/src/.nuget/optdata/optdata.csproj b/src/.nuget/optdata/optdata.csproj
new file mode 100644
index 0000000..20e2a40
--- /dev/null
+++ b/src/.nuget/optdata/optdata.csproj
@@ -0,0 +1,24 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
+
+ <PropertyGroup>
+ <TargetFramework>netstandard</TargetFramework>
+ <DisableImplicitFrameworkReferences>true</DisableImplicitFrameworkReferences>
+ <RuntimeIdentifiers>win7-x64;win7-x86;linux-x64</RuntimeIdentifiers>
+ </PropertyGroup>
+
+ <ItemGroup>
+ <PackageReference Include="optimization.PGO.CoreCLR" Version="$(PgoDataPackageVersion)" Condition="'$(PgoDataPackageVersion)'!=''" />
+ <PackageReference Include="optimization.IBC.CoreCLR" Version="$(IbcDataPackageVersion)" Condition="'$(IbcDataPackageVersion)'!=''" />
+ </ItemGroup>
+
+ <Target Name="DumpPgoDataPackageVersion">
+ <Message Importance="high" Text="$(PgoDataPackageVersion)" />
+ </Target>
+
+ <Target Name="DumpIbcDataPackageVersion">
+ <Message Importance="high" Text="$(IbcDataPackageVersion)" />
+ </Target>
+
+</Project>
diff --git a/src/.nuget/packages.builds b/src/.nuget/packages.builds
index f57b9a9..0c0f65d 100644
--- a/src/.nuget/packages.builds
+++ b/src/.nuget/packages.builds
@@ -25,5 +25,9 @@
<Project Include="Microsoft.NETCore.ILDAsm\Microsoft.NETCore.ILDAsm.builds" />
</ItemGroup>
+ <Import Project="$(ToolsDir)versioning.targets" />
+ <!-- Make sure we create version.txt file since it will be packaged -->
+ <Target Name="EnsureVersionInfoFileExists" BeforeTargets="Build" DependsOnTargets="CreateVersionInfoFile" />
+
<Import Project="$(MSBuildThisFileDirectory)..\..\dir.traversal.targets" />
</Project>
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 9598d0c..b761b6a 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -149,11 +149,6 @@ add_subdirectory(utilcode)
add_subdirectory(gcinfo)
add_subdirectory(coreclr)
add_subdirectory(jit)
-
-if(IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/jit32")
- add_subdirectory(jit32)
-endif()
-
add_subdirectory(gc)
add_subdirectory(vm)
add_subdirectory(md)
diff --git a/src/ToolBox/SOS/NETCore/SOS.NETCore.csproj b/src/ToolBox/SOS/NETCore/SOS.NETCore.csproj
index 440cff5..c579b59 100644
--- a/src/ToolBox/SOS/NETCore/SOS.NETCore.csproj
+++ b/src/ToolBox/SOS/NETCore/SOS.NETCore.csproj
@@ -11,13 +11,15 @@
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<NoStdLib>true</NoStdLib>
<NoCompilerStandardLib>true</NoCompilerStandardLib>
- <UseOpenKey Condition="'$(UseOpenKey)'==''">true</UseOpenKey>
+ <IsDotNetFrameworkProductAssembly>true</IsDotNetFrameworkProductAssembly>
+ <AssemblyKey>Open</AssemblyKey>
+ <ExcludeMscorlibFacade>true</ExcludeMscorlibFacade>
+ <ContainsPackageReferences>true</ContainsPackageReferences>
<!-- We don't use any of MSBuild's resolution logic for resolving the framework, so just set these two properties to any folder that exists to skip
the GenerateReferenceAssemblyPaths task (not target) and to prevent it from outputting a warning (MSB3644). -->
<_TargetFrameworkDirectories>$(MSBuildThisFileDirectory)/Documentation</_TargetFrameworkDirectories>
<_FullFrameworkReferenceAssemblyPaths>$(MSBuildThisFileDirectory)/Documentation</_FullFrameworkReferenceAssemblyPaths>
-
</PropertyGroup>
<!-- Default configurations to help VS understand the options -->
@@ -39,8 +41,25 @@
<Compile Include="SymbolReader.cs" />
</ItemGroup>
+ <PropertyGroup>
+ <TargetFramework>netcoreapp1.0</TargetFramework>
+ <TargetFrameworkIdentifier>.NETCoreApp</TargetFrameworkIdentifier>
+ <PackageTargetFallback>$(PackageTargetFallback);portable-net45+win8</PackageTargetFallback>
+ </PropertyGroup>
+
<ItemGroup>
- <None Include="project.json" />
+ <PackageReference Include="Microsoft.NETCore.Platforms">
+ <Version>$(RuntimeIdGraphDefinitionVersion)</Version>
+ </PackageReference>
+ <PackageReference Include="System.IO.FileSystem">
+ <Version>4.0.1</Version>
+ </PackageReference>
+ <PackageReference Include="System.Runtime.InteropServices">
+ <Version>4.1.0</Version>
+ </PackageReference>
+ <PackageReference Include="System.Reflection.Metadata">
+ <Version>1.4.1</Version>
+ </PackageReference>
</ItemGroup>
<Target Name="CopyItemsToDirectory" AfterTargets="Build">
@@ -52,7 +71,7 @@
UseHardlinksIfPossible="false">
</Copy>
- <Copy
+ <Copy
SourceFiles="$(OutputPath)$(AssemblyName).pdb"
DestinationFolder="$(BinDir)\PDB"
SkipUnchangedFiles="false"
diff --git a/src/ToolBox/SOS/NETCore/project.json b/src/ToolBox/SOS/NETCore/project.json
deleted file mode 100644
index a92b173..0000000
--- a/src/ToolBox/SOS/NETCore/project.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "dependencies": {
- "Microsoft.NETCore.Platforms": "1.0.1",
- "System.IO.FileSystem": "4.0.1",
- "System.Runtime.InteropServices": "4.1.0",
- "System.Reflection.Metadata": "1.4.1"
- },
- "frameworks": {
- "netcoreapp1.0": {
- "imports": [
- "portable-net45+win8"
- ]
- }
- }
-}
diff --git a/src/ToolBox/SOS/Strike/sosdocsunix.txt b/src/ToolBox/SOS/Strike/sosdocsunix.txt
index 517227c..e9fd59c 100644
--- a/src/ToolBox/SOS/Strike/sosdocsunix.txt
+++ b/src/ToolBox/SOS/Strike/sosdocsunix.txt
@@ -623,6 +623,7 @@ createdump [options] [dumpFileName]
-n - create minidump.
-h - create minidump with heap (default).
-t - create triage minidump.
+-f - create full core dump (everything).
-d - enable diagnostic messages.
Creates a platform (ELF core on Linux, etc.) minidump. The pid can be placed in the dump
diff --git a/src/ToolBox/SOS/Strike/strike.cpp b/src/ToolBox/SOS/Strike/strike.cpp
index 0d5d8c3..1fff17f 100644
--- a/src/ToolBox/SOS/Strike/strike.cpp
+++ b/src/ToolBox/SOS/Strike/strike.cpp
@@ -14385,6 +14385,7 @@ DECLARE_API(CreateDump)
BOOL normal = FALSE;
BOOL withHeap = FALSE;
BOOL triage = FALSE;
+ BOOL full = FALSE;
BOOL diag = FALSE;
size_t nArg = 0;
@@ -14393,6 +14394,7 @@ DECLARE_API(CreateDump)
{"-n", &normal, COBOOL, FALSE},
{"-h", &withHeap, COBOOL, FALSE},
{"-t", &triage, COBOOL, FALSE},
+ {"-f", &full, COBOOL, FALSE},
{"-d", &diag, COBOOL, FALSE},
};
CMDValue arg[] =
@@ -14407,7 +14409,11 @@ DECLARE_API(CreateDump)
ULONG pid = 0;
g_ExtSystem->GetCurrentProcessId(&pid);
- if (withHeap)
+ if (full)
+ {
+ minidumpType = MiniDumpWithFullMemory;
+ }
+ else if (withHeap)
{
minidumpType = MiniDumpWithPrivateReadWriteMemory;
}
diff --git a/src/ToolBox/SOS/lldbplugin/CMakeLists.txt b/src/ToolBox/SOS/lldbplugin/CMakeLists.txt
index f0c2176..fe816ab 100644
--- a/src/ToolBox/SOS/lldbplugin/CMakeLists.txt
+++ b/src/ToolBox/SOS/lldbplugin/CMakeLists.txt
@@ -45,7 +45,6 @@ elseif(CLR_CMAKE_PLATFORM_ARCH_ARM64)
SET(REQUIRE_LLDBPLUGIN false)
endif()
-
set(LLVM_HOST_DIR "$ENV{LLVM_HOME}")
set(WITH_LLDB_LIBS "${LLVM_HOST_DIR}/lib" CACHE PATH "Path to LLDB libraries")
set(WITH_LLDB_INCLUDES "${LLVM_HOST_DIR}/include" CACHE PATH "Path to LLDB headers")
@@ -54,20 +53,22 @@ if(NOT ENABLE_LLDBPLUGIN)
return()
endif()
-# Check for LLDB library
-find_library(LLDB NAMES LLDB lldb lldb-4.0 lldb-3.9 lldb-3.8 lldb-3.7 lldb-3.6 lldb-3.5 PATHS "${WITH_LLDB_LIBS}" PATH_SUFFIXES llvm NO_DEFAULT_PATH)
-find_library(LLDB NAMES LLDB lldb lldb-4.0 lldb-3.8 lldb-3.7 lldb-3.6 lldb-3.5 PATH_SUFFIXES llvm)
-if(LLDB STREQUAL LLDB-NOTFOUND)
- if(REQUIRE_LLDBPLUGIN)
- set(MESSAGE_MODE FATAL_ERROR)
- else()
- set(MESSAGE_MODE WARNING)
+if (CLR_CMAKE_PLATFORM_DARWIN)
+ # Check for LLDB library
+ find_library(LLDB NAMES LLDB lldb lldb-4.0 lldb-3.9 lldb-3.8 lldb-3.7 lldb-3.6 lldb-3.5 PATHS "${WITH_LLDB_LIBS}" PATH_SUFFIXES llvm NO_DEFAULT_PATH)
+ find_library(LLDB NAMES LLDB lldb lldb-4.0 lldb-3.9 lldb-3.8 lldb-3.7 lldb-3.6 lldb-3.5 PATH_SUFFIXES llvm)
+ if(LLDB STREQUAL LLDB-NOTFOUND)
+ if(REQUIRE_LLDBPLUGIN)
+ set(MESSAGE_MODE FATAL_ERROR)
+ else()
+ set(MESSAGE_MODE WARNING)
+ endif()
+ message(${MESSAGE_MODE} "Cannot find lldb-3.5, lldb-3.6, lldb-3.8, lldb-3.9 or lldb-4.0. Try installing lldb-3.6-dev (or the appropriate package for your platform)")
+ return()
endif()
- message(${MESSAGE_MODE} "Cannot find lldb-3.5, lldb-3.6, lldb-3.8, lldb-3.9 or lldb-4.0. Try installing lldb-3.6-dev (or the appropriate package for your platform)")
- return()
-endif()
-message(STATUS "LLDB: ${LLDB}")
+ message(STATUS "LLDB: ${LLDB}")
+endif()
# Check for LLDB headers
# Multiple versions of LLDB can install side-by-side, so we need to check for lldb in various locations.
@@ -120,8 +121,8 @@ endif(UPPERCASE_CMAKE_BUILD_TYPE STREQUAL DEBUG OR UPPERCASE_CMAKE_BUILD_TYPE ST
_add_library(sosplugin SHARED ${SOURCES})
add_dependencies(sosplugin sos)
-if (CLR_CMAKE_PLATFORM_UNIX)
- target_link_libraries(sosplugin ${LLDB})
+if (CLR_CMAKE_PLATFORM_DARWIN)
+ target_link_libraries(sosplugin ${LLDB})
endif()
# add the install targets
diff --git a/src/binder/assemblybinder.cpp b/src/binder/assemblybinder.cpp
index a73f79f..73ea025 100644
--- a/src/binder/assemblybinder.cpp
+++ b/src/binder/assemblybinder.cpp
@@ -685,26 +685,21 @@ namespace BINDER_SPACE
StackSString sCoreLib;
- // At run-time, System.Private.CoreLib.ni.dll is typically always available, and
- // System.Private.CoreLib.dll is typically not. So check for the NI first.
+ // At run-time, System.Private.CoreLib.dll is expected to be the NI image.
sCoreLib = sCoreLibDir;
- sCoreLib.Append(CoreLibName_NI_W);
- if (!fBindToNativeImage || FAILED(AssemblyBinder::GetAssembly(sCoreLib,
- FALSE /* fInspectionOnly */,
- TRUE /* fIsInGAC */,
- TRUE /* fExplicitBindToNativeImage */,
- &pSystemAssembly)))
- {
- // If System.Private.CoreLib.ni.dll is unavailable, look for System.Private.CoreLib.dll instead
- sCoreLib = sCoreLibDir;
- sCoreLib.Append(CoreLibName_IL_W);
- IF_FAIL_GO(AssemblyBinder::GetAssembly(sCoreLib,
+ sCoreLib.Append(CoreLibName_IL_W);
+ BOOL fExplicitBindToNativeImage = (fBindToNativeImage == true)? TRUE:FALSE;
+#ifdef FEATURE_NI_BIND_FALLBACK
+ // Some non-Windows platforms do not automatically generate the NI image as CoreLib.dll.
+ // If those platforms also do not support automatic fallback from NI to IL, bind as IL.
+ fExplicitBindToNativeImage = FALSE;
+#endif // FEATURE_NI_BIND_FALLBACK
+ IF_FAIL_GO(AssemblyBinder::GetAssembly(sCoreLib,
FALSE /* fInspectionOnly */,
TRUE /* fIsInGAC */,
- FALSE /* fExplicitBindToNativeImage */,
+ fExplicitBindToNativeImage,
&pSystemAssembly));
- }
-
+
*ppSystemAssembly = pSystemAssembly.Extract();
Exit:
@@ -1601,8 +1596,13 @@ namespace BINDER_SPACE
IF_FAIL_GO(BinderHasNativeHeader(pNativePEImage, &hasHeader));
if (!hasHeader)
{
- pPEImage = pNativePEImage;
- pNativePEImage = NULL;
+ BinderReleasePEImage(pPEImage);
+ BinderReleasePEImage(pNativePEImage);
+
+ BINDER_LOG_ENTER(W("BinderAcquirePEImageIL"));
+ hr = BinderAcquirePEImage(szAssemblyPath, &pPEImage, &pNativePEImage, false);
+ BINDER_LOG_LEAVE_HR(W("BinderAcquirePEImageIL"), hr);
+ IF_FAIL_GO(hr);
}
}
diff --git a/src/build.proj b/src/build.proj
index 5da94e4..7962d27 100644
--- a/src/build.proj
+++ b/src/build.proj
@@ -17,13 +17,21 @@
</Target>
<ItemGroup>
+ <ILToCopy Include="$(BinDir)System.Private.CoreLib.dll"/>
<PDBSToMove Include="$(BinDir)System.Private.CoreLib.pdb"/>
</ItemGroup>
<PropertyGroup>
+ <CoreLibPath>$(BinDir)System.Private.CoreLib.dll</CoreLibPath>
<CoreLibPDBPath>$(BinDir)System.Private.CoreLib.pdb</CoreLibPDBPath>
</PropertyGroup>
+ <Target Name="CopyCoreLib" AfterTargets="Build">
+ <Copy Condition="Exists($(CoreLibPath))"
+ SourceFiles="@(ILToCopy)"
+ DestinationFolder="$(BinDir)IL" />
+ </Target>
+
<Target Name="MovePDB" AfterTargets="Build">
<Move Condition="Exists($(CoreLibPDBPath))"
SourceFiles="@(PDBSToMove)"
diff --git a/src/classlibnative/bcltype/arraynative.cpp b/src/classlibnative/bcltype/arraynative.cpp
index c54d2f3..232f59d 100644
--- a/src/classlibnative/bcltype/arraynative.cpp
+++ b/src/classlibnative/bcltype/arraynative.cpp
@@ -319,14 +319,16 @@ ArrayNative::AssignArrayEnum ArrayNative::CanAssignArrayTypeNoGC(const BASEARRAY
return AssignDontKnow;
}
- const CorElementType srcElType = srcTH.GetSignatureCorElementType();
- const CorElementType destElType = destTH.GetSignatureCorElementType();
+ const CorElementType srcElType = srcTH.GetVerifierCorElementType();
+ const CorElementType destElType = destTH.GetVerifierCorElementType();
_ASSERTE(srcElType < ELEMENT_TYPE_MAX);
_ASSERTE(destElType < ELEMENT_TYPE_MAX);
// Copying primitives from one type to another
if (CorTypeInfo::IsPrimitiveType_NoThrow(srcElType) && CorTypeInfo::IsPrimitiveType_NoThrow(destElType))
{
+ if (srcElType == destElType)
+ return AssignWillWork;
if (InvokeUtil::CanPrimitiveWiden(destElType, srcElType))
return AssignPrimitiveWiden;
else
@@ -349,10 +351,6 @@ ArrayNative::AssignArrayEnum ArrayNative::CanAssignArrayTypeNoGC(const BASEARRAY
if (srcTH.IsInterface() && destElType != ELEMENT_TYPE_VALUETYPE)
return AssignMustCast;
- // Enum is stored as a primitive of type dest.
- if (srcTH.IsEnum() && srcTH.GetInternalCorElementType() == destElType)
- return AssignWillWork;
-
return AssignDontKnow;
}
@@ -405,14 +403,16 @@ ArrayNative::AssignArrayEnum ArrayNative::CanAssignArrayType(const BASEARRAYREF
return AssignWrongType;
}
- const CorElementType srcElType = srcTH.GetSignatureCorElementType();
- const CorElementType destElType = destTH.GetSignatureCorElementType();
+ const CorElementType srcElType = srcTH.GetVerifierCorElementType();
+ const CorElementType destElType = destTH.GetVerifierCorElementType();
_ASSERTE(srcElType < ELEMENT_TYPE_MAX);
_ASSERTE(destElType < ELEMENT_TYPE_MAX);
// Copying primitives from one type to another
if (CorTypeInfo::IsPrimitiveType_NoThrow(srcElType) && CorTypeInfo::IsPrimitiveType_NoThrow(destElType))
{
+ if (srcElType == destElType)
+ return AssignWillWork;
if (InvokeUtil::CanPrimitiveWiden(destElType, srcElType))
return AssignPrimitiveWiden;
else
@@ -435,10 +435,6 @@ ArrayNative::AssignArrayEnum ArrayNative::CanAssignArrayType(const BASEARRAYREF
if (srcTH.IsInterface() && destElType != ELEMENT_TYPE_VALUETYPE)
return AssignMustCast;
- // Enum is stored as a primitive of type dest.
- if (srcTH.IsEnum() && srcTH.GetInternalCorElementType() == destElType)
- return AssignWillWork;
-
return AssignWrongType;
}
@@ -631,8 +627,8 @@ void ArrayNative::PrimitiveWiden(BASEARRAYREF pSrc, unsigned int srcIndex, BASEA
TypeHandle srcTH = pSrc->GetArrayElementTypeHandle();
TypeHandle destTH = pDest->GetArrayElementTypeHandle();
- const CorElementType srcElType = srcTH.GetSignatureCorElementType();
- const CorElementType destElType = destTH.GetSignatureCorElementType();
+ const CorElementType srcElType = srcTH.GetVerifierCorElementType();
+ const CorElementType destElType = destTH.GetVerifierCorElementType();
const unsigned int srcSize = GetSizeForCorElementType(srcElType);
const unsigned int destSize = GetSizeForCorElementType(destElType);
diff --git a/src/corefx/System.Globalization.Native/icushim.h b/src/corefx/System.Globalization.Native/icushim.h
index 408ec15..313002e 100644
--- a/src/corefx/System.Globalization.Native/icushim.h
+++ b/src/corefx/System.Globalization.Native/icushim.h
@@ -32,6 +32,8 @@
#include <unicode/usearch.h>
#include <unicode/utf16.h>
#include <unicode/utypes.h>
+#include <unicode/urename.h>
+#include <unicode/ustring.h>
// List of all functions from the ICU libraries that are used in the System.Globalization.Native.so
#define FOR_ALL_UNCONDITIONAL_ICU_FUNCTIONS \
diff --git a/src/createVersionFile.proj b/src/createVersionFile.proj
new file mode 100644
index 0000000..4edddc7
--- /dev/null
+++ b/src/createVersionFile.proj
@@ -0,0 +1,13 @@
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+
+ <Import Project="..\dir.props" />
+ <Import Project="$(ToolsDir)versioning.targets" Condition="Exists('$(ToolsDir)versioning.targets')"/>
+
+ <PropertyGroup>
+ <VersionPropsImported>false</VersionPropsImported>
+ </PropertyGroup>
+
+ <Target Name="Build"
+ DependsOnTargets="CreateOrUpdateCurrentVersionFile">
+ </Target>
+</Project> \ No newline at end of file
diff --git a/src/debug/createdump/CMakeLists.txt b/src/debug/createdump/CMakeLists.txt
index 5b5ec0a..4272cfc 100644
--- a/src/debug/createdump/CMakeLists.txt
+++ b/src/debug/createdump/CMakeLists.txt
@@ -2,6 +2,17 @@ project(createdump)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
+# Set the RPATH of createdump so that it can find dependencies without needing to set LD_LIBRARY_PATH
+# For more information: http://www.cmake.org/Wiki/CMake_RPATH_handling.
+if (CORECLR_SET_RPATH)
+ set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
+ if(CLR_CMAKE_PLATFORM_DARWIN)
+ set(CMAKE_INSTALL_RPATH "@loader_path")
+ else()
+ set(CMAKE_INSTALL_RPATH "\$ORIGIN")
+ endif(CLR_CMAKE_PLATFORM_DARWIN)
+endif (CORECLR_SET_RPATH)
+
remove_definitions(-DUNICODE)
remove_definitions(-D_UNICODE)
diff --git a/src/debug/createdump/crashinfo.cpp b/src/debug/createdump/crashinfo.cpp
index cae8857..b825f4d 100644
--- a/src/debug/createdump/crashinfo.cpp
+++ b/src/debug/createdump/crashinfo.cpp
@@ -155,33 +155,68 @@ CrashInfo::GatherCrashInfo(const char* programPath, MINIDUMP_TYPE minidumpType)
{
return false;
}
- // Get shared module debug info
- if (!GetDSOInfo())
- {
- return false;
- }
// Gather all the module memory mappings (from /dev/$pid/maps)
if (!EnumerateModuleMappings())
{
return false;
}
- // Gather all the useful memory regions from the DAC
- if (!EnumerateMemoryRegionsWithDAC(programPath, minidumpType))
+ // Get shared module debug info
+ if (!GetDSOInfo())
{
return false;
}
- // Add the thread's stack and some code memory to core
- for (ThreadInfo* thread : m_threads)
+ // If full memory dump, include everything regardless of permissions
+ if (minidumpType & MiniDumpWithFullMemory)
+ {
+ for (const MemoryRegion& region : m_moduleMappings)
+ {
+ if (ValidRegion(region))
+ {
+ InsertMemoryRegion(region);
+ }
+ }
+ for (const MemoryRegion& region : m_otherMappings)
+ {
+ if (ValidRegion(region))
+ {
+ InsertMemoryRegion(region);
+ }
+ }
+ }
+ else
{
- uint64_t start;
- size_t size;
+ // Add all the heap (read/write) memory regions but not the modules' r/w data segments
+ if (minidumpType & MiniDumpWithPrivateReadWriteMemory)
+ {
+ for (const MemoryRegion& region : m_otherMappings)
+ {
+ if (region.Permissions() == (PF_R | PF_W))
+ {
+ if (ValidRegion(region))
+ {
+ InsertMemoryRegion(region);
+ }
+ }
+ }
+ }
+ // Gather all the useful memory regions from the DAC
+ if (!EnumerateMemoryRegionsWithDAC(programPath, minidumpType))
+ {
+ return false;
+ }
+ // Add the thread's stack and some code memory to core
+ for (ThreadInfo* thread : m_threads)
+ {
+ uint64_t start;
+ size_t size;
- // Add the thread's stack and some of the code
- thread->GetThreadStack(*this, &start, &size);
- InsertMemoryRegion(start, size);
+ // Add the thread's stack and some of the code
+ thread->GetThreadStack(*this, &start, &size);
+ InsertMemoryRegion(start, size);
- thread->GetThreadCode(&start, &size);
- InsertMemoryRegion(start, size);
+ thread->GetThreadCode(&start, &size);
+ InsertMemoryRegion(start, size);
+ }
}
// Join all adjacent memory regions
CombineMemoryRegions();
@@ -240,7 +275,7 @@ CrashInfo::EnumerateModuleMappings()
// Here we read /proc/<pid>/maps file in order to parse it and figure out what it says
// about a library we are looking for. This file looks something like this:
//
- // [address] [perms] [offset] [dev] [inode] [pathname] - HEADER is not preset in an actual file
+ // [address] [perms] [offset] [dev] [inode] [pathname] - HEADER is not preset in an actual file
//
// 35b1800000-35b1820000 r-xp 00000000 08:02 135522 /usr/lib64/ld-2.15.so
// 35b1a1f000-35b1a20000 r--p 0001f000 08:02 135522 /usr/lib64/ld-2.15.so
@@ -282,8 +317,8 @@ CrashInfo::EnumerateModuleMappings()
char* permissions = nullptr;
char* moduleName = nullptr;
- int c = 0;
- if ((c = sscanf(line, "%lx-%lx %m[-rwxsp] %lx %*[:0-9a-f] %*d %ms\n", &start, &end, &permissions, &offset, &moduleName)) == 5)
+ int c = sscanf(line, "%lx-%lx %m[-rwxsp] %lx %*[:0-9a-f] %*d %ms\n", &start, &end, &permissions, &offset, &moduleName);
+ if (c == 4 || c == 5)
{
if (linuxGateAddress != nullptr && reinterpret_cast<void*>(start) == linuxGateAddress)
{
@@ -335,60 +370,6 @@ CrashInfo::EnumerateModuleMappings()
}
bool
-CrashInfo::EnumerateMemoryRegionsWithDAC(const char* programPath, MINIDUMP_TYPE minidumpType)
-{
- PFN_CLRDataCreateInstance pfnCLRDataCreateInstance = nullptr;
- ICLRDataEnumMemoryRegions *clrDataEnumRegions = nullptr;
- HMODULE hdac = nullptr;
- HRESULT hr = S_OK;
- bool result = false;
-
- // We assume that the DAC is in the same location as this createdump exe
- std::string dacPath;
- dacPath.append(programPath);
- dacPath.append("/");
- dacPath.append(MAKEDLLNAME_A("mscordaccore"));
-
- // Load and initialize the DAC
- hdac = LoadLibraryA(dacPath.c_str());
- if (hdac == nullptr)
- {
- fprintf(stderr, "LoadLibraryA(%s) FAILED %d\n", dacPath.c_str(), GetLastError());
- goto exit;
- }
- pfnCLRDataCreateInstance = (PFN_CLRDataCreateInstance)GetProcAddress(hdac, "CLRDataCreateInstance");
- if (pfnCLRDataCreateInstance == nullptr)
- {
- fprintf(stderr, "GetProcAddress(CLRDataCreateInstance) FAILED %d\n", GetLastError());
- goto exit;
- }
- hr = pfnCLRDataCreateInstance(__uuidof(ICLRDataEnumMemoryRegions), m_dataTarget, (void**)&clrDataEnumRegions);
- if (FAILED(hr))
- {
- fprintf(stderr, "CLRDataCreateInstance(ICLRDataEnumMemoryRegions) FAILED %08x\n", hr);
- goto exit;
- }
- // Calls CrashInfo::EnumMemoryRegion for each memory region found by the DAC
- hr = clrDataEnumRegions->EnumMemoryRegions(this, minidumpType, CLRDATA_ENUM_MEM_DEFAULT);
- if (FAILED(hr))
- {
- fprintf(stderr, "EnumMemoryRegions FAILED %08x\n", hr);
- goto exit;
- }
- result = true;
-exit:
- if (clrDataEnumRegions != nullptr)
- {
- clrDataEnumRegions->Release();
- }
- if (hdac != nullptr)
- {
- FreeLibrary(hdac);
- }
- return result;
-}
-
-bool
CrashInfo::GetDSOInfo()
{
Phdr* phdrAddr = reinterpret_cast<Phdr*>(m_auxvValues[AT_PHDR]);
@@ -453,24 +434,87 @@ CrashInfo::GetDSOInfo()
}
// Add the DSO link_map entries
+ ArrayHolder<char> moduleName = new char[PATH_MAX];
for (struct link_map* linkMapAddr = debugEntry.r_map; linkMapAddr != nullptr;) {
struct link_map map;
if (!ReadMemory(linkMapAddr, &map, sizeof(map))) {
return false;
}
- char moduleName[257] = { 0 };
+ int i = 0;
if (map.l_name != nullptr) {
- if (!ReadMemory(map.l_name, &moduleName, sizeof(moduleName) - 1)) {
- return false;
+ for (; i < PATH_MAX; i++)
+ {
+ if (!ReadMemory(map.l_name + i, &moduleName[i], 1)) {
+ TRACE("DSO: ReadMemory link_map name %p + %d FAILED\n", map.l_name, i);
+ break;
+ }
+ if (moduleName[i] == '\0') {
+ break;
+ }
}
}
- TRACE("DSO: link_map entry %p l_ld %p l_addr %lx %s\n", linkMapAddr, map.l_ld, map.l_addr, moduleName);
+ moduleName[i] = '\0';
+ TRACE("DSO: link_map entry %p l_ld %p l_addr %lx %s\n", linkMapAddr, map.l_ld, map.l_addr, (char*)moduleName);
linkMapAddr = map.l_next;
}
return true;
}
+bool
+CrashInfo::EnumerateMemoryRegionsWithDAC(const char* programPath, MINIDUMP_TYPE minidumpType)
+{
+ PFN_CLRDataCreateInstance pfnCLRDataCreateInstance = nullptr;
+ ICLRDataEnumMemoryRegions *clrDataEnumRegions = nullptr;
+ HMODULE hdac = nullptr;
+ HRESULT hr = S_OK;
+ bool result = false;
+
+ // We assume that the DAC is in the same location as this createdump exe
+ std::string dacPath;
+ dacPath.append(programPath);
+ dacPath.append("/");
+ dacPath.append(MAKEDLLNAME_A("mscordaccore"));
+
+ // Load and initialize the DAC
+ hdac = LoadLibraryA(dacPath.c_str());
+ if (hdac == nullptr)
+ {
+ fprintf(stderr, "LoadLibraryA(%s) FAILED %d\n", dacPath.c_str(), GetLastError());
+ goto exit;
+ }
+ pfnCLRDataCreateInstance = (PFN_CLRDataCreateInstance)GetProcAddress(hdac, "CLRDataCreateInstance");
+ if (pfnCLRDataCreateInstance == nullptr)
+ {
+ fprintf(stderr, "GetProcAddress(CLRDataCreateInstance) FAILED %d\n", GetLastError());
+ goto exit;
+ }
+ hr = pfnCLRDataCreateInstance(__uuidof(ICLRDataEnumMemoryRegions), m_dataTarget, (void**)&clrDataEnumRegions);
+ if (FAILED(hr))
+ {
+ fprintf(stderr, "CLRDataCreateInstance(ICLRDataEnumMemoryRegions) FAILED %08x\n", hr);
+ goto exit;
+ }
+ // Calls CrashInfo::EnumMemoryRegion for each memory region found by the DAC
+ hr = clrDataEnumRegions->EnumMemoryRegions(this, minidumpType, CLRDATA_ENUM_MEM_DEFAULT);
+ if (FAILED(hr))
+ {
+ fprintf(stderr, "EnumMemoryRegions FAILED %08x\n", hr);
+ goto exit;
+ }
+ result = true;
+exit:
+ if (clrDataEnumRegions != nullptr)
+ {
+ clrDataEnumRegions->Release();
+ }
+ if (hdac != nullptr)
+ {
+ FreeLibrary(hdac);
+ }
+ return result;
+}
+
//
// ReadMemory from target and add to memory regions list
//
@@ -480,6 +524,7 @@ CrashInfo::ReadMemory(void* address, void* buffer, size_t size)
uint32_t read = 0;
if (FAILED(m_dataTarget->ReadVirtual(reinterpret_cast<CLRDATA_ADDRESS>(address), reinterpret_cast<PBYTE>(buffer), size, &read)))
{
+ fprintf(stderr, "ReadMemory(%p, %lx) FAILED\n", address, size);
return false;
}
InsertMemoryRegion(reinterpret_cast<uint64_t>(address), size);
@@ -501,38 +546,67 @@ CrashInfo::InsertMemoryRegion(uint64_t address, size_t size)
uint64_t end = ((address + size) + (PAGE_SIZE - 1)) & PAGE_MASK;
assert(end > 0);
- MemoryRegion memoryRegionFull(start, end);
+ MemoryRegion region(start, end);
+ InsertMemoryRegion(region);
+}
+//
+// Add a memory region to the list
+//
+void
+CrashInfo::InsertMemoryRegion(const MemoryRegion& region)
+{
// First check if the full memory region can be added without conflicts
- const auto& found = m_memoryRegions.find(memoryRegionFull);
+ const auto& found = m_memoryRegions.find(region);
if (found == m_memoryRegions.end())
{
// Add full memory region
- m_memoryRegions.insert(memoryRegionFull);
+ m_memoryRegions.insert(region);
}
else
{
// The memory region is not wholely contained in region found
- if (!found->Contains(memoryRegionFull))
+ if (!found->Contains(region))
{
+ uint64_t start = region.StartAddress();
+
// The region overlaps/conflicts with one already in the set so
// add one page at a time to avoid the overlapping pages.
- uint64_t numberPages = (end - start) >> PAGE_SHIFT;
+ uint64_t numberPages = region.Size() >> PAGE_SHIFT;
for (int p = 0; p < numberPages; p++, start += PAGE_SIZE)
{
- MemoryRegion memoryRegion(start, start + PAGE_SIZE);
+ MemoryRegion memoryRegionPage(start, start + PAGE_SIZE);
- const auto& found = m_memoryRegions.find(memoryRegion);
+ const auto& found = m_memoryRegions.find(memoryRegionPage);
if (found == m_memoryRegions.end())
{
- m_memoryRegions.insert(memoryRegion);
+ m_memoryRegions.insert(memoryRegionPage);
}
}
}
}
}
+bool
+CrashInfo::ValidRegion(const MemoryRegion& region)
+{
+ uint64_t start = region.StartAddress();
+ uint64_t numberPages = region.Size() >> PAGE_SHIFT;
+
+ for (int p = 0; p < numberPages; p++, start += PAGE_SIZE)
+ {
+ BYTE buffer[1];
+ uint32_t read;
+
+ if (FAILED(m_dataTarget->ReadVirtual(start, buffer, 1, &read)))
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
//
// Combine any adjacent memory regions into one
//
diff --git a/src/debug/createdump/crashinfo.h b/src/debug/createdump/crashinfo.h
index 40d7f5d..914a88e 100644
--- a/src/debug/createdump/crashinfo.h
+++ b/src/debug/createdump/crashinfo.h
@@ -65,9 +65,11 @@ public:
private:
bool GetAuxvEntries();
bool EnumerateModuleMappings();
- bool EnumerateMemoryRegionsWithDAC(const char* programPath, MINIDUMP_TYPE minidumpType);
bool GetDSOInfo();
+ bool EnumerateMemoryRegionsWithDAC(const char* programPath, MINIDUMP_TYPE minidumpType);
bool ReadMemory(void* address, void* buffer, size_t size);
void InsertMemoryRegion(uint64_t address, size_t size);
+ void InsertMemoryRegion(const MemoryRegion& region);
+ bool ValidRegion(const MemoryRegion& region);
void CombineMemoryRegions();
};
diff --git a/src/debug/createdump/createdump.cpp b/src/debug/createdump/createdump.cpp
index 0a95e53..f6ea1db 100644
--- a/src/debug/createdump/createdump.cpp
+++ b/src/debug/createdump/createdump.cpp
@@ -15,8 +15,8 @@ CreateDumpCommon(const char* programPath, const char* dumpPathTemplate, MINIDUMP
ReleaseHolder<DumpWriter> dumpWriter = new DumpWriter(*crashInfo);
bool result = false;
- ArrayHolder<char> dumpPath = new char[MAX_LONGPATH];
- snprintf(dumpPath, MAX_LONGPATH, dumpPathTemplate, crashInfo->Pid());
+ ArrayHolder<char> dumpPath = new char[PATH_MAX];
+ snprintf(dumpPath, PATH_MAX, dumpPathTemplate, crashInfo->Pid());
const char* dumpType = "minidump";
switch (minidumpType)
@@ -29,6 +29,10 @@ CreateDumpCommon(const char* programPath, const char* dumpPathTemplate, MINIDUMP
dumpType = "triage minidump";
break;
+ case MiniDumpWithFullMemory:
+ dumpType = "full dump";
+ break;
+
default:
break;
}
diff --git a/src/debug/createdump/datatarget.cpp b/src/debug/createdump/datatarget.cpp
index 38505e2..9609fa3 100644
--- a/src/debug/createdump/datatarget.cpp
+++ b/src/debug/createdump/datatarget.cpp
@@ -159,7 +159,6 @@ DumpDataTarget::ReadVirtual(
size_t read = pread64(m_fd, buffer, size, (off64_t)address);
if (read == -1)
{
- fprintf(stderr, "ReadVirtual FAILED %016lx %08x\n", address, size);
*done = 0;
return E_FAIL;
}
diff --git a/src/debug/createdump/dumpwriter.cpp b/src/debug/createdump/dumpwriter.cpp
index 9057d18..69f0ece 100644
--- a/src/debug/createdump/dumpwriter.cpp
+++ b/src/debug/createdump/dumpwriter.cpp
@@ -209,7 +209,7 @@ DumpWriter::WriteDump()
// Write all the thread's state and registers
for (const ThreadInfo* thread : m_crashInfo.Threads())
{
- if (!WriteThread(*thread, 0)) {
+ if (!WriteThread(*thread, SIGABRT)) {
return false;
}
}
diff --git a/src/debug/createdump/main.cpp b/src/debug/createdump/main.cpp
index 0338277..cb4d3c6 100644
--- a/src/debug/createdump/main.cpp
+++ b/src/debug/createdump/main.cpp
@@ -9,6 +9,7 @@ const char* g_help = "createdump [options] pid\n"
"-n, --normal - create minidump.\n"
"-h, --withheap - create minidump with heap (default).\n"
"-t, --triage - create triage minidump.\n"
+"-u, --full - create full core dump.\n"
"-d, --diag - enable diagnostic messages.\n";
bool CreateDumpCommon(const char* programPath, const char* dumpPathTemplate, MINIDUMP_TYPE minidumpType, CrashInfo* crashInfo);
@@ -60,6 +61,10 @@ int __cdecl main(const int argc, const char* argv[])
{
minidumpType = MiniDumpFilterTriage;
}
+ else if ((strcmp(*argv, "-u") == 0) || (strcmp(*argv, "--full") == 0))
+ {
+ minidumpType = MiniDumpWithFullMemory;
+ }
else if ((strcmp(*argv, "-d") == 0) || (strcmp(*argv, "--diag") == 0))
{
g_diagnostics = true;
diff --git a/src/debug/createdump/memoryregion.h b/src/debug/createdump/memoryregion.h
index 16c4d1c..1332ab1 100644
--- a/src/debug/createdump/memoryregion.h
+++ b/src/debug/createdump/memoryregion.h
@@ -36,35 +36,12 @@ public:
assert((end & ~PAGE_MASK) == 0);
}
- const uint32_t Permissions() const
- {
- return m_permissions;
- }
-
- const uint64_t StartAddress() const
- {
- return m_startAddress;
- }
-
- const uint64_t EndAddress() const
- {
- return m_endAddress;
- }
-
- const uint64_t Size() const
- {
- return m_endAddress - m_startAddress;
- }
-
- const uint64_t Offset() const
- {
- return m_offset;
- }
-
- const char* FileName() const
- {
- return m_fileName;
- }
+ const uint32_t Permissions() const { return m_permissions; }
+ const uint64_t StartAddress() const { return m_startAddress; }
+ const uint64_t EndAddress() const { return m_endAddress; }
+ const uint64_t Size() const { return m_endAddress - m_startAddress; }
+ const uint64_t Offset() const { return m_offset; }
+ const char* FileName() const { return m_fileName; }
bool operator<(const MemoryRegion& rhs) const
{
@@ -88,10 +65,10 @@ public:
void Print() const
{
if (m_fileName != nullptr) {
- TRACE("%016lx - %016lx (%04ld) %016lx %x %s\n", m_startAddress, m_endAddress, (Size() >> PAGE_SHIFT), m_offset, m_permissions, m_fileName);
+ TRACE("%016lx - %016lx (%06ld) %016lx %x %s\n", m_startAddress, m_endAddress, (Size() >> PAGE_SHIFT), m_offset, m_permissions, m_fileName);
}
else {
- TRACE("%016lx - %016lx (%04ld) %02x\n", m_startAddress, m_endAddress, (Size() >> PAGE_SHIFT), m_permissions);
+ TRACE("%016lx - %016lx (%06ld) %x\n", m_startAddress, m_endAddress, (Size() >> PAGE_SHIFT), m_permissions);
}
}
};
diff --git a/src/debug/createdump/threadinfo.cpp b/src/debug/createdump/threadinfo.cpp
index 8e73fcf..e2c10fc 100644
--- a/src/debug/createdump/threadinfo.cpp
+++ b/src/debug/createdump/threadinfo.cpp
@@ -38,7 +38,7 @@ ThreadInfo::Initialize(ICLRDataTarget* dataTarget)
return false;
}
}
- TRACE("Thread %04x RIP %016llx RSP %016llx\n", m_tid, m_gpRegisters.rip, m_gpRegisters.rsp);
+ TRACE("Thread %04x RIP %016llx RSP %016llx\n", m_tid, (unsigned long long)m_gpRegisters.rip, (unsigned long long)m_gpRegisters.rsp);
return true;
}
diff --git a/src/debug/daccess/daccess.cpp b/src/debug/daccess/daccess.cpp
index dcf6314..14ce251 100644
--- a/src/debug/daccess/daccess.cpp
+++ b/src/debug/daccess/daccess.cpp
@@ -6305,8 +6305,6 @@ bool ClrDataAccess::ReportMem(TADDR addr, TSIZE_T size, bool fExpectSuccess /*=
status = m_enumMemCb->EnumMemoryRegion(TO_CDADDR(addr), enumSize);
if (status != S_OK)
{
- m_memStatus = status;
-
// If dump generation was cancelled, allow us to throw upstack so we'll actually quit.
if ((fExpectSuccess) && (status != COR_E_OPERATIONCANCELED))
return false;
diff --git a/src/debug/daccess/dacimpl.h b/src/debug/daccess/dacimpl.h
index 635be80..cd133eb 100644
--- a/src/debug/daccess/dacimpl.h
+++ b/src/debug/daccess/dacimpl.h
@@ -1432,7 +1432,6 @@ private:
ICLRMetadataLocator * m_legacyMetaDataLocator;
LONG m_refs;
- HRESULT m_memStatus;
MDImportsCache m_mdImports;
ICLRDataEnumMemoryRegionsCallback* m_enumMemCb;
ICLRDataEnumMemoryRegionsCallback2* m_updateMemCb;
diff --git a/src/debug/daccess/enummem.cpp b/src/debug/daccess/enummem.cpp
index 9305bba..ebe0fc8 100644
--- a/src/debug/daccess/enummem.cpp
+++ b/src/debug/daccess/enummem.cpp
@@ -374,7 +374,6 @@ HRESULT ClrDataAccess::EnumMemoryRegionsWorkerHeap(IN CLRDataEnumMemoryFlags fla
// now dump the memory get dragged in by using DAC API implicitly.
m_dumpStats.m_cbImplicity = m_instances.DumpAllInstances(m_enumMemCb);
- status = m_memStatus;
// Do not let any remaining implicitly enumerated memory leak out.
Flush();
@@ -394,7 +393,7 @@ HRESULT ClrDataAccess::DumpManagedObject(CLRDataEnumMemoryFlags flags, OBJECTREF
{
SUPPORTS_DAC;
- HRESULT status = S_OK;
+ HRESULT status = S_OK;
if (objRef == NULL)
{
@@ -1616,7 +1615,6 @@ HRESULT ClrDataAccess::EnumMemoryRegionsWorkerSkinny(IN CLRDataEnumMemoryFlags f
// now dump the memory get dragged in by using DAC API implicitly.
m_dumpStats.m_cbImplicity = m_instances.DumpAllInstances(m_enumMemCb);
- status = m_memStatus;
// Do not let any remaining implicitly enumerated memory leak out.
Flush();
@@ -1667,7 +1665,6 @@ HRESULT ClrDataAccess::EnumMemoryRegionsWorkerMicroTriage(IN CLRDataEnumMemoryFl
// now dump the memory get dragged in by using DAC API implicitly.
m_dumpStats.m_cbImplicity = m_instances.DumpAllInstances(m_enumMemCb);
- status = m_memStatus;
// Do not let any remaining implicitly enumerated memory leak out.
Flush();
@@ -1811,8 +1808,6 @@ HRESULT ClrDataAccess::EnumMemoryRegionsWorkerCustom()
status = E_INVALIDARG;
}
- status = m_memStatus;
-
return S_OK;
}
@@ -1935,7 +1930,6 @@ ClrDataAccess::EnumMemoryRegions(IN ICLRDataEnumMemoryRegionsCallback* callback,
// We should not be trying to enumerate while we have an enumeration outstanding
_ASSERTE(m_enumMemCb==NULL);
- m_memStatus = S_OK;
m_enumMemCb = callback;
// QI for ICLRDataEnumMemoryRegionsCallback2 will succeed only for Win8+.
diff --git a/src/debug/di/cordb.cpp b/src/debug/di/cordb.cpp
index e6ed44d..ae74c34 100644
--- a/src/debug/di/cordb.cpp
+++ b/src/debug/di/cordb.cpp
@@ -20,6 +20,13 @@
#include "dbgtransportmanager.h"
#endif // FEATURE_DBGIPC_TRANSPORT_DI
+#if defined(PLATFORM_UNIX) || defined(__ANDROID__)
+// Local (in-process) debugging is not supported for UNIX and Android.
+#define SUPPORT_LOCAL_DEBUGGING 0
+#else
+#define SUPPORT_LOCAL_DEBUGGING 1
+#endif
+
//********** Globals. *********************************************************
#ifndef FEATURE_PAL
HINSTANCE g_hInst; // Instance handle to this piece of code.
@@ -499,7 +506,7 @@ DbiGetThreadContext(HANDLE hThread,
DT_CONTEXT *lpContext)
{
// if we aren't local debugging this isn't going to work
-#if !defined(_ARM_) || defined(FEATURE_DBGIPC_TRANSPORT_DI) || defined(__ANDROID__)
+#if !defined(_ARM_) || defined(FEATURE_DBGIPC_TRANSPORT_DI) || !SUPPORT_LOCAL_DEBUGGING
_ASSERTE(!"Can't use local GetThreadContext remotely, this needed to go to datatarget");
return FALSE;
#else
@@ -538,7 +545,7 @@ BOOL
DbiSetThreadContext(HANDLE hThread,
const DT_CONTEXT *lpContext)
{
-#if !defined(_ARM_) || defined(FEATURE_DBGIPC_TRANSPORT_DI) || defined(__ANDROID__)
+#if !defined(_ARM_) || defined(FEATURE_DBGIPC_TRANSPORT_DI) || !SUPPORT_LOCAL_DEBUGGING
_ASSERTE(!"Can't use local GetThreadContext remotely, this needed to go to datatarget");
return FALSE;
#else
diff --git a/src/debug/shared/amd64/primitives.cpp b/src/debug/shared/amd64/primitives.cpp
index fb5d95b..6fead57 100644
--- a/src/debug/shared/amd64/primitives.cpp
+++ b/src/debug/shared/amd64/primitives.cpp
@@ -63,7 +63,7 @@ void CORDbgCopyThreadContext(DT_CONTEXT* pDst, const DT_CONTEXT* pSrc)
if ((dstFlags & srcFlags & CONTEXT_FLOATING_POINT) == CONTEXT_FLOATING_POINT)
{
// Xmm0-Xmm15
- CopyContextChunk(&(pDst->Xmm0), &(pSrc->Xmm0), &(pDst->Xmm15) + sizeof(M128A),
+ CopyContextChunk(&(pDst->Xmm0), &(pSrc->Xmm0), &(pDst->Xmm15) + 1,
CONTEXT_FLOATING_POINT);
// MxCsr
diff --git a/src/dlls/mscordac/mscordac_unixexports.src b/src/dlls/mscordac/mscordac_unixexports.src
index b0c3b04..9881def 100644
--- a/src/dlls/mscordac/mscordac_unixexports.src
+++ b/src/dlls/mscordac/mscordac_unixexports.src
@@ -39,6 +39,7 @@ PAL_fprintf
PAL__wcstoui64
PAL_wcstoul
PAL_iswprint
+PAL_VirtualReserveFromExecutableMemoryAllocatorWithinRange
PAL_wcslen
PAL_wcsncmp
PAL_wcsrchr
diff --git a/src/dlls/mscoree/CMakeLists.txt b/src/dlls/mscoree/CMakeLists.txt
index b9c129d..8fc3ebf 100644
--- a/src/dlls/mscoree/CMakeLists.txt
+++ b/src/dlls/mscoree/CMakeLists.txt
@@ -22,6 +22,11 @@ else()
set (DEF_SOURCES
mscorwks_unixexports.src
)
+if(FEATURE_GDBJIT)
+ list(APPEND DEF_SOURCES
+ gdbjit_unixexports.src
+ )
+endif(FEATURE_GDBJIT)
endif(WIN32)
convert_to_absolute_path(DEF_SOURCES ${DEF_SOURCES})
diff --git a/src/dlls/mscoree/coreclr/CMakeLists.txt b/src/dlls/mscoree/coreclr/CMakeLists.txt
index afa253f..7a4617f 100644
--- a/src/dlls/mscoree/coreclr/CMakeLists.txt
+++ b/src/dlls/mscoree/coreclr/CMakeLists.txt
@@ -141,6 +141,12 @@ if(CLR_CMAKE_PLATFORM_UNIX AND FEATURE_EVENT_TRACE)
)
endif(CLR_CMAKE_PLATFORM_UNIX AND FEATURE_EVENT_TRACE)
+if(CLR_CMAKE_PLATFORM_LINUX)
+ list(APPEND CORECLR_LIBRARIES
+ eventpipe
+ )
+endif(CLR_CMAKE_PLATFORM_LINUX)
+
target_link_libraries(coreclr ${CORECLR_LIBRARIES})
if(WIN32)
diff --git a/src/dlls/mscoree/gdbjit_unixexports.src b/src/dlls/mscoree/gdbjit_unixexports.src
new file mode 100644
index 0000000..b820aeb
--- /dev/null
+++ b/src/dlls/mscoree/gdbjit_unixexports.src
@@ -0,0 +1,3 @@
+; exported for GDBJIT
+__jit_debug_register_code
+__jit_debug_descriptor \ No newline at end of file
diff --git a/src/dlls/mscorpe/iceefilegen.cpp b/src/dlls/mscorpe/iceefilegen.cpp
index f4323b9..c48ae7e 100644
--- a/src/dlls/mscorpe/iceefilegen.cpp
+++ b/src/dlls/mscorpe/iceefilegen.cpp
@@ -151,7 +151,9 @@ HRESULT ICeeFileGen::CreateCeeFileFromICeeGen(ICeeGen *pICeeGen, HCEEFILE *ceeFi
return E_POINTER;
CCeeGen *genFrom = reinterpret_cast<CCeeGen*>(pICeeGen);
CeeFileGenWriter *gen = NULL;
- if (FAILED(CeeFileGenWriter::CreateNewInstance(genFrom, gen, createFlags))) return FALSE;
+ HRESULT hr = CeeFileGenWriter::CreateNewInstance(genFrom, gen, createFlags);
+ if (FAILED(hr))
+ return hr;
TESTANDRETURN(gen != NULL, E_OUTOFMEMORY);
*ceeFile = gen;
return S_OK;
diff --git a/src/gc/handletablecore.cpp b/src/gc/handletablecore.cpp
index 00ab6a2..228b8bf 100644
--- a/src/gc/handletablecore.cpp
+++ b/src/gc/handletablecore.cpp
@@ -1592,6 +1592,7 @@ void SegmentResortChains(TableSegment *pSegment)
// clear the sort flag for this segment
pSegment->fResortChains = FALSE;
+ BOOL fScavengingOccurred = FALSE;
// first, do we need to scavenge any blocks?
if (pSegment->fNeedsScavenging)
@@ -1599,6 +1600,8 @@ void SegmentResortChains(TableSegment *pSegment)
// clear the scavenge flag
pSegment->fNeedsScavenging = FALSE;
+ fScavengingOccurred = TRUE;
+
// we may need to explicitly scan the user data chain too
BOOL fCleanupUserData = FALSE;
@@ -1758,6 +1761,21 @@ void SegmentResortChains(TableSegment *pSegment)
if (pSegment->rgBlockType[pSegment->rgHint[uType]] != uType)
pSegment->rgHint[uType] = bBlock;
}
+ else
+ {
+ // No blocks of this type were found in the rgBlockType array, meaning either there were no
+ // such blocks on entry to this function (in which case the associated tail is guaranteed
+ // to already be marked invalid) OR that there were blocks but all of them were reclaimed
+ // by the scavenging logic above (in which case the associated tail is guaranteed to point
+ // to one of the scavenged blocks). In the latter case, the tail is currently "stale"
+ // and therefore needs to be manually updated.
+ if (pSegment->rgTail[uType] != BLOCK_INVALID)
+ {
+ _ASSERTE(fScavengingOccurred);
+ pSegment->rgTail[uType] = BLOCK_INVALID;
+ pSegment->rgHint[uType] = BLOCK_INVALID;
+ }
+ }
}
// store the new free list head
@@ -2549,6 +2567,14 @@ uint32_t BlockFreeHandles(TableSegment *pSegment, uint32_t uBlock, OBJECTHANDLE
if (fAllMasksWeTouchedAreFree)
{
// is the block unlocked?
+ // NOTE: This check is incorrect and defeats the intended purpose of scavenging. If the
+ // current block is locked and has just been emptied, then it cannot be removed right now
+ // and therefore will nominally need to be scavenged. The only code that triggers
+ // scavenging is in SegmentRemoveFreeBlocks, and setting the flag is the only way to
+ // trigger a call into SegmentRemoveFreeBlocks call. As a result, by NOT setting the flag
+ // this code is generally PREVENTING scavenging in exactly the cases where scavenging is
+ // needed. The code is not being changed because it has always been this way and scavenging
+ // itself generally has extremely low value.
if (!BlockIsLocked(pSegment, uBlock))
{
// tell the caller it might be a good idea to scan for free blocks
diff --git a/src/gc/objecthandle.cpp b/src/gc/objecthandle.cpp
index dd43ec2..7df915f 100644
--- a/src/gc/objecthandle.cpp
+++ b/src/gc/objecthandle.cpp
@@ -608,7 +608,8 @@ HandleTableBucketHolder::~HandleTableBucketHolder()
}
delete [] m_bucket->pTable;
}
- delete m_bucket;
+
+ // we do not own m_bucket, so we shouldn't delete it here.
}
bool Ref_Initialize()
diff --git a/src/ilasm/asmman.cpp b/src/ilasm/asmman.cpp
index 22e780f..47dc6eb 100644
--- a/src/ilasm/asmman.cpp
+++ b/src/ilasm/asmman.cpp
@@ -131,6 +131,17 @@ mdToken AsmMan::GetAsmRefTokByName(__in __nullterminated const char*
AsmManAssembly* tmp = GetAsmRefByName(szAsmRefName);
return(tmp ? tmp->tkTok : mdAssemblyRefNil);
}
+AsmManAssembly* AsmMan::GetAsmRefByAsmName(__in __nullterminated const char* szAsmName)
+{
+ AsmManAssembly* ret = NULL;
+ if(szAsmName)
+ {
+ for(int i=0; (ret = m_AsmRefLst.PEEK(i))&&
+ (strcmp(ret->szName,szAsmName)); i++);
+ }
+ return ret;
+}
+
//==============================================================================================================
void AsmMan::SetModuleName(__inout_opt __nullterminated char* szName)
{
diff --git a/src/ilasm/asmman.hpp b/src/ilasm/asmman.hpp
index 0ee875b..00f4d52 100644
--- a/src/ilasm/asmman.hpp
+++ b/src/ilasm/asmman.hpp
@@ -272,6 +272,8 @@ public:
void SetManifestResFile(__in __nullterminated char* szFileName, ULONG ulOffset);
void SetManifestResAsmRef(__in __nullterminated char* szAsmRefName);
+ AsmManAssembly* GetAsmRefByAsmName(__in __nullterminated const char* szAsmName);
+
mdToken GetFileTokByName(__in __nullterminated char* szFileName);
mdToken GetAsmRefTokByName(__in __nullterminated const char* szAsmRefName);
mdToken GetAsmTokByName(__in __nullterminated const char* szAsmName)
diff --git a/src/ilasm/assembler.cpp b/src/ilasm/assembler.cpp
index 957b0bd..be535ab 100644
--- a/src/ilasm/assembler.cpp
+++ b/src/ilasm/assembler.cpp
@@ -276,14 +276,22 @@ mdToken Assembler::GetAsmRef(__in __nullterminated const char* szName)
mdToken Assembler::GetBaseAsmRef()
{
- if (RidFromToken(m_pManifest->GetAsmRefTokByName("System.Runtime")) != 0)
+ AsmManAssembly* sysRuntime = m_pManifest->GetAsmRefByAsmName("System.Runtime");
+ if(sysRuntime != NULL)
{
- return GetAsmRef("System.Runtime");
+ return GetAsmRef(sysRuntime->szAlias ? sysRuntime->szAlias : sysRuntime->szName);
}
- if (RidFromToken(m_pManifest->GetAsmRefTokByName("netstandard")) != 0)
+ AsmManAssembly* mscorlibAsm = m_pManifest->GetAsmRefByAsmName("mscorlib");
+ if(mscorlibAsm != NULL)
{
- return GetAsmRef("netstandard");
+ return GetAsmRef(mscorlibAsm->szAlias ? mscorlibAsm->szAlias : mscorlibAsm->szName);
+ }
+
+ AsmManAssembly* netstandardAsm = m_pManifest->GetAsmRefByAsmName("netstandard");
+ if (netstandardAsm != NULL)
+ {
+ return GetAsmRef(netstandardAsm->szAlias ? netstandardAsm->szAlias : netstandardAsm->szName);
}
return GetAsmRef("mscorlib");
diff --git a/src/ilasm/prebuilt/asmparse.cpp b/src/ilasm/prebuilt/asmparse.cpp
index 50c6203..389546e 100644
--- a/src/ilasm/prebuilt/asmparse.cpp
+++ b/src/ilasm/prebuilt/asmparse.cpp
@@ -4,12 +4,13 @@
#line 2 "asmparse.y"
- // Licensed to the .NET Foundation under one or more agreements.
- // The .NET Foundation licenses this file to you under the MIT license.
- // See the LICENSE file in the project root for more information.
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
//
// File asmparse.y
//
+
#include "ilasmpch.h"
#include "grammar_before.cpp"
@@ -1729,7 +1730,7 @@ YYSTATIC YYCONST short yyrecover[] = {
#endif
/* SCCSWHAT( "@(#)yypars.c 3.1 88/11/16 22:00:49 " ) */
-#line 3 "D:\\ProjectK3\\src\\tools\\devdiv\\x86\\yypars.c"
+#line 3 "O:\\tfs\\cgm\\src\\Tools\\devdiv\\amd64\\yypars.c"
#if ! defined(YYAPI_PACKAGE)
/*
** YYAPI_TOKENNAME : name used for return value of yylex
@@ -1833,9 +1834,16 @@ YYSTATIC char *yyscpy(register char*t, register char*f)
YYSTATIC short yyn;
YYSTATIC short yystate = 0;
- YYSTATIC short *yyps= &yys[-1];
+#ifdef _PREFAST_
+#pragma warning(push)
+#pragma warning(disable: 6200) // Index '-1' is out of valid index range...for non-stack buffer...
+#endif
+ YYSTATIC short *yyps= &yys[-1];
YYSTATIC YYSTYPE *yypv= &yyv[-1];
- YYSTATIC short yyj;
+#ifdef _PREFAST_
+#pragma warning(pop)
+#endif
+ YYSTATIC short yyj;
YYSTATIC short yym;
#endif
@@ -1852,8 +1860,17 @@ YYLOCAL YYNEAR YYPASCAL YYPARSER()
YYAPI_TOKENNAME = YYAPI_TOKENNONE;
yystate = 0;
- yyps= &yys[-1];
- yypv= &yyv[-1];
+
+#ifdef _PREFAST_
+#pragma warning(push)
+#pragma warning(disable:6200) // Index '-1' is out of valid index range...for non-stack buffer...
+#endif
+ yyps= &yys[-1];
+ yypv= &yyv[-1];
+#ifdef _PREFAST_
+#pragma warning(pop)
+#endif
+
#endif
#ifdef YYDUMP
@@ -4872,7 +4889,7 @@ case 834:
case 835:
#line 2045 "asmparse.y"
{ PASMM->SetManifestResAsmRef(yypvt[-0].string); } break;/* End of actions */
-#line 329 "D:\\ProjectK3\\src\\tools\\devdiv\\x86\\yypars.c"
+#line 329 "O:\\tfs\\cgm\\src\\Tools\\devdiv\\amd64\\yypars.c"
}
}
goto yystack; /* stack new state and value */
diff --git a/src/inc/CrstTypes.def b/src/inc/CrstTypes.def
index 227f986..5bf4ec6 100644
--- a/src/inc/CrstTypes.def
+++ b/src/inc/CrstTypes.def
@@ -781,5 +781,5 @@ Crst InlineTrackingMap
End
Crst EventPipe
- AcquiredBefore ThreadIdDispenser ThreadStore
+ AcquiredBefore ThreadIdDispenser ThreadStore DomainLocalBlock InstMethodHashTable
End
diff --git a/src/inc/clrconfigvalues.h b/src/inc/clrconfigvalues.h
index a0c2456..c4722bc 100644
--- a/src/inc/clrconfigvalues.h
+++ b/src/inc/clrconfigvalues.h
@@ -460,20 +460,6 @@ RETAIL_CONFIG_STRING_INFO_EX(INTERNAL_AltJitNgen, W("AltJitNgen"), "Enables AltJ
#endif // defined(ALLOW_SXS_JIT_NGEN)
CONFIG_DWORD_INFO_EX(INTERNAL_JitNoCMOV, W("JitNoCMOV"), 0, "", CLRConfig::REGUTIL_default)
-#if defined(_TARGET_AMD64_)
-// UseRyuJIT is only looked up in HKLM in the registry, not in config files or environment variables. It should only be set by the .NET 4.6 (and later version) installers,
-// not by users. See the "RyuJIT Compatibility Fallback Design Specification.docx" document for details.
-RETAIL_CONFIG_DWORD_INFO_EX(INTERNAL_UseRyuJit, W("UseRyuJIT"), 0, "Set to 1 by .NET 4.6 installer to indicate RyuJIT should be used, not JIT64.", CLRConfig::IgnoreEnv | CLRConfig::IgnoreHKCU | CLRConfig::IgnoreConfigFiles)
-RETAIL_CONFIG_DWORD_INFO(EXTERNAL_UseLegacyJit, W("useLegacyJit"), 0, "Set to 1 to do all JITing with compatjit.dll. Only applicable to x64.")
-RETAIL_CONFIG_STRING_INFO_EX(EXTERNAL_DisableNativeImageLoadList, W("DisableNativeImageLoadList"), "Refuse to load native images corresponding to one of the assemblies on this semicolon-delimited list of assembly names.", CLRConfig::REGUTIL_default)
-#endif
-
-#if defined(_TARGET_X86_)
-RETAIL_CONFIG_DWORD_INFO(EXTERNAL_UseWindowsX86CoreLegacyJit, W("UseWindowsX86CoreLegacyJit"), 0, "Set to 1 to do all JITing with compatjit.dll. Only applicable to Windows x86 .NET Core.")
-#endif
-
-RETAIL_CONFIG_DWORD_INFO(EXTERNAL_RequireLegacyJit, W("RequireLegacyJit"), 0, "Set to 1 to require the use of legacy JIT (via COMPlus_useLegacyJit=1 or COMPlus_UseWindowsX86CoreLegacyJit=1).")
-
CONFIG_STRING_INFO_EX(INTERNAL_JitValNumCSE, W("JitValNumCSE"), "Enables ValNum CSE for the specified methods", CLRConfig::REGUTIL_default)
CONFIG_STRING_INFO_EX(INTERNAL_JitLexicalCSE, W("JitLexicalCSE"), "Enables Lexical CSE for the specified methods", CLRConfig::REGUTIL_default)
CONFIG_DWORD_INFO_EX(INTERNAL_JitNoCSE, W("JitNoCSE"), 0, "", CLRConfig::REGUTIL_default)
diff --git a/src/inc/corcompile.h b/src/inc/corcompile.h
index f99e27e..68eefc1 100644
--- a/src/inc/corcompile.h
+++ b/src/inc/corcompile.h
@@ -468,15 +468,6 @@ struct CORCOMPILE_EE_INFO_TABLE
DWORD threadTlsIndex;
DWORD rvaStaticTlsIndex;
-
-// These are used by the 64-bit JITs to detect calls to thunks in the .nep section
-// and conditionally eliminate double-thunking (managed-to-native-to-managed).
-// During prejit these are set to the RVAs of the .nep section. When the prejitted
-// image is actually loaded, these are fixed up to point to the actual .nep section
-// of the ijw image (not the native image).
-
- BYTE * nativeEntryPointStart;
- BYTE * nativeEntryPointEnd;
};
/*********************************************************************************/
diff --git a/src/inc/corprof.idl b/src/inc/corprof.idl
index 3378431..db67b3c 100644
--- a/src/inc/corprof.idl
+++ b/src/inc/corprof.idl
@@ -621,9 +621,11 @@ typedef enum
COR_PRF_HIGH_IN_MEMORY_SYMBOLS_UPDATED = 0x00000002,
+ COR_PRF_HIGH_MONITOR_DYNAMIC_FUNCTION_UNLOADS = 0x00000004,
+
COR_PRF_HIGH_REQUIRE_PROFILE_IMAGE = 0,
- COR_PRF_HIGH_ALLOWABLE_AFTER_ATTACH = COR_PRF_HIGH_IN_MEMORY_SYMBOLS_UPDATED,
+ COR_PRF_HIGH_ALLOWABLE_AFTER_ATTACH = COR_PRF_HIGH_IN_MEMORY_SYMBOLS_UPDATED | COR_PRF_HIGH_MONITOR_DYNAMIC_FUNCTION_UNLOADS,
// MONITOR_IMMUTABLE represents all flags that may only be set during initialization.
// Trying to change any of these flags elsewhere will result in a
@@ -2408,6 +2410,20 @@ interface ICorProfilerCallback8 : ICorProfilerCallback7
[in] BOOL fIsSafeToBlock);
}
+[
+ object,
+ uuid(27583EC3-C8F5-482F-8052-194B8CE4705A),
+ pointer_default(unique),
+ local
+]
+interface ICorProfilerCallback9 : ICorProfilerCallback8
+{
+ // This event is triggered whenever a dynamic method is garbage collected
+ // and subsequently unloaded.
+
+ HRESULT DynamicMethodUnloaded([in] FunctionID functionId);
+}
+
/*
* COR_PRF_CODEGEN_FLAGS controls various flags and hooks for a specific
diff --git a/src/inc/crsttypes.h b/src/inc/crsttypes.h
index b4f6f49..55dc5bd 100644
--- a/src/inc/crsttypes.h
+++ b/src/inc/crsttypes.h
@@ -237,7 +237,7 @@ int g_rgCrstLevelMap[] =
3, // CrstDynamicMT
3, // CrstDynLinkZapItems
7, // CrstEtwTypeLogHash
- 11, // CrstEventPipe
+ 17, // CrstEventPipe
0, // CrstEventStore
0, // CrstException
7, // CrstExecuteManLock
@@ -560,4 +560,3 @@ inline static LPCSTR GetCrstName(CrstType crstType)
}
#endif // defined(__IN_CRST_CPP) && defined(_DEBUG)
-
diff --git a/src/inc/daccess.h b/src/inc/daccess.h
index 7d82e86..40aba86 100644
--- a/src/inc/daccess.h
+++ b/src/inc/daccess.h
@@ -617,6 +617,11 @@ typedef struct _DacGlobals
ULONG fn__ThreadpoolMgr__AsyncTimerCallbackCompletion;
ULONG fn__DACNotifyCompilationFinished;
ULONG fn__ThePreStub;
+
+#ifdef _TARGET_ARM_
+ ULONG fn__ThePreStubCompactARM;
+#endif // _TARGET_ARM_
+
ULONG fn__ThePreStubPatchLabel;
ULONG fn__PrecodeFixupThunk;
ULONG fn__StubDispatchFixupStub;
@@ -2345,6 +2350,7 @@ typedef ArrayDPTR(signed char) PTR_SBYTE;
typedef ArrayDPTR(const BYTE) PTR_CBYTE;
typedef DPTR(INT8) PTR_INT8;
typedef DPTR(INT16) PTR_INT16;
+typedef DPTR(UINT16) PTR_UINT16;
typedef DPTR(WORD) PTR_WORD;
typedef DPTR(USHORT) PTR_USHORT;
typedef DPTR(DWORD) PTR_DWORD;
diff --git a/src/inc/eventtracebase.h b/src/inc/eventtracebase.h
index bd5ad1a..2ed5317 100644
--- a/src/inc/eventtracebase.h
+++ b/src/inc/eventtracebase.h
@@ -103,7 +103,18 @@ enum EtwThreadFlags
#else //defined(FEATURE_PAL)
+#if defined(FEATURE_PERFTRACING)
+#define ETW_INLINE
+#define ETWOnStartup(StartEventName, EndEventName)
+#define ETWFireEvent(EventName)
+#define ETW_TRACING_INITIALIZED(RegHandle) (TRUE)
+#define ETW_EVENT_ENABLED(Context, EventDescriptor) (EventPipeHelper::Enabled() || XplatEventLogger::IsEventLoggingEnabled())
+#define ETW_CATEGORY_ENABLED(Context, Level, Keyword) (EventPipeHelper::Enabled() || XplatEventLogger::IsEventLoggingEnabled())
+#define ETW_TRACING_ENABLED(Context, EventDescriptor) (EventEnabled##EventDescriptor())
+#define ETW_TRACING_CATEGORY_ENABLED(Context, Level, Keyword) (EventPipeHelper::Enabled() || XplatEventLogger::IsEventLoggingEnabled())
+#define ETW_PROVIDER_ENABLED(ProviderSymbol) (TRUE)
+#else //defined(FEATURE_PERFTRACING)
#define ETW_INLINE
#define ETWOnStartup(StartEventName, EndEventName)
#define ETWFireEvent(EventName)
@@ -114,7 +125,7 @@ enum EtwThreadFlags
#define ETW_TRACING_ENABLED(Context, EventDescriptor) (EventEnabled##EventDescriptor())
#define ETW_TRACING_CATEGORY_ENABLED(Context, Level, Keyword) (XplatEventLogger::IsEventLoggingEnabled())
#define ETW_PROVIDER_ENABLED(ProviderSymbol) (TRUE)
-
+#endif // defined(FEATURE_PERFTRACING)
#endif // !defined(FEATURE_PAL)
#else // FEATURE_EVENT_TRACE
@@ -217,6 +228,14 @@ extern BOOL g_fEEIJWStartup;
#define GetClrInstanceId() (static_cast<UINT16>(g_nClrInstanceId))
+#if defined(FEATURE_PERFTRACING)
+class EventPipeHelper
+{
+public:
+ static bool Enabled();
+};
+#endif // defined(FEATURE_PERFTRACING)
+
#if defined(FEATURE_EVENT_TRACE) || defined(FEATURE_EVENTSOURCE_XPLAT)
#include "clrconfig.h"
diff --git a/src/inc/profilepriv.inl b/src/inc/profilepriv.inl
index e7c8207..d334e10 100644
--- a/src/inc/profilepriv.inl
+++ b/src/inc/profilepriv.inl
@@ -736,6 +736,21 @@ inline BOOL CORProfilerInMemorySymbolsUpdatesEnabled()
((&g_profControlBlock)->dwEventMaskHigh & COR_PRF_HIGH_IN_MEMORY_SYMBOLS_UPDATED));
}
+inline BOOL CORProfilerIsMonitoringDynamicFunctionUnloads()
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ CANNOT_TAKE_LOCK;
+ SO_NOT_MAINLINE;
+ }
+ CONTRACTL_END;
+
+ return (CORProfilerPresent() &&
+ ((&g_profControlBlock)->dwEventMaskHigh & COR_PRF_HIGH_MONITOR_DYNAMIC_FUNCTION_UNLOADS));
+}
+
#if defined(PROFILING_SUPPORTED) && !defined(CROSSGEN_COMPILE)
#if defined(FEATURE_PROFAPI_ATTACH_DETACH)
diff --git a/src/inc/switches.h b/src/inc/switches.h
index bb30387..7996453 100644
--- a/src/inc/switches.h
+++ b/src/inc/switches.h
@@ -235,3 +235,6 @@
#endif // !defined(CROSSGEN_COMPILE)
+#if defined(FEATURE_INTERPRETER) && defined(CROSSGEN_COMPILE)
+#undef FEATURE_INTERPRETER
+#endif
diff --git a/src/inc/winrt/paraminstanceapi.h b/src/inc/winrt/paraminstanceapi.h
index 062c7f3..81ee4c5 100644
--- a/src/inc/winrt/paraminstanceapi.h
+++ b/src/inc/winrt/paraminstanceapi.h
@@ -1642,7 +1642,14 @@ namespace Ro { namespace detail {
DWORD dwcb;
DWORD dwcbResult;
+#ifdef _PREFAST_
+#pragma warning(push)
+#pragma warning(disable: 33098) // "Banned hash algorithm is used" - SHA-1 is required for compatibility
+#endif // _PREFAST_
CHKNT(BCryptOpenAlgorithmProvider(&_hAlg, BCRYPT_SHA1_ALGORITHM, MS_PRIMITIVE_PROVIDER, 0));
+#ifdef _PREFAST_
+#pragma warning(pop)
+#endif // _PREFAST_
CHKNT(BCryptGetProperty(_hAlg, BCRYPT_OBJECT_LENGTH, reinterpret_cast<PBYTE>(&dwcb), sizeof(dwcb), &dwcbResult, 0));
diff --git a/src/jit/assertionprop.cpp b/src/jit/assertionprop.cpp
index 767d63a..04f2fbe 100644
--- a/src/jit/assertionprop.cpp
+++ b/src/jit/assertionprop.cpp
@@ -4556,7 +4556,7 @@ ASSERT_TP* Compiler::optInitAssertionDataflowFlags()
}
// Compute the data flow values for all tracked expressions
// IN and OUT never change for the initial basic block B1
- BitVecOps::ClearD(apTraits, fgFirstBB->bbAssertionIn);
+ BitVecOps::OldStyleClearD(apTraits, fgFirstBB->bbAssertionIn);
return jumpDestOut;
}
diff --git a/src/jit/bitset.h b/src/jit/bitset.h
index 4ecb2fc..a4b0091 100644
--- a/src/jit/bitset.h
+++ b/src/jit/bitset.h
@@ -205,9 +205,13 @@ class BitSetOps
// Destructively set "bs" to be the empty set. This method is unique, in that it does *not*
// require "bs" to be a bitset of the current epoch. It ensures that it is after, however.
// (If the representation is indirect, this requires allocating a new, empty representation.
- // If this is a performance issue, we could provide a new version of ClearD that assumes/asserts
+ // If this is a performance issue, we could provide a new version of OldStyleClearD that assumes/asserts
// that the rep is for the current epoch -- this would be useful if a given bitset were repeatedly
// cleared within an epoch.)
+ // TODO #11263: delete it.
+ static void OldStyleClearD(Env env, BitSetType& bs);
+
+ // Destructively set "bs" to be the empty set.
static void ClearD(Env env, BitSetType& bs);
// Returns a copy of "bs". If the representation of "bs" involves a level of indirection, the data
@@ -326,6 +330,11 @@ public:
BitSetTraits::GetOpCounter(env)->RecordOp(BitSetSupport::BSOP_AssignNocopy);
BSO::AssignNoCopy(env, lhs, rhs);
}
+ static void OldStyleClearD(Env env, BitSetType& bs)
+ {
+ BitSetTraits::GetOpCounter(env)->RecordOp(BitSetSupport::BSOP_OldStyleClearD);
+ BSO::OldStyleClearD(env, bs);
+ }
static void ClearD(Env env, BitSetType& bs)
{
BitSetTraits::GetOpCounter(env)->RecordOp(BitSetSupport::BSOP_ClearD);
diff --git a/src/jit/bitsetasshortlong.h b/src/jit/bitsetasshortlong.h
index 163cb36..962a8bb 100644
--- a/src/jit/bitsetasshortlong.h
+++ b/src/jit/bitsetasshortlong.h
@@ -43,6 +43,7 @@ private:
static void DiffDLong(Env env, BitSetShortLongRep& bs1, BitSetShortLongRep bs2);
static void AddElemDLong(Env env, BitSetShortLongRep& bs, unsigned i);
static void RemoveElemDLong(Env env, BitSetShortLongRep& bs, unsigned i);
+ static void OldStyleClearDLong(Env env, BitSetShortLongRep& bs);
static void ClearDLong(Env env, BitSetShortLongRep& bs);
static BitSetShortLongRep MakeUninitArrayBits(Env env);
static BitSetShortLongRep MakeEmptyArrayBits(Env env);
@@ -122,6 +123,19 @@ public:
lhs = rhs;
}
+ static void OldStyleClearD(Env env, BitSetShortLongRep& bs)
+ {
+ if (IsShort(env))
+ {
+ bs = (BitSetShortLongRep) nullptr;
+ }
+ else
+ {
+ assert(bs != UninitVal());
+ OldStyleClearDLong(env, bs);
+ }
+ }
+
static void ClearD(Env env, BitSetShortLongRep& bs)
{
if (IsShort(env))
@@ -661,15 +675,29 @@ template <typename Env, typename BitSetTraits>
void BitSetOps</*BitSetType*/ BitSetShortLongRep,
/*Brand*/ BSShortLong,
/*Env*/ Env,
- /*BitSetTraits*/ BitSetTraits>::ClearDLong(Env env, BitSetShortLongRep& bs)
+ /*BitSetTraits*/ BitSetTraits>::OldStyleClearDLong(Env env, BitSetShortLongRep& bs)
{
assert(!IsShort(env));
- // Recall that ClearD does *not* require "bs" to be of the current epoch.
+ // Recall that OldStyleClearD does *not* require "bs" to be of the current epoch.
// Therefore, we must allocate a new representation.
bs = MakeEmptyArrayBits(env);
}
template <typename Env, typename BitSetTraits>
+void BitSetOps</*BitSetType*/ BitSetShortLongRep,
+ /*Brand*/ BSShortLong,
+ /*Env*/ Env,
+ /*BitSetTraits*/ BitSetTraits>::ClearDLong(Env env, BitSetShortLongRep& bs)
+{
+ assert(!IsShort(env));
+ unsigned len = BitSetTraits::GetArrSize(env, sizeof(size_t));
+ for (unsigned i = 0; i < len; i++)
+ {
+ bs[i] = 0;
+ }
+}
+
+template <typename Env, typename BitSetTraits>
BitSetShortLongRep BitSetOps</*BitSetType*/ BitSetShortLongRep,
/*Brand*/ BSShortLong,
/*Env*/ Env,
diff --git a/src/jit/bitsetasuint64.h b/src/jit/bitsetasuint64.h
index 243e9e3..aec4d05 100644
--- a/src/jit/bitsetasuint64.h
+++ b/src/jit/bitsetasuint64.h
@@ -44,6 +44,11 @@ public:
lhs = rhs;
}
+ static void OldStyleClearD(Env env, UINT64& bs)
+ {
+ bs = 0;
+ }
+
static void ClearD(Env env, UINT64& bs)
{
bs = 0;
diff --git a/src/jit/bitsetasuint64inclass.h b/src/jit/bitsetasuint64inclass.h
index be92624..ffa99d3 100644
--- a/src/jit/bitsetasuint64inclass.h
+++ b/src/jit/bitsetasuint64inclass.h
@@ -178,16 +178,22 @@ private:
return res;
}
- inline void ClearD(Env env)
+ inline void OldStyleClearD(Env env)
{
- // Recall that ClearD does *not* require "*this" to be of the current epoch.
- Uint64BitSetOps::ClearD(env, m_bits);
+ // Recall that OldStyleClearD does *not* require "*this" to be of the current epoch.
+ Uint64BitSetOps::OldStyleClearD(env, m_bits);
#ifdef DEBUG
// But it updates it to of the current epoch.
m_epoch = BitSetTraits::GetEpoch(env);
#endif
}
+ inline void ClearD(Env env)
+ {
+ assert(m_epoch == BitSetTraits::GetEpoch(env));
+ Uint64BitSetOps::ClearD(env, m_bits);
+ }
+
inline bool IsEmpty(Env env) const
{
CheckEpoch(env);
@@ -369,6 +375,11 @@ public:
lhs = rhs;
}
+ static void OldStyleClearD(Env env, BST& bs)
+ {
+ bs.OldStyleClearD(env);
+ }
+
static void ClearD(Env env, BST& bs)
{
bs.ClearD(env);
diff --git a/src/jit/bitsetops.h b/src/jit/bitsetops.h
index edf39ea..bb4db9d 100644
--- a/src/jit/bitsetops.h
+++ b/src/jit/bitsetops.h
@@ -5,6 +5,7 @@
BSOPNAME(BSOP_Assign)
BSOPNAME(BSOP_AssignAllowUninitRhs)
BSOPNAME(BSOP_AssignNocopy)
+BSOPNAME(BSOP_OldStyleClearD)
BSOPNAME(BSOP_ClearD)
BSOPNAME(BSOP_MakeSingleton)
BSOPNAME(BSOP_MakeEmpty)
diff --git a/src/jit/codegenarm.cpp b/src/jit/codegenarm.cpp
index c28b27b..40371e3 100644
--- a/src/jit/codegenarm.cpp
+++ b/src/jit/codegenarm.cpp
@@ -259,6 +259,11 @@ void CodeGen::genReturn(GenTreePtr treeNode)
GenTreePtr op1 = treeNode->gtGetOp1();
var_types targetType = treeNode->TypeGet();
+ // A void GT_RETFILT is the end of a finally. For non-void filter returns we need to load the result in the return
+ // register, if it's not already there. The processing is the same as GT_RETURN. For filters, the IL spec says the
+ // result is type int32. Further, the only legal values are 0 or 1; the use of other values is "undefined".
+ assert(!treeNode->OperIs(GT_RETFILT) || (targetType == TYP_VOID) || (targetType == TYP_INT));
+
#ifdef DEBUG
if (targetType == TYP_VOID)
{
@@ -315,741 +320,6 @@ void CodeGen::genReturn(GenTreePtr treeNode)
}
//------------------------------------------------------------------------
-// genCodeForTreeNode Generate code for a single node in the tree.
-//
-// Preconditions:
-// All operands have been evaluated.
-//
-void CodeGen::genCodeForTreeNode(GenTreePtr treeNode)
-{
- regNumber targetReg = treeNode->gtRegNum;
- var_types targetType = treeNode->TypeGet();
- emitter* emit = getEmitter();
-
-#ifdef DEBUG
- lastConsumedNode = nullptr;
- if (compiler->verbose)
- {
- unsigned seqNum = treeNode->gtSeqNum; // Useful for setting a conditional break in Visual Studio
- compiler->gtDispLIRNode(treeNode, "Generating: ");
- }
-#endif
-
- // contained nodes are part of their parents for codegen purposes
- // ex : immediates, most LEAs
- if (treeNode->isContained())
- {
- return;
- }
-
- switch (treeNode->gtOper)
- {
- case GT_LCLHEAP:
- genLclHeap(treeNode);
- break;
-
- case GT_CNS_INT:
- case GT_CNS_DBL:
- genSetRegToConst(targetReg, targetType, treeNode);
- genProduceReg(treeNode);
- break;
-
- case GT_NOT:
- assert(!varTypeIsFloating(targetType));
-
- __fallthrough;
-
- case GT_NEG:
- {
- instruction ins = genGetInsForOper(treeNode->OperGet(), targetType);
-
- // The arithmetic node must be sitting in a register (since it's not contained)
- assert(!treeNode->isContained());
- // The dst can only be a register.
- assert(targetReg != REG_NA);
-
- GenTreePtr operand = treeNode->gtGetOp1();
- assert(!operand->isContained());
- // The src must be a register.
- regNumber operandReg = genConsumeReg(operand);
-
- if (ins == INS_vneg)
- {
- getEmitter()->emitIns_R_R(ins, emitTypeSize(treeNode), targetReg, operandReg);
- }
- else
- {
- getEmitter()->emitIns_R_R_I(ins, emitTypeSize(treeNode), targetReg, operandReg, 0);
- }
- }
- genProduceReg(treeNode);
- break;
-
- case GT_OR:
- case GT_XOR:
- case GT_AND:
- assert(varTypeIsIntegralOrI(treeNode));
- __fallthrough;
-
- case GT_ADD_LO:
- case GT_ADD_HI:
- case GT_SUB_LO:
- case GT_SUB_HI:
- case GT_ADD:
- case GT_SUB:
- case GT_MUL:
- genConsumeOperands(treeNode->AsOp());
- genCodeForBinary(treeNode);
- break;
-
- case GT_LSH:
- case GT_RSH:
- case GT_RSZ:
- case GT_ROR:
- genCodeForShift(treeNode);
- break;
-
- case GT_LSH_HI:
- case GT_RSH_LO:
- genCodeForShiftLong(treeNode);
- break;
-
- case GT_CAST:
- // Cast is never contained (?)
- noway_assert(targetReg != REG_NA);
-
- if (varTypeIsFloating(targetType) && varTypeIsFloating(treeNode->gtOp.gtOp1))
- {
- // Casts float/double <--> double/float
- genFloatToFloatCast(treeNode);
- }
- else if (varTypeIsFloating(treeNode->gtOp.gtOp1))
- {
- // Casts float/double --> int32/int64
- genFloatToIntCast(treeNode);
- }
- else if (varTypeIsFloating(targetType))
- {
- // Casts int32/uint32/int64/uint64 --> float/double
- genIntToFloatCast(treeNode);
- }
- else
- {
- // Casts int <--> int
- genIntToIntCast(treeNode);
- }
- // The per-case functions call genProduceReg()
- break;
-
- case GT_LCL_VAR:
- {
- GenTreeLclVarCommon* lcl = treeNode->AsLclVarCommon();
- // lcl_vars are not defs
- assert((treeNode->gtFlags & GTF_VAR_DEF) == 0);
-
- bool isRegCandidate = compiler->lvaTable[lcl->gtLclNum].lvIsRegCandidate();
-
- if (isRegCandidate && !(treeNode->gtFlags & GTF_VAR_DEATH))
- {
- assert((treeNode->InReg()) || (treeNode->gtFlags & GTF_SPILLED));
- }
-
- // If this is a register candidate that has been spilled, genConsumeReg() will
- // reload it at the point of use. Otherwise, if it's not in a register, we load it here.
-
- if (!treeNode->InReg() && !(treeNode->gtFlags & GTF_SPILLED))
- {
- assert(!isRegCandidate);
- emit->emitIns_R_S(ins_Load(treeNode->TypeGet()), emitTypeSize(treeNode), treeNode->gtRegNum,
- lcl->gtLclNum, 0);
- genProduceReg(treeNode);
- }
- }
- break;
-
- case GT_LCL_FLD_ADDR:
- case GT_LCL_VAR_ADDR:
- {
- // Address of a local var. This by itself should never be allocated a register.
- // If it is worth storing the address in a register then it should be cse'ed into
- // a temp and that would be allocated a register.
- noway_assert(targetType == TYP_BYREF);
- noway_assert(!treeNode->InReg());
-
- inst_RV_TT(INS_lea, targetReg, treeNode, 0, EA_BYREF);
- }
- genProduceReg(treeNode);
- break;
-
- case GT_LCL_FLD:
- {
- NYI_IF(targetType == TYP_STRUCT, "GT_LCL_FLD: struct load local field not supported");
- NYI_IF(treeNode->gtRegNum == REG_NA, "GT_LCL_FLD: load local field not into a register is not supported");
-
- emitAttr size = emitTypeSize(targetType);
- unsigned offs = treeNode->gtLclFld.gtLclOffs;
- unsigned varNum = treeNode->gtLclVarCommon.gtLclNum;
- assert(varNum < compiler->lvaCount);
-
- if (varTypeIsFloating(targetType))
- {
- if (treeNode->InReg())
- {
- NYI("GT_LCL_FLD with reg-to-reg floating point move");
- }
- else
- {
- emit->emitIns_R_S(ins_Load(targetType), size, targetReg, varNum, offs);
- }
- }
- else
- {
- emit->emitIns_R_S(ins_Move_Extend(targetType, treeNode->InReg()), size, targetReg, varNum, offs);
- }
- }
- genProduceReg(treeNode);
- break;
-
- case GT_STORE_LCL_FLD:
- {
- noway_assert(targetType != TYP_STRUCT);
-
- // record the offset
- unsigned offset = treeNode->gtLclFld.gtLclOffs;
-
- // We must have a stack store with GT_STORE_LCL_FLD
- noway_assert(!treeNode->InReg());
- noway_assert(targetReg == REG_NA);
-
- GenTreeLclVarCommon* varNode = treeNode->AsLclVarCommon();
- unsigned varNum = varNode->gtLclNum;
- assert(varNum < compiler->lvaCount);
- LclVarDsc* varDsc = &(compiler->lvaTable[varNum]);
-
- // Ensure that lclVar nodes are typed correctly.
- assert(!varDsc->lvNormalizeOnStore() || targetType == genActualType(varDsc->TypeGet()));
-
- GenTreePtr data = treeNode->gtOp.gtOp1->gtEffectiveVal();
- instruction ins = ins_Store(targetType);
- emitAttr attr = emitTypeSize(targetType);
- if (data->isContainedIntOrIImmed())
- {
- assert(data->IsIntegralConst(0));
- NYI_ARM("st.lclFld contained operand");
- }
- else
- {
- assert(!data->isContained());
- genConsumeReg(data);
- emit->emitIns_S_R(ins, attr, data->gtRegNum, varNum, offset);
- }
-
- genUpdateLife(varNode);
- varDsc->lvRegNum = REG_STK;
- }
- break;
-
- case GT_STORE_LCL_VAR:
- {
- GenTreeLclVarCommon* varNode = treeNode->AsLclVarCommon();
-
- unsigned varNum = varNode->gtLclNum;
- assert(varNum < compiler->lvaCount);
- LclVarDsc* varDsc = &(compiler->lvaTable[varNum]);
- unsigned offset = 0;
-
- // Ensure that lclVar nodes are typed correctly.
- assert(!varDsc->lvNormalizeOnStore() || targetType == genActualType(varDsc->TypeGet()));
-
- GenTreePtr data = treeNode->gtOp.gtOp1->gtEffectiveVal();
-
- // var = call, where call returns a multi-reg return value
- // case is handled separately.
- if (data->gtSkipReloadOrCopy()->IsMultiRegCall())
- {
- genMultiRegCallStoreToLocal(treeNode);
- break;
- }
- else
- {
- if (treeNode->TypeGet() == TYP_LONG)
- {
- genStoreLongLclVar(treeNode);
- break;
- }
-
- genConsumeRegs(data);
-
- regNumber dataReg = REG_NA;
- if (data->isContainedIntOrIImmed())
- {
- assert(data->IsIntegralConst(0));
- NYI_ARM("st.lclVar contained operand");
- }
- else
- {
- assert(!data->isContained());
- dataReg = data->gtRegNum;
- }
- assert(dataReg != REG_NA);
-
- if (targetReg == REG_NA) // store into stack based LclVar
- {
- inst_set_SV_var(varNode);
-
- instruction ins = ins_Store(targetType);
- emitAttr attr = emitTypeSize(targetType);
-
- emit->emitIns_S_R(ins, attr, dataReg, varNum, offset);
-
- genUpdateLife(varNode);
-
- varDsc->lvRegNum = REG_STK;
- }
- else // store into register (i.e move into register)
- {
- if (dataReg != targetReg)
- {
- // Assign into targetReg when dataReg (from op1) is not the same register
- inst_RV_RV(ins_Copy(targetType), targetReg, dataReg, targetType);
- }
- genProduceReg(treeNode);
- }
- }
- }
- break;
-
- case GT_RETFILT:
- // A void GT_RETFILT is the end of a finally. For non-void filter returns we need to load the result in
- // the return register, if it's not already there. The processing is the same as GT_RETURN.
- if (targetType != TYP_VOID)
- {
- // For filters, the IL spec says the result is type int32. Further, the only specified legal values
- // are 0 or 1, with the use of other values "undefined".
- assert(targetType == TYP_INT);
- }
-
- __fallthrough;
-
- case GT_RETURN:
- genReturn(treeNode);
- break;
-
- case GT_LEA:
- {
- // if we are here, it is the case where there is an LEA that cannot
- // be folded into a parent instruction
- GenTreeAddrMode* lea = treeNode->AsAddrMode();
- genLeaInstruction(lea);
- }
- // genLeaInstruction calls genProduceReg()
- break;
-
- case GT_IND:
- genConsumeAddress(treeNode->AsIndir()->Addr());
- emit->emitInsLoadStoreOp(ins_Load(targetType), emitTypeSize(treeNode), targetReg, treeNode->AsIndir());
- genProduceReg(treeNode);
- break;
-
- case GT_MOD:
- case GT_UDIV:
- case GT_UMOD:
- // We shouldn't be seeing GT_MOD on float/double args as it should get morphed into a
- // helper call by front-end. Similarly we shouldn't be seeing GT_UDIV and GT_UMOD
- // on float/double args.
- noway_assert(!varTypeIsFloating(treeNode));
- __fallthrough;
-
- case GT_DIV:
- {
- genConsumeOperands(treeNode->AsOp());
-
- noway_assert(targetReg != REG_NA);
-
- GenTreePtr dst = treeNode;
- GenTreePtr src1 = treeNode->gtGetOp1();
- GenTreePtr src2 = treeNode->gtGetOp2();
- instruction ins = genGetInsForOper(treeNode->OperGet(), targetType);
- emitAttr attr = emitTypeSize(treeNode);
- regNumber result = REG_NA;
-
- // dst can only be a reg
- assert(!dst->isContained());
-
- // src can be only reg
- assert(!src1->isContained() || !src2->isContained());
-
- if (varTypeIsFloating(targetType))
- {
- // Floating point divide never raises an exception
-
- emit->emitIns_R_R_R(ins, attr, dst->gtRegNum, src1->gtRegNum, src2->gtRegNum);
- }
- else // an signed integer divide operation
- {
- // TODO-ARM-Bug: handle zero division exception.
-
- emit->emitIns_R_R_R(ins, attr, dst->gtRegNum, src1->gtRegNum, src2->gtRegNum);
- }
-
- genProduceReg(treeNode);
- }
- break;
-
- case GT_INTRINSIC:
- {
- genIntrinsic(treeNode);
- }
- break;
-
- case GT_EQ:
- case GT_NE:
- case GT_LT:
- case GT_LE:
- case GT_GE:
- case GT_GT:
- {
- // TODO-ARM-CQ: Check if we can use the currently set flags.
- // TODO-ARM-CQ: Check for the case where we can simply transfer the carry bit to a register
- // (signed < or >= where targetReg != REG_NA)
-
- GenTreeOp* tree = treeNode->AsOp();
- GenTreePtr op1 = tree->gtOp1->gtEffectiveVal();
- GenTreePtr op2 = tree->gtOp2->gtEffectiveVal();
-
- genConsumeIfReg(op1);
- genConsumeIfReg(op2);
-
- instruction ins = INS_cmp;
- emitAttr cmpAttr;
- if (varTypeIsFloating(op1))
- {
- assert(op1->TypeGet() == op2->TypeGet());
- ins = INS_vcmp;
- cmpAttr = emitTypeSize(op1->TypeGet());
- emit->emitInsBinary(ins, cmpAttr, op1, op2);
- // vmrs with register 0xf has special meaning of transferring flags
- emit->emitIns_R(INS_vmrs, EA_4BYTE, REG_R15);
- }
- else if (varTypeIsLong(op1))
- {
-#ifdef DEBUG
- // The result of an unlowered long compare on a 32-bit target must either be
- // a) materialized into a register, or
- // b) unused.
- //
- // A long compare that has a result that is used but not materialized into a register should
- // have been handled by Lowering::LowerCompare.
-
- LIR::Use use;
- assert((treeNode->gtRegNum != REG_NA) || !LIR::AsRange(compiler->compCurBB).TryGetUse(treeNode, &use));
-#endif
- genCompareLong(treeNode);
- break;
- }
- else
- {
- var_types op1Type = op1->TypeGet();
- var_types op2Type = op2->TypeGet();
- assert(!varTypeIsFloating(op2Type));
- ins = INS_cmp;
- if (op1Type == op2Type)
- {
- cmpAttr = emitTypeSize(op1Type);
- }
- else
- {
- var_types cmpType = TYP_INT;
- bool op1Is64Bit = (varTypeIsLong(op1Type) || op1Type == TYP_REF);
- bool op2Is64Bit = (varTypeIsLong(op2Type) || op2Type == TYP_REF);
- NYI_IF(op1Is64Bit || op2Is64Bit, "Long compare");
- assert(!op1->isUsedFromMemory() || op1Type == op2Type);
- assert(!op2->isUsedFromMemory() || op1Type == op2Type);
- cmpAttr = emitTypeSize(cmpType);
- }
- emit->emitInsBinary(ins, cmpAttr, op1, op2);
- }
-
- // Are we evaluating this into a register?
- if (targetReg != REG_NA)
- {
- genSetRegToCond(targetReg, tree);
- genProduceReg(tree);
- }
- }
- break;
-
- case GT_JTRUE:
- genCodeForJumpTrue(treeNode);
- break;
-
- case GT_JCC:
- {
- GenTreeJumpCC* jcc = treeNode->AsJumpCC();
-
- assert(compiler->compCurBB->bbJumpKind == BBJ_COND);
-
- CompareKind compareKind = ((jcc->gtFlags & GTF_UNSIGNED) != 0) ? CK_UNSIGNED : CK_SIGNED;
- emitJumpKind jumpKind = genJumpKindForOper(jcc->gtCondition, compareKind);
-
- inst_JMP(jumpKind, compiler->compCurBB->bbJumpDest);
- }
- break;
-
- case GT_RETURNTRAP:
- {
- // this is nothing but a conditional call to CORINFO_HELP_STOP_FOR_GC
- // based on the contents of 'data'
-
- GenTree* data = treeNode->gtOp.gtOp1->gtEffectiveVal();
- genConsumeIfReg(data);
- GenTreeIntCon cns = intForm(TYP_INT, 0);
- emit->emitInsBinary(INS_cmp, emitTypeSize(TYP_INT), data, &cns);
-
- BasicBlock* skipLabel = genCreateTempLabel();
-
- emitJumpKind jmpEqual = genJumpKindForOper(GT_EQ, CK_SIGNED);
- inst_JMP(jmpEqual, skipLabel);
- // emit the call to the EE-helper that stops for GC (or other reasons)
-
- genEmitHelperCall(CORINFO_HELP_STOP_FOR_GC, 0, EA_UNKNOWN);
- genDefineTempLabel(skipLabel);
- }
- break;
-
- case GT_STOREIND:
- {
- GenTreeStoreInd* storeInd = treeNode->AsStoreInd();
- GenTree* data = storeInd->Data();
- GenTree* addr = storeInd->Addr();
- var_types targetType = storeInd->TypeGet();
-
- assert(!varTypeIsFloating(targetType) || (targetType == data->TypeGet()));
-
- GCInfo::WriteBarrierForm writeBarrierForm = gcInfo.gcIsWriteBarrierCandidate(treeNode, data);
- if (writeBarrierForm != GCInfo::WBF_NoBarrier)
- {
- // data and addr must be in registers.
- // Consume both registers so that any copies of interfering
- // registers are taken care of.
- genConsumeOperands(storeInd->AsOp());
-
-#if NOGC_WRITE_BARRIERS
- NYI_ARM("NOGC_WRITE_BARRIERS");
-#else
- // At this point, we should not have any interference.
- // That is, 'data' must not be in REG_ARG_0,
- // as that is where 'addr' must go.
- noway_assert(data->gtRegNum != REG_ARG_0);
-
- // addr goes in REG_ARG_0
- if (addr->gtRegNum != REG_ARG_0)
- {
- inst_RV_RV(INS_mov, REG_ARG_0, addr->gtRegNum, addr->TypeGet());
- }
-
- // data goes in REG_ARG_1
- if (data->gtRegNum != REG_ARG_1)
- {
- inst_RV_RV(INS_mov, REG_ARG_1, data->gtRegNum, data->TypeGet());
- }
-#endif // NOGC_WRITE_BARRIERS
-
- genGCWriteBarrier(storeInd, writeBarrierForm);
- }
- else // A normal store, not a WriteBarrier store
- {
- bool reverseOps = ((storeInd->gtFlags & GTF_REVERSE_OPS) != 0);
- bool dataIsUnary = false;
-
- // We must consume the operands in the proper execution order,
- // so that liveness is updated appropriately.
- if (!reverseOps)
- {
- genConsumeAddress(addr);
- }
-
- if (!data->isContained())
- {
- genConsumeRegs(data);
- }
-
- if (reverseOps)
- {
- genConsumeAddress(addr);
- }
-
- emit->emitInsLoadStoreOp(ins_Store(targetType), emitTypeSize(storeInd), data->gtRegNum,
- treeNode->AsIndir());
- }
- }
- break;
-
- case GT_COPY:
- // This is handled at the time we call genConsumeReg() on the GT_COPY
- break;
-
- case GT_LIST:
- case GT_FIELD_LIST:
- case GT_ARGPLACE:
- // Nothing to do
- break;
-
- case GT_PUTARG_STK:
- genPutArgStk(treeNode->AsPutArgStk());
- break;
-
- case GT_PUTARG_REG:
- {
- NYI_IF(targetType == TYP_STRUCT, "GT_PUTARG_REG: struct support not implemented");
-
- // commas show up here commonly, as part of a nullchk operation
- GenTree* op1 = treeNode->gtOp.gtOp1->gtEffectiveVal();
- // If child node is not already in the register we need, move it
- genConsumeReg(op1);
- if (treeNode->gtRegNum != op1->gtRegNum)
- {
- inst_RV_RV(ins_Move_Extend(targetType, true), treeNode->gtRegNum, op1->gtRegNum, targetType);
- }
- }
- genProduceReg(treeNode);
- break;
-
- case GT_CALL:
- genCallInstruction(treeNode->AsCall());
- break;
-
- case GT_LOCKADD:
- case GT_XCHG:
- case GT_XADD:
- genLockedInstructions(treeNode->AsOp());
- break;
-
- case GT_MEMORYBARRIER:
- instGen_MemoryBarrier();
- break;
-
- case GT_CMPXCHG:
- {
- NYI("GT_CMPXCHG");
- }
- genProduceReg(treeNode);
- break;
-
- case GT_RELOAD:
- // do nothing - reload is just a marker.
- // The parent node will call genConsumeReg on this which will trigger the unspill of this node's child
- // into the register specified in this node.
- break;
-
- case GT_NOP:
- break;
-
- case GT_NO_OP:
- if (treeNode->gtFlags & GTF_NO_OP_NO)
- {
- noway_assert(!"GTF_NO_OP_NO should not be set");
- }
- else
- {
- instGen(INS_nop);
- }
- break;
-
- case GT_ARR_BOUNDS_CHECK:
- genRangeCheck(treeNode);
- break;
-
- case GT_PHYSREG:
- if (treeNode->gtRegNum != treeNode->AsPhysReg()->gtSrcReg)
- {
- inst_RV_RV(INS_mov, treeNode->gtRegNum, treeNode->AsPhysReg()->gtSrcReg, targetType);
-
- genTransferRegGCState(treeNode->gtRegNum, treeNode->AsPhysReg()->gtSrcReg);
- }
- break;
-
- case GT_PHYSREGDST:
- break;
-
- case GT_NULLCHECK:
- {
- assert(!treeNode->gtOp.gtOp1->isContained());
- regNumber addrReg = genConsumeReg(treeNode->gtOp.gtOp1);
- emit->emitIns_R_R_I(INS_ldr, EA_4BYTE, targetReg, addrReg, 0);
- }
- break;
-
- case GT_CATCH_ARG:
-
- noway_assert(handlerGetsXcptnObj(compiler->compCurBB->bbCatchTyp));
-
- /* Catch arguments get passed in a register. genCodeForBBlist()
- would have marked it as holding a GC object, but not used. */
-
- noway_assert(gcInfo.gcRegGCrefSetCur & RBM_EXCEPTION_OBJECT);
- genConsumeReg(treeNode);
- break;
-
- case GT_PINVOKE_PROLOG:
- noway_assert(((gcInfo.gcRegGCrefSetCur | gcInfo.gcRegByrefSetCur) & ~fullIntArgRegMask()) == 0);
-
- // the runtime side requires the codegen here to be consistent
- emit->emitDisableRandomNops();
- break;
-
- case GT_LABEL:
- genPendingCallLabel = genCreateTempLabel();
- treeNode->gtLabel.gtLabBB = genPendingCallLabel;
- emit->emitIns_J_R(INS_adr, EA_PTRSIZE, genPendingCallLabel, treeNode->gtRegNum);
- break;
-
- case GT_CLS_VAR_ADDR:
- emit->emitIns_R_C(INS_lea, EA_PTRSIZE, targetReg, treeNode->gtClsVar.gtClsVarHnd, 0);
- genProduceReg(treeNode);
- break;
-
- case GT_STORE_DYN_BLK:
- case GT_STORE_BLK:
- genCodeForStoreBlk(treeNode->AsBlk());
- break;
-
- case GT_JMPTABLE:
- genJumpTable(treeNode);
- break;
-
- case GT_SWITCH_TABLE:
- genTableBasedSwitch(treeNode);
- break;
-
- case GT_ARR_INDEX:
- genCodeForArrIndex(treeNode->AsArrIndex());
- break;
-
- case GT_ARR_OFFSET:
- genCodeForArrOffset(treeNode->AsArrOffs());
- break;
-
- case GT_IL_OFFSET:
- // Do nothing; these nodes are simply markers for debug info.
- break;
-
- default:
- {
-#ifdef DEBUG
- char message[256];
- _snprintf_s(message, _countof(message), _TRUNCATE, "NYI: Unimplemented node type %s",
- GenTree::NodeName(treeNode->OperGet()));
- NYIRAW(message);
-#else
- NYI("unimplemented node");
-#endif
- }
- break;
- }
-}
-
-//------------------------------------------------------------------------
// genLockedInstructions: Generate code for the locked operations.
//
// Notes:
@@ -1511,43 +781,161 @@ void CodeGen::genCodeForInitBlkUnroll(GenTreeBlk* initBlkNode)
NYI_ARM("genCodeForInitBlkUnroll");
}
-void CodeGen::genCodeForStoreBlk(GenTreeBlk* blkOp)
+//------------------------------------------------------------------------
+// genCodeForNegNot: Produce code for a GT_NEG/GT_NOT node.
+//
+// Arguments:
+// tree - the node
+//
+void CodeGen::genCodeForNegNot(GenTree* tree)
{
- if (blkOp->gtBlkOpGcUnsafe)
+ assert(tree->OperIs(GT_NEG, GT_NOT));
+
+ var_types targetType = tree->TypeGet();
+
+ assert(!tree->OperIs(GT_NOT) || !varTypeIsFloating(targetType));
+
+ regNumber targetReg = tree->gtRegNum;
+ instruction ins = genGetInsForOper(tree->OperGet(), targetType);
+
+ // The arithmetic node must be sitting in a register (since it's not contained)
+ assert(!tree->isContained());
+ // The dst can only be a register.
+ assert(targetReg != REG_NA);
+
+ GenTreePtr operand = tree->gtGetOp1();
+ assert(!operand->isContained());
+ // The src must be a register.
+ regNumber operandReg = genConsumeReg(operand);
+
+ if (ins == INS_vneg)
{
- getEmitter()->emitDisableGC();
+ getEmitter()->emitIns_R_R(ins, emitTypeSize(tree), targetReg, operandReg);
}
- bool isCopyBlk = blkOp->OperIsCopyBlkOp();
+ else
+ {
+ getEmitter()->emitIns_R_R_I(ins, emitTypeSize(tree), targetReg, operandReg, 0);
+ }
+
+ genProduceReg(tree);
+}
- switch (blkOp->gtBlkOpKind)
+// Generate code for CpObj nodes wich copy structs that have interleaved
+// GC pointers.
+// For this case we'll generate a sequence of loads/stores in the case of struct
+// slots that don't contain GC pointers. The generated code will look like:
+// ldr tempReg, [R13, #8]
+// str tempReg, [R14, #8]
+//
+// In the case of a GC-Pointer we'll call the ByRef write barrier helper
+// who happens to use the same registers as the previous call to maintain
+// the same register requirements and register killsets:
+// bl CORINFO_HELP_ASSIGN_BYREF
+//
+// So finally an example would look like this:
+// ldr tempReg, [R13, #8]
+// str tempReg, [R14, #8]
+// bl CORINFO_HELP_ASSIGN_BYREF
+// ldr tempReg, [R13, #8]
+// str tempReg, [R14, #8]
+// bl CORINFO_HELP_ASSIGN_BYREF
+// ldr tempReg, [R13, #8]
+// str tempReg, [R14, #8]
+void CodeGen::genCodeForCpObj(GenTreeObj* cpObjNode)
+{
+ GenTreePtr dstAddr = cpObjNode->Addr();
+ GenTreePtr source = cpObjNode->Data();
+ var_types srcAddrType = TYP_BYREF;
+ bool sourceIsLocal = false;
+ regNumber dstReg = REG_NA;
+ regNumber srcReg = REG_NA;
+
+ assert(source->isContained());
+ if (source->gtOper == GT_IND)
{
- case GenTreeBlk::BlkOpKindHelper:
- if (isCopyBlk)
- {
- genCodeForCpBlk(blkOp);
- }
- else
- {
- genCodeForInitBlk(blkOp);
- }
- break;
- case GenTreeBlk::BlkOpKindUnroll:
- if (isCopyBlk)
- {
- genCodeForCpBlkUnroll(blkOp);
- }
- else
- {
- genCodeForInitBlkUnroll(blkOp);
- }
- break;
- default:
- unreached();
+ GenTree* srcAddr = source->gtGetOp1();
+ assert(!srcAddr->isContained());
+ srcAddrType = srcAddr->TypeGet();
+ }
+ else
+ {
+ noway_assert(source->IsLocal());
+ sourceIsLocal = true;
+ }
+
+ bool dstOnStack = dstAddr->OperIsLocalAddr();
+
+#ifdef DEBUG
+ assert(!dstAddr->isContained());
+
+ // This GenTree node has data about GC pointers, this means we're dealing
+ // with CpObj.
+ assert(cpObjNode->gtGcPtrCount > 0);
+#endif // DEBUG
+
+ // Consume the operands and get them into the right registers.
+ // They may now contain gc pointers (depending on their type; gcMarkRegPtrVal will "do the right thing").
+ genConsumeBlockOp(cpObjNode, REG_WRITE_BARRIER_DST_BYREF, REG_WRITE_BARRIER_SRC_BYREF, REG_NA);
+ gcInfo.gcMarkRegPtrVal(REG_WRITE_BARRIER_SRC_BYREF, srcAddrType);
+ gcInfo.gcMarkRegPtrVal(REG_WRITE_BARRIER_DST_BYREF, dstAddr->TypeGet());
+
+ // Temp register used to perform the sequence of loads and stores.
+ regNumber tmpReg = cpObjNode->ExtractTempReg();
+ assert(genIsValidIntReg(tmpReg));
+
+ unsigned slots = cpObjNode->gtSlots;
+ emitter* emit = getEmitter();
+
+ BYTE* gcPtrs = cpObjNode->gtGcPtrs;
+
+ // If we can prove it's on the stack we don't need to use the write barrier.
+ emitAttr attr = EA_PTRSIZE;
+ if (dstOnStack)
+ {
+ for (unsigned i = 0; i < slots; ++i)
+ {
+ if (gcPtrs[i] == GCT_GCREF)
+ attr = EA_GCREF;
+ else if (gcPtrs[i] == GCT_BYREF)
+ attr = EA_BYREF;
+ emit->emitIns_R_R_I(INS_ldr, attr, tmpReg, REG_WRITE_BARRIER_SRC_BYREF, TARGET_POINTER_SIZE,
+ INS_FLAGS_DONT_CARE, INS_OPTS_LDST_POST_INC);
+ emit->emitIns_R_R_I(INS_str, attr, tmpReg, REG_WRITE_BARRIER_DST_BYREF, TARGET_POINTER_SIZE,
+ INS_FLAGS_DONT_CARE, INS_OPTS_LDST_POST_INC);
+ }
}
- if (blkOp->gtBlkOpGcUnsafe)
+ else
{
- getEmitter()->emitEnableGC();
+ unsigned gcPtrCount = cpObjNode->gtGcPtrCount;
+
+ unsigned i = 0;
+ while (i < slots)
+ {
+ switch (gcPtrs[i])
+ {
+ case TYPE_GC_NONE:
+ emit->emitIns_R_R_I(INS_ldr, attr, tmpReg, REG_WRITE_BARRIER_SRC_BYREF, TARGET_POINTER_SIZE,
+ INS_FLAGS_DONT_CARE, INS_OPTS_LDST_POST_INC);
+ emit->emitIns_R_R_I(INS_str, attr, tmpReg, REG_WRITE_BARRIER_DST_BYREF, TARGET_POINTER_SIZE,
+ INS_FLAGS_DONT_CARE, INS_OPTS_LDST_POST_INC);
+ break;
+
+ default:
+ // In the case of a GC-Pointer we'll call the ByRef write barrier helper
+ genEmitHelperCall(CORINFO_HELP_ASSIGN_BYREF, 0, EA_PTRSIZE);
+
+ gcPtrCount--;
+ break;
+ }
+ ++i;
+ }
+ assert(gcPtrCount == 0);
}
+
+ // Clear the gcInfo for registers of source and dest.
+ // While we normally update GC info prior to the last instruction that uses them,
+ // these actually live into the helper call.
+ gcInfo.gcMarkRegSetNpt(RBM_WRITE_BARRIER_SRC_BYREF | RBM_WRITE_BARRIER_DST_BYREF);
}
//------------------------------------------------------------------------
@@ -1614,6 +1002,155 @@ void CodeGen::genCodeForShiftLong(GenTreePtr tree)
}
//------------------------------------------------------------------------
+// genCodeForLclVar: Produce code for a GT_LCL_VAR node.
+//
+// Arguments:
+// tree - the GT_LCL_VAR node
+//
+void CodeGen::genCodeForLclVar(GenTreeLclVar* tree)
+{
+ // lcl_vars are not defs
+ assert((tree->gtFlags & GTF_VAR_DEF) == 0);
+
+ bool isRegCandidate = compiler->lvaTable[tree->gtLclNum].lvIsRegCandidate();
+
+ if (isRegCandidate && !(tree->gtFlags & GTF_VAR_DEATH))
+ {
+ assert((tree->InReg()) || (tree->gtFlags & GTF_SPILLED));
+ }
+
+ // If this is a register candidate that has been spilled, genConsumeReg() will
+ // reload it at the point of use. Otherwise, if it's not in a register, we load it here.
+
+ if (!tree->InReg() && !(tree->gtFlags & GTF_SPILLED))
+ {
+ assert(!isRegCandidate);
+ getEmitter()->emitIns_R_S(ins_Load(tree->TypeGet()), emitTypeSize(tree), tree->gtRegNum, tree->gtLclNum, 0);
+ genProduceReg(tree);
+ }
+}
+
+//------------------------------------------------------------------------
+// genCodeForStoreLclFld: Produce code for a GT_STORE_LCL_FLD node.
+//
+// Arguments:
+// tree - the GT_STORE_LCL_FLD node
+//
+void CodeGen::genCodeForStoreLclFld(GenTreeLclFld* tree)
+{
+ var_types targetType = tree->TypeGet();
+ regNumber targetReg = tree->gtRegNum;
+ emitter* emit = getEmitter();
+
+ noway_assert(targetType != TYP_STRUCT);
+
+ // record the offset
+ unsigned offset = tree->gtLclOffs;
+
+ // We must have a stack store with GT_STORE_LCL_FLD
+ noway_assert(!tree->InReg());
+ noway_assert(targetReg == REG_NA);
+
+ unsigned varNum = tree->gtLclNum;
+ assert(varNum < compiler->lvaCount);
+ LclVarDsc* varDsc = &(compiler->lvaTable[varNum]);
+
+ // Ensure that lclVar nodes are typed correctly.
+ assert(!varDsc->lvNormalizeOnStore() || targetType == genActualType(varDsc->TypeGet()));
+
+ GenTreePtr data = tree->gtOp1->gtEffectiveVal();
+ instruction ins = ins_Store(targetType);
+ emitAttr attr = emitTypeSize(targetType);
+ if (data->isContainedIntOrIImmed())
+ {
+ assert(data->IsIntegralConst(0));
+ NYI_ARM("st.lclFld contained operand");
+ }
+ else
+ {
+ assert(!data->isContained());
+ genConsumeReg(data);
+ emit->emitIns_S_R(ins, attr, data->gtRegNum, varNum, offset);
+ }
+
+ genUpdateLife(tree);
+ varDsc->lvRegNum = REG_STK;
+}
+
+//------------------------------------------------------------------------
+// genCodeForStoreLclVar: Produce code for a GT_STORE_LCL_VAR node.
+//
+// Arguments:
+// tree - the GT_STORE_LCL_VAR node
+//
+void CodeGen::genCodeForStoreLclVar(GenTreeLclVar* tree)
+{
+ var_types targetType = tree->TypeGet();
+ regNumber targetReg = tree->gtRegNum;
+ emitter* emit = getEmitter();
+
+ unsigned varNum = tree->gtLclNum;
+ assert(varNum < compiler->lvaCount);
+ LclVarDsc* varDsc = &(compiler->lvaTable[varNum]);
+
+ // Ensure that lclVar nodes are typed correctly.
+ assert(!varDsc->lvNormalizeOnStore() || targetType == genActualType(varDsc->TypeGet()));
+
+ GenTreePtr data = tree->gtOp1->gtEffectiveVal();
+
+ // var = call, where call returns a multi-reg return value
+ // case is handled separately.
+ if (data->gtSkipReloadOrCopy()->IsMultiRegCall())
+ {
+ genMultiRegCallStoreToLocal(tree);
+ }
+ else if (tree->TypeGet() == TYP_LONG)
+ {
+ genStoreLongLclVar(tree);
+ }
+ else
+ {
+ genConsumeRegs(data);
+
+ regNumber dataReg = REG_NA;
+ if (data->isContainedIntOrIImmed())
+ {
+ assert(data->IsIntegralConst(0));
+ NYI_ARM("st.lclVar contained operand");
+ }
+ else
+ {
+ assert(!data->isContained());
+ dataReg = data->gtRegNum;
+ }
+ assert(dataReg != REG_NA);
+
+ if (targetReg == REG_NA) // store into stack based LclVar
+ {
+ inst_set_SV_var(tree);
+
+ instruction ins = ins_Store(targetType);
+ emitAttr attr = emitTypeSize(targetType);
+
+ emit->emitIns_S_R(ins, attr, dataReg, varNum, /* offset */ 0);
+
+ genUpdateLife(tree);
+
+ varDsc->lvRegNum = REG_STK;
+ }
+ else // store into register (i.e move into register)
+ {
+ if (dataReg != targetReg)
+ {
+ // Assign into targetReg when dataReg (from op1) is not the same register
+ inst_RV_RV(ins_Copy(targetType), targetReg, dataReg, targetType);
+ }
+ genProduceReg(tree);
+ }
+ }
+}
+
+//------------------------------------------------------------------------
// genLeaInstruction: Produce code for a GT_LEA subnode.
//
void CodeGen::genLeaInstruction(GenTreeAddrMode* lea)
@@ -1641,6 +1178,254 @@ void CodeGen::genLeaInstruction(GenTreeAddrMode* lea)
}
//------------------------------------------------------------------------
+// genCodeForDivMod: Produce code for a GT_DIV/GT_UDIV/GT_MOD/GT_UMOD node.
+//
+// Arguments:
+// tree - the node
+//
+void CodeGen::genCodeForDivMod(GenTreeOp* tree)
+{
+ assert(tree->OperIs(GT_DIV, GT_UDIV, GT_MOD, GT_UMOD));
+
+ // We shouldn't be seeing GT_MOD on float/double args as it should get morphed into a
+ // helper call by front-end. Similarly we shouldn't be seeing GT_UDIV and GT_UMOD
+ // on float/double args.
+ noway_assert(tree->OperIs(GT_DIV) || !varTypeIsFloating(tree));
+
+ var_types targetType = tree->TypeGet();
+ regNumber targetReg = tree->gtRegNum;
+ emitter* emit = getEmitter();
+
+ genConsumeOperands(tree);
+
+ noway_assert(targetReg != REG_NA);
+
+ GenTreePtr dst = tree;
+ GenTreePtr src1 = tree->gtGetOp1();
+ GenTreePtr src2 = tree->gtGetOp2();
+ instruction ins = genGetInsForOper(tree->OperGet(), targetType);
+ emitAttr attr = emitTypeSize(tree);
+ regNumber result = REG_NA;
+
+ // dst can only be a reg
+ assert(!dst->isContained());
+
+ // src can be only reg
+ assert(!src1->isContained() || !src2->isContained());
+
+ if (varTypeIsFloating(targetType))
+ {
+ // Floating point divide never raises an exception
+
+ emit->emitIns_R_R_R(ins, attr, dst->gtRegNum, src1->gtRegNum, src2->gtRegNum);
+ }
+ else // an signed integer divide operation
+ {
+ // TODO-ARM-Bug: handle zero division exception.
+
+ emit->emitIns_R_R_R(ins, attr, dst->gtRegNum, src1->gtRegNum, src2->gtRegNum);
+ }
+
+ genProduceReg(tree);
+}
+
+//------------------------------------------------------------------------
+// genCodeForCompare: Produce code for a GT_EQ/GT_NE/GT_LT/GT_LE/GT_GE/GT_GT node.
+//
+// Arguments:
+// tree - the node
+//
+void CodeGen::genCodeForCompare(GenTreeOp* tree)
+{
+ // TODO-ARM-CQ: Check if we can use the currently set flags.
+ // TODO-ARM-CQ: Check for the case where we can simply transfer the carry bit to a register
+ // (signed < or >= where targetReg != REG_NA)
+
+ GenTreePtr op1 = tree->gtOp1->gtEffectiveVal();
+ GenTreePtr op2 = tree->gtOp2->gtEffectiveVal();
+
+ if (varTypeIsLong(op1))
+ {
+#ifdef DEBUG
+ // The result of an unlowered long compare on a 32-bit target must either be
+ // a) materialized into a register, or
+ // b) unused.
+ //
+ // A long compare that has a result that is used but not materialized into a register should
+ // have been handled by Lowering::LowerCompare.
+
+ LIR::Use use;
+ assert((tree->gtRegNum != REG_NA) || !LIR::AsRange(compiler->compCurBB).TryGetUse(tree, &use));
+#endif
+ genCompareLong(tree);
+ }
+ else
+ {
+ regNumber targetReg = tree->gtRegNum;
+ emitter* emit = getEmitter();
+ emitAttr cmpAttr;
+
+ genConsumeIfReg(op1);
+ genConsumeIfReg(op2);
+
+ if (varTypeIsFloating(op1))
+ {
+ assert(op1->TypeGet() == op2->TypeGet());
+ instruction ins = INS_vcmp;
+ cmpAttr = emitTypeSize(op1->TypeGet());
+ emit->emitInsBinary(ins, cmpAttr, op1, op2);
+ // vmrs with register 0xf has special meaning of transferring flags
+ emit->emitIns_R(INS_vmrs, EA_4BYTE, REG_R15);
+ }
+ else
+ {
+ var_types op1Type = op1->TypeGet();
+ var_types op2Type = op2->TypeGet();
+ assert(!varTypeIsFloating(op2Type));
+ instruction ins = INS_cmp;
+ if (op1Type == op2Type)
+ {
+ cmpAttr = emitTypeSize(op1Type);
+ }
+ else
+ {
+ var_types cmpType = TYP_INT;
+ bool op1Is64Bit = (varTypeIsLong(op1Type) || op1Type == TYP_REF);
+ bool op2Is64Bit = (varTypeIsLong(op2Type) || op2Type == TYP_REF);
+ NYI_IF(op1Is64Bit || op2Is64Bit, "Long compare");
+ assert(!op1->isUsedFromMemory() || op1Type == op2Type);
+ assert(!op2->isUsedFromMemory() || op1Type == op2Type);
+ cmpAttr = emitTypeSize(cmpType);
+ }
+ emit->emitInsBinary(ins, cmpAttr, op1, op2);
+ }
+
+ // Are we evaluating this into a register?
+ if (targetReg != REG_NA)
+ {
+ genSetRegToCond(targetReg, tree);
+ genProduceReg(tree);
+ }
+ }
+}
+
+//------------------------------------------------------------------------
+// genCodeForJcc: Produce code for a GT_JCC node.
+//
+// Arguments:
+// tree - the node
+//
+void CodeGen::genCodeForJcc(GenTreeJumpCC* tree)
+{
+ assert(compiler->compCurBB->bbJumpKind == BBJ_COND);
+
+ CompareKind compareKind = ((tree->gtFlags & GTF_UNSIGNED) != 0) ? CK_UNSIGNED : CK_SIGNED;
+ emitJumpKind jumpKind = genJumpKindForOper(tree->gtCondition, compareKind);
+
+ inst_JMP(jumpKind, compiler->compCurBB->bbJumpDest);
+}
+
+//------------------------------------------------------------------------
+// genCodeForReturnTrap: Produce code for a GT_RETURNTRAP node.
+//
+// Arguments:
+// tree - the GT_RETURNTRAP node
+//
+void CodeGen::genCodeForReturnTrap(GenTreeOp* tree)
+{
+ assert(tree->OperGet() == GT_RETURNTRAP);
+
+ // this is nothing but a conditional call to CORINFO_HELP_STOP_FOR_GC
+ // based on the contents of 'data'
+
+ GenTree* data = tree->gtOp1->gtEffectiveVal();
+ genConsumeIfReg(data);
+ GenTreeIntCon cns = intForm(TYP_INT, 0);
+ getEmitter()->emitInsBinary(INS_cmp, emitTypeSize(TYP_INT), data, &cns);
+
+ BasicBlock* skipLabel = genCreateTempLabel();
+
+ emitJumpKind jmpEqual = genJumpKindForOper(GT_EQ, CK_SIGNED);
+ inst_JMP(jmpEqual, skipLabel);
+ // emit the call to the EE-helper that stops for GC (or other reasons)
+
+ genEmitHelperCall(CORINFO_HELP_STOP_FOR_GC, 0, EA_UNKNOWN);
+ genDefineTempLabel(skipLabel);
+}
+
+//------------------------------------------------------------------------
+// genCodeForStoreInd: Produce code for a GT_STOREIND node.
+//
+// Arguments:
+// tree - the GT_STOREIND node
+//
+void CodeGen::genCodeForStoreInd(GenTreeStoreInd* tree)
+{
+ GenTree* data = tree->Data();
+ GenTree* addr = tree->Addr();
+ var_types targetType = tree->TypeGet();
+ emitter* emit = getEmitter();
+
+ assert(!varTypeIsFloating(targetType) || (targetType == data->TypeGet()));
+
+ GCInfo::WriteBarrierForm writeBarrierForm = gcInfo.gcIsWriteBarrierCandidate(tree, data);
+ if (writeBarrierForm != GCInfo::WBF_NoBarrier)
+ {
+ // data and addr must be in registers.
+ // Consume both registers so that any copies of interfering
+ // registers are taken care of.
+ genConsumeOperands(tree);
+
+#if NOGC_WRITE_BARRIERS
+ NYI_ARM("NOGC_WRITE_BARRIERS");
+#else
+ // At this point, we should not have any interference.
+ // That is, 'data' must not be in REG_ARG_0,
+ // as that is where 'addr' must go.
+ noway_assert(data->gtRegNum != REG_ARG_0);
+
+ // addr goes in REG_ARG_0
+ if (addr->gtRegNum != REG_ARG_0)
+ {
+ inst_RV_RV(INS_mov, REG_ARG_0, addr->gtRegNum, addr->TypeGet());
+ }
+
+ // data goes in REG_ARG_1
+ if (data->gtRegNum != REG_ARG_1)
+ {
+ inst_RV_RV(INS_mov, REG_ARG_1, data->gtRegNum, data->TypeGet());
+ }
+#endif // NOGC_WRITE_BARRIERS
+
+ genGCWriteBarrier(tree, writeBarrierForm);
+ }
+ else // A normal store, not a WriteBarrier store
+ {
+ bool reverseOps = ((tree->gtFlags & GTF_REVERSE_OPS) != 0);
+ bool dataIsUnary = false;
+
+ // We must consume the operands in the proper execution order,
+ // so that liveness is updated appropriately.
+ if (!reverseOps)
+ {
+ genConsumeAddress(addr);
+ }
+
+ if (!data->isContained())
+ {
+ genConsumeRegs(data);
+ }
+
+ if (reverseOps)
+ {
+ genConsumeAddress(addr);
+ }
+
+ emit->emitInsLoadStoreOp(ins_Store(targetType), emitTypeSize(tree), data->gtRegNum, tree);
+ }
+}
+
+//------------------------------------------------------------------------
// genCompareLong: Generate code for comparing two longs when the result of the compare
// is manifested in a register.
//
diff --git a/src/jit/codegenarm64.cpp b/src/jit/codegenarm64.cpp
index 7de19f9..0aa1421 100644
--- a/src/jit/codegenarm64.cpp
+++ b/src/jit/codegenarm64.cpp
@@ -1366,18 +1366,59 @@ void CodeGen::instGen_Set_Reg_To_Imm(emitAttr size, regNumber reg, ssize_t imm,
}
else
{
- getEmitter()->emitIns_R_I(INS_mov, size, reg, (imm & 0xffff));
- getEmitter()->emitIns_R_I_I(INS_movk, size, reg, ((imm >> 16) & 0xffff), 16, INS_OPTS_LSL);
+ // Arm64 allows any arbitrary 16-bit constant to be loaded into a register halfword
+ // There are three forms
+ // movk which loads into any halfword preserving the remaining halfwords
+ // movz which loads into any halfword zeroing the remaining halfwords
+ // movn which loads into any halfword zeroing the remaining halfwords then bitwise inverting the register
+ // In some cases it is preferable to use movn, because it has the side effect of filling the other halfwords
+ // with ones
+
+ // Determine whether movn or movz will require the fewest instructions to populate the immediate
+ int preferMovn = 0;
+
+ for (int i = (size == EA_8BYTE) ? 48 : 16; i >= 0; i -= 16)
+ {
+ if (uint16_t(imm >> i) == 0xffff)
+ ++preferMovn; // a single movk 0xffff could be skipped if movn was used
+ else if (uint16_t(imm >> i) == 0x0000)
+ --preferMovn; // a single movk 0 could be skipped if movz was used
+ }
+
+ // Select the first instruction. Any additional instruction will use movk
+ instruction ins = (preferMovn > 0) ? INS_movn : INS_movz;
- if ((size == EA_8BYTE) &&
- ((imm >> 32) != 0)) // Sometimes the upper 32 bits are zero and the first mov has zero-ed them
+ // Initial movz or movn will fill the remaining bytes with the skipVal
+ // This can allow skipping filling a halfword
+ uint16_t skipVal = (preferMovn > 0) ? 0xffff : 0;
+
+ unsigned bits = (size == EA_8BYTE) ? 64 : 32;
+
+ // Iterate over imm examining 16 bits at a time
+ for (unsigned i = 0; i < bits; i += 16)
{
- getEmitter()->emitIns_R_I_I(INS_movk, EA_8BYTE, reg, ((imm >> 32) & 0xffff), 32, INS_OPTS_LSL);
- if ((imm >> 48) != 0) // Frequently the upper 16 bits are zero and the first mov has zero-ed them
+ uint16_t imm16 = uint16_t(imm >> i);
+
+ if (imm16 != skipVal)
{
- getEmitter()->emitIns_R_I_I(INS_movk, EA_8BYTE, reg, ((imm >> 48) & 0xffff), 48, INS_OPTS_LSL);
+ if (ins == INS_movn)
+ {
+ // For the movn case, we need to bitwise invert the immediate. This is because
+ // (movn x0, ~imm16) === (movz x0, imm16; or x0, x0, #0xffff`ffff`ffff`0000)
+ imm16 = ~imm16;
+ }
+
+ getEmitter()->emitIns_R_I_I(ins, size, reg, imm16, i, INS_OPTS_LSL);
+
+ // Once the initial movz/movn is emitted the remaining instructions will all use movk
+ ins = INS_movk;
}
}
+
+ // We must emit a movn or movz or we have not done anything
+ // The cases which hit this assert should be (emitIns_valid_imm_for_mov() == true) and
+ // should not be in this else condition
+ assert(ins == INS_movk);
}
// The caller may have requested that the flags be set on this mov (rarely/never)
if (flags == INS_FLAGS_SET)
@@ -1503,18 +1544,13 @@ void CodeGen::genCodeForMulHi(GenTreeOp* treeNode)
{
inst_RV_RV(INS_mov, targetReg, REG_RDX, targetType);
}
+
+ genProduceReg(treeNode);
#else // !0
NYI("genCodeForMulHi");
#endif // !0
}
-// generate code for a DIV or MOD operation
-//
-void CodeGen::genCodeForDivMod(GenTreeOp* treeNode)
-{
- // unused on ARM64
-}
-
// Generate code for ADD, SUB, MUL, DIV, UDIV, AND, OR and XOR
// This method is expected to have called genConsumeOperands() before calling it.
void CodeGen::genCodeForBinary(GenTree* treeNode)
@@ -1541,6 +1577,177 @@ void CodeGen::genCodeForBinary(GenTree* treeNode)
}
//------------------------------------------------------------------------
+// genCodeForLclVar: Produce code for a GT_LCL_VAR node.
+//
+// Arguments:
+// tree - the GT_LCL_VAR node
+//
+void CodeGen::genCodeForLclVar(GenTreeLclVar* tree)
+{
+ var_types targetType = tree->TypeGet();
+ emitter* emit = getEmitter();
+
+ unsigned varNum = tree->gtLclNum;
+ assert(varNum < compiler->lvaCount);
+ LclVarDsc* varDsc = &(compiler->lvaTable[varNum]);
+ bool isRegCandidate = varDsc->lvIsRegCandidate();
+
+ // lcl_vars are not defs
+ assert((tree->gtFlags & GTF_VAR_DEF) == 0);
+
+ if (isRegCandidate && !(tree->gtFlags & GTF_VAR_DEATH))
+ {
+ assert((tree->InReg()) || (tree->gtFlags & GTF_SPILLED));
+ }
+
+ // If this is a register candidate that has been spilled, genConsumeReg() will
+ // reload it at the point of use. Otherwise, if it's not in a register, we load it here.
+
+ if (!tree->InReg() && !(tree->gtFlags & GTF_SPILLED))
+ {
+ assert(!isRegCandidate);
+
+ // targetType must be a normal scalar type and not a TYP_STRUCT
+ assert(targetType != TYP_STRUCT);
+
+ instruction ins = ins_Load(targetType);
+ emitAttr attr = emitTypeSize(targetType);
+
+ attr = emit->emitInsAdjustLoadStoreAttr(ins, attr);
+
+ emit->emitIns_R_S(ins, attr, tree->gtRegNum, varNum, 0);
+ genProduceReg(tree);
+ }
+}
+
+//------------------------------------------------------------------------
+// genCodeForStoreLclFld: Produce code for a GT_STORE_LCL_FLD node.
+//
+// Arguments:
+// tree - the GT_STORE_LCL_FLD node
+//
+void CodeGen::genCodeForStoreLclFld(GenTreeLclFld* tree)
+{
+ var_types targetType = tree->TypeGet();
+ regNumber targetReg = tree->gtRegNum;
+ emitter* emit = getEmitter();
+ noway_assert(targetType != TYP_STRUCT);
+
+ // record the offset
+ unsigned offset = tree->gtLclOffs;
+
+ // We must have a stack store with GT_STORE_LCL_FLD
+ noway_assert(!tree->InReg());
+ noway_assert(targetReg == REG_NA);
+
+ unsigned varNum = tree->gtLclNum;
+ assert(varNum < compiler->lvaCount);
+ LclVarDsc* varDsc = &(compiler->lvaTable[varNum]);
+
+ // Ensure that lclVar nodes are typed correctly.
+ assert(!varDsc->lvNormalizeOnStore() || targetType == genActualType(varDsc->TypeGet()));
+
+ GenTreePtr data = tree->gtOp1->gtEffectiveVal();
+ genConsumeRegs(data);
+
+ regNumber dataReg = REG_NA;
+ if (data->isContainedIntOrIImmed())
+ {
+ assert(data->IsIntegralConst(0));
+ dataReg = REG_ZR;
+ }
+ else
+ {
+ assert(!data->isContained());
+ dataReg = data->gtRegNum;
+ }
+ assert(dataReg != REG_NA);
+
+ instruction ins = ins_Store(targetType);
+
+ emitAttr attr = emitTypeSize(targetType);
+
+ attr = emit->emitInsAdjustLoadStoreAttr(ins, attr);
+
+ emit->emitIns_S_R(ins, attr, dataReg, varNum, offset);
+
+ genUpdateLife(tree);
+
+ varDsc->lvRegNum = REG_STK;
+}
+
+//------------------------------------------------------------------------
+// genCodeForStoreLclVar: Produce code for a GT_STORE_LCL_VAR node.
+//
+// Arguments:
+// tree - the GT_STORE_LCL_VAR node
+//
+void CodeGen::genCodeForStoreLclVar(GenTreeLclVar* tree)
+{
+ var_types targetType = tree->TypeGet();
+ regNumber targetReg = tree->gtRegNum;
+ emitter* emit = getEmitter();
+
+ unsigned varNum = tree->gtLclNum;
+ assert(varNum < compiler->lvaCount);
+ LclVarDsc* varDsc = &(compiler->lvaTable[varNum]);
+
+ // Ensure that lclVar nodes are typed correctly.
+ assert(!varDsc->lvNormalizeOnStore() || targetType == genActualType(varDsc->TypeGet()));
+
+ GenTreePtr data = tree->gtOp1->gtEffectiveVal();
+
+ // var = call, where call returns a multi-reg return value
+ // case is handled separately.
+ if (data->gtSkipReloadOrCopy()->IsMultiRegCall())
+ {
+ genMultiRegCallStoreToLocal(tree);
+ }
+ else
+ {
+ genConsumeRegs(data);
+
+ regNumber dataReg = REG_NA;
+ if (data->isContainedIntOrIImmed())
+ {
+ assert(data->IsIntegralConst(0));
+ dataReg = REG_ZR;
+ }
+ else
+ {
+ assert(!data->isContained());
+ dataReg = data->gtRegNum;
+ }
+ assert(dataReg != REG_NA);
+
+ if (targetReg == REG_NA) // store into stack based LclVar
+ {
+ inst_set_SV_var(tree);
+
+ instruction ins = ins_Store(targetType);
+ emitAttr attr = emitTypeSize(targetType);
+
+ attr = emit->emitInsAdjustLoadStoreAttr(ins, attr);
+
+ emit->emitIns_S_R(ins, attr, dataReg, varNum, /* offset */ 0);
+
+ genUpdateLife(tree);
+
+ varDsc->lvRegNum = REG_STK;
+ }
+ else // store into register (i.e move into register)
+ {
+ if (dataReg != targetReg)
+ {
+ // Assign into targetReg when dataReg (from op1) is not the same register
+ inst_RV_RV(ins_Copy(targetType), targetReg, dataReg, targetType);
+ }
+ genProduceReg(tree);
+ }
+ }
+}
+
+//------------------------------------------------------------------------
// isStructReturn: Returns whether the 'treeNode' is returning a struct.
//
// Arguments:
@@ -1771,6 +1978,11 @@ void CodeGen::genReturn(GenTreePtr treeNode)
GenTreePtr op1 = treeNode->gtGetOp1();
var_types targetType = treeNode->TypeGet();
+ // A void GT_RETFILT is the end of a finally. For non-void filter returns we need to load the result in the return
+ // register, if it's not already there. The processing is the same as GT_RETURN. For filters, the IL spec says the
+ // result is type int32. Further, the only legal values are 0 or 1; the use of other values is "undefined".
+ assert(!treeNode->OperIs(GT_RETFILT) || (targetType == TYP_VOID) || (targetType == TYP_INT));
+
#ifdef DEBUG
if (targetType == TYP_VOID)
{
@@ -1840,985 +2052,6 @@ void CodeGen::genReturn(GenTreePtr treeNode)
#endif
}
-/*****************************************************************************
- *
- * Generate code for a single node in the tree.
- * Preconditions: All operands have been evaluated
- *
- */
-void CodeGen::genCodeForTreeNode(GenTreePtr treeNode)
-{
- regNumber targetReg = treeNode->gtRegNum;
- var_types targetType = treeNode->TypeGet();
- emitter* emit = getEmitter();
-
-#ifdef DEBUG
- // Validate that all the operands for the current node are consumed in order.
- // This is important because LSRA ensures that any necessary copies will be
- // handled correctly.
- lastConsumedNode = nullptr;
- if (compiler->verbose)
- {
- unsigned seqNum = treeNode->gtSeqNum; // Useful for setting a conditional break in Visual Studio
- compiler->gtDispLIRNode(treeNode, "Generating: ");
- }
-#endif // DEBUG
-
- // Is this a node whose value is already in a register? LSRA denotes this by
- // setting the GTF_REUSE_REG_VAL flag.
- if (treeNode->IsReuseRegVal())
- {
- // For now, this is only used for constant nodes.
- assert((treeNode->OperGet() == GT_CNS_INT) || (treeNode->OperGet() == GT_CNS_DBL));
- JITDUMP(" TreeNode is marked ReuseReg\n");
- return;
- }
-
- // contained nodes are part of their parents for codegen purposes
- // ex : immediates, most LEAs
- if (treeNode->isContained())
- {
- return;
- }
-
- switch (treeNode->gtOper)
- {
- case GT_START_NONGC:
- getEmitter()->emitDisableGC();
- break;
-
- case GT_PROF_HOOK:
- // We should be seeing this only if profiler hook is needed
- noway_assert(compiler->compIsProfilerHookNeeded());
-
-#ifdef PROFILING_SUPPORTED
- // Right now this node is used only for tail calls. In future if
- // we intend to use it for Enter or Leave hooks, add a data member
- // to this node indicating the kind of profiler hook. For example,
- // helper number can be used.
- genProfilingLeaveCallback(CORINFO_HELP_PROF_FCN_TAILCALL);
-#endif // PROFILING_SUPPORTED
- break;
-
- case GT_LCLHEAP:
- genLclHeap(treeNode);
- break;
-
- case GT_CNS_INT:
- case GT_CNS_DBL:
- genSetRegToConst(targetReg, targetType, treeNode);
- genProduceReg(treeNode);
- break;
-
- case GT_NOT:
- assert(!varTypeIsFloating(targetType));
-
- __fallthrough;
-
- case GT_NEG:
- {
- instruction ins = genGetInsForOper(treeNode->OperGet(), targetType);
-
- // The arithmetic node must be sitting in a register (since it's not contained)
- assert(!treeNode->isContained());
- // The dst can only be a register.
- assert(targetReg != REG_NA);
-
- GenTreePtr operand = treeNode->gtGetOp1();
- assert(!operand->isContained());
- // The src must be a register.
- regNumber operandReg = genConsumeReg(operand);
-
- getEmitter()->emitIns_R_R(ins, emitTypeSize(treeNode), targetReg, operandReg);
- }
- genProduceReg(treeNode);
- break;
-
- case GT_DIV:
- case GT_UDIV:
- genConsumeOperands(treeNode->AsOp());
-
- if (varTypeIsFloating(targetType))
- {
- // Floating point divide never raises an exception
- genCodeForBinary(treeNode);
- }
- else // an integer divide operation
- {
- GenTreePtr divisorOp = treeNode->gtGetOp2();
- emitAttr size = EA_ATTR(genTypeSize(genActualType(treeNode->TypeGet())));
-
- if (divisorOp->IsIntegralConst(0))
- {
- // We unconditionally throw a divide by zero exception
- genJumpToThrowHlpBlk(EJ_jmp, SCK_DIV_BY_ZERO);
-
- // We still need to call genProduceReg
- genProduceReg(treeNode);
- }
- else // the divisor is not the constant zero
- {
- regNumber divisorReg = divisorOp->gtRegNum;
-
- // Generate the require runtime checks for GT_DIV or GT_UDIV
- if (treeNode->gtOper == GT_DIV)
- {
- BasicBlock* sdivLabel = genCreateTempLabel();
-
- // Two possible exceptions:
- // (AnyVal / 0) => DivideByZeroException
- // (MinInt / -1) => ArithmeticException
- //
- bool checkDividend = true;
-
- // Do we have an immediate for the 'divisorOp'?
- //
- if (divisorOp->IsCnsIntOrI())
- {
- GenTreeIntConCommon* intConstTree = divisorOp->AsIntConCommon();
- ssize_t intConstValue = intConstTree->IconValue();
- assert(intConstValue != 0); // already checked above by IsIntegralConst(0))
- if (intConstValue != -1)
- {
- checkDividend = false; // We statically know that the dividend is not -1
- }
- }
- else // insert check for divison by zero
- {
- // Check if the divisor is zero throw a DivideByZeroException
- emit->emitIns_R_I(INS_cmp, size, divisorReg, 0);
- emitJumpKind jmpEqual = genJumpKindForOper(GT_EQ, CK_SIGNED);
- genJumpToThrowHlpBlk(jmpEqual, SCK_DIV_BY_ZERO);
- }
-
- if (checkDividend)
- {
- // Check if the divisor is not -1 branch to 'sdivLabel'
- emit->emitIns_R_I(INS_cmp, size, divisorReg, -1);
-
- emitJumpKind jmpNotEqual = genJumpKindForOper(GT_NE, CK_SIGNED);
- inst_JMP(jmpNotEqual, sdivLabel);
- // If control flow continues past here the 'divisorReg' is known to be -1
-
- regNumber dividendReg = treeNode->gtGetOp1()->gtRegNum;
- // At this point the divisor is known to be -1
- //
- // Issue the 'adds zr, dividendReg, dividendReg' instruction
- // this will set both the Z and V flags only when dividendReg is MinInt
- //
- emit->emitIns_R_R_R(INS_adds, size, REG_ZR, dividendReg, dividendReg);
- inst_JMP(jmpNotEqual, sdivLabel); // goto sdiv if the Z flag is clear
- genJumpToThrowHlpBlk(EJ_vs, SCK_ARITH_EXCPN); // if the V flags is set throw
- // ArithmeticException
-
- genDefineTempLabel(sdivLabel);
- }
- genCodeForBinary(treeNode); // Generate the sdiv instruction
- }
- else // (treeNode->gtOper == GT_UDIV)
- {
- // Only one possible exception
- // (AnyVal / 0) => DivideByZeroException
- //
- // Note that division by the constant 0 was already checked for above by the
- // op2->IsIntegralConst(0) check
- //
- if (!divisorOp->IsCnsIntOrI())
- {
- // divisorOp is not a constant, so it could be zero
- //
- emit->emitIns_R_I(INS_cmp, size, divisorReg, 0);
- emitJumpKind jmpEqual = genJumpKindForOper(GT_EQ, CK_SIGNED);
- genJumpToThrowHlpBlk(jmpEqual, SCK_DIV_BY_ZERO);
- }
- genCodeForBinary(treeNode);
- }
- }
- }
- break;
-
- case GT_OR:
- case GT_XOR:
- case GT_AND:
- assert(varTypeIsIntegralOrI(treeNode));
- __fallthrough;
- case GT_ADD:
- case GT_SUB:
- case GT_MUL:
- genConsumeOperands(treeNode->AsOp());
- genCodeForBinary(treeNode);
- break;
-
- case GT_LSH:
- case GT_RSH:
- case GT_RSZ:
- case GT_ROR:
- genCodeForShift(treeNode);
- // genCodeForShift() calls genProduceReg()
- break;
-
- case GT_CAST:
- if (varTypeIsFloating(targetType) && varTypeIsFloating(treeNode->gtOp.gtOp1))
- {
- // Casts float/double <--> double/float
- genFloatToFloatCast(treeNode);
- }
- else if (varTypeIsFloating(treeNode->gtOp.gtOp1))
- {
- // Casts float/double --> int32/int64
- genFloatToIntCast(treeNode);
- }
- else if (varTypeIsFloating(targetType))
- {
- // Casts int32/uint32/int64/uint64 --> float/double
- genIntToFloatCast(treeNode);
- }
- else
- {
- // Casts int <--> int
- genIntToIntCast(treeNode);
- }
- // The per-case functions call genProduceReg()
- break;
-
- case GT_LCL_FLD_ADDR:
- case GT_LCL_VAR_ADDR:
- // Address of a local var. This by itself should never be allocated a register.
- // If it is worth storing the address in a register then it should be cse'ed into
- // a temp and that would be allocated a register.
- noway_assert(targetType == TYP_BYREF);
- noway_assert(!treeNode->InReg());
-
- inst_RV_TT(INS_lea, targetReg, treeNode, 0, EA_BYREF);
- genProduceReg(treeNode);
- break;
-
- case GT_LCL_FLD:
- {
- GenTreeLclVarCommon* varNode = treeNode->AsLclVarCommon();
- assert(varNode->gtLclNum < compiler->lvaCount);
- unsigned varNum = varNode->gtLclNum;
- LclVarDsc* varDsc = &(compiler->lvaTable[varNum]);
-
- if (targetType == TYP_STRUCT)
- {
- NYI("GT_LCL_FLD with TYP_STRUCT");
- }
- emitAttr size = emitTypeSize(targetType);
-
- noway_assert(targetType != TYP_STRUCT);
- noway_assert(targetReg != REG_NA);
-
- unsigned offset = treeNode->gtLclFld.gtLclOffs;
-
- if (varTypeIsFloating(targetType))
- {
- if (treeNode->InReg())
- {
- NYI("GT_LCL_FLD with register to register Floating point move");
- }
- else
- {
- emit->emitIns_R_S(ins_Load(targetType), size, targetReg, varNum, offset);
- }
- }
- else
- {
- size = EA_SET_SIZE(size, EA_8BYTE);
- emit->emitIns_R_S(ins_Move_Extend(targetType, treeNode->InReg()), size, targetReg, varNum, offset);
- }
- genProduceReg(treeNode);
- }
- break;
-
- case GT_LCL_VAR:
- {
- GenTreeLclVarCommon* varNode = treeNode->AsLclVarCommon();
-
- unsigned varNum = varNode->gtLclNum;
- assert(varNum < compiler->lvaCount);
- LclVarDsc* varDsc = &(compiler->lvaTable[varNum]);
- bool isRegCandidate = varDsc->lvIsRegCandidate();
-
- // lcl_vars are not defs
- assert((treeNode->gtFlags & GTF_VAR_DEF) == 0);
-
- if (isRegCandidate && !(treeNode->gtFlags & GTF_VAR_DEATH))
- {
- assert((treeNode->InReg()) || (treeNode->gtFlags & GTF_SPILLED));
- }
-
- // If this is a register candidate that has been spilled, genConsumeReg() will
- // reload it at the point of use. Otherwise, if it's not in a register, we load it here.
-
- if (!treeNode->InReg() && !(treeNode->gtFlags & GTF_SPILLED))
- {
- assert(!isRegCandidate);
-
- // targetType must be a normal scalar type and not a TYP_STRUCT
- assert(targetType != TYP_STRUCT);
-
- instruction ins = ins_Load(targetType);
- emitAttr attr = emitTypeSize(targetType);
-
- attr = emit->emitInsAdjustLoadStoreAttr(ins, attr);
-
- emit->emitIns_R_S(ins, attr, targetReg, varNum, 0);
- genProduceReg(treeNode);
- }
- }
- break;
-
- case GT_STORE_LCL_FLD:
- {
- noway_assert(targetType != TYP_STRUCT);
-
- // record the offset
- unsigned offset = treeNode->gtLclFld.gtLclOffs;
-
- // We must have a stack store with GT_STORE_LCL_FLD
- noway_assert(!treeNode->InReg());
- noway_assert(targetReg == REG_NA);
-
- GenTreeLclVarCommon* varNode = treeNode->AsLclVarCommon();
- unsigned varNum = varNode->gtLclNum;
- assert(varNum < compiler->lvaCount);
- LclVarDsc* varDsc = &(compiler->lvaTable[varNum]);
-
- // Ensure that lclVar nodes are typed correctly.
- assert(!varDsc->lvNormalizeOnStore() || targetType == genActualType(varDsc->TypeGet()));
-
- GenTreePtr data = treeNode->gtOp.gtOp1->gtEffectiveVal();
- genConsumeRegs(data);
-
- regNumber dataReg = REG_NA;
- if (data->isContainedIntOrIImmed())
- {
- assert(data->IsIntegralConst(0));
- dataReg = REG_ZR;
- }
- else
- {
- assert(!data->isContained());
- dataReg = data->gtRegNum;
- }
- assert(dataReg != REG_NA);
-
- instruction ins = ins_Store(targetType);
-
- emitAttr attr = emitTypeSize(targetType);
-
- attr = emit->emitInsAdjustLoadStoreAttr(ins, attr);
-
- emit->emitIns_S_R(ins, attr, dataReg, varNum, offset);
-
- genUpdateLife(varNode);
-
- varDsc->lvRegNum = REG_STK;
- }
- break;
-
- case GT_STORE_LCL_VAR:
- {
- GenTreeLclVarCommon* varNode = treeNode->AsLclVarCommon();
-
- unsigned varNum = varNode->gtLclNum;
- assert(varNum < compiler->lvaCount);
- LclVarDsc* varDsc = &(compiler->lvaTable[varNum]);
- unsigned offset = 0;
-
- // Ensure that lclVar nodes are typed correctly.
- assert(!varDsc->lvNormalizeOnStore() || targetType == genActualType(varDsc->TypeGet()));
-
- GenTreePtr data = treeNode->gtOp.gtOp1->gtEffectiveVal();
-
- // var = call, where call returns a multi-reg return value
- // case is handled separately.
- if (data->gtSkipReloadOrCopy()->IsMultiRegCall())
- {
- genMultiRegCallStoreToLocal(treeNode);
- }
- else
- {
- genConsumeRegs(data);
-
- regNumber dataReg = REG_NA;
- if (data->isContainedIntOrIImmed())
- {
- assert(data->IsIntegralConst(0));
- dataReg = REG_ZR;
- }
- else
- {
- assert(!data->isContained());
- dataReg = data->gtRegNum;
- }
- assert(dataReg != REG_NA);
-
- if (targetReg == REG_NA) // store into stack based LclVar
- {
- inst_set_SV_var(varNode);
-
- instruction ins = ins_Store(targetType);
- emitAttr attr = emitTypeSize(targetType);
-
- attr = emit->emitInsAdjustLoadStoreAttr(ins, attr);
-
- emit->emitIns_S_R(ins, attr, dataReg, varNum, offset);
-
- genUpdateLife(varNode);
-
- varDsc->lvRegNum = REG_STK;
- }
- else // store into register (i.e move into register)
- {
- if (dataReg != targetReg)
- {
- // Assign into targetReg when dataReg (from op1) is not the same register
- inst_RV_RV(ins_Copy(targetType), targetReg, dataReg, targetType);
- }
- genProduceReg(treeNode);
- }
- }
- }
- break;
-
- case GT_RETFILT:
- // A void GT_RETFILT is the end of a finally. For non-void filter returns we need to load the result in
- // the return register, if it's not already there. The processing is the same as GT_RETURN.
- if (targetType != TYP_VOID)
- {
- // For filters, the IL spec says the result is type int32. Further, the only specified legal values
- // are 0 or 1, with the use of other values "undefined".
- assert(targetType == TYP_INT);
- }
-
- __fallthrough;
-
- case GT_RETURN:
- genReturn(treeNode);
- break;
-
- case GT_LEA:
- {
- // if we are here, it is the case where there is an LEA that cannot
- // be folded into a parent instruction
- GenTreeAddrMode* lea = treeNode->AsAddrMode();
- genLeaInstruction(lea);
- }
- // genLeaInstruction calls genProduceReg()
- break;
-
- case GT_IND:
- genConsumeAddress(treeNode->AsIndir()->Addr());
- emit->emitInsLoadStoreOp(ins_Load(targetType), emitTypeSize(treeNode), targetReg, treeNode->AsIndir());
- genProduceReg(treeNode);
- break;
-
- case GT_MULHI:
- genCodeForMulHi(treeNode->AsOp());
- genProduceReg(treeNode);
- break;
-
- case GT_MOD:
- case GT_UMOD:
- // Integer MOD should have been morphed into a sequence of sub, mul, div in fgMorph.
- //
- // We shouldn't be seeing GT_MOD on float/double as it is morphed into a helper call by front-end.
- noway_assert(!"Codegen for GT_MOD/GT_UMOD");
- break;
-
- case GT_INTRINSIC:
- genIntrinsic(treeNode);
- break;
-
-#ifdef FEATURE_SIMD
- case GT_SIMD:
- genSIMDIntrinsic(treeNode->AsSIMD());
- break;
-#endif // FEATURE_SIMD
-
- case GT_CKFINITE:
- genCkfinite(treeNode);
- break;
-
- case GT_EQ:
- case GT_NE:
- case GT_LT:
- case GT_LE:
- case GT_GE:
- case GT_GT:
- {
- // TODO-ARM64-CQ: Check if we can use the currently set flags.
- // TODO-ARM64-CQ: Check for the case where we can simply transfer the carry bit to a register
- // (signed < or >= where targetReg != REG_NA)
-
- GenTreeOp* tree = treeNode->AsOp();
- GenTreePtr op1 = tree->gtOp1;
- GenTreePtr op2 = tree->gtOp2;
- var_types op1Type = op1->TypeGet();
- var_types op2Type = op2->TypeGet();
-
- assert(!op1->isUsedFromMemory());
- assert(!op2->isUsedFromMemory());
-
- genConsumeOperands(tree);
-
- emitAttr cmpSize = EA_UNKNOWN;
-
- if (varTypeIsFloating(op1Type))
- {
- assert(varTypeIsFloating(op2Type));
- assert(!op1->isContained());
- assert(op1Type == op2Type);
- cmpSize = EA_ATTR(genTypeSize(op1Type));
-
- if (op2->IsIntegralConst(0))
- {
- emit->emitIns_R_F(INS_fcmp, cmpSize, op1->gtRegNum, 0.0);
- }
- else
- {
- assert(!op2->isContained());
- emit->emitIns_R_R(INS_fcmp, cmpSize, op1->gtRegNum, op2->gtRegNum);
- }
- }
- else
- {
- assert(!varTypeIsFloating(op2Type));
- // We don't support swapping op1 and op2 to generate cmp reg, imm
- assert(!op1->isContainedIntOrIImmed());
-
- // TODO-ARM64-CQ: the second register argument of a CMP can be sign/zero
- // extended as part of the instruction (using "CMP (extended register)").
- // We should use that if possible, swapping operands
- // (and reversing the condition) if necessary.
- unsigned op1Size = genTypeSize(op1Type);
- unsigned op2Size = genTypeSize(op2Type);
-
- if ((op1Size < 4) || (op1Size < op2Size))
- {
- // We need to sign/zero extend op1 up to 32 or 64 bits.
- instruction ins = ins_Move_Extend(op1Type, true);
- inst_RV_RV(ins, op1->gtRegNum, op1->gtRegNum);
- }
-
- if (!op2->isContainedIntOrIImmed())
- {
- if ((op2Size < 4) || (op2Size < op1Size))
- {
- // We need to sign/zero extend op2 up to 32 or 64 bits.
- instruction ins = ins_Move_Extend(op2Type, true);
- inst_RV_RV(ins, op2->gtRegNum, op2->gtRegNum);
- }
- }
- cmpSize = EA_4BYTE;
- if ((op1Size == EA_8BYTE) || (op2Size == EA_8BYTE))
- {
- cmpSize = EA_8BYTE;
- }
-
- if (op2->isContainedIntOrIImmed())
- {
- GenTreeIntConCommon* intConst = op2->AsIntConCommon();
- emit->emitIns_R_I(INS_cmp, cmpSize, op1->gtRegNum, intConst->IconValue());
- }
- else
- {
- emit->emitIns_R_R(INS_cmp, cmpSize, op1->gtRegNum, op2->gtRegNum);
- }
- }
-
- // Are we evaluating this into a register?
- if (targetReg != REG_NA)
- {
- genSetRegToCond(targetReg, tree);
- genProduceReg(tree);
- }
- }
- break;
-
- case GT_JTRUE:
- genCodeForJumpTrue(treeNode);
- break;
-
- case GT_RETURNTRAP:
- {
- // this is nothing but a conditional call to CORINFO_HELP_STOP_FOR_GC
- // based on the contents of 'data'
-
- GenTree* data = treeNode->gtOp.gtOp1;
- genConsumeRegs(data);
- emit->emitIns_R_I(INS_cmp, EA_4BYTE, data->gtRegNum, 0);
-
- BasicBlock* skipLabel = genCreateTempLabel();
-
- emitJumpKind jmpEqual = genJumpKindForOper(GT_EQ, CK_SIGNED);
- inst_JMP(jmpEqual, skipLabel);
- // emit the call to the EE-helper that stops for GC (or other reasons)
-
- genEmitHelperCall(CORINFO_HELP_STOP_FOR_GC, 0, EA_UNKNOWN);
- genDefineTempLabel(skipLabel);
- }
- break;
-
- case GT_STOREIND:
- {
- GenTree* data = treeNode->gtOp.gtOp2;
- GenTree* addr = treeNode->gtOp.gtOp1;
- GCInfo::WriteBarrierForm writeBarrierForm = gcInfo.gcIsWriteBarrierCandidate(treeNode, data);
- if (writeBarrierForm != GCInfo::WBF_NoBarrier)
- {
- // data and addr must be in registers.
- // Consume both registers so that any copies of interfering
- // registers are taken care of.
- genConsumeOperands(treeNode->AsOp());
-
-#if NOGC_WRITE_BARRIERS
- // At this point, we should not have any interference.
- // That is, 'data' must not be in REG_WRITE_BARRIER_DST_BYREF,
- // as that is where 'addr' must go.
- noway_assert(data->gtRegNum != REG_WRITE_BARRIER_DST_BYREF);
-
- // 'addr' goes into x14 (REG_WRITE_BARRIER_DST_BYREF)
- if (addr->gtRegNum != REG_WRITE_BARRIER_DST_BYREF)
- {
- inst_RV_RV(INS_mov, REG_WRITE_BARRIER_DST_BYREF, addr->gtRegNum, addr->TypeGet());
- }
-
- // 'data' goes into x15 (REG_WRITE_BARRIER)
- if (data->gtRegNum != REG_WRITE_BARRIER)
- {
- inst_RV_RV(INS_mov, REG_WRITE_BARRIER, data->gtRegNum, data->TypeGet());
- }
-#else
- // At this point, we should not have any interference.
- // That is, 'data' must not be in REG_ARG_0,
- // as that is where 'addr' must go.
- noway_assert(data->gtRegNum != REG_ARG_0);
-
- // addr goes in REG_ARG_0
- if (addr->gtRegNum != REG_ARG_0)
- {
- inst_RV_RV(INS_mov, REG_ARG_0, addr->gtRegNum, addr->TypeGet());
- }
-
- // data goes in REG_ARG_1
- if (data->gtRegNum != REG_ARG_1)
- {
- inst_RV_RV(INS_mov, REG_ARG_1, data->gtRegNum, data->TypeGet());
- }
-#endif // NOGC_WRITE_BARRIERS
-
- genGCWriteBarrier(treeNode, writeBarrierForm);
- }
- else // A normal store, not a WriteBarrier store
- {
- bool reverseOps = ((treeNode->gtFlags & GTF_REVERSE_OPS) != 0);
- bool dataIsUnary = false;
- GenTree* nonRMWsrc = nullptr;
- // We must consume the operands in the proper execution order,
- // so that liveness is updated appropriately.
- if (!reverseOps)
- {
- genConsumeAddress(addr);
- }
-
- if (!data->isContained())
- {
- genConsumeRegs(data);
- }
-
- if (reverseOps)
- {
- genConsumeAddress(addr);
- }
-
- regNumber dataReg = REG_NA;
- if (data->isContainedIntOrIImmed())
- {
- assert(data->IsIntegralConst(0));
- dataReg = REG_ZR;
- }
- else // data is not contained, so evaluate it into a register
- {
- assert(!data->isContained());
- dataReg = data->gtRegNum;
- }
-
- emit->emitInsLoadStoreOp(ins_Store(targetType), emitTypeSize(treeNode), dataReg, treeNode->AsIndir());
- }
- }
- break;
-
- case GT_COPY:
- // This is handled at the time we call genConsumeReg() on the GT_COPY
- break;
-
- case GT_SWAP:
- {
- // Swap is only supported for lclVar operands that are enregistered
- // We do not consume or produce any registers. Both operands remain enregistered.
- // However, the gc-ness may change.
- assert(genIsRegCandidateLocal(treeNode->gtOp.gtOp1) && genIsRegCandidateLocal(treeNode->gtOp.gtOp2));
-
- GenTreeLclVarCommon* lcl1 = treeNode->gtOp.gtOp1->AsLclVarCommon();
- LclVarDsc* varDsc1 = &(compiler->lvaTable[lcl1->gtLclNum]);
- var_types type1 = varDsc1->TypeGet();
- GenTreeLclVarCommon* lcl2 = treeNode->gtOp.gtOp2->AsLclVarCommon();
- LclVarDsc* varDsc2 = &(compiler->lvaTable[lcl2->gtLclNum]);
- var_types type2 = varDsc2->TypeGet();
-
- // We must have both int or both fp regs
- assert(!varTypeIsFloating(type1) || varTypeIsFloating(type2));
-
- // FP swap is not yet implemented (and should have NYI'd in LSRA)
- assert(!varTypeIsFloating(type1));
-
- regNumber oldOp1Reg = lcl1->gtRegNum;
- regMaskTP oldOp1RegMask = genRegMask(oldOp1Reg);
- regNumber oldOp2Reg = lcl2->gtRegNum;
- regMaskTP oldOp2RegMask = genRegMask(oldOp2Reg);
-
- // We don't call genUpdateVarReg because we don't have a tree node with the new register.
- varDsc1->lvRegNum = oldOp2Reg;
- varDsc2->lvRegNum = oldOp1Reg;
-
- // Do the xchg
- emitAttr size = EA_PTRSIZE;
- if (varTypeGCtype(type1) != varTypeGCtype(type2))
- {
- // If the type specified to the emitter is a GC type, it will swap the GC-ness of the registers.
- // Otherwise it will leave them alone, which is correct if they have the same GC-ness.
- size = EA_GCREF;
- }
-
- NYI("register swap");
- // inst_RV_RV(INS_xchg, oldOp1Reg, oldOp2Reg, TYP_I_IMPL, size);
-
- // Update the gcInfo.
- // Manually remove these regs for the gc sets (mostly to avoid confusing duplicative dump output)
- gcInfo.gcRegByrefSetCur &= ~(oldOp1RegMask | oldOp2RegMask);
- gcInfo.gcRegGCrefSetCur &= ~(oldOp1RegMask | oldOp2RegMask);
-
- // gcMarkRegPtrVal will do the appropriate thing for non-gc types.
- // It will also dump the updates.
- gcInfo.gcMarkRegPtrVal(oldOp2Reg, type1);
- gcInfo.gcMarkRegPtrVal(oldOp1Reg, type2);
- }
- break;
-
- case GT_LIST:
- case GT_FIELD_LIST:
- case GT_ARGPLACE:
- // Nothing to do
- break;
-
- case GT_PUTARG_STK:
- genPutArgStk(treeNode->AsPutArgStk());
- break;
-
- case GT_PUTARG_REG:
- assert(targetType != TYP_STRUCT); // Any TYP_STRUCT register args should have been removed by
- // fgMorphMultiregStructArg
- // We have a normal non-Struct targetType
- {
- GenTree* op1 = treeNode->gtOp.gtOp1;
- // If child node is not already in the register we need, move it
- genConsumeReg(op1);
- if (targetReg != op1->gtRegNum)
- {
- inst_RV_RV(ins_Copy(targetType), targetReg, op1->gtRegNum, targetType);
- }
- }
- genProduceReg(treeNode);
- break;
-
- case GT_CALL:
- genCallInstruction(treeNode->AsCall());
- break;
-
- case GT_JMP:
- genJmpMethod(treeNode);
- break;
-
- case GT_LOCKADD:
- case GT_XCHG:
- case GT_XADD:
- genLockedInstructions(treeNode->AsOp());
- break;
-
- case GT_MEMORYBARRIER:
- instGen_MemoryBarrier();
- break;
-
- case GT_CMPXCHG:
- NYI("GT_CMPXCHG");
- break;
-
- case GT_RELOAD:
- // do nothing - reload is just a marker.
- // The parent node will call genConsumeReg on this which will trigger the unspill of this node's child
- // into the register specified in this node.
- break;
-
- case GT_NOP:
- break;
-
- case GT_NO_OP:
- if (treeNode->gtFlags & GTF_NO_OP_NO)
- {
- noway_assert(!"GTF_NO_OP_NO should not be set");
- }
- else
- {
- instGen(INS_nop);
- }
- break;
-
- case GT_ARR_BOUNDS_CHECK:
-#ifdef FEATURE_SIMD
- case GT_SIMD_CHK:
-#endif // FEATURE_SIMD
- genRangeCheck(treeNode);
- break;
-
- case GT_PHYSREG:
- if (targetReg != treeNode->AsPhysReg()->gtSrcReg)
- {
- inst_RV_RV(ins_Copy(targetType), targetReg, treeNode->AsPhysReg()->gtSrcReg, targetType);
-
- genTransferRegGCState(targetReg, treeNode->AsPhysReg()->gtSrcReg);
- }
- genProduceReg(treeNode);
- break;
-
- case GT_PHYSREGDST:
- break;
-
- case GT_NULLCHECK:
- {
- assert(!treeNode->gtOp.gtOp1->isContained());
- regNumber reg = genConsumeReg(treeNode->gtOp.gtOp1);
- emit->emitIns_R_R_I(INS_ldr, EA_4BYTE, REG_ZR, reg, 0);
- }
- break;
-
- case GT_CATCH_ARG:
-
- noway_assert(handlerGetsXcptnObj(compiler->compCurBB->bbCatchTyp));
-
- /* Catch arguments get passed in a register. genCodeForBBlist()
- would have marked it as holding a GC object, but not used. */
-
- noway_assert(gcInfo.gcRegGCrefSetCur & RBM_EXCEPTION_OBJECT);
- genConsumeReg(treeNode);
- break;
-
- case GT_PINVOKE_PROLOG:
- noway_assert(((gcInfo.gcRegGCrefSetCur | gcInfo.gcRegByrefSetCur) & ~fullIntArgRegMask()) == 0);
-
- // the runtime side requires the codegen here to be consistent
- emit->emitDisableRandomNops();
- break;
-
- case GT_LABEL:
- genPendingCallLabel = genCreateTempLabel();
- treeNode->gtLabel.gtLabBB = genPendingCallLabel;
-
- // For long address (default): `adrp + add` will be emitted.
- // For short address (proven later): `adr` will be emitted.
- emit->emitIns_R_L(INS_adr, EA_PTRSIZE, genPendingCallLabel, targetReg);
- break;
-
- case GT_STORE_OBJ:
- if (treeNode->OperIsCopyBlkOp())
- {
- assert(treeNode->AsObj()->gtGcPtrCount != 0);
- genCodeForCpObj(treeNode->AsObj());
- break;
- }
- __fallthrough;
-
- case GT_STORE_DYN_BLK:
- case GT_STORE_BLK:
- {
- GenTreeBlk* blkOp = treeNode->AsBlk();
- if (blkOp->gtBlkOpGcUnsafe)
- {
- getEmitter()->emitDisableGC();
- }
- bool isCopyBlk = blkOp->OperIsCopyBlkOp();
-
- switch (blkOp->gtBlkOpKind)
- {
- case GenTreeBlk::BlkOpKindHelper:
- if (isCopyBlk)
- {
- genCodeForCpBlk(blkOp);
- }
- else
- {
- genCodeForInitBlk(blkOp);
- }
- break;
- case GenTreeBlk::BlkOpKindUnroll:
- if (isCopyBlk)
- {
- genCodeForCpBlkUnroll(blkOp);
- }
- else
- {
- genCodeForInitBlkUnroll(blkOp);
- }
- break;
- default:
- unreached();
- }
- if (blkOp->gtBlkOpGcUnsafe)
- {
- getEmitter()->emitEnableGC();
- }
- }
- break;
-
- case GT_JMPTABLE:
- genJumpTable(treeNode);
- break;
-
- case GT_SWITCH_TABLE:
- genTableBasedSwitch(treeNode);
- break;
-
- case GT_ARR_INDEX:
- genCodeForArrIndex(treeNode->AsArrIndex());
- break;
-
- case GT_ARR_OFFSET:
- genCodeForArrOffset(treeNode->AsArrOffs());
- break;
-
- case GT_CLS_VAR_ADDR:
- NYI("GT_CLS_VAR_ADDR");
- break;
-
- case GT_IL_OFFSET:
- // Do nothing; these nodes are simply markers for debug info.
- break;
-
- default:
- {
-#ifdef DEBUG
- char message[256];
- _snprintf_s(message, _countof(message), _TRUNCATE, "Unimplemented node type %s\n",
- GenTree::NodeName(treeNode->OperGet()));
-#endif
- assert(!"Unknown node in codegen");
- }
- break;
- }
-}
-
/***********************************************************************************************
* Generate code for localloc
*/
@@ -3158,6 +2391,154 @@ BAILOUT:
genProduceReg(tree);
}
+//------------------------------------------------------------------------
+// genCodeForNegNot: Produce code for a GT_NEG/GT_NOT node.
+//
+// Arguments:
+// tree - the node
+//
+void CodeGen::genCodeForNegNot(GenTree* tree)
+{
+ assert(tree->OperIs(GT_NEG, GT_NOT));
+
+ var_types targetType = tree->TypeGet();
+
+ assert(!tree->OperIs(GT_NOT) || !varTypeIsFloating(targetType));
+
+ regNumber targetReg = tree->gtRegNum;
+ instruction ins = genGetInsForOper(tree->OperGet(), targetType);
+
+ // The arithmetic node must be sitting in a register (since it's not contained)
+ assert(!tree->isContained());
+ // The dst can only be a register.
+ assert(targetReg != REG_NA);
+
+ GenTreePtr operand = tree->gtGetOp1();
+ assert(!operand->isContained());
+ // The src must be a register.
+ regNumber operandReg = genConsumeReg(operand);
+
+ getEmitter()->emitIns_R_R(ins, emitTypeSize(tree), targetReg, operandReg);
+
+ genProduceReg(tree);
+}
+
+//------------------------------------------------------------------------
+// genCodeForDivMod: Produce code for a GT_DIV/GT_UDIV node. We don't see MOD:
+// (1) integer MOD is morphed into a sequence of sub, mul, div in fgMorph;
+// (2) float/double MOD is morphed into a helper call by front-end.
+//
+// Arguments:
+// tree - the node
+//
+void CodeGen::genCodeForDivMod(GenTreeOp* tree)
+{
+ assert(tree->OperIs(GT_DIV, GT_UDIV));
+
+ var_types targetType = tree->TypeGet();
+ emitter* emit = getEmitter();
+
+ genConsumeOperands(tree);
+
+ if (varTypeIsFloating(targetType))
+ {
+ // Floating point divide never raises an exception
+ genCodeForBinary(tree);
+ }
+ else // an integer divide operation
+ {
+ GenTreePtr divisorOp = tree->gtGetOp2();
+ emitAttr size = EA_ATTR(genTypeSize(genActualType(tree->TypeGet())));
+
+ if (divisorOp->IsIntegralConst(0))
+ {
+ // We unconditionally throw a divide by zero exception
+ genJumpToThrowHlpBlk(EJ_jmp, SCK_DIV_BY_ZERO);
+
+ // We still need to call genProduceReg
+ genProduceReg(tree);
+ }
+ else // the divisor is not the constant zero
+ {
+ regNumber divisorReg = divisorOp->gtRegNum;
+
+ // Generate the require runtime checks for GT_DIV or GT_UDIV
+ if (tree->gtOper == GT_DIV)
+ {
+ BasicBlock* sdivLabel = genCreateTempLabel();
+
+ // Two possible exceptions:
+ // (AnyVal / 0) => DivideByZeroException
+ // (MinInt / -1) => ArithmeticException
+ //
+ bool checkDividend = true;
+
+ // Do we have an immediate for the 'divisorOp'?
+ //
+ if (divisorOp->IsCnsIntOrI())
+ {
+ GenTreeIntConCommon* intConstTree = divisorOp->AsIntConCommon();
+ ssize_t intConstValue = intConstTree->IconValue();
+ assert(intConstValue != 0); // already checked above by IsIntegralConst(0))
+ if (intConstValue != -1)
+ {
+ checkDividend = false; // We statically know that the dividend is not -1
+ }
+ }
+ else // insert check for divison by zero
+ {
+ // Check if the divisor is zero throw a DivideByZeroException
+ emit->emitIns_R_I(INS_cmp, size, divisorReg, 0);
+ emitJumpKind jmpEqual = genJumpKindForOper(GT_EQ, CK_SIGNED);
+ genJumpToThrowHlpBlk(jmpEqual, SCK_DIV_BY_ZERO);
+ }
+
+ if (checkDividend)
+ {
+ // Check if the divisor is not -1 branch to 'sdivLabel'
+ emit->emitIns_R_I(INS_cmp, size, divisorReg, -1);
+
+ emitJumpKind jmpNotEqual = genJumpKindForOper(GT_NE, CK_SIGNED);
+ inst_JMP(jmpNotEqual, sdivLabel);
+ // If control flow continues past here the 'divisorReg' is known to be -1
+
+ regNumber dividendReg = tree->gtGetOp1()->gtRegNum;
+ // At this point the divisor is known to be -1
+ //
+ // Issue the 'adds zr, dividendReg, dividendReg' instruction
+ // this will set both the Z and V flags only when dividendReg is MinInt
+ //
+ emit->emitIns_R_R_R(INS_adds, size, REG_ZR, dividendReg, dividendReg);
+ inst_JMP(jmpNotEqual, sdivLabel); // goto sdiv if the Z flag is clear
+ genJumpToThrowHlpBlk(EJ_vs, SCK_ARITH_EXCPN); // if the V flags is set throw
+ // ArithmeticException
+
+ genDefineTempLabel(sdivLabel);
+ }
+ genCodeForBinary(tree); // Generate the sdiv instruction
+ }
+ else // (tree->gtOper == GT_UDIV)
+ {
+ // Only one possible exception
+ // (AnyVal / 0) => DivideByZeroException
+ //
+ // Note that division by the constant 0 was already checked for above by the
+ // op2->IsIntegralConst(0) check
+ //
+ if (!divisorOp->IsCnsIntOrI())
+ {
+ // divisorOp is not a constant, so it could be zero
+ //
+ emit->emitIns_R_I(INS_cmp, size, divisorReg, 0);
+ emitJumpKind jmpEqual = genJumpKindForOper(GT_EQ, CK_SIGNED);
+ genJumpToThrowHlpBlk(jmpEqual, SCK_DIV_BY_ZERO);
+ }
+ genCodeForBinary(tree);
+ }
+ }
+ }
+}
+
// Generate code for InitBlk by performing a loop unroll
// Preconditions:
// a) Both the size and fill byte value are integer constants.
@@ -3182,6 +2563,12 @@ void CodeGen::genCodeForInitBlkUnroll(GenTreeBlk* initBlkNode)
genConsumeOperands(initBlkNode);
+ if (initBlkNode->gtFlags & GTF_BLK_VOLATILE)
+ {
+ // issue a full memory barrier before volatile an initBlockUnroll operation
+ instGen_MemoryBarrier();
+ }
+
regNumber valReg = initVal->IsIntegralConst(0) ? REG_ZR : initVal->gtRegNum;
assert(!initVal->IsIntegralConst(0) || (valReg == REG_ZR));
@@ -3257,9 +2644,7 @@ void CodeGen::genCodeForLoadPairOffset(regNumber dst, regNumber dst2, GenTree* b
if (base->gtOper == GT_LCL_FLD_ADDR)
offset += base->gtLclFld.gtLclOffs;
- // TODO-ARM64-CQ: Implement support for using a ldp instruction with a varNum (see emitIns_R_S)
- emit->emitIns_R_S(INS_ldr, EA_8BYTE, dst, base->gtLclVarCommon.gtLclNum, offset);
- emit->emitIns_R_S(INS_ldr, EA_8BYTE, dst2, base->gtLclVarCommon.gtLclNum, offset + REGSIZE_BYTES);
+ emit->emitIns_R_R_S_S(INS_ldp, EA_8BYTE, EA_8BYTE, dst, dst2, base->gtLclVarCommon.gtLclNum, offset);
}
else
{
@@ -3298,9 +2683,7 @@ void CodeGen::genCodeForStorePairOffset(regNumber src, regNumber src2, GenTree*
if (base->gtOper == GT_LCL_FLD_ADDR)
offset += base->gtLclFld.gtLclOffs;
- // TODO-ARM64-CQ: Implement support for using a stp instruction with a varNum (see emitIns_S_R)
- emit->emitIns_S_R(INS_str, EA_8BYTE, src, base->gtLclVarCommon.gtLclNum, offset);
- emit->emitIns_S_R(INS_str, EA_8BYTE, src2, base->gtLclVarCommon.gtLclNum, offset + REGSIZE_BYTES);
+ emit->emitIns_S_S_R_R(INS_stp, EA_8BYTE, EA_8BYTE, src, src2, base->gtLclVarCommon.gtLclNum, offset);
}
else
{
@@ -3324,6 +2707,12 @@ void CodeGen::genCodeForCpBlkUnroll(GenTreeBlk* cpBlkNode)
emitter* emit = getEmitter();
+ if (cpBlkNode->gtFlags & GTF_BLK_VOLATILE)
+ {
+ // issue a full memory barrier before & after a volatile CpBlkUnroll operation
+ instGen_MemoryBarrier();
+ }
+
if (source->gtOper == GT_IND)
{
srcAddr = source->gtGetOp1();
@@ -3402,6 +2791,12 @@ void CodeGen::genCodeForCpBlkUnroll(GenTreeBlk* cpBlkNode)
genCodeForStoreOffset(INS_strb, EA_1BYTE, tmpReg, dstAddr, offset);
}
}
+
+ if (cpBlkNode->gtFlags & GTF_BLK_VOLATILE)
+ {
+ // issue a full memory barrier before & after a volatile CpBlkUnroll operation
+ instGen_MemoryBarrier();
+ }
}
// Generate code for CpObj nodes wich copy structs that have interleaved
@@ -3461,30 +2856,60 @@ void CodeGen::genCodeForCpObj(GenTreeObj* cpObjNode)
gcInfo.gcMarkRegPtrVal(REG_WRITE_BARRIER_SRC_BYREF, srcAddrType);
gcInfo.gcMarkRegPtrVal(REG_WRITE_BARRIER_DST_BYREF, dstAddr->TypeGet());
- // Temp register used to perform the sequence of loads and stores.
- regNumber tmpReg = cpObjNode->GetSingleTempReg();
+ unsigned slots = cpObjNode->gtSlots;
+
+ // Temp register(s) used to perform the sequence of loads and stores.
+ regNumber tmpReg = cpObjNode->ExtractTempReg();
+ regNumber tmpReg2 = REG_NA;
+
assert(genIsValidIntReg(tmpReg));
+ assert(tmpReg != REG_WRITE_BARRIER_SRC_BYREF);
+ assert(tmpReg != REG_WRITE_BARRIER_DST_BYREF);
- unsigned slots = cpObjNode->gtSlots;
- emitter* emit = getEmitter();
+ if (slots > 1)
+ {
+ tmpReg2 = cpObjNode->GetSingleTempReg();
+ assert(tmpReg2 != tmpReg);
+ assert(genIsValidIntReg(tmpReg2));
+ assert(tmpReg2 != REG_WRITE_BARRIER_DST_BYREF);
+ assert(tmpReg2 != REG_WRITE_BARRIER_SRC_BYREF);
+ }
+
+ if (cpObjNode->gtFlags & GTF_BLK_VOLATILE)
+ {
+ // issue a full memory barrier before & after a volatile CpObj operation
+ instGen_MemoryBarrier();
+ }
+
+ emitter* emit = getEmitter();
BYTE* gcPtrs = cpObjNode->gtGcPtrs;
// If we can prove it's on the stack we don't need to use the write barrier.
if (dstOnStack)
{
- // TODO-ARM64-CQ: Consider using LDP/STP to save codesize.
- for (unsigned i = 0; i < slots; ++i)
+ unsigned i = 0;
+ // Check if two or more remaining slots and use a ldp/stp sequence
+ while (i < slots - 1)
{
- emitAttr attr = EA_8BYTE;
- if (gcPtrs[i] == GCT_GCREF)
- attr = EA_GCREF;
- else if (gcPtrs[i] == GCT_BYREF)
- attr = EA_BYREF;
+ emitAttr attr0 = emitTypeSize(compiler->getJitGCType(gcPtrs[i + 0]));
+ emitAttr attr1 = emitTypeSize(compiler->getJitGCType(gcPtrs[i + 1]));
+
+ emit->emitIns_R_R_R_I(INS_ldp, attr0, tmpReg, tmpReg2, REG_WRITE_BARRIER_SRC_BYREF, 2 * TARGET_POINTER_SIZE,
+ INS_OPTS_POST_INDEX, attr1);
+ emit->emitIns_R_R_R_I(INS_stp, attr0, tmpReg, tmpReg2, REG_WRITE_BARRIER_DST_BYREF, 2 * TARGET_POINTER_SIZE,
+ INS_OPTS_POST_INDEX, attr1);
+ i += 2;
+ }
+
+ // Use a ldr/str sequence for the last remainder
+ if (i < slots)
+ {
+ emitAttr attr0 = emitTypeSize(compiler->getJitGCType(gcPtrs[i + 0]));
- emit->emitIns_R_R_I(INS_ldr, attr, tmpReg, REG_WRITE_BARRIER_SRC_BYREF, TARGET_POINTER_SIZE,
+ emit->emitIns_R_R_I(INS_ldr, attr0, tmpReg, REG_WRITE_BARRIER_SRC_BYREF, TARGET_POINTER_SIZE,
INS_OPTS_POST_INDEX);
- emit->emitIns_R_R_I(INS_str, attr, tmpReg, REG_WRITE_BARRIER_DST_BYREF, TARGET_POINTER_SIZE,
+ emit->emitIns_R_R_I(INS_str, attr0, tmpReg, REG_WRITE_BARRIER_DST_BYREF, TARGET_POINTER_SIZE,
INS_OPTS_POST_INDEX);
}
}
@@ -3498,11 +2923,22 @@ void CodeGen::genCodeForCpObj(GenTreeObj* cpObjNode)
switch (gcPtrs[i])
{
case TYPE_GC_NONE:
- // TODO-ARM64-CQ: Consider using LDP/STP to save codesize in case of contigous NON-GC slots.
- emit->emitIns_R_R_I(INS_ldr, EA_8BYTE, tmpReg, REG_WRITE_BARRIER_SRC_BYREF, TARGET_POINTER_SIZE,
- INS_OPTS_POST_INDEX);
- emit->emitIns_R_R_I(INS_str, EA_8BYTE, tmpReg, REG_WRITE_BARRIER_DST_BYREF, TARGET_POINTER_SIZE,
- INS_OPTS_POST_INDEX);
+ // Check if the next slot's type is also TYP_GC_NONE and use ldp/stp
+ if ((i + 1 < slots) && (gcPtrs[i + 1] == TYPE_GC_NONE))
+ {
+ emit->emitIns_R_R_R_I(INS_ldp, EA_8BYTE, tmpReg, tmpReg2, REG_WRITE_BARRIER_SRC_BYREF,
+ 2 * TARGET_POINTER_SIZE, INS_OPTS_POST_INDEX);
+ emit->emitIns_R_R_R_I(INS_stp, EA_8BYTE, tmpReg, tmpReg2, REG_WRITE_BARRIER_DST_BYREF,
+ 2 * TARGET_POINTER_SIZE, INS_OPTS_POST_INDEX);
+ ++i; // extra increment of i, since we are copying two items
+ }
+ else
+ {
+ emit->emitIns_R_R_I(INS_ldr, EA_8BYTE, tmpReg, REG_WRITE_BARRIER_SRC_BYREF, TARGET_POINTER_SIZE,
+ INS_OPTS_POST_INDEX);
+ emit->emitIns_R_R_I(INS_str, EA_8BYTE, tmpReg, REG_WRITE_BARRIER_DST_BYREF, TARGET_POINTER_SIZE,
+ INS_OPTS_POST_INDEX);
+ }
break;
default:
@@ -3517,6 +2953,12 @@ void CodeGen::genCodeForCpObj(GenTreeObj* cpObjNode)
assert(gcPtrCount == 0);
}
+ if (cpObjNode->gtFlags & GTF_BLK_VOLATILE)
+ {
+ // issue a full memory barrier before & after a volatile CpObj operation
+ instGen_MemoryBarrier();
+ }
+
// Clear the gcInfo for REG_WRITE_BARRIER_SRC_BYREF and REG_WRITE_BARRIER_DST_BYREF.
// While we normally update GC info prior to the last instruction that uses them,
// these actually live into the helper call.
@@ -4069,6 +3511,194 @@ void CodeGen::genLeaInstruction(GenTreeAddrMode* lea)
genProduceReg(lea);
}
+//------------------------------------------------------------------------
+// genCodeForReturnTrap: Produce code for a GT_RETURNTRAP node.
+//
+// Arguments:
+// tree - the GT_RETURNTRAP node
+//
+void CodeGen::genCodeForReturnTrap(GenTreeOp* tree)
+{
+ assert(tree->OperGet() == GT_RETURNTRAP);
+
+ // this is nothing but a conditional call to CORINFO_HELP_STOP_FOR_GC
+ // based on the contents of 'data'
+
+ GenTree* data = tree->gtOp1;
+ genConsumeRegs(data);
+ getEmitter()->emitIns_R_I(INS_cmp, EA_4BYTE, data->gtRegNum, 0);
+
+ BasicBlock* skipLabel = genCreateTempLabel();
+
+ emitJumpKind jmpEqual = genJumpKindForOper(GT_EQ, CK_SIGNED);
+ inst_JMP(jmpEqual, skipLabel);
+ // emit the call to the EE-helper that stops for GC (or other reasons)
+
+ genEmitHelperCall(CORINFO_HELP_STOP_FOR_GC, 0, EA_UNKNOWN);
+ genDefineTempLabel(skipLabel);
+}
+
+//------------------------------------------------------------------------
+// genCodeForStoreInd: Produce code for a GT_STOREIND node.
+//
+// Arguments:
+// tree - the GT_STOREIND node
+//
+void CodeGen::genCodeForStoreInd(GenTreeStoreInd* tree)
+{
+ GenTree* data = tree->Data();
+ GenTree* addr = tree->Addr();
+ var_types targetType = tree->TypeGet();
+ emitter* emit = getEmitter();
+
+ GCInfo::WriteBarrierForm writeBarrierForm = gcInfo.gcIsWriteBarrierCandidate(tree, data);
+ if (writeBarrierForm != GCInfo::WBF_NoBarrier)
+ {
+ // data and addr must be in registers.
+ // Consume both registers so that any copies of interfering
+ // registers are taken care of.
+ genConsumeOperands(tree);
+
+#if NOGC_WRITE_BARRIERS
+ // At this point, we should not have any interference.
+ // That is, 'data' must not be in REG_WRITE_BARRIER_DST_BYREF,
+ // as that is where 'addr' must go.
+ noway_assert(data->gtRegNum != REG_WRITE_BARRIER_DST_BYREF);
+
+ // 'addr' goes into x14 (REG_WRITE_BARRIER_DST_BYREF)
+ if (addr->gtRegNum != REG_WRITE_BARRIER_DST_BYREF)
+ {
+ inst_RV_RV(INS_mov, REG_WRITE_BARRIER_DST_BYREF, addr->gtRegNum, addr->TypeGet());
+ }
+
+ // 'data' goes into x15 (REG_WRITE_BARRIER)
+ if (data->gtRegNum != REG_WRITE_BARRIER)
+ {
+ inst_RV_RV(INS_mov, REG_WRITE_BARRIER, data->gtRegNum, data->TypeGet());
+ }
+#else
+ // At this point, we should not have any interference.
+ // That is, 'data' must not be in REG_ARG_0,
+ // as that is where 'addr' must go.
+ noway_assert(data->gtRegNum != REG_ARG_0);
+
+ // addr goes in REG_ARG_0
+ if (addr->gtRegNum != REG_ARG_0)
+ {
+ inst_RV_RV(INS_mov, REG_ARG_0, addr->gtRegNum, addr->TypeGet());
+ }
+
+ // data goes in REG_ARG_1
+ if (data->gtRegNum != REG_ARG_1)
+ {
+ inst_RV_RV(INS_mov, REG_ARG_1, data->gtRegNum, data->TypeGet());
+ }
+#endif // NOGC_WRITE_BARRIERS
+
+ genGCWriteBarrier(tree, writeBarrierForm);
+ }
+ else // A normal store, not a WriteBarrier store
+ {
+ bool reverseOps = ((tree->gtFlags & GTF_REVERSE_OPS) != 0);
+ bool dataIsUnary = false;
+ GenTree* nonRMWsrc = nullptr;
+ // We must consume the operands in the proper execution order,
+ // so that liveness is updated appropriately.
+ if (!reverseOps)
+ {
+ genConsumeAddress(addr);
+ }
+
+ if (!data->isContained())
+ {
+ genConsumeRegs(data);
+ }
+
+ if (reverseOps)
+ {
+ genConsumeAddress(addr);
+ }
+
+ regNumber dataReg = REG_NA;
+ if (data->isContainedIntOrIImmed())
+ {
+ assert(data->IsIntegralConst(0));
+ dataReg = REG_ZR;
+ }
+ else // data is not contained, so evaluate it into a register
+ {
+ assert(!data->isContained());
+ dataReg = data->gtRegNum;
+ }
+
+ if (tree->gtFlags & GTF_IND_VOLATILE)
+ {
+ // issue a full memory barrier a before volatile StInd
+ instGen_MemoryBarrier();
+ }
+
+ emit->emitInsLoadStoreOp(ins_Store(targetType), emitTypeSize(tree), dataReg, tree);
+ }
+}
+
+//------------------------------------------------------------------------
+// genCodeForSwap: Produce code for a GT_SWAP node.
+//
+// Arguments:
+// tree - the GT_SWAP node
+//
+void CodeGen::genCodeForSwap(GenTreeOp* tree)
+{
+ // Swap is only supported for lclVar operands that are enregistered
+ // We do not consume or produce any registers. Both operands remain enregistered.
+ // However, the gc-ness may change.
+ assert(genIsRegCandidateLocal(tree->gtOp1) && genIsRegCandidateLocal(tree->gtOp2));
+
+ GenTreeLclVarCommon* lcl1 = tree->gtOp1->AsLclVarCommon();
+ LclVarDsc* varDsc1 = &(compiler->lvaTable[lcl1->gtLclNum]);
+ var_types type1 = varDsc1->TypeGet();
+ GenTreeLclVarCommon* lcl2 = tree->gtOp2->AsLclVarCommon();
+ LclVarDsc* varDsc2 = &(compiler->lvaTable[lcl2->gtLclNum]);
+ var_types type2 = varDsc2->TypeGet();
+
+ // We must have both int or both fp regs
+ assert(!varTypeIsFloating(type1) || varTypeIsFloating(type2));
+
+ // FP swap is not yet implemented (and should have NYI'd in LSRA)
+ assert(!varTypeIsFloating(type1));
+
+ regNumber oldOp1Reg = lcl1->gtRegNum;
+ regMaskTP oldOp1RegMask = genRegMask(oldOp1Reg);
+ regNumber oldOp2Reg = lcl2->gtRegNum;
+ regMaskTP oldOp2RegMask = genRegMask(oldOp2Reg);
+
+ // We don't call genUpdateVarReg because we don't have a tree node with the new register.
+ varDsc1->lvRegNum = oldOp2Reg;
+ varDsc2->lvRegNum = oldOp1Reg;
+
+ // Do the xchg
+ emitAttr size = EA_PTRSIZE;
+ if (varTypeGCtype(type1) != varTypeGCtype(type2))
+ {
+ // If the type specified to the emitter is a GC type, it will swap the GC-ness of the registers.
+ // Otherwise it will leave them alone, which is correct if they have the same GC-ness.
+ size = EA_GCREF;
+ }
+
+ NYI("register swap");
+ // inst_RV_RV(INS_xchg, oldOp1Reg, oldOp2Reg, TYP_I_IMPL, size);
+
+ // Update the gcInfo.
+ // Manually remove these regs for the gc sets (mostly to avoid confusing duplicative dump output)
+ gcInfo.gcRegByrefSetCur &= ~(oldOp1RegMask | oldOp2RegMask);
+ gcInfo.gcRegGCrefSetCur &= ~(oldOp1RegMask | oldOp2RegMask);
+
+ // gcMarkRegPtrVal will do the appropriate thing for non-gc types.
+ // It will also dump the updates.
+ gcInfo.gcMarkRegPtrVal(oldOp2Reg, type1);
+ gcInfo.gcMarkRegPtrVal(oldOp1Reg, type2);
+}
+
//-------------------------------------------------------------------------------------------
// genSetRegToCond: Set a register 'dstReg' to the appropriate one or zero value
// corresponding to a binary Relational operator result.
@@ -4335,6 +3965,104 @@ void CodeGen::genCkfinite(GenTreePtr treeNode)
genProduceReg(treeNode);
}
+//------------------------------------------------------------------------
+// genCodeForCompare: Produce code for a GT_EQ/GT_NE/GT_LT/GT_LE/GT_GE/GT_GT node.
+//
+// Arguments:
+// tree - the node
+//
+void CodeGen::genCodeForCompare(GenTreeOp* tree)
+{
+ regNumber targetReg = tree->gtRegNum;
+ emitter* emit = getEmitter();
+
+ // TODO-ARM64-CQ: Check if we can use the currently set flags.
+ // TODO-ARM64-CQ: Check for the case where we can simply transfer the carry bit to a register
+ // (signed < or >= where targetReg != REG_NA)
+
+ GenTreePtr op1 = tree->gtOp1;
+ GenTreePtr op2 = tree->gtOp2;
+ var_types op1Type = op1->TypeGet();
+ var_types op2Type = op2->TypeGet();
+
+ assert(!op1->isUsedFromMemory());
+ assert(!op2->isUsedFromMemory());
+
+ genConsumeOperands(tree);
+
+ emitAttr cmpSize = EA_UNKNOWN;
+
+ if (varTypeIsFloating(op1Type))
+ {
+ assert(varTypeIsFloating(op2Type));
+ assert(!op1->isContained());
+ assert(op1Type == op2Type);
+ cmpSize = EA_ATTR(genTypeSize(op1Type));
+
+ if (op2->IsIntegralConst(0))
+ {
+ emit->emitIns_R_F(INS_fcmp, cmpSize, op1->gtRegNum, 0.0);
+ }
+ else
+ {
+ assert(!op2->isContained());
+ emit->emitIns_R_R(INS_fcmp, cmpSize, op1->gtRegNum, op2->gtRegNum);
+ }
+ }
+ else
+ {
+ assert(!varTypeIsFloating(op2Type));
+ // We don't support swapping op1 and op2 to generate cmp reg, imm
+ assert(!op1->isContainedIntOrIImmed());
+
+ // TODO-ARM64-CQ: the second register argument of a CMP can be sign/zero
+ // extended as part of the instruction (using "CMP (extended register)").
+ // We should use that if possible, swapping operands
+ // (and reversing the condition) if necessary.
+ unsigned op1Size = genTypeSize(op1Type);
+ unsigned op2Size = genTypeSize(op2Type);
+
+ if ((op1Size < 4) || (op1Size < op2Size))
+ {
+ // We need to sign/zero extend op1 up to 32 or 64 bits.
+ instruction ins = ins_Move_Extend(op1Type, true);
+ inst_RV_RV(ins, op1->gtRegNum, op1->gtRegNum);
+ }
+
+ if (!op2->isContainedIntOrIImmed())
+ {
+ if ((op2Size < 4) || (op2Size < op1Size))
+ {
+ // We need to sign/zero extend op2 up to 32 or 64 bits.
+ instruction ins = ins_Move_Extend(op2Type, true);
+ inst_RV_RV(ins, op2->gtRegNum, op2->gtRegNum);
+ }
+ }
+ cmpSize = EA_4BYTE;
+ if ((op1Size == EA_8BYTE) || (op2Size == EA_8BYTE))
+ {
+ cmpSize = EA_8BYTE;
+ }
+
+ if (op2->isContainedIntOrIImmed())
+ {
+ GenTreeIntConCommon* intConst = op2->AsIntConCommon();
+ emit->emitIns_R_I(INS_cmp, cmpSize, op1->gtRegNum, intConst->IconValue());
+ }
+ else
+ {
+ emit->emitIns_R_R(INS_cmp, cmpSize, op1->gtRegNum, op2->gtRegNum);
+ }
+ }
+
+ // Are we evaluating this into a register?
+ if (targetReg != REG_NA)
+ {
+ genSetRegToCond(targetReg, tree);
+ genProduceReg(tree);
+ }
+}
+
int CodeGenInterface::genSPtoFPdelta()
{
int delta;
@@ -4552,6 +4280,17 @@ void CodeGen::genArm64EmitterUnitTests()
theEmitter->emitIns_R_R_I(INS_ldr, EA_8BYTE, REG_R8, REG_R9, 1, INS_OPTS_POST_INDEX);
theEmitter->emitIns_R_R_I(INS_ldr, EA_8BYTE, REG_R8, REG_R9, 1, INS_OPTS_PRE_INDEX);
+ // ldar/stlr Rt, [reg]
+ theEmitter->emitIns_R_R(INS_ldar, EA_8BYTE, REG_R9, REG_R8);
+ theEmitter->emitIns_R_R(INS_ldar, EA_4BYTE, REG_R7, REG_R10);
+ theEmitter->emitIns_R_R(INS_ldarb, EA_4BYTE, REG_R5, REG_R11);
+ theEmitter->emitIns_R_R(INS_ldarh, EA_4BYTE, REG_R5, REG_R12);
+
+ theEmitter->emitIns_R_R(INS_stlr, EA_8BYTE, REG_R9, REG_R8);
+ theEmitter->emitIns_R_R(INS_stlr, EA_4BYTE, REG_R7, REG_R13);
+ theEmitter->emitIns_R_R(INS_stlrb, EA_4BYTE, REG_R5, REG_R14);
+ theEmitter->emitIns_R_R(INS_stlrh, EA_4BYTE, REG_R3, REG_R15);
+
#endif // ALL_ARM64_EMITTER_UNIT_TESTS
#ifdef ALL_ARM64_EMITTER_UNIT_TESTS
diff --git a/src/jit/codegenarmarch.cpp b/src/jit/codegenarmarch.cpp
index c541472..103ce47 100644
--- a/src/jit/codegenarmarch.cpp
+++ b/src/jit/codegenarmarch.cpp
@@ -25,6 +25,382 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
#include "emit.h"
//------------------------------------------------------------------------
+// genCodeForTreeNode Generate code for a single node in the tree.
+//
+// Preconditions:
+// All operands have been evaluated.
+//
+void CodeGen::genCodeForTreeNode(GenTreePtr treeNode)
+{
+ regNumber targetReg = treeNode->gtRegNum;
+ var_types targetType = treeNode->TypeGet();
+ emitter* emit = getEmitter();
+
+#ifdef DEBUG
+ // Validate that all the operands for the current node are consumed in order.
+ // This is important because LSRA ensures that any necessary copies will be
+ // handled correctly.
+ lastConsumedNode = nullptr;
+ if (compiler->verbose)
+ {
+ unsigned seqNum = treeNode->gtSeqNum; // Useful for setting a conditional break in Visual Studio
+ compiler->gtDispLIRNode(treeNode, "Generating: ");
+ }
+#endif // DEBUG
+
+#ifdef _TARGET_ARM64_ // TODO-ARM: is this applicable to ARM32?
+ // Is this a node whose value is already in a register? LSRA denotes this by
+ // setting the GTF_REUSE_REG_VAL flag.
+ if (treeNode->IsReuseRegVal())
+ {
+ // For now, this is only used for constant nodes.
+ assert((treeNode->OperGet() == GT_CNS_INT) || (treeNode->OperGet() == GT_CNS_DBL));
+ JITDUMP(" TreeNode is marked ReuseReg\n");
+ return;
+ }
+#endif // _TARGET_ARM64_
+
+ // contained nodes are part of their parents for codegen purposes
+ // ex : immediates, most LEAs
+ if (treeNode->isContained())
+ {
+ return;
+ }
+
+ switch (treeNode->gtOper)
+ {
+#ifdef _TARGET_ARM64_
+
+ case GT_START_NONGC:
+ getEmitter()->emitDisableGC();
+ break;
+
+ case GT_PROF_HOOK:
+ // We should be seeing this only if profiler hook is needed
+ noway_assert(compiler->compIsProfilerHookNeeded());
+
+#ifdef PROFILING_SUPPORTED
+ // Right now this node is used only for tail calls. In future if
+ // we intend to use it for Enter or Leave hooks, add a data member
+ // to this node indicating the kind of profiler hook. For example,
+ // helper number can be used.
+ genProfilingLeaveCallback(CORINFO_HELP_PROF_FCN_TAILCALL);
+#endif // PROFILING_SUPPORTED
+ break;
+
+#endif // _TARGET_ARM64_
+
+ case GT_LCLHEAP:
+ genLclHeap(treeNode);
+ break;
+
+ case GT_CNS_INT:
+ case GT_CNS_DBL:
+ genSetRegToConst(targetReg, targetType, treeNode);
+ genProduceReg(treeNode);
+ break;
+
+ case GT_NOT:
+ case GT_NEG:
+ genCodeForNegNot(treeNode);
+ break;
+
+ case GT_MOD:
+ case GT_UMOD:
+ case GT_DIV:
+ case GT_UDIV:
+ genCodeForDivMod(treeNode->AsOp());
+ break;
+
+ case GT_OR:
+ case GT_XOR:
+ case GT_AND:
+ assert(varTypeIsIntegralOrI(treeNode));
+
+ __fallthrough;
+
+#ifdef _TARGET_ARM_
+ case GT_ADD_LO:
+ case GT_ADD_HI:
+ case GT_SUB_LO:
+ case GT_SUB_HI:
+#endif // _TARGET_ARM_
+
+ case GT_ADD:
+ case GT_SUB:
+ case GT_MUL:
+ genConsumeOperands(treeNode->AsOp());
+ genCodeForBinary(treeNode);
+ break;
+
+ case GT_LSH:
+ case GT_RSH:
+ case GT_RSZ:
+ case GT_ROR:
+ genCodeForShift(treeNode);
+ break;
+
+#ifdef _TARGET_ARM_
+
+ case GT_LSH_HI:
+ case GT_RSH_LO:
+ genCodeForShiftLong(treeNode);
+ break;
+
+#endif // _TARGET_ARM_
+
+ case GT_CAST:
+ genCodeForCast(treeNode->AsOp());
+ break;
+
+ case GT_LCL_FLD_ADDR:
+ case GT_LCL_VAR_ADDR:
+ genCodeForLclAddr(treeNode);
+ break;
+
+ case GT_LCL_FLD:
+ genCodeForLclFld(treeNode->AsLclFld());
+ break;
+
+ case GT_LCL_VAR:
+ genCodeForLclVar(treeNode->AsLclVar());
+ break;
+
+ case GT_STORE_LCL_FLD:
+ genCodeForStoreLclFld(treeNode->AsLclFld());
+ break;
+
+ case GT_STORE_LCL_VAR:
+ genCodeForStoreLclVar(treeNode->AsLclVar());
+ break;
+
+ case GT_RETFILT:
+ case GT_RETURN:
+ genReturn(treeNode);
+ break;
+
+ case GT_LEA:
+ // if we are here, it is the case where there is an LEA that cannot
+ // be folded into a parent instruction
+ genLeaInstruction(treeNode->AsAddrMode());
+ break;
+
+ case GT_IND:
+ genCodeForIndir(treeNode->AsIndir());
+ break;
+
+#ifdef _TARGET_ARM64_
+
+ case GT_MULHI:
+ genCodeForMulHi(treeNode->AsOp());
+ break;
+
+ case GT_CKFINITE:
+ genCkfinite(treeNode);
+ break;
+
+ case GT_SWAP:
+ genCodeForSwap(treeNode->AsOp());
+ break;
+
+ case GT_JMP:
+ genJmpMethod(treeNode);
+ break;
+
+#endif // _TARGET_ARM64_
+
+ case GT_INTRINSIC:
+ genIntrinsic(treeNode);
+ break;
+
+#ifdef FEATURE_SIMD
+ case GT_SIMD:
+ genSIMDIntrinsic(treeNode->AsSIMD());
+ break;
+#endif // FEATURE_SIMD
+
+ case GT_EQ:
+ case GT_NE:
+ case GT_LT:
+ case GT_LE:
+ case GT_GE:
+ case GT_GT:
+ genCodeForCompare(treeNode->AsOp());
+ break;
+
+ case GT_JTRUE:
+ genCodeForJumpTrue(treeNode);
+ break;
+
+#ifdef _TARGET_ARM_
+
+ case GT_JCC:
+ genCodeForJcc(treeNode->AsJumpCC());
+ break;
+
+#endif // _TARGET_ARM_
+
+ case GT_RETURNTRAP:
+ genCodeForReturnTrap(treeNode->AsOp());
+ break;
+
+ case GT_STOREIND:
+ genCodeForStoreInd(treeNode->AsStoreInd());
+ break;
+
+ case GT_COPY:
+ // This is handled at the time we call genConsumeReg() on the GT_COPY
+ break;
+
+ case GT_LIST:
+ case GT_FIELD_LIST:
+ case GT_ARGPLACE:
+ // Nothing to do
+ break;
+
+ case GT_PUTARG_STK:
+ genPutArgStk(treeNode->AsPutArgStk());
+ break;
+
+ case GT_PUTARG_REG:
+ genPutArgReg(treeNode->AsOp());
+ break;
+
+ case GT_CALL:
+ genCallInstruction(treeNode->AsCall());
+ break;
+
+ case GT_LOCKADD:
+ case GT_XCHG:
+ case GT_XADD:
+ genLockedInstructions(treeNode->AsOp());
+ break;
+
+ case GT_MEMORYBARRIER:
+ instGen_MemoryBarrier();
+ break;
+
+ case GT_CMPXCHG:
+ NYI("GT_CMPXCHG");
+ break;
+
+ case GT_RELOAD:
+ // do nothing - reload is just a marker.
+ // The parent node will call genConsumeReg on this which will trigger the unspill of this node's child
+ // into the register specified in this node.
+ break;
+
+ case GT_NOP:
+ break;
+
+ case GT_NO_OP:
+ if (treeNode->gtFlags & GTF_NO_OP_NO)
+ {
+ noway_assert(!"GTF_NO_OP_NO should not be set");
+ }
+ else
+ {
+ instGen(INS_nop);
+ }
+ break;
+
+ case GT_ARR_BOUNDS_CHECK:
+#ifdef FEATURE_SIMD
+ case GT_SIMD_CHK:
+#endif // FEATURE_SIMD
+ genRangeCheck(treeNode);
+ break;
+
+ case GT_PHYSREG:
+ genCodeForPhysReg(treeNode->AsPhysReg());
+ break;
+
+ case GT_PHYSREGDST:
+ break;
+
+ case GT_NULLCHECK:
+ genCodeForNullCheck(treeNode->AsOp());
+ break;
+
+ case GT_CATCH_ARG:
+
+ noway_assert(handlerGetsXcptnObj(compiler->compCurBB->bbCatchTyp));
+
+ /* Catch arguments get passed in a register. genCodeForBBlist()
+ would have marked it as holding a GC object, but not used. */
+
+ noway_assert(gcInfo.gcRegGCrefSetCur & RBM_EXCEPTION_OBJECT);
+ genConsumeReg(treeNode);
+ break;
+
+ case GT_PINVOKE_PROLOG:
+ noway_assert(((gcInfo.gcRegGCrefSetCur | gcInfo.gcRegByrefSetCur) & ~fullIntArgRegMask()) == 0);
+
+ // the runtime side requires the codegen here to be consistent
+ emit->emitDisableRandomNops();
+ break;
+
+ case GT_LABEL:
+ genPendingCallLabel = genCreateTempLabel();
+ treeNode->gtLabel.gtLabBB = genPendingCallLabel;
+#if defined(_TARGET_ARM_)
+ emit->emitIns_J_R(INS_adr, EA_PTRSIZE, genPendingCallLabel, targetReg);
+#elif defined(_TARGET_ARM64_)
+ emit->emitIns_R_L(INS_adr, EA_PTRSIZE, genPendingCallLabel, targetReg);
+#endif
+ break;
+
+ case GT_STORE_OBJ:
+ case GT_STORE_DYN_BLK:
+ case GT_STORE_BLK:
+ genCodeForStoreBlk(treeNode->AsBlk());
+ break;
+
+ case GT_JMPTABLE:
+ genJumpTable(treeNode);
+ break;
+
+ case GT_SWITCH_TABLE:
+ genTableBasedSwitch(treeNode);
+ break;
+
+ case GT_ARR_INDEX:
+ genCodeForArrIndex(treeNode->AsArrIndex());
+ break;
+
+ case GT_ARR_OFFSET:
+ genCodeForArrOffset(treeNode->AsArrOffs());
+ break;
+
+#ifdef _TARGET_ARM_
+
+ case GT_CLS_VAR_ADDR:
+ emit->emitIns_R_C(INS_lea, EA_PTRSIZE, targetReg, treeNode->gtClsVar.gtClsVarHnd, 0);
+ genProduceReg(treeNode);
+ break;
+
+#endif // _TARGET_ARM_
+
+ case GT_IL_OFFSET:
+ // Do nothing; these nodes are simply markers for debug info.
+ break;
+
+ default:
+ {
+#ifdef DEBUG
+ char message[256];
+ _snprintf_s(message, _countof(message), _TRUNCATE, "NYI: Unimplemented node type %s",
+ GenTree::NodeName(treeNode->OperGet()));
+ NYIRAW(message);
+#else
+ NYI("unimplemented node");
+#endif
+ }
+ break;
+ }
+}
+
+//------------------------------------------------------------------------
// genSetRegToIcon: Generate code that will set the given register to the integer constant.
//
void CodeGen::genSetRegToIcon(regNumber reg, ssize_t val, var_types type, insFlags flags)
@@ -51,6 +427,8 @@ void CodeGen::genSetRegToIcon(regNumber reg, ssize_t val, var_types type, insFla
//
void CodeGen::genIntrinsic(GenTreePtr treeNode)
{
+ assert(treeNode->OperIs(GT_INTRINSIC));
+
// Both operand and its result must be of the same floating point type.
GenTreePtr srcNode = treeNode->gtOp.gtOp1;
assert(varTypeIsFloating(srcNode));
@@ -95,7 +473,7 @@ void CodeGen::genIntrinsic(GenTreePtr treeNode)
//
void CodeGen::genPutArgStk(GenTreePutArgStk* treeNode)
{
- assert(treeNode->OperGet() == GT_PUTARG_STK);
+ assert(treeNode->OperIs(GT_PUTARG_STK));
var_types targetType = treeNode->TypeGet();
GenTreePtr source = treeNode->gtOp1;
emitter* emit = getEmitter();
@@ -284,6 +662,14 @@ void CodeGen::genPutArgStk(GenTreePutArgStk* treeNode)
genConsumeAddress(addrNode);
addrReg = addrNode->gtRegNum;
+ // If addrReg equal to loReg, swap(loReg, hiReg)
+ // This reduces code complexity by only supporting one addrReg overwrite case
+ if (loReg == addrReg)
+ {
+ loReg = hiReg;
+ hiReg = addrReg;
+ }
+
CORINFO_CLASS_HANDLE objClass = source->gtObj.gtClass;
structSize = compiler->info.compCompHnd->getClassSize(objClass);
@@ -291,8 +677,6 @@ void CodeGen::genPutArgStk(GenTreePutArgStk* treeNode)
gcPtrCount = compiler->info.compCompHnd->getClassGClayout(objClass, &gcPtrs[0]);
}
- bool hasGCpointers = (gcPtrCount > 0); // true if there are any GC pointers in the struct
-
// If we have an HFA we can't have any GC pointers,
// if not then the max size for the the struct is 16 bytes
if (isHfa)
@@ -306,28 +690,9 @@ void CodeGen::genPutArgStk(GenTreePutArgStk* treeNode)
noway_assert(structSize <= MAX_PASS_MULTIREG_BYTES);
- // For a 16-byte structSize with GC pointers we will use two ldr and two str instructions
- // ldr x2, [x0]
- // ldr x3, [x0, #8]
- // str x2, [sp, #16]
- // str x3, [sp, #24]
- //
- // For a 16-byte structSize with no GC pointers we will use a ldp and two str instructions
+ // For a >= 16-byte structSize we will generate a ldp and stp instruction each loop
// ldp x2, x3, [x0]
- // str x2, [sp, #16]
- // str x3, [sp, #24]
- //
- // For a 32-byte structSize with no GC pointers we will use two ldp and four str instructions
- // ldp x2, x3, [x0]
- // str x2, [sp, #16]
- // str x3, [sp, #24]
- // ldp x2, x3, [x0]
- // str x2, [sp, #32]
- // str x3, [sp, #40]
- //
- // Note that when loading from a varNode we currently can't use the ldp instruction
- // TODO-ARM64-CQ: Implement support for using a ldp instruction with a varNum (see emitIns_R_S)
- //
+ // stp x2, x3, [sp, #16]
int remainingSize = structSize;
unsigned structOffset = 0;
@@ -338,63 +703,26 @@ void CodeGen::genPutArgStk(GenTreePutArgStk* treeNode)
var_types type0 = compiler->getJitGCType(gcPtrs[nextIndex + 0]);
var_types type1 = compiler->getJitGCType(gcPtrs[nextIndex + 1]);
- if (hasGCpointers)
+ if (varNode != nullptr)
{
- // We have GC pointers, so use two ldr instructions
- //
- // We must do it this way because we can't currently pass or track
- // two different emitAttr values for a ldp instruction.
-
- // Make sure that the first load instruction does not overwrite the addrReg.
- //
- if (loReg != addrReg)
- {
- if (varNode != nullptr)
- {
- // Load from our varNumImp source
- emit->emitIns_R_S(ins_Load(type0), emitTypeSize(type0), loReg, varNumInp, 0);
- emit->emitIns_R_S(ins_Load(type1), emitTypeSize(type1), hiReg, varNumInp,
- TARGET_POINTER_SIZE);
- }
- else
- {
- // Load from our address expression source
- emit->emitIns_R_R_I(ins_Load(type0), emitTypeSize(type0), loReg, addrReg, structOffset);
- emit->emitIns_R_R_I(ins_Load(type1), emitTypeSize(type1), hiReg, addrReg,
- structOffset + TARGET_POINTER_SIZE);
- }
- }
- else // loReg == addrReg
- {
- assert(varNode == nullptr); // because addrReg is REG_NA when varNode is non-null
- assert(hiReg != addrReg);
- // Load from our address expression source
- emit->emitIns_R_R_I(ins_Load(type1), emitTypeSize(type1), hiReg, addrReg,
- structOffset + TARGET_POINTER_SIZE);
- emit->emitIns_R_R_I(ins_Load(type0), emitTypeSize(type0), loReg, addrReg, structOffset);
- }
+ // Load from our varNumImp source
+ emit->emitIns_R_R_S_S(INS_ldp, emitTypeSize(type0), emitTypeSize(type1), loReg, hiReg, varNumInp,
+ 0);
}
- else // our struct has no GC pointers
+ else
{
- if (varNode != nullptr)
- {
- // Load from our varNumImp source, currently we can't use a ldp instruction to do this
- emit->emitIns_R_S(ins_Load(type0), emitTypeSize(type0), loReg, varNumInp, 0);
- emit->emitIns_R_S(ins_Load(type1), emitTypeSize(type1), hiReg, varNumInp, TARGET_POINTER_SIZE);
- }
- else
- {
- // Use a ldp instruction
+ // check for case of destroying the addrRegister while we still need it
+ assert(loReg != addrReg);
+ noway_assert((remainingSize == 2 * TARGET_POINTER_SIZE) || (hiReg != addrReg));
- // Load from our address expression source
- emit->emitIns_R_R_R_I(INS_ldp, EA_PTRSIZE, loReg, hiReg, addrReg, structOffset);
- }
+ // Load from our address expression source
+ emit->emitIns_R_R_R_I(INS_ldp, emitTypeSize(type0), loReg, hiReg, addrReg, structOffset,
+ INS_OPTS_NONE, emitTypeSize(type0));
}
- // Emit two store instructions to store the two registers into the outgoing argument area
- emit->emitIns_S_R(ins_Store(type0), emitTypeSize(type0), loReg, varNumOut, argOffsetOut);
- emit->emitIns_S_R(ins_Store(type1), emitTypeSize(type1), hiReg, varNumOut,
- argOffsetOut + TARGET_POINTER_SIZE);
+ // Emit stp instruction to store the two registers into the outgoing argument area
+ emit->emitIns_S_S_R_R(INS_stp, emitTypeSize(type0), emitTypeSize(type1), loReg, hiReg, varNumOut,
+ argOffsetOut);
argOffsetOut += (2 * TARGET_POINTER_SIZE); // We stored 16-bytes of the struct
assert(argOffsetOut <= argOffsetMax); // We can't write beyound the outgoing area area
@@ -408,23 +736,9 @@ void CodeGen::genPutArgStk(GenTreePutArgStk* treeNode)
// ldr w3, [x0, #8]
// str x2, [sp, #16]
// str w3, [sp, #24]
- //
- // When the first instruction has a loReg that is the same register as the addrReg,
- // we set deferLoad to true and issue the intructions in the reverse order
- // ldr x3, [x2, #8]
- // ldr x2, [x2]
- // str x2, [sp, #16]
- // str x3, [sp, #24]
- //
var_types nextType = compiler->getJitGCType(gcPtrs[nextIndex]);
emitAttr nextAttr = emitTypeSize(nextType);
- regNumber curReg = loReg;
-
- bool deferLoad = false;
- var_types deferType = TYP_UNKNOWN;
- emitAttr deferAttr = EA_PTRSIZE;
- int deferOffset = 0;
while (remainingSize > 0)
{
@@ -432,31 +746,23 @@ void CodeGen::genPutArgStk(GenTreePutArgStk* treeNode)
{
remainingSize -= TARGET_POINTER_SIZE;
- if ((curReg == addrReg) && (remainingSize != 0))
+ if (varNode != nullptr)
{
- deferLoad = true;
- deferType = nextType;
- deferAttr = emitTypeSize(nextType);
- deferOffset = structOffset;
+ // Load from our varNumImp source
+ emit->emitIns_R_S(ins_Load(nextType), nextAttr, loReg, varNumInp, structOffset);
}
- else // the typical case
+ else
{
- if (varNode != nullptr)
- {
- // Load from our varNumImp source
- emit->emitIns_R_S(ins_Load(nextType), nextAttr, curReg, varNumInp, structOffset);
- }
- else
- {
- // Load from our address expression source
- emit->emitIns_R_R_I(ins_Load(nextType), nextAttr, curReg, addrReg, structOffset);
- }
- // Emit a store instruction to store the register into the outgoing argument area
- emit->emitIns_S_R(ins_Store(nextType), nextAttr, curReg, varNumOut, argOffsetOut);
- argOffsetOut += EA_SIZE_IN_BYTES(nextAttr);
- assert(argOffsetOut <= argOffsetMax); // We can't write beyound the outgoing area area
+ assert(loReg != addrReg);
+
+ // Load from our address expression source
+ emit->emitIns_R_R_I(ins_Load(nextType), nextAttr, loReg, addrReg, structOffset);
}
- curReg = hiReg;
+ // Emit a store instruction to store the register into the outgoing argument area
+ emit->emitIns_S_R(ins_Store(nextType), nextAttr, loReg, varNumOut, argOffsetOut);
+ argOffsetOut += EA_SIZE_IN_BYTES(nextAttr);
+ assert(argOffsetOut <= argOffsetMax); // We can't write beyound the outgoing area area
+
structOffset += TARGET_POINTER_SIZE;
nextIndex++;
nextType = compiler->getJitGCType(gcPtrs[nextIndex]);
@@ -491,39 +797,52 @@ void CodeGen::genPutArgStk(GenTreePutArgStk* treeNode)
instruction loadIns = ins_Load(loadType);
emitAttr loadAttr = emitAttr(loadSize);
- // When deferLoad is false, curReg can be the same as addrReg
- // because the last instruction is allowed to overwrite addrReg.
- //
- noway_assert(!deferLoad || (curReg != addrReg));
+ assert(loReg != addrReg);
- emit->emitIns_R_R_I(loadIns, loadAttr, curReg, addrReg, structOffset);
+ emit->emitIns_R_R_I(loadIns, loadAttr, loReg, addrReg, structOffset);
// Emit a store instruction to store the register into the outgoing argument area
- emit->emitIns_S_R(ins_Store(loadType), loadAttr, curReg, varNumOut, argOffsetOut);
+ emit->emitIns_S_R(ins_Store(loadType), loadAttr, loReg, varNumOut, argOffsetOut);
argOffsetOut += EA_SIZE_IN_BYTES(loadAttr);
assert(argOffsetOut <= argOffsetMax); // We can't write beyound the outgoing area area
}
}
- if (deferLoad)
- {
- // We should never have to do a deferred load when we have a LclVar source
- assert(varNode == nullptr);
+#endif // _TARGET_ARM64_
+ }
+ }
+}
+
+//---------------------------------------------------------------------
+// genPutArgReg - generate code for a GT_PUTARG_REG node
+//
+// Arguments
+// tree - the GT_PUTARG_REG node
+//
+// Return value:
+// None
+//
+void CodeGen::genPutArgReg(GenTreeOp* tree)
+{
+ assert(tree->OperIs(GT_PUTARG_REG));
+ var_types targetType = tree->TypeGet();
+ regNumber targetReg = tree->gtRegNum;
- curReg = addrReg;
+ // Any TYP_STRUCT register args should have been removed by fgMorphMultiregStructArg
+ assert(targetType != TYP_STRUCT);
- // Load from our address expression source
- emit->emitIns_R_R_I(ins_Load(deferType), deferAttr, curReg, addrReg, deferOffset);
+ // We have a normal non-Struct targetType
- // Emit a store instruction to store the register into the outgoing argument area
- emit->emitIns_S_R(ins_Store(nextType), nextAttr, curReg, varNumOut, argOffsetOut);
- argOffsetOut += EA_SIZE_IN_BYTES(nextAttr);
- assert(argOffsetOut <= argOffsetMax); // We can't write beyound the outgoing area area
- }
+ GenTree* op1 = tree->gtOp1;
+ genConsumeReg(op1);
-#endif // _TARGET_ARM64_
- }
+ // If child node is not already in the register we need, move it
+ if (targetReg != op1->gtRegNum)
+ {
+ inst_RV_RV(ins_Copy(targetType), targetReg, op1->gtRegNum, targetType);
}
+
+ genProduceReg(tree);
}
//----------------------------------------------------------------------------------
@@ -646,6 +965,54 @@ void CodeGen::genRangeCheck(GenTreePtr oper)
genJumpToThrowHlpBlk(jmpKind, SCK_RNGCHK_FAIL, bndsChk->gtIndRngFailBB);
}
+//---------------------------------------------------------------------
+// genCodeForPhysReg - generate code for a GT_PHYSREG node
+//
+// Arguments
+// tree - the GT_PHYSREG node
+//
+// Return value:
+// None
+//
+void CodeGen::genCodeForPhysReg(GenTreePhysReg* tree)
+{
+ assert(tree->OperIs(GT_PHYSREG));
+ var_types targetType = tree->TypeGet();
+ regNumber targetReg = tree->gtRegNum;
+
+ if (targetReg != tree->gtSrcReg)
+ {
+ inst_RV_RV(ins_Copy(targetType), targetReg, tree->gtSrcReg, targetType);
+ genTransferRegGCState(targetReg, tree->gtSrcReg);
+ }
+
+ genProduceReg(tree);
+}
+
+//---------------------------------------------------------------------
+// genCodeForNullCheck - generate code for a GT_NULLCHECK node
+//
+// Arguments
+// tree - the GT_NULLCHECK node
+//
+// Return value:
+// None
+//
+void CodeGen::genCodeForNullCheck(GenTreeOp* tree)
+{
+ assert(tree->OperIs(GT_NULLCHECK));
+ assert(!tree->gtOp1->isContained());
+ regNumber addrReg = genConsumeReg(tree->gtOp1);
+
+#ifdef _TARGET_ARM64_
+ regNumber targetReg = REG_ZR;
+#else
+ regNumber targetReg = tree->gtRegNum;
+#endif
+
+ getEmitter()->emitIns_R_R_I(INS_ldr, EA_4BYTE, targetReg, addrReg, 0);
+}
+
//------------------------------------------------------------------------
// genOffsetOfMDArrayLowerBound: Returns the offset from the Array object to the
// lower bound for the given dimension.
@@ -853,6 +1220,137 @@ void CodeGen::genCodeForShift(GenTreePtr tree)
genProduceReg(tree);
}
+//------------------------------------------------------------------------
+// genCodeForCast: Generates the code for GT_CAST.
+//
+// Arguments:
+// tree - the GT_CAST node.
+//
+void CodeGen::genCodeForCast(GenTreeOp* tree)
+{
+ assert(tree->OperIs(GT_CAST));
+
+ var_types targetType = tree->TypeGet();
+ regNumber targetReg = tree->gtRegNum;
+
+ // Cast is never contained (?)
+ noway_assert(targetReg != REG_NA);
+
+ if (varTypeIsFloating(targetType) && varTypeIsFloating(tree->gtOp1))
+ {
+ // Casts float/double <--> double/float
+ genFloatToFloatCast(tree);
+ }
+ else if (varTypeIsFloating(tree->gtOp1))
+ {
+ // Casts float/double --> int32/int64
+ genFloatToIntCast(tree);
+ }
+ else if (varTypeIsFloating(targetType))
+ {
+ // Casts int32/uint32/int64/uint64 --> float/double
+ genIntToFloatCast(tree);
+ }
+ else
+ {
+ // Casts int <--> int
+ genIntToIntCast(tree);
+ }
+ // The per-case functions call genProduceReg()
+}
+
+//------------------------------------------------------------------------
+// genCodeForLclAddr: Generates the code for GT_LCL_FLD_ADDR/GT_LCL_VAR_ADDR.
+//
+// Arguments:
+// tree - the node.
+//
+void CodeGen::genCodeForLclAddr(GenTree* tree)
+{
+ assert(tree->OperIs(GT_LCL_FLD_ADDR, GT_LCL_VAR_ADDR));
+
+ var_types targetType = tree->TypeGet();
+ regNumber targetReg = tree->gtRegNum;
+
+ // Address of a local var. This by itself should never be allocated a register.
+ // If it is worth storing the address in a register then it should be cse'ed into
+ // a temp and that would be allocated a register.
+ noway_assert(targetType == TYP_BYREF);
+ noway_assert(!tree->InReg());
+
+ inst_RV_TT(INS_lea, targetReg, tree, 0, EA_BYREF);
+ genProduceReg(tree);
+}
+
+//------------------------------------------------------------------------
+// genCodeForLclFld: Produce code for a GT_LCL_FLD node.
+//
+// Arguments:
+// tree - the GT_LCL_FLD node
+//
+void CodeGen::genCodeForLclFld(GenTreeLclFld* tree)
+{
+ assert(tree->OperIs(GT_LCL_FLD));
+
+ var_types targetType = tree->TypeGet();
+ regNumber targetReg = tree->gtRegNum;
+ emitter* emit = getEmitter();
+
+ NYI_IF(targetType == TYP_STRUCT, "GT_LCL_FLD: struct load local field not supported");
+ NYI_IF(targetReg == REG_NA, "GT_LCL_FLD: load local field not into a register is not supported");
+
+ emitAttr size = emitTypeSize(targetType);
+ unsigned offs = tree->gtLclOffs;
+ unsigned varNum = tree->gtLclNum;
+ assert(varNum < compiler->lvaCount);
+
+ if (varTypeIsFloating(targetType))
+ {
+ if (tree->InReg())
+ {
+ NYI("GT_LCL_FLD with register to register Floating point move");
+ }
+ else
+ {
+ emit->emitIns_R_S(ins_Load(targetType), size, targetReg, varNum, offs);
+ }
+ }
+ else
+ {
+#ifdef _TARGET_ARM64_
+ size = EA_SET_SIZE(size, EA_8BYTE);
+#endif // _TARGET_ARM64_
+ emit->emitIns_R_S(ins_Move_Extend(targetType, tree->InReg()), size, targetReg, varNum, offs);
+ }
+
+ genProduceReg(tree);
+}
+
+//------------------------------------------------------------------------
+// genCodeForIndir: Produce code for a GT_IND node.
+//
+// Arguments:
+// tree - the GT_IND node
+//
+void CodeGen::genCodeForIndir(GenTreeIndir* tree)
+{
+ assert(tree->OperIs(GT_IND));
+
+ var_types targetType = tree->TypeGet();
+ regNumber targetReg = tree->gtRegNum;
+ emitter* emit = getEmitter();
+
+ genConsumeAddress(tree->Addr());
+ emit->emitInsLoadStoreOp(ins_Load(targetType), emitTypeSize(tree), targetReg, tree);
+ genProduceReg(tree);
+
+ if (tree->gtFlags & GTF_IND_VOLATILE)
+ {
+ // issue a full memory barrier after a volatile LdInd operation
+ instGen_MemoryBarrier();
+ }
+}
+
// Generate code for a CpBlk node by the means of the VM memcpy helper call
// Preconditions:
// a) The size argument of the CpBlk is not an integer constant
@@ -873,7 +1371,19 @@ void CodeGen::genCodeForCpBlk(GenTreeBlk* cpBlkNode)
}
#endif // _TARGET_ARM64_
+ if (cpBlkNode->gtFlags & GTF_BLK_VOLATILE)
+ {
+ // issue a full memory barrier before & after a volatile CpBlkUnroll operation
+ instGen_MemoryBarrier();
+ }
+
genEmitHelperCall(CORINFO_HELP_MEMCPY, 0, EA_UNKNOWN);
+
+ if (cpBlkNode->gtFlags & GTF_BLK_VOLATILE)
+ {
+ // issue a full memory barrier before & after a volatile CpBlkUnroll operation
+ instGen_MemoryBarrier();
+ }
}
// Generates code for InitBlk by calling the VM memset helper function.
@@ -910,6 +1420,13 @@ void CodeGen::genCodeForInitBlk(GenTreeBlk* initBlkNode)
#endif // _TARGET_ARM64_
genConsumeBlockOp(initBlkNode, REG_ARG_0, REG_ARG_1, REG_ARG_2);
+
+ if (initBlkNode->gtFlags & GTF_BLK_VOLATILE)
+ {
+ // issue a full memory barrier before a volatile initBlock Operation
+ instGen_MemoryBarrier();
+ }
+
genEmitHelperCall(CORINFO_HELP_MEMSET, 0, EA_UNKNOWN);
}
@@ -1830,6 +2347,63 @@ void CodeGen::genCodeForJumpTrue(GenTreePtr tree)
}
}
+//------------------------------------------------------------------------
+// genCodeForStoreBlk: Produce code for a GT_STORE_OBJ/GT_STORE_DYN_BLK/GT_STORE_BLK node.
+//
+// Arguments:
+// tree - the node
+//
+void CodeGen::genCodeForStoreBlk(GenTreeBlk* blkOp)
+{
+ assert(blkOp->OperIs(GT_STORE_OBJ, GT_STORE_DYN_BLK, GT_STORE_BLK));
+
+ if (blkOp->OperIs(GT_STORE_OBJ) && blkOp->OperIsCopyBlkOp())
+ {
+ assert(blkOp->AsObj()->gtGcPtrCount != 0);
+ genCodeForCpObj(blkOp->AsObj());
+ return;
+ }
+
+ if (blkOp->gtBlkOpGcUnsafe)
+ {
+ getEmitter()->emitDisableGC();
+ }
+ bool isCopyBlk = blkOp->OperIsCopyBlkOp();
+
+ switch (blkOp->gtBlkOpKind)
+ {
+ case GenTreeBlk::BlkOpKindHelper:
+ if (isCopyBlk)
+ {
+ genCodeForCpBlk(blkOp);
+ }
+ else
+ {
+ genCodeForInitBlk(blkOp);
+ }
+ break;
+
+ case GenTreeBlk::BlkOpKindUnroll:
+ if (isCopyBlk)
+ {
+ genCodeForCpBlkUnroll(blkOp);
+ }
+ else
+ {
+ genCodeForInitBlkUnroll(blkOp);
+ }
+ break;
+
+ default:
+ unreached();
+ }
+
+ if (blkOp->gtBlkOpGcUnsafe)
+ {
+ getEmitter()->emitEnableGC();
+ }
+}
+
#endif // _TARGET_ARMARCH_
#endif // !LEGACY_BACKEND
diff --git a/src/jit/codegencommon.cpp b/src/jit/codegencommon.cpp
index 64561de..94cc9b9 100644
--- a/src/jit/codegencommon.cpp
+++ b/src/jit/codegencommon.cpp
@@ -631,6 +631,8 @@ regMaskTP Compiler::compHelperCallKillSet(CorInfoHelpFunc helper)
return RBM_WRITE_BARRIER_SRC_BYREF | RBM_WRITE_BARRIER_DST_BYREF | RBM_CALLEE_TRASH_NOGC;
#elif defined(_TARGET_X86_)
return RBM_ESI | RBM_EDI | RBM_ECX;
+#elif defined(_TARGET_ARM_)
+ return RBM_ARG_1 | RBM_ARG_0 | RBM_CALLEE_TRASH_NOGC;
#else
NYI("Model kill set for CORINFO_HELP_ASSIGN_BYREF on target arch");
return RBM_CALLEE_TRASH;
@@ -7444,7 +7446,17 @@ void CodeGen::genProfilingEnterCallback(regNumber initReg, bool* pInitRegZeroed)
var_types storeType = varDsc->lvaArgType();
regNumber argReg = varDsc->lvArgReg;
- getEmitter()->emitIns_S_R(ins_Store(storeType), emitTypeSize(storeType), argReg, varNum, 0);
+
+ instruction store_ins = ins_Store(storeType);
+
+#ifdef FEATURE_SIMD
+ if ((storeType == TYP_SIMD8) && genIsValidIntReg(argReg))
+ {
+ store_ins = INS_mov;
+ }
+#endif // FEATURE_SIMD
+
+ getEmitter()->emitIns_S_R(store_ins, emitTypeSize(storeType), argReg, varNum, 0);
}
}
@@ -7507,7 +7519,17 @@ void CodeGen::genProfilingEnterCallback(regNumber initReg, bool* pInitRegZeroed)
var_types loadType = varDsc->lvaArgType();
regNumber argReg = varDsc->lvArgReg;
- getEmitter()->emitIns_R_S(ins_Load(loadType), emitTypeSize(loadType), argReg, varNum, 0);
+
+ instruction load_ins = ins_Load(loadType);
+
+#ifdef FEATURE_SIMD
+ if ((loadType == TYP_SIMD8) && genIsValidIntReg(argReg))
+ {
+ load_ins = INS_mov;
+ }
+#endif // FEATURE_SIMD
+
+ getEmitter()->emitIns_R_S(load_ins, emitTypeSize(loadType), argReg, varNum, 0);
#if FEATURE_VARARG
if (compiler->info.compIsVarArgs && varTypeIsFloating(loadType))
diff --git a/src/jit/codegenlinear.cpp b/src/jit/codegenlinear.cpp
index c8fcd88..afc7db3 100644
--- a/src/jit/codegenlinear.cpp
+++ b/src/jit/codegenlinear.cpp
@@ -1087,7 +1087,11 @@ void CodeGen::genCheckConsumeNode(GenTree* const node)
if (verbose)
{
- if ((node->gtDebugFlags & GTF_DEBUG_NODE_CG_CONSUMED) != 0)
+ if (node->gtUseNum == -1)
+ {
+ // nothing wrong if the node was not consumed
+ }
+ else if ((node->gtDebugFlags & GTF_DEBUG_NODE_CG_CONSUMED) != 0)
{
printf("Node was consumed twice:\n");
compiler->gtDispTree(node, nullptr, nullptr, true);
@@ -1224,7 +1228,7 @@ void CodeGen::genConsumeRegs(GenTree* tree)
genConsumeAddress(tree->AsIndir()->Addr());
}
#ifdef _TARGET_XARCH_
- else if (tree->OperGet() == GT_LCL_VAR)
+ else if (tree->OperIsLocalRead())
{
// A contained lcl var must be living on stack and marked as reg optional, or not be a
// register candidate.
diff --git a/src/jit/codegenlinear.h b/src/jit/codegenlinear.h
index 715e87a..3bd0eac 100644
--- a/src/jit/codegenlinear.h
+++ b/src/jit/codegenlinear.h
@@ -11,9 +11,7 @@
#ifndef LEGACY_BACKEND // Not necessary (it's this way in the #include location), but helpful to IntelliSense
void genSetRegToConst(regNumber targetReg, var_types targetType, GenTreePtr tree);
-
void genCodeForTreeNode(GenTreePtr treeNode);
-
void genCodeForBinary(GenTreePtr treeNode);
#if defined(_TARGET_X86_)
@@ -21,11 +19,8 @@ void genCodeForLongUMod(GenTreeOp* node);
#endif // _TARGET_X86_
void genCodeForDivMod(GenTreeOp* treeNode);
-
void genCodeForMulHi(GenTreeOp* treeNode);
-
void genLeaInstruction(GenTreeAddrMode* lea);
-
void genSetRegToCond(regNumber dstReg, GenTreePtr tree);
#if !defined(_TARGET_64BIT_)
@@ -33,26 +28,24 @@ void genLongToIntCast(GenTreePtr treeNode);
#endif
void genIntToIntCast(GenTreePtr treeNode);
-
void genFloatToFloatCast(GenTreePtr treeNode);
-
void genFloatToIntCast(GenTreePtr treeNode);
-
void genIntToFloatCast(GenTreePtr treeNode);
-
void genCkfinite(GenTreePtr treeNode);
-
+void genCodeForCompare(GenTreeOp* tree);
void genIntrinsic(GenTreePtr treeNode);
-
void genPutArgStk(GenTreePutArgStk* treeNode);
+void genPutArgReg(GenTreeOp* tree);
+
+#if defined(_TARGET_XARCH_)
unsigned getBaseVarForPutArgStk(GenTreePtr treeNode);
+#endif // _TARGET_XARCH_
#if defined(_TARGET_XARCH_) || defined(_TARGET_ARM64_)
unsigned getFirstArgWithStackSlot();
#endif // _TARGET_XARCH_ || _TARGET_ARM64_
void genCompareFloat(GenTreePtr treeNode);
-
void genCompareInt(GenTreePtr treeNode);
#if !defined(_TARGET_64BIT_)
@@ -87,7 +80,6 @@ void genSIMDIntrinsicGetItem(GenTreeSIMD* simdNode);
void genSIMDIntrinsicShuffleSSE2(GenTreeSIMD* simdNode);
void genSIMDIntrinsicUpperSave(GenTreeSIMD* simdNode);
void genSIMDIntrinsicUpperRestore(GenTreeSIMD* simdNode);
-
void genSIMDIntrinsic(GenTreeSIMD* simdNode);
void genSIMDCheck(GenTree* treeNode);
@@ -115,11 +107,8 @@ void genStoreLongLclVar(GenTree* treeNode);
#endif // !defined(_TARGET_64BIT_)
void genProduceReg(GenTree* tree);
-
void genUnspillRegIfNeeded(GenTree* tree);
-
regNumber genConsumeReg(GenTree* tree);
-
void genCopyRegIfNeeded(GenTree* tree, regNumber needReg);
void genConsumeRegAndCopy(GenTree* tree, regNumber needReg);
@@ -132,13 +121,9 @@ void genConsumeIfReg(GenTreePtr tree)
}
void genRegCopy(GenTreePtr tree);
-
void genTransferRegGCState(regNumber dst, regNumber src);
-
void genConsumeAddress(GenTree* addr);
-
void genConsumeAddrMode(GenTreeAddrMode* mode);
-
void genSetBlockSize(GenTreeBlk* blkNode, regNumber sizeReg);
void genConsumeBlockSrc(GenTreeBlk* blkNode);
void genSetBlockSrc(GenTreeBlk* blkNode, regNumber srcReg);
@@ -149,13 +134,9 @@ void genConsumePutStructArgStk(GenTreePutArgStk* putArgStkNode, regNumber dstReg
#endif // FEATURE_PUT_STRUCT_ARG_STK
void genConsumeRegs(GenTree* tree);
-
void genConsumeOperands(GenTreeOp* tree);
-
void genEmitGSCookieCheck(bool pushReg);
-
void genSetRegToIcon(regNumber reg, ssize_t val, var_types type = TYP_INT, insFlags flags = INS_FLAGS_DONT_CARE);
-
void genCodeForShift(GenTreePtr tree);
#if defined(_TARGET_X86_) || defined(_TARGET_ARM_)
@@ -166,13 +147,24 @@ void genCodeForShiftLong(GenTreePtr tree);
void genCodeForShiftRMW(GenTreeStoreInd* storeInd);
#endif // _TARGET_XARCH_
+void genCodeForCast(GenTreeOp* tree);
+void genCodeForLclAddr(GenTree* tree);
+void genCodeForIndir(GenTreeIndir* tree);
+void genCodeForNegNot(GenTree* tree);
+void genCodeForLclVar(GenTreeLclVar* tree);
+void genCodeForLclFld(GenTreeLclFld* tree);
+void genCodeForStoreLclFld(GenTreeLclFld* tree);
+void genCodeForStoreLclVar(GenTreeLclVar* tree);
+void genCodeForReturnTrap(GenTreeOp* tree);
+void genCodeForJcc(GenTreeJumpCC* tree);
+void genCodeForStoreInd(GenTreeStoreInd* tree);
+void genCodeForSwap(GenTreeOp* tree);
void genCodeForCpObj(GenTreeObj* cpObjNode);
-
void genCodeForCpBlk(GenTreeBlk* cpBlkNode);
-
void genCodeForCpBlkRepMovs(GenTreeBlk* cpBlkNode);
-
void genCodeForCpBlkUnroll(GenTreeBlk* cpBlkNode);
+void genCodeForPhysReg(GenTreePhysReg* tree);
+void genCodeForNullCheck(GenTreeOp* tree);
void genAlignStackBeforeCall(GenTreePutArgStk* putArgStk);
void genAlignStackBeforeCall(GenTreeCall* call);
@@ -231,43 +223,27 @@ void genStoreRegToStackArg(var_types type, regNumber reg, int offset);
#endif // FEATURE_PUT_STRUCT_ARG_STK
void genCodeForLoadOffset(instruction ins, emitAttr size, regNumber dst, GenTree* base, unsigned offset);
-
void genCodeForStoreOffset(instruction ins, emitAttr size, regNumber src, GenTree* base, unsigned offset);
#ifdef _TARGET_ARM64_
void genCodeForLoadPairOffset(regNumber dst, regNumber dst2, GenTree* base, unsigned offset);
-
void genCodeForStorePairOffset(regNumber src, regNumber src2, GenTree* base, unsigned offset);
#endif // _TARGET_ARM64_
void genCodeForStoreBlk(GenTreeBlk* storeBlkNode);
-
void genCodeForInitBlk(GenTreeBlk* initBlkNode);
-
void genCodeForInitBlkRepStos(GenTreeBlk* initBlkNode);
-
void genCodeForInitBlkUnroll(GenTreeBlk* initBlkNode);
-
void genJumpTable(GenTree* tree);
-
void genTableBasedSwitch(GenTree* tree);
-
void genCodeForArrIndex(GenTreeArrIndex* treeNode);
-
void genCodeForArrOffset(GenTreeArrOffs* treeNode);
-
instruction genGetInsForOper(genTreeOps oper, var_types type);
-
void genStoreInd(GenTreePtr node);
-
bool genEmitOptimizedGCWriteBarrier(GCInfo::WriteBarrierForm writeBarrierForm, GenTree* addr, GenTree* data);
-
void genCallInstruction(GenTreeCall* call);
-
void genJmpMethod(GenTreePtr jmp);
-
BasicBlock* genCallFinally(BasicBlock* block);
-
void genCodeForJumpTrue(GenTreePtr tree);
#if FEATURE_EH_FUNCLETS
@@ -282,7 +258,6 @@ void genMultiRegCallStoreToLocal(GenTreePtr treeNode);
bool isStructReturn(GenTreePtr treeNode);
void genStructReturn(GenTreePtr treeNode);
-// Codegen for GT_RETURN.
void genReturn(GenTreePtr treeNode);
void genLclHeap(GenTreePtr tree);
diff --git a/src/jit/codegenxarch.cpp b/src/jit/codegenxarch.cpp
index d693ff9..252f004 100644
--- a/src/jit/codegenxarch.cpp
+++ b/src/jit/codegenxarch.cpp
@@ -1558,6 +1558,8 @@ void CodeGen::genCodeForTreeNode(GenTreePtr treeNode)
GenTreePtr op1 = treeNode->gtGetOp1();
genConsumeRegs(op1);
emit->emitInsBinary(ins_Store(targetType), emitTypeSize(treeNode), treeNode, op1);
+
+ genUpdateLife(treeNode);
}
break;
@@ -5404,8 +5406,9 @@ void CodeGen::genJmpMethod(GenTreePtr jmp)
// assert should hold.
assert(varDsc->lvRegNum != REG_STK);
- var_types loadType = varDsc->lvaArgType();
- getEmitter()->emitIns_S_R(ins_Store(loadType), emitTypeSize(loadType), varDsc->lvRegNum, varNum, 0);
+ assert(!varDsc->lvIsStructField || (compiler->lvaTable[varDsc->lvParentLcl].lvFieldCnt == 1));
+ var_types storeType = genActualType(varDsc->lvaArgType()); // We own the memory and can use the full move.
+ getEmitter()->emitIns_S_R(ins_Store(storeType), emitTypeSize(storeType), varDsc->lvRegNum, varNum, 0);
// Update lvRegNum life and GC info to indicate lvRegNum is dead and varDsc stack slot is going live.
// Note that we cannot modify varDsc->lvRegNum here because another basic block may not be expecting it.
diff --git a/src/jit/compiler.h b/src/jit/compiler.h
index 998b647..5bff8dd 100644
--- a/src/jit/compiler.h
+++ b/src/jit/compiler.h
@@ -3187,7 +3187,7 @@ private:
static fgWalkPreFn impFindValueClasses;
void impSpillLclRefs(ssize_t lclNum);
- BasicBlock* impPushCatchArgOnStack(BasicBlock* hndBlk, CORINFO_CLASS_HANDLE clsHnd);
+ BasicBlock* impPushCatchArgOnStack(BasicBlock* hndBlk, CORINFO_CLASS_HANDLE clsHnd, bool isSingleBlockFilter);
void impImportBlockCode(BasicBlock* block);
@@ -4719,7 +4719,7 @@ private:
const SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR* structDescPtr));
void fgFixupStructReturn(GenTreePtr call);
- GenTreePtr fgMorphLocalVar(GenTreePtr tree);
+ GenTreePtr fgMorphLocalVar(GenTreePtr tree, bool forceRemorph);
bool fgAddrCouldBeNull(GenTreePtr addr);
GenTreePtr fgMorphField(GenTreePtr tree, MorphAddrContext* mac);
bool fgCanFastTailCall(GenTreeCall* call);
@@ -5005,7 +5005,8 @@ protected:
unsigned lnum,
LoopHoistContext* hoistCtxt,
bool* firstBlockAndBeforeSideEffect,
- bool* pHoistable);
+ bool* pHoistable,
+ bool* pCctorDependent);
// Performs the hoisting 'tree' into the PreHeader for loop 'lnum'
void optHoistCandidate(GenTreePtr tree, unsigned lnum, LoopHoistContext* hoistCtxt);
diff --git a/src/jit/copyprop.cpp b/src/jit/copyprop.cpp
index bf714f0..b17956d 100644
--- a/src/jit/copyprop.cpp
+++ b/src/jit/copyprop.cpp
@@ -296,7 +296,7 @@ void Compiler::optBlockCopyProp(BasicBlock* block, LclNumToGenTreePtrStack* curS
VarSetOps::Assign(this, compCurLife, block->bbLiveIn);
for (GenTreePtr stmt = block->bbTreeList; stmt; stmt = stmt->gtNext)
{
- VarSetOps::ClearD(this, optCopyPropKillSet);
+ VarSetOps::OldStyleClearD(this, optCopyPropKillSet);
// Walk the tree to find if any local variable can be replaced with current live definitions.
for (GenTreePtr tree = stmt->gtStmt.gtStmtList; tree; tree = tree->gtNext)
diff --git a/src/jit/decomposelongs.cpp b/src/jit/decomposelongs.cpp
index d284c1c..4168e77 100644
--- a/src/jit/decomposelongs.cpp
+++ b/src/jit/decomposelongs.cpp
@@ -922,11 +922,15 @@ GenTree* DecomposeLongs::DecomposeNeg(LIR::Use& use)
loResult->gtType = TYP_INT;
loResult->gtOp.gtOp1 = loOp1;
- GenTree* zero = m_compiler->gtNewZeroConNode(TYP_INT);
+ GenTree* zero = m_compiler->gtNewZeroConNode(TYP_INT);
+#if defined(_TARGET_X86_)
GenTree* hiAdjust = m_compiler->gtNewOperNode(GT_ADD_HI, TYP_INT, hiOp1, zero);
GenTree* hiResult = m_compiler->gtNewOperNode(GT_NEG, TYP_INT, hiAdjust);
-
Range().InsertAfter(loResult, zero, hiAdjust, hiResult);
+#elif defined(_TARGET_ARM_)
+ GenTree* hiResult = m_compiler->gtNewOperNode(GT_SUB_HI, TYP_INT, zero, hiOp1);
+ Range().InsertAfter(loResult, zero, hiResult);
+#endif
return FinalizeDecomposition(use, loResult, hiResult, hiResult);
}
diff --git a/src/jit/ee_il_dll.cpp b/src/jit/ee_il_dll.cpp
index c0384f3..3389608 100644
--- a/src/jit/ee_il_dll.cpp
+++ b/src/jit/ee_il_dll.cpp
@@ -1295,7 +1295,7 @@ const char* Compiler::eeGetMethodName(CORINFO_METHOD_HANDLE method, const char**
// If it's something unknown from a RET VM, or from SuperPMI, then use our own helper name table.
if ((strcmp(name, "AnyJITHelper") == 0) || (strcmp(name, "Yickish helper name") == 0))
{
- if (ftnNum < CORINFO_HELP_COUNT)
+ if ((unsigned)ftnNum < CORINFO_HELP_COUNT)
{
name = jitHlpFuncTable[ftnNum];
}
diff --git a/src/jit/emit.cpp b/src/jit/emit.cpp
index 3b765b9..d2aa29f 100644
--- a/src/jit/emit.cpp
+++ b/src/jit/emit.cpp
@@ -1472,8 +1472,8 @@ void emitter::emitBegProlog()
/* Nothing is live on entry to the prolog */
// These were initialized to Empty at the start of compilation.
- VarSetOps::ClearD(emitComp, emitInitGCrefVars);
- VarSetOps::ClearD(emitComp, emitPrevGCrefVars);
+ VarSetOps::OldStyleClearD(emitComp, emitInitGCrefVars);
+ VarSetOps::OldStyleClearD(emitComp, emitPrevGCrefVars);
emitInitGCrefRegs = RBM_NONE;
emitPrevGCrefRegs = RBM_NONE;
emitInitByrefRegs = RBM_NONE;
@@ -4564,7 +4564,7 @@ unsigned emitter::emitEndCodeGen(Compiler* comp,
/* Assume no live GC ref variables on entry */
- VarSetOps::ClearD(emitComp, emitThisGCrefVars); // This is initialized to Empty at the start of codegen.
+ VarSetOps::OldStyleClearD(emitComp, emitThisGCrefVars); // This is initialized to Empty at the start of codegen.
emitThisGCrefRegs = emitThisByrefRegs = RBM_NONE;
emitThisGCrefVset = true;
diff --git a/src/jit/emit.h b/src/jit/emit.h
index e1c924f..5ec8a6a 100644
--- a/src/jit/emit.h
+++ b/src/jit/emit.h
@@ -718,7 +718,7 @@ protected:
#define ID_EXTRA_BITFIELD_BITS (16)
#elif defined(_TARGET_ARM64_)
-// For Arm64, we have used 15 bits from the second DWORD.
+// For Arm64, we have used 16 bits from the second DWORD.
#define ID_EXTRA_BITFIELD_BITS (16)
#elif defined(_TARGET_XARCH_) && !defined(LEGACY_BACKEND)
// For xarch !LEGACY_BACKEND, we have used 14 bits from the second DWORD.
@@ -882,14 +882,16 @@ protected:
void checkSizes();
union idAddrUnion {
- // TODO-Cleanup: We should really add a DEBUG-only tag to this union so we can add asserts
- // about reading what we think is here, to avoid unexpected corruption issues.
+// TODO-Cleanup: We should really add a DEBUG-only tag to this union so we can add asserts
+// about reading what we think is here, to avoid unexpected corruption issues.
+#ifndef _TARGET_ARM64_
emitLclVarAddr iiaLclVar;
- BasicBlock* iiaBBlabel;
- insGroup* iiaIGlabel;
- BYTE* iiaAddr;
- emitAddrMode iiaAddrMode;
+#endif
+ BasicBlock* iiaBBlabel;
+ insGroup* iiaIGlabel;
+ BYTE* iiaAddr;
+ emitAddrMode iiaAddrMode;
CORINFO_FIELD_HANDLE iiaFieldHnd; // iiaFieldHandle is also used to encode
// an offset into the JIT data constant area
@@ -920,11 +922,14 @@ protected:
struct
{
- regNumber _idReg3 : REGNUM_BITS;
- regNumber _idReg4 : REGNUM_BITS;
#ifdef _TARGET_ARM64_
- unsigned _idReg3Scaled : 1; // Reg3 is scaled by idOpSize bits
+ // For 64-bit architecture this 32-bit structure can pack with these unsigned bit fields
+ emitLclVarAddr iiaLclVar;
+ unsigned _idReg3Scaled : 1; // Reg3 is scaled by idOpSize bits
+ GCtype _idGCref2 : 2;
#endif
+ regNumber _idReg3 : REGNUM_BITS;
+ regNumber _idReg4 : REGNUM_BITS;
};
#elif defined(_TARGET_XARCH_) && !defined(LEGACY_BACKEND)
struct
@@ -1072,6 +1077,21 @@ protected:
assert(reg == _idReg1);
}
+#ifdef _TARGET_ARM64_
+ GCtype idGCrefReg2() const
+ {
+ assert(!idIsTiny());
+ assert(!idIsSmallDsc());
+ return (GCtype)idAddr()->_idGCref2;
+ }
+ void idGCrefReg2(GCtype gctype)
+ {
+ assert(!idIsTiny());
+ assert(!idIsSmallDsc());
+ idAddr()->_idGCref2 = gctype;
+ }
+#endif // _TARGET_ARM64_
+
regNumber idReg2() const
{
return _idReg2;
@@ -2006,6 +2026,9 @@ public:
// Returns true if the instruction may write to more than one register.
bool emitInsMayWriteMultipleRegs(instrDesc* id);
+
+ // Returns "true" if instruction "id->idIns()" writes to a LclVar stack slot pair.
+ bool emitInsWritesToLclVarStackLocPair(instrDesc* id);
#endif // _TARGET_ARMARCH_
/************************************************************************/
diff --git a/src/jit/emitarm64.cpp b/src/jit/emitarm64.cpp
index 0328cb6..4097b66 100644
--- a/src/jit/emitarm64.cpp
+++ b/src/jit/emitarm64.cpp
@@ -883,6 +883,26 @@ bool emitter::emitInsWritesToLclVarStackLoc(instrDesc* id)
}
}
+bool emitter::emitInsWritesToLclVarStackLocPair(instrDesc* id)
+{
+ if (!id->idIsLclVar())
+ return false;
+
+ instruction ins = id->idIns();
+
+ // This list is related to the list of instructions used to store local vars in emitIns_S_S_R_R().
+ // We don't accept writing to float local vars.
+
+ switch (ins)
+ {
+ case INS_stnp:
+ case INS_stp:
+ return true;
+ default:
+ return false;
+ }
+}
+
bool emitter::emitInsMayWriteMultipleRegs(instrDesc* id)
{
instruction ins = id->idIns();
@@ -3858,6 +3878,26 @@ void emitter::emitIns_R_R(
fmt = IF_DV_2M;
break;
+ case INS_ldar:
+ case INS_stlr:
+ assert(isValidGeneralDatasize(size));
+
+ __fallthrough;
+
+ case INS_ldarb:
+ case INS_ldarh:
+ case INS_stlrb:
+ case INS_stlrh:
+ assert(isValidGeneralLSDatasize(size));
+ assert(isGeneralRegisterOrZR(reg1));
+ assert(isGeneralRegisterOrSP(reg2));
+ assert(insOptsNone(opt));
+
+ reg2 = encodingSPtoZR(reg2);
+
+ fmt = IF_LS_2A;
+ break;
+
case INS_ldr:
case INS_ldrb:
case INS_ldrh:
@@ -5072,7 +5112,8 @@ void emitter::emitIns_R_R_R_I(instruction ins,
regNumber reg2,
regNumber reg3,
ssize_t imm,
- insOpts opt /* = INS_OPTS_NONE */)
+ insOpts opt /* = INS_OPTS_NONE */,
+ emitAttr attrReg2 /* = EA_UNKNOWN */)
{
emitAttr size = EA_SIZE(attr);
emitAttr elemsize = EA_UNKNOWN;
@@ -5347,6 +5388,22 @@ void emitter::emitIns_R_R_R_I(instruction ins,
id->idReg2(reg2);
id->idReg3(reg3);
+ // Record the attribute for the second register in the pair
+ id->idGCrefReg2(GCT_NONE);
+ if (attrReg2 != EA_UNKNOWN)
+ {
+ // Record the attribute for the second register in the pair
+ assert((fmt == IF_LS_3B) || (fmt == IF_LS_3C));
+ if (EA_IS_GCREF(attrReg2))
+ {
+ id->idGCrefReg2(GCT_GCREF);
+ }
+ else if (EA_IS_BYREF(attrReg2))
+ {
+ id->idGCrefReg2(GCT_BYREF);
+ }
+ }
+
dispIns(id);
appendToCurIG(id);
}
@@ -6072,6 +6129,102 @@ void emitter::emitIns_R_S(instruction ins, emitAttr attr, regNumber reg1, int va
/*****************************************************************************
*
+ * Add an instruction referencing two register and consectutive stack-based local variable slots.
+ */
+void emitter::emitIns_R_R_S_S(
+ instruction ins, emitAttr attr1, emitAttr attr2, regNumber reg1, regNumber reg2, int varx, int offs)
+{
+ assert((ins == INS_ldp) || (ins == INS_ldnp));
+ assert(EA_8BYTE == EA_SIZE(attr1));
+ assert(EA_8BYTE == EA_SIZE(attr2));
+ assert(isGeneralRegisterOrZR(reg1));
+ assert(isGeneralRegisterOrZR(reg2));
+ assert(offs >= 0);
+
+ emitAttr size = EA_SIZE(attr1);
+ insFormat fmt = IF_LS_3B;
+ int disp = 0;
+ const unsigned scale = 3;
+
+ /* Figure out the variable's frame position */
+ int base;
+ bool FPbased;
+
+ base = emitComp->lvaFrameAddress(varx, &FPbased);
+ disp = base + offs;
+
+ // TODO-ARM64-CQ: with compLocallocUsed, should we use REG_SAVED_LOCALLOC_SP instead?
+ regNumber reg3 = FPbased ? REG_FPBASE : REG_SPBASE;
+ reg3 = encodingSPtoZR(reg3);
+
+ bool useRegForAdr = true;
+ ssize_t imm = disp;
+ ssize_t mask = (1 << scale) - 1; // the mask of low bits that must be zero to encode the immediate
+ if (imm == 0)
+ {
+ useRegForAdr = false;
+ }
+ else
+ {
+ if ((imm & mask) == 0)
+ {
+ ssize_t immShift = imm >> scale; // The immediate is scaled by the size of the ld/st
+
+ if ((immShift >= -64) && (immShift <= 63))
+ {
+ fmt = IF_LS_3C;
+ useRegForAdr = false;
+ imm = immShift;
+ }
+ }
+ }
+
+ if (useRegForAdr)
+ {
+ regNumber rsvd = codeGen->rsGetRsvdReg();
+ emitIns_R_R_Imm(INS_add, EA_8BYTE, rsvd, reg3, imm);
+ reg3 = rsvd;
+ imm = 0;
+ }
+
+ assert(fmt != IF_NONE);
+
+ instrDesc* id = emitNewInstrCns(attr1, imm);
+
+ id->idIns(ins);
+ id->idInsFmt(fmt);
+ id->idInsOpt(INS_OPTS_NONE);
+
+ // Record the attribute for the second register in the pair
+ if (EA_IS_GCREF(attr2))
+ {
+ id->idGCrefReg2(GCT_GCREF);
+ }
+ else if (EA_IS_BYREF(attr2))
+ {
+ id->idGCrefReg2(GCT_BYREF);
+ }
+ else
+ {
+ id->idGCrefReg2(GCT_NONE);
+ }
+
+ id->idReg1(reg1);
+ id->idReg2(reg2);
+ id->idReg3(reg3);
+ id->idAddr()->iiaLclVar.initLclVarAddr(varx, offs);
+ id->idSetIsLclVar();
+
+#ifdef DEBUG
+ id->idDebugOnlyInfo()->idVarRefOffs = emitVarRefOffs;
+#endif
+
+ dispIns(id);
+ appendToCurIG(id);
+}
+
+/*****************************************************************************
+ *
* Add an instruction referencing a stack-based local variable and a register
*/
void emitter::emitIns_S_R(instruction ins, emitAttr attr, regNumber reg1, int varx, int offs)
@@ -6202,6 +6355,102 @@ void emitter::emitIns_S_R(instruction ins, emitAttr attr, regNumber reg1, int va
/*****************************************************************************
*
+ * Add an instruction referencing consecutive stack-based local variable slots and two registers
+ */
+void emitter::emitIns_S_S_R_R(
+ instruction ins, emitAttr attr1, emitAttr attr2, regNumber reg1, regNumber reg2, int varx, int offs)
+{
+ assert((ins == INS_stp) || (ins == INS_stnp));
+ assert(EA_8BYTE == EA_SIZE(attr1));
+ assert(EA_8BYTE == EA_SIZE(attr2));
+ assert(isGeneralRegisterOrZR(reg1));
+ assert(isGeneralRegisterOrZR(reg2));
+ assert(offs >= 0);
+
+ emitAttr size = EA_SIZE(attr1);
+ insFormat fmt = IF_LS_3B;
+ int disp = 0;
+ const unsigned scale = 3;
+
+ /* Figure out the variable's frame position */
+ int base;
+ bool FPbased;
+
+ base = emitComp->lvaFrameAddress(varx, &FPbased);
+ disp = base + offs;
+
+ // TODO-ARM64-CQ: with compLocallocUsed, should we use REG_SAVED_LOCALLOC_SP instead?
+ regNumber reg3 = FPbased ? REG_FPBASE : REG_SPBASE;
+ reg3 = encodingSPtoZR(reg3);
+
+ bool useRegForAdr = true;
+ ssize_t imm = disp;
+ ssize_t mask = (1 << scale) - 1; // the mask of low bits that must be zero to encode the immediate
+ if (imm == 0)
+ {
+ useRegForAdr = false;
+ }
+ else
+ {
+ if ((imm & mask) == 0)
+ {
+ ssize_t immShift = imm >> scale; // The immediate is scaled by the size of the ld/st
+
+ if ((immShift >= -64) && (immShift <= 63))
+ {
+ fmt = IF_LS_3C;
+ useRegForAdr = false;
+ imm = immShift;
+ }
+ }
+ }
+
+ if (useRegForAdr)
+ {
+ regNumber rsvd = codeGen->rsGetRsvdReg();
+ emitIns_R_R_Imm(INS_add, EA_8BYTE, rsvd, reg3, imm);
+ reg3 = rsvd;
+ imm = 0;
+ }
+
+ assert(fmt != IF_NONE);
+
+ instrDesc* id = emitNewInstrCns(attr1, imm);
+
+ id->idIns(ins);
+ id->idInsFmt(fmt);
+ id->idInsOpt(INS_OPTS_NONE);
+
+ // Record the attribute for the second register in the pair
+ if (EA_IS_GCREF(attr2))
+ {
+ id->idGCrefReg2(GCT_GCREF);
+ }
+ else if (EA_IS_BYREF(attr2))
+ {
+ id->idGCrefReg2(GCT_BYREF);
+ }
+ else
+ {
+ id->idGCrefReg2(GCT_NONE);
+ }
+
+ id->idReg1(reg1);
+ id->idReg2(reg2);
+ id->idReg3(reg3);
+ id->idAddr()->iiaLclVar.initLclVarAddr(varx, offs);
+ id->idSetIsLclVar();
+
+#ifdef DEBUG
+ id->idDebugOnlyInfo()->idVarRefOffs = emitVarRefOffs;
+#endif
+
+ dispIns(id);
+ appendToCurIG(id);
+}
+
+/*****************************************************************************
+ *
* Add an instruction referencing stack-based local variable and an immediate
*/
void emitter::emitIns_S_I(instruction ins, emitAttr attr, int varx, int offs, int val)
@@ -9324,33 +9573,34 @@ size_t emitter::emitOutputInstr(insGroup* ig, instrDesc* id, BYTE** dp)
// for stores, but we ignore those cases here.)
if (emitInsMayWriteToGCReg(id)) // True if "id->idIns()" writes to a register than can hold GC ref.
{
- // If we ever generate instructions that write to multiple registers,
- // then we'd need to more work here to ensure that changes in the status of GC refs are
- // tracked properly.
- if (emitInsMayWriteMultipleRegs(id))
+ // We assume that "idReg1" is the primary destination register for all instructions
+ if (id->idGCref() != GCT_NONE)
{
- // INS_ldp etc...
- // We assume that "idReg1" and "idReg2" are the destination register for all instructions
- emitGCregDeadUpd(id->idReg1(), dst);
- emitGCregDeadUpd(id->idReg2(), dst);
+ emitGCregLiveUpd(id->idGCref(), id->idReg1(), dst);
}
else
{
- // We assume that "idReg1" is the destination register for all instructions
- if (id->idGCref() != GCT_NONE)
+ emitGCregDeadUpd(id->idReg1(), dst);
+ }
+
+ if (emitInsMayWriteMultipleRegs(id))
+ {
+ // INS_ldp etc...
+ // "idReg2" is the secondary destination register
+ if (id->idGCrefReg2() != GCT_NONE)
{
- emitGCregLiveUpd(id->idGCref(), id->idReg1(), dst);
+ emitGCregLiveUpd(id->idGCrefReg2(), id->idReg2(), dst);
}
else
{
- emitGCregDeadUpd(id->idReg1(), dst);
+ emitGCregDeadUpd(id->idReg2(), dst);
}
}
}
// Now we determine if the instruction has written to a (local variable) stack location, and either written a GC
// ref or overwritten one.
- if (emitInsWritesToLclVarStackLoc(id))
+ if (emitInsWritesToLclVarStackLoc(id) || emitInsWritesToLclVarStackLocPair(id))
{
int varNum = id->idAddr()->iiaLclVar.lvaVarNum();
unsigned ofs = AlignDown(id->idAddr()->iiaLclVar.lvaOffset(), sizeof(size_t));
@@ -9377,6 +9627,31 @@ size_t emitter::emitOutputInstr(insGroup* ig, instrDesc* id, BYTE** dp)
if (vt == TYP_REF || vt == TYP_BYREF)
emitGCvarDeadUpd(adr + ofs, dst);
}
+ if (emitInsWritesToLclVarStackLocPair(id))
+ {
+ unsigned ofs2 = ofs + sizeof(size_t);
+ if (id->idGCrefReg2() != GCT_NONE)
+ {
+ emitGCvarLiveUpd(adr + ofs2, varNum, id->idGCrefReg2(), dst);
+ }
+ else
+ {
+ // If the type of the local is a gc ref type, update the liveness.
+ var_types vt;
+ if (varNum >= 0)
+ {
+ // "Regular" (non-spill-temp) local.
+ vt = var_types(emitComp->lvaTable[varNum].lvType);
+ }
+ else
+ {
+ TempDsc* tmpDsc = emitComp->tmpFindNum(varNum);
+ vt = tmpDsc->tdTempType();
+ }
+ if (vt == TYP_REF || vt == TYP_BYREF)
+ emitGCvarDeadUpd(adr + ofs2, dst);
+ }
+ }
}
#ifdef DEBUG
diff --git a/src/jit/emitarm64.h b/src/jit/emitarm64.h
index 6a8e42b..09158fb 100644
--- a/src/jit/emitarm64.h
+++ b/src/jit/emitarm64.h
@@ -724,7 +724,8 @@ void emitIns_R_R_R_I(instruction ins,
regNumber reg2,
regNumber reg3,
ssize_t imm,
- insOpts opt = INS_OPTS_NONE);
+ insOpts opt = INS_OPTS_NONE,
+ emitAttr attrReg2 = EA_UNKNOWN);
void emitIns_R_R_R_Ext(instruction ins,
emitAttr attr,
@@ -757,8 +758,14 @@ void emitIns_S(instruction ins, emitAttr attr, int varx, int offs);
void emitIns_S_R(instruction ins, emitAttr attr, regNumber ireg, int varx, int offs);
+void emitIns_S_S_R_R(
+ instruction ins, emitAttr attr, emitAttr attr2, regNumber ireg, regNumber ireg2, int varx, int offs);
+
void emitIns_R_S(instruction ins, emitAttr attr, regNumber ireg, int varx, int offs);
+void emitIns_R_R_S_S(
+ instruction ins, emitAttr attr, emitAttr attr2, regNumber ireg, regNumber ireg2, int varx, int offs);
+
void emitIns_S_I(instruction ins, emitAttr attr, int varx, int offs, int val);
void emitIns_R_C(
diff --git a/src/jit/emitxarch.cpp b/src/jit/emitxarch.cpp
index 7608130..8614069 100644
--- a/src/jit/emitxarch.cpp
+++ b/src/jit/emitxarch.cpp
@@ -4821,6 +4821,12 @@ void emitter::emitIns_S_R(instruction ins, emitAttr attr, regNumber ireg, int va
UNATIVE_OFFSET sz = emitInsSizeSV(insCodeMR(ins), varx, offs);
insFormat fmt = emitInsModeFormat(ins, IF_SRD_RRD);
+#ifdef _TARGET_X86_
+ if (attr == EA_1BYTE)
+ {
+ assert(isByteReg(ireg));
+ }
+#endif
// 16-bit operand instructions will need a prefix
if (EA_SIZE(attr) == EA_2BYTE)
{
diff --git a/src/jit/flowgraph.cpp b/src/jit/flowgraph.cpp
index 0c57862..f11d556 100644
--- a/src/jit/flowgraph.cpp
+++ b/src/jit/flowgraph.cpp
@@ -1815,9 +1815,9 @@ void Compiler::fgComputeReachabilitySets()
for (block = fgFirstBB; block != nullptr; block = block->bbNext)
{
- // Initialize the per-block bbReach sets. (Note that we can't just call BlockSetOps::ClearD()
- // when re-running this computation, because if the epoch changes, the size and representation of the
- // sets might change).
+ // Initialize the per-block bbReach sets. It creates a new empty set,
+ // because the block epoch could change since the previous initialization
+ // and the old set could have wrong size.
block->bbReach = BlockSetOps::MakeEmpty(this);
/* Mark block as reaching itself */
@@ -4335,7 +4335,7 @@ void Compiler::fgFindJumpTargets(const BYTE* codeAddr, IL_OFFSET codeSize, BYTE*
DECODE_OPCODE:
- if (opcode >= CEE_COUNT)
+ if ((unsigned)opcode >= CEE_COUNT)
{
BADCODE3("Illegal opcode", ": %02X", (int)opcode);
}
@@ -5231,7 +5231,7 @@ unsigned Compiler::fgMakeBasicBlocks(const BYTE* codeAddr, IL_OFFSET codeSize, B
/* Get the size of additional parameters */
- noway_assert(opcode < CEE_COUNT);
+ noway_assert((unsigned)opcode < CEE_COUNT);
sz = opcodeSizes[opcode];
@@ -10011,7 +10011,7 @@ void Compiler::fgCompactBlocks(BasicBlock* block, BasicBlock* bNext)
if (fgDomsComputed && block->bbNum > fgDomBBcount)
{
BlockSetOps::Assign(this, block->bbReach, bNext->bbReach);
- BlockSetOps::ClearD(this, bNext->bbReach);
+ BlockSetOps::OldStyleClearD(this, bNext->bbReach);
block->bbIDom = bNext->bbIDom;
bNext->bbIDom = nullptr;
@@ -17055,8 +17055,8 @@ bool Compiler::fgCheckEHCanInsertAfterBlock(BasicBlock* blk, unsigned regionInde
//
// Return Value:
// A block with the desired characteristics, so the new block will be inserted after this one.
-// If there is no suitable location, return nullptr. This should basically never happen except in the case of
-// single-block filters.
+// If there is no suitable location, return nullptr. This should basically never happen.
+//
BasicBlock* Compiler::fgFindInsertPoint(unsigned regionIndex,
bool putInTryRegion,
BasicBlock* startBlk,
@@ -17284,19 +17284,21 @@ BasicBlock* Compiler::fgFindInsertPoint(unsigned regionIndex,
DONE:
+#if defined(JIT32_GCENCODER)
// If we are inserting into a filter and the best block is the end of the filter region, we need to
- // insert after its predecessor instead: the CLR ABI states that the terminal block of a filter region
- // is its exit block. If the filter region consists of a single block, a new block cannot be inserted
- // without either splitting the single block before inserting a new block or inserting the new block
- // before the single block and updating the filter description such that the inserted block is marked
- // as the entry block for the filter. This work must be done by the caller; this function returns
- // `nullptr` to indicate this case.
- if (insertingIntoFilter && (bestBlk == endBlk->bbPrev) && (bestBlk == startBlk))
+ // insert after its predecessor instead: the JIT32 GC encoding used by the x86 CLR ABI states that the
+ // terminal block of a filter region is its exit block. If the filter region consists of a single block,
+ // a new block cannot be inserted without either splitting the single block before inserting a new block
+ // or inserting the new block before the single block and updating the filter description such that the
+ // inserted block is marked as the entry block for the filter. Becuase this sort of split can be complex
+ // (especially given that it must ensure that the liveness of the exception object is properly tracked),
+ // we avoid this situation by never generating single-block filters on x86 (see impPushCatchArgOnStack).
+ if (insertingIntoFilter && (bestBlk == endBlk->bbPrev))
{
- assert(bestBlk != nullptr);
- assert(bestBlk->bbJumpKind == BBJ_EHFILTERRET);
- bestBlk = nullptr;
+ assert(bestBlk != startBlk);
+ bestBlk = bestBlk->bbPrev;
}
+#endif // defined(JIT32_GCENCODER)
return bestBlk;
}
@@ -17475,21 +17477,6 @@ BasicBlock* Compiler::fgNewBBinRegion(BBjumpKinds jumpKind,
// Now find the insertion point.
afterBlk = fgFindInsertPoint(regionIndex, putInTryRegion, startBlk, endBlk, nearBlk, nullptr, runRarely);
- // If afterBlk is nullptr, we must be inserting into a single-block filter region. Because the CLR ABI requires
- // that control exits a filter via the last instruction in the filter range, this situation requires logically
- // splitting the single block. In practice, we simply insert a new block at the beginning of the filter region
- // that transfers control flow to the existing single block.
- if (afterBlk == nullptr)
- {
- assert(putInFilter);
-
- BasicBlock* newFilterEntryBlock = fgNewBBbefore(BBJ_ALWAYS, startBlk, true);
- newFilterEntryBlock->bbJumpDest = startBlk;
- fgAddRefPred(startBlk, newFilterEntryBlock);
-
- afterBlk = newFilterEntryBlock;
- }
-
_FoundAfterBlk:;
/* We have decided to insert the block after 'afterBlk'. */
@@ -17788,10 +17775,12 @@ BasicBlock* Compiler::fgAddCodeRef(BasicBlock* srcBlk, unsigned refData, Special
#if defined(UNIX_X86_ABI)
codeGen->setFrameRequired(true);
+ codeGen->setFramePointerRequiredGCInfo(true);
#else // !defined(UNIX_X86_ABI)
if (add->acdStkLvl != stkDepth)
{
codeGen->setFrameRequired(true);
+ codeGen->setFramePointerRequiredGCInfo(true);
}
#endif // !defined(UNIX_X86_ABI)
#endif // _TARGET_X86_
diff --git a/src/jit/gentree.cpp b/src/jit/gentree.cpp
index a2156d0..25e9e10 100644
--- a/src/jit/gentree.cpp
+++ b/src/jit/gentree.cpp
@@ -5249,6 +5249,13 @@ unsigned Compiler::gtSetEvalOrder(GenTree* tree)
// so if possible it was set above.
tryToSwap = false;
}
+ else if ((oper == GT_INTRINSIC) &&
+ Compiler::IsIntrinsicImplementedByUserCall(tree->AsIntrinsic()->gtIntrinsicId))
+ {
+ // We do not swap operand execution order for intrinsics that are implemented by user calls
+ // because of trickiness around ensuring the execution order does not change during rationalization.
+ tryToSwap = false;
+ }
else
{
if (tree->gtFlags & GTF_REVERSE_OPS)
@@ -11162,7 +11169,7 @@ void Compiler::gtDispLeaf(GenTree* tree, IndentStack* indentStack)
}
else
{
- printf("%d", jitGetILoffs(tree->gtStmt.gtStmtILoffsx));
+ printf("0x%x", jitGetILoffs(tree->gtStmt.gtStmtILoffsx));
}
break;
@@ -17083,4 +17090,4 @@ regNumber GenTree::ExtractTempReg(regMaskTP mask /* = (regMaskTP)-1 */)
return genRegNumFromMask(tempRegMask);
}
-#endif // !LEGACY_BACKEND \ No newline at end of file
+#endif // !LEGACY_BACKEND
diff --git a/src/jit/gentree.h b/src/jit/gentree.h
index d3a03ee..1833a39 100644
--- a/src/jit/gentree.h
+++ b/src/jit/gentree.h
@@ -926,6 +926,7 @@ public:
#define GTF_FLD_NULLCHECK 0x80000000 // GT_FIELD -- need to nullcheck the "this" pointer
#define GTF_FLD_VOLATILE 0x40000000 // GT_FIELD/GT_CLS_VAR -- same as GTF_IND_VOLATILE
+#define GTF_FLD_INITCLASS 0x20000000 // GT_FIELD/GT_CLS_VAR -- field access requires preceding class/static init helper
#define GTF_INX_RNGCHK 0x80000000 // GT_INDEX -- the array reference should be range-checked.
#define GTF_INX_REFARR_LAYOUT 0x20000000 // GT_INDEX -- same as GTF_IND_REFARR_LAYOUT
@@ -955,8 +956,10 @@ public:
(GTF_IND_VOLATILE | GTF_IND_REFARR_LAYOUT | GTF_IND_TGTANYWHERE | GTF_IND_NONFAULTING | GTF_IND_TLS_REF | \
GTF_IND_UNALIGNED | GTF_IND_INVARIANT | GTF_IND_ARR_INDEX)
-#define GTF_CLS_VAR_ASG_LHS 0x04000000 // GT_CLS_VAR -- this GT_CLS_VAR node is (the effective val) of the LHS
- // of an assignment; don't evaluate it independently.
+#define GTF_CLS_VAR_ASG_LHS 0x04000000 // GT_CLS_VAR -- this GT_CLS_VAR node is (the effective val) of the LHS
+ // of an assignment; don't evaluate it independently.
+#define GTF_CLS_VAR_VOLATILE 0x40000000 // GT_FIELD/GT_CLS_VAR -- same as GTF_IND_VOLATILE
+#define GTF_CLS_VAR_INITCLASS 0x20000000 // GT_FIELD/GT_CLS_VAR -- same as GTF_FLD_INITCLASS
#define GTF_ADDR_ONSTACK 0x80000000 // GT_ADDR -- this expression is guaranteed to be on the stack
@@ -1004,6 +1007,14 @@ public:
#define GTF_ICON_SIMD_COUNT 0x04000000 // GT_CNS_INT -- constant is Vector<T>.Count
+#define GTF_ICON_INITCLASS 0x02000000 // GT_CNS_INT -- Constant is used to access a static that requires preceding
+ // class/static init helper. In some cases, the constant is
+ // the address of the static field itself, and in other cases
+ // there's an extra layer of indirection and it is the address
+ // of the cell that the runtime will fill in with the address
+ // of the static field; in both of those cases, the constant
+ // is what gets flagged.
+
#define GTF_BLK_VOLATILE 0x40000000 // GT_ASG, GT_STORE_BLK, GT_STORE_OBJ, GT_STORE_DYNBLK
// -- is a volatile block operation
#define GTF_BLK_UNALIGNED 0x02000000 // GT_ASG, GT_STORE_BLK, GT_STORE_OBJ, GT_STORE_DYNBLK
diff --git a/src/jit/importer.cpp b/src/jit/importer.cpp
index a991598..74018c4 100644
--- a/src/jit/importer.cpp
+++ b/src/jit/importer.cpp
@@ -2402,7 +2402,7 @@ void Compiler::impSpillLclRefs(ssize_t lclNum)
* Returns the basic block of the actual handler.
*/
-BasicBlock* Compiler::impPushCatchArgOnStack(BasicBlock* hndBlk, CORINFO_CLASS_HANDLE clsHnd)
+BasicBlock* Compiler::impPushCatchArgOnStack(BasicBlock* hndBlk, CORINFO_CLASS_HANDLE clsHnd, bool isSingleBlockFilter)
{
// Do not inject the basic block twice on reimport. This should be
// hit only under JIT stress. See if the block is the one we injected.
@@ -2440,8 +2440,14 @@ BasicBlock* Compiler::impPushCatchArgOnStack(BasicBlock* hndBlk, CORINFO_CLASS_H
* moved around since it is tied to a fixed location (EAX) */
arg->gtFlags |= GTF_ORDER_SIDEEFF;
+#if defined(JIT32_GCENCODER)
+ const bool forceInsertNewBlock = isSingleBlockFilter || compStressCompile(STRESS_CATCH_ARG, 5);
+#else
+ const bool forceInsertNewBlock = compStressCompile(STRESS_CATCH_ARG, 5);
+#endif // defined(JIT32_GCENCODER)
+
/* Spill GT_CATCH_ARG to a temp if there are jumps to the beginning of the handler */
- if (hndBlk->bbRefs > 1 || compStressCompile(STRESS_CATCH_ARG, 5))
+ if (hndBlk->bbRefs > 1 || forceInsertNewBlock)
{
if (hndBlk->bbRefs == 1)
{
@@ -3520,6 +3526,10 @@ GenTreePtr Compiler::impIntrinsic(GenTreePtr newobjThis,
gtNewIconNode(offsetof(CORINFO_String, stringLen), TYP_I_IMPL));
op1 = gtNewOperNode(GT_IND, TYP_INT, op1);
}
+
+ // Getting the length of a null string should throw
+ op1->gtFlags |= GTF_EXCEPT;
+
retNode = op1;
break;
@@ -6047,6 +6057,11 @@ GenTreePtr Compiler::impImportStaticFieldAccess(CORINFO_RESOLVED_TOKEN* pResolve
// In future, it may be better to just create the right tree here instead of folding it later.
op1 = gtNewFieldRef(lclTyp, pResolvedToken->hField);
+ if (pFieldInfo->fieldFlags & CORINFO_FLG_FIELD_INITCLASS)
+ {
+ op1->gtFlags |= GTF_FLD_INITCLASS;
+ }
+
if (pFieldInfo->fieldFlags & CORINFO_FLG_FIELD_STATIC_IN_HEAP)
{
op1->gtType = TYP_REF; // points at boxed object
@@ -6078,14 +6093,16 @@ GenTreePtr Compiler::impImportStaticFieldAccess(CORINFO_RESOLVED_TOKEN* pResolve
FieldSeqNode* fldSeq = GetFieldSeqStore()->CreateSingleton(pResolvedToken->hField);
/* Create the data member node */
- if (pFldAddr == nullptr)
+ op1 = gtNewIconHandleNode(pFldAddr == nullptr ? (size_t)fldAddr : (size_t)pFldAddr, GTF_ICON_STATIC_HDL,
+ fldSeq);
+
+ if (pFieldInfo->fieldFlags & CORINFO_FLG_FIELD_INITCLASS)
{
- op1 = gtNewIconHandleNode((size_t)fldAddr, GTF_ICON_STATIC_HDL, fldSeq);
+ op1->gtFlags |= GTF_ICON_INITCLASS;
}
- else
- {
- op1 = gtNewIconHandleNode((size_t)pFldAddr, GTF_ICON_STATIC_HDL, fldSeq);
+ if (pFldAddr != nullptr)
+ {
// There are two cases here, either the static is RVA based,
// in which case the type of the FIELD node is not a GC type
// and the handle to the RVA is a TYP_I_IMPL. Or the FIELD node is
@@ -7325,8 +7342,7 @@ var_types Compiler::impImportCall(OPCODE opcode,
// instParam.
instParam = gtNewIconNode(0, TYP_REF);
}
-
- if (!exactContextNeedsRuntimeLookup)
+ else if (!exactContextNeedsRuntimeLookup)
{
#ifdef FEATURE_READYTORUN_COMPILER
if (opts.IsReadyToRun())
@@ -14806,6 +14822,11 @@ void Compiler::impImportBlockCode(BasicBlock* block)
// Could point anywhere, example a boxed class static int
op1->gtFlags |= GTF_IND_TGTANYWHERE | GTF_GLOB_REF;
assertImp(varTypeIsArithmetic(op1->gtType));
+
+ if (prefixFlags & PREFIX_UNALIGNED)
+ {
+ op1->gtFlags |= GTF_IND_UNALIGNED;
+ }
}
else
{
@@ -15616,7 +15637,7 @@ void Compiler::impVerifyEHBlock(BasicBlock* block, bool isTryStart)
// push catch arg the stack, spill to a temp if necessary
// Note: can update HBtab->ebdHndBeg!
- hndBegBB = impPushCatchArgOnStack(hndBegBB, clsHnd);
+ hndBegBB = impPushCatchArgOnStack(hndBegBB, clsHnd, false);
}
// Queue up the handler for importing
@@ -15637,7 +15658,8 @@ void Compiler::impVerifyEHBlock(BasicBlock* block, bool isTryStart)
// push catch arg the stack, spill to a temp if necessary
// Note: can update HBtab->ebdFilter!
- filterBB = impPushCatchArgOnStack(filterBB, impGetObjectClass());
+ const bool isSingleBlockFilter = (filterBB->bbNext == hndBegBB);
+ filterBB = impPushCatchArgOnStack(filterBB, impGetObjectClass(), isSingleBlockFilter);
impImportBlockPending(filterBB);
}
@@ -17954,8 +17976,12 @@ GenTreePtr Compiler::impInlineFetchArg(unsigned lclNum, InlArgInfo* inlArgInfo,
op1 = argInfo.argNode;
argInfo.argTmpNum = op1->gtLclVarCommon.gtLclNum;
- // Use an equivalent copy if this is the second or subsequent use.
- if (argInfo.argIsUsed)
+ // Use an equivalent copy if this is the second or subsequent
+ // use, or if we need to retype.
+ //
+ // Note argument type mismatches that prevent inlining should
+ // have been caught in impInlineInitVars.
+ if (argInfo.argIsUsed || (op1->TypeGet() != lclTyp))
{
assert(op1->gtOper == GT_LCL_VAR);
assert(lclNum == op1->gtLclVar.gtLclILoffs);
@@ -18568,7 +18594,20 @@ void Compiler::impDevirtualizeCall(GenTreeCall* call,
#if defined(DEBUG)
// Validate that callInfo has up to date method flags
const DWORD freshBaseMethodAttribs = info.compCompHnd->getMethodAttribs(baseMethod);
- assert(freshBaseMethodAttribs == baseMethodAttribs);
+
+ // All the base method attributes should agree, save that
+ // CORINFO_FLG_DONT_INLINE may have changed from 0 to 1
+ // because of concurrent jitting activity.
+ //
+ // Note we don't look at this particular flag bit below, and
+ // later on (if we do try and inline) we will rediscover why
+ // the method can't be inlined, so there's no danger here in
+ // seeing this particular flag bit in different states between
+ // the cached and fresh values.
+ if ((freshBaseMethodAttribs & ~CORINFO_FLG_DONT_INLINE) != (baseMethodAttribs & ~CORINFO_FLG_DONT_INLINE))
+ {
+ assert(!"mismatched method attributes");
+ }
#endif // DEBUG
}
diff --git a/src/jit/instrsarm64.h b/src/jit/instrsarm64.h
index e91aaa6..d8c66b3 100644
--- a/src/jit/instrsarm64.h
+++ b/src/jit/instrsarm64.h
@@ -555,6 +555,15 @@ INST2(sli, "sli", 0, 0, IF_EN2N, 0x7F005400, 0x2F005400)
// sli Vd,Vn,imm DV_2N 011111110iiiiiii 010101nnnnnddddd 7F00 5400 Vd Vn imm (shift - scalar)
// sli Vd,Vn,imm DV_2O 0Q1011110iiiiiii 010101nnnnnddddd 2F00 5400 Vd,Vn imm (shift - vector)
+INST1(ldar, "ldar", 0,LD, IF_LS_2A, 0x88DFFC00)
+ // ldar Rt,[Xn] LS_2A 1X00100011011111 111111nnnnnttttt 88DF FC00
+
+INST1(ldarb, "ldarb", 0,LD, IF_LS_2A, 0x08DFFC00)
+ // ldarb Rt,[Xn] LS_2A 0000100011011111 111111nnnnnttttt 08DF FC00
+
+INST1(ldarh, "ldarh", 0,LD, IF_LS_2A, 0x48DFFC00)
+ // ldarh Rt,[Xn] LS_2A 0100100011011111 111111nnnnnttttt 48DF FC00
+
INST1(ldur, "ldur", 0,LD, IF_LS_2C, 0xB8400000)
// ldur Rt,[Xn+simm9] LS_2C 1X111000010iiiii iiii00nnnnnttttt B840 0000 [Xn imm(-256..+255)]
@@ -573,6 +582,15 @@ INST1(ldursh, "ldursh", 0,LD, IF_LS_2C, 0x78800000)
INST1(ldursw, "ldursw", 0,LD, IF_LS_2C, 0xB8800000)
// ldursw Rt,[Xn+simm9] LS_2C 10111000100iiiii iiii00nnnnnttttt B880 0000 [Xn imm(-256..+255)]
+INST1(stlr, "stlr", 0,ST, IF_LS_2A, 0x889FFC00)
+ // stlr Rt,[Xn] LS_2A 1X00100010011111 111111nnnnnttttt 889F FC00
+
+INST1(stlrb, "stlrb", 0,ST, IF_LS_2A, 0x089FFC00)
+ // stlrb Rt,[Xn] LS_2A 0000100010011111 111111nnnnnttttt 089F FC00
+
+INST1(stlrh, "stlrh", 0,ST, IF_LS_2A, 0x489FFC00)
+ // stlrh Rt,[Xn] LS_2A 0100100010011111 111111nnnnnttttt 489F FC00
+
INST1(stur, "stur", 0,ST, IF_LS_2C, 0xB8000000)
// stur Rt,[Xn+simm9] LS_2C 1X111000000iiiii iiii00nnnnnttttt B800 0000 [Xn imm(-256..+255)]
diff --git a/src/jit/lclvars.cpp b/src/jit/lclvars.cpp
index e64b5a1..4770a1d 100644
--- a/src/jit/lclvars.cpp
+++ b/src/jit/lclvars.cpp
@@ -1833,7 +1833,10 @@ bool Compiler::lvaShouldPromoteStructVar(unsigned lclNum, lvaStructPromotionInfo
// TODO-PERF - Implement struct promotion for incoming multireg structs
// Currently it hits assert(lvFieldCnt==1) in lclvar.cpp line 4417
-
+ // Also the implementation of jmp uses the 4 byte move to store
+ // byte parameters to the stack, so that if we have a byte field
+ // with something else occupying the same 4-byte slot, it will
+ // overwrite other fields.
if (structPromotionInfo->fieldCnt != 1)
{
JITDUMP("Not promoting promotable struct local V%02u, because lvIsParam is true and #fields = "
diff --git a/src/jit/liveness.cpp b/src/jit/liveness.cpp
index d498a6f..73f72e7 100644
--- a/src/jit/liveness.cpp
+++ b/src/jit/liveness.cpp
@@ -418,6 +418,8 @@ void Compiler::fgPerBlockLocalVarLiveness()
}
#endif // DEBUG
+ unsigned livenessVarEpoch = GetCurLVEpoch();
+
BasicBlock* block;
#if CAN_DISABLE_DFA
@@ -587,6 +589,7 @@ void Compiler::fgPerBlockLocalVarLiveness()
block->bbMemoryLiveIn = emptyMemoryKindSet;
}
+ noway_assert(livenessVarEpoch == GetCurLVEpoch());
#ifdef DEBUG
if (verbose)
{
diff --git a/src/jit/lower.cpp b/src/jit/lower.cpp
index 035f094..72dba4e 100644
--- a/src/jit/lower.cpp
+++ b/src/jit/lower.cpp
@@ -2872,8 +2872,10 @@ void Lowering::InsertPInvokeMethodProlog()
store->gtOp.gtOp1 = call;
store->gtFlags |= GTF_VAR_DEF;
+ GenTree* const insertionPoint = firstBlockRange.FirstNonPhiOrCatchArgNode();
+
comp->fgMorphTree(store);
- firstBlockRange.InsertAtEnd(LIR::SeqTree(comp, store));
+ firstBlockRange.InsertBefore(insertionPoint, LIR::SeqTree(comp, store));
DISPTREERANGE(firstBlockRange, store);
#if !defined(_TARGET_X86_) && !defined(_TARGET_ARM_)
@@ -2887,7 +2889,7 @@ void Lowering::InsertPInvokeMethodProlog()
GenTreeLclFld(GT_STORE_LCL_FLD, TYP_I_IMPL, comp->lvaInlinedPInvokeFrameVar, callFrameInfo.offsetOfCallSiteSP);
storeSP->gtOp1 = PhysReg(REG_SPBASE);
- firstBlockRange.InsertAtEnd(LIR::SeqTree(comp, storeSP));
+ firstBlockRange.InsertBefore(insertionPoint, LIR::SeqTree(comp, storeSP));
DISPTREERANGE(firstBlockRange, storeSP);
#endif // !defined(_TARGET_X86_) && !defined(_TARGET_ARM_)
@@ -2903,7 +2905,7 @@ void Lowering::InsertPInvokeMethodProlog()
callFrameInfo.offsetOfCalleeSavedFP);
storeFP->gtOp1 = PhysReg(REG_FPBASE);
- firstBlockRange.InsertAtEnd(LIR::SeqTree(comp, storeFP));
+ firstBlockRange.InsertBefore(insertionPoint, LIR::SeqTree(comp, storeFP));
DISPTREERANGE(firstBlockRange, storeFP);
#endif // !defined(_TARGET_ARM_)
@@ -2918,7 +2920,7 @@ void Lowering::InsertPInvokeMethodProlog()
// Push a frame - if we are NOT in an IL stub, this is done right before the call
// The init routine sets InlinedCallFrame's m_pNext, so we just set the thead's top-of-stack
GenTree* frameUpd = CreateFrameLinkUpdate(PushFrame);
- firstBlockRange.InsertAtEnd(LIR::SeqTree(comp, frameUpd));
+ firstBlockRange.InsertBefore(insertionPoint, LIR::SeqTree(comp, frameUpd));
DISPTREERANGE(firstBlockRange, frameUpd);
}
#endif // _TARGET_64BIT_
diff --git a/src/jit/lower.h b/src/jit/lower.h
index bcc2baf..5a55d2d 100644
--- a/src/jit/lower.h
+++ b/src/jit/lower.h
@@ -178,15 +178,19 @@ private:
{
assert(GenTree::OperIsBinary(tree->OperGet()));
- GenTree* op1 = tree->gtGetOp1();
- GenTree* op2 = tree->gtGetOp2();
+ GenTree* const op1 = tree->gtGetOp1();
+ GenTree* const op2 = tree->gtGetOp2();
- if (tree->OperIsCommutative() && tree->TypeGet() == op1->TypeGet())
+ const unsigned operatorSize = genTypeSize(tree->TypeGet());
+
+ const bool op1Legal = tree->OperIsCommutative() && (operatorSize == genTypeSize(op1->TypeGet()));
+ const bool op2Legal = operatorSize == genTypeSize(op2->TypeGet());
+
+ if (op1Legal)
{
- GenTree* preferredOp = PreferredRegOptionalOperand(tree);
- SetRegOptional(preferredOp);
+ SetRegOptional(op2Legal ? PreferredRegOptionalOperand(tree) : op1);
}
- else if (tree->TypeGet() == op2->TypeGet())
+ else if (op2Legal)
{
SetRegOptional(op2);
}
diff --git a/src/jit/lowerarmarch.cpp b/src/jit/lowerarmarch.cpp
index 4ff3552..4c269af 100644
--- a/src/jit/lowerarmarch.cpp
+++ b/src/jit/lowerarmarch.cpp
@@ -175,11 +175,6 @@ void Lowering::LowerBlockStore(GenTreeBlk* blkNode)
if (blkNode->OperGet() == GT_STORE_OBJ)
{
// CopyObj
-
- NYI_ARM("Lowering for GT_STORE_OBJ isn't implemented");
-
-#ifdef _TARGET_ARM64_
-
GenTreeObj* objNode = blkNode->AsObj();
unsigned slots = objNode->gtSlots;
@@ -205,8 +200,6 @@ void Lowering::LowerBlockStore(GenTreeBlk* blkNode)
#endif
blkNode->gtBlkOpKind = GenTreeBlk::BlkOpKindUnroll;
-
-#endif // _TARGET_ARM64_
}
else
{
diff --git a/src/jit/lsra.cpp b/src/jit/lsra.cpp
index 3718ddf..647b058 100644
--- a/src/jit/lsra.cpp
+++ b/src/jit/lsra.cpp
@@ -737,15 +737,30 @@ void LinearScan::associateRefPosWithInterval(RefPosition* rp)
else if (rp->refType == RefTypeUse)
{
// Ensure that we have consistent def/use on SDSU temps.
- // However, in the case of a non-commutative rmw def, we must avoid over-constraining
- // the def, so don't propagate a single-register restriction from the consumer to the producer
+ // However, there are a couple of cases where this may over-constrain allocation:
+ // 1. In the case of a non-commutative rmw def (in which the rmw source must be delay-free), or
+ // 2. In the case where the defining node requires a temp distinct from the target (also a
+ // delay-free case).
+ // In those cases, if we propagate a single-register restriction from the consumer to the producer
+ // the delayed uses will not see a fixed reference in the PhysReg at that position, and may
+ // incorrectly allocate that register.
+ // TODO-CQ: This means that we may often require a copy at the use of this node's result.
+ // This case could be moved to BuildRefPositionsForNode, at the point where the def RefPosition is
+ // created, causing a RefTypeFixedRef to be added at that location. This, however, results in
+ // more PhysReg RefPositions (a throughput impact), and a large number of diffs that require
+ // further analysis to determine benefit.
+ // See Issue #11274.
RefPosition* prevRefPosition = theInterval->recentRefPosition;
assert(prevRefPosition != nullptr && theInterval->firstRefPosition == prevRefPosition);
+ // All defs must have a valid treeNode, but we check it below to be conservative.
+ assert(prevRefPosition->treeNode != nullptr);
regMaskTP prevAssignment = prevRefPosition->registerAssignment;
regMaskTP newAssignment = (prevAssignment & rp->registerAssignment);
if (newAssignment != RBM_NONE)
{
- if (!theInterval->hasNonCommutativeRMWDef || !isSingleRegister(newAssignment))
+ if (!isSingleRegister(newAssignment) ||
+ (!theInterval->hasNonCommutativeRMWDef && (prevRefPosition->treeNode != nullptr) &&
+ !prevRefPosition->treeNode->gtLsraInfo.isInternalRegDelayFree))
{
prevRefPosition->registerAssignment = newAssignment;
}
@@ -1317,6 +1332,8 @@ void LinearScan::setBlockSequence()
compiler->EnsureBasicBlockEpoch();
bbVisitedSet = BlockSetOps::MakeEmpty(compiler);
BlockSet BLOCKSET_INIT_NOCOPY(readySet, BlockSetOps::MakeEmpty(compiler));
+ BlockSet BLOCKSET_INIT_NOCOPY(predSet, BlockSetOps::MakeEmpty(compiler));
+
assert(blockSequence == nullptr && bbSeqCount == 0);
blockSequence = new (compiler, CMK_LSRA) BasicBlock*[compiler->fgBBcount];
bbNumMaxBeforeResolution = compiler->fgBBNumMax;
@@ -1400,7 +1417,7 @@ void LinearScan::setBlockSequence()
// (i.e. pred-first or random, since layout order is handled above).
if (!BlockSetOps::IsMember(compiler, readySet, succ->bbNum))
{
- addToBlockSequenceWorkList(readySet, succ);
+ addToBlockSequenceWorkList(readySet, succ, predSet);
BlockSetOps::AddElemD(compiler, readySet, succ->bbNum);
}
}
@@ -1433,7 +1450,7 @@ void LinearScan::setBlockSequence()
{
if (!isBlockVisited(block))
{
- addToBlockSequenceWorkList(readySet, block);
+ addToBlockSequenceWorkList(readySet, block, predSet);
BlockSetOps::AddElemD(compiler, readySet, block->bbNum);
}
}
@@ -1442,7 +1459,7 @@ void LinearScan::setBlockSequence()
{
if (!isBlockVisited(block))
{
- addToBlockSequenceWorkList(readySet, block);
+ addToBlockSequenceWorkList(readySet, block, predSet);
BlockSetOps::AddElemD(compiler, readySet, block->bbNum);
}
}
@@ -1540,6 +1557,9 @@ int LinearScan::compareBlocksForSequencing(BasicBlock* block1, BasicBlock* block
// Arguments:
// sequencedBlockSet - the set of blocks that are already sequenced
// block - the new block to be added
+// predSet - the buffer to save predecessors set. A block set allocated by the caller used here as a
+// temporary block set for constructing a predecessor set. Allocated by the caller to avoid reallocating a new block
+// set with every call to this function
//
// Return Value:
// None.
@@ -1561,13 +1581,13 @@ int LinearScan::compareBlocksForSequencing(BasicBlock* block1, BasicBlock* block
// Note also that, when random traversal order is implemented, this method
// should insert the blocks into the list in random order, so that we can always
// simply select the first block in the list.
-void LinearScan::addToBlockSequenceWorkList(BlockSet sequencedBlockSet, BasicBlock* block)
+void LinearScan::addToBlockSequenceWorkList(BlockSet sequencedBlockSet, BasicBlock* block, BlockSet& predSet)
{
// The block that is being added is not already sequenced
assert(!BlockSetOps::IsMember(compiler, sequencedBlockSet, block->bbNum));
// Get predSet of block
- BlockSet BLOCKSET_INIT_NOCOPY(predSet, BlockSetOps::MakeEmpty(compiler));
+ BlockSetOps::ClearD(compiler, predSet);
flowList* pred;
for (pred = block->bbPreds; pred != nullptr; pred = pred->flNext)
{
@@ -1723,6 +1743,8 @@ void LinearScan::doLinearScan()
}
#endif // DEBUG
+ unsigned lsraBlockEpoch = compiler->GetCurBasicBlockEpoch();
+
splitBBNumToTargetBBNumMap = nullptr;
// This is complicated by the fact that physical registers have refs associated
@@ -1738,7 +1760,7 @@ void LinearScan::doLinearScan()
DBEXEC(VERBOSE, lsraDumpIntervals("after buildIntervals"));
- BlockSetOps::ClearD(compiler, bbVisitedSet);
+ clearVisitedBlocks();
initVarRegMaps();
allocateRegisters();
compiler->EndPhase(PHASE_LINEAR_SCAN_ALLOC);
@@ -1759,6 +1781,7 @@ void LinearScan::doLinearScan()
DBEXEC(VERBOSE, TupleStyleDump(LSRA_DUMP_POST));
compiler->compLSRADone = true;
+ noway_assert(lsraBlockEpoch = compiler->GetCurBasicBlockEpoch());
}
//------------------------------------------------------------------------
@@ -2747,16 +2770,6 @@ regMaskTP LinearScan::getKillSetForNode(GenTree* tree)
}
break;
- case GT_LSH:
- case GT_RSH:
- case GT_RSZ:
- case GT_ROL:
- case GT_ROR:
- if (tree->gtLsraInfo.isHelperCallWithKills)
- {
- killMask = RBM_CALLEE_TRASH;
- }
- break;
case GT_RETURNTRAP:
killMask = compiler->compHelperCallKillSet(CORINFO_HELP_STOP_FOR_GC);
break;
@@ -5607,6 +5620,22 @@ regNumber LinearScan::tryAllocateFreeReg(Interval* currentInterval, RefPosition*
else if ((bestScore & UNASSIGNED) != 0 && intervalToUnassign != nullptr)
{
availablePhysRegInterval->previousInterval = intervalToUnassign;
+#ifdef _TARGET_ARM_
+ // TODO-ARM-Throughput: For ARM, this should not be necessary, i.e. keeping a same
+ // previous interval in two RegRecords, because we will always manage the register
+ // assignment of TYP_DOUBLE intervals together.
+ // Later we should be able to remove this and update unassignPhysReg() where
+ // previousInterval is used. Please also take a look at unassignPhysReg().
+
+ // Update overlapping floating point register for TYP_DOUBLE
+ if (intervalToUnassign->registerType == TYP_DOUBLE)
+ {
+ assert(isFloatRegType(availablePhysRegInterval->registerType));
+ regNumber nextRegNum = REG_NEXT(availablePhysRegInterval->regNum);
+ RegRecord* nextRegRec = getRegisterRecord(nextRegNum);
+ nextRegRec->previousInterval = intervalToUnassign;
+ }
+#endif
}
}
else
@@ -6027,6 +6056,19 @@ void LinearScan::checkAndAssignInterval(RegRecord* regRec, Interval* interval)
}
regRec->assignedInterval = interval;
+
+#ifdef _TARGET_ARM_
+ // Update second RegRecord of double register
+ if ((interval->registerType == TYP_DOUBLE) && isFloatRegType(regRec->registerType))
+ {
+ assert(genIsValidDoubleReg(regRec->regNum));
+
+ regNumber nextRegNum = REG_NEXT(regRec->regNum);
+ RegRecord* nextRegRec = getRegisterRecord(nextRegNum);
+
+ nextRegRec->assignedInterval = interval;
+ }
+#endif // _TARGET_ARM_
}
// Assign the given physical register interval to the given interval
@@ -6038,16 +6080,6 @@ void LinearScan::assignPhysReg(RegRecord* regRec, Interval* interval)
checkAndAssignInterval(regRec, interval);
interval->assignedReg = regRec;
-#ifdef _TARGET_ARM_
- if ((interval->registerType == TYP_DOUBLE) && isFloatRegType(regRec->registerType))
- {
- regNumber nextRegNum = REG_NEXT(regRec->regNum);
- RegRecord* nextRegRec = getRegisterRecord(nextRegNum);
-
- checkAndAssignInterval(nextRegRec, interval);
- }
-#endif // _TARGET_ARM_
-
interval->physReg = regRec->regNum;
interval->isActive = true;
if (interval->isLocalVar)
@@ -6239,6 +6271,19 @@ void LinearScan::checkAndClearInterval(RegRecord* regRec, RefPosition* spillRefP
}
regRec->assignedInterval = nullptr;
+
+#ifdef _TARGET_ARM_
+ // Update second RegRecord of double register
+ if ((assignedInterval->registerType == TYP_DOUBLE) && isFloatRegType(regRec->registerType))
+ {
+ assert(genIsValidDoubleReg(regRec->regNum));
+
+ regNumber nextRegNum = REG_NEXT(regRec->regNum);
+ RegRecord* nextRegRec = getRegisterRecord(nextRegNum);
+
+ nextRegRec->assignedInterval = nullptr;
+ }
+#endif // _TARGET_ARM_
}
//------------------------------------------------------------------------
@@ -6262,15 +6307,35 @@ void LinearScan::unassignPhysReg(RegRecord* regRec, RefPosition* spillRefPositio
{
Interval* assignedInterval = regRec->assignedInterval;
assert(assignedInterval != nullptr);
- checkAndClearInterval(regRec, spillRefPosition);
+
regNumber thisRegNum = regRec->regNum;
#ifdef _TARGET_ARM_
- if ((assignedInterval->registerType == TYP_DOUBLE) && isFloatRegType(regRec->registerType))
+ regNumber nextRegNum = REG_NA;
+ RegRecord* nextRegRec = nullptr;
+
+ // Prepare second half RegRecord of a double register for TYP_DOUBLE
+ if (assignedInterval->registerType == TYP_DOUBLE)
{
- regNumber nextRegNum = REG_NEXT(regRec->regNum);
- RegRecord* nextRegRec = getRegisterRecord(nextRegNum);
- checkAndClearInterval(nextRegRec, spillRefPosition);
+ assert(isFloatRegType(regRec->registerType));
+ assert(genIsValidDoubleReg(regRec->regNum));
+
+ nextRegNum = REG_NEXT(regRec->regNum);
+ nextRegRec = getRegisterRecord(nextRegNum);
+
+ // Both two RegRecords should have been assigned to the same interval.
+ assert(assignedInterval == nextRegRec->assignedInterval);
+ }
+#endif // _TARGET_ARM_
+
+ checkAndClearInterval(regRec, spillRefPosition);
+
+#ifdef _TARGET_ARM_
+ if (assignedInterval->registerType == TYP_DOUBLE)
+ {
+ // Both two RegRecords should have been unassigned together.
+ assert(regRec->assignedInterval == nullptr);
+ assert(nextRegRec->assignedInterval == nullptr);
}
#endif // _TARGET_ARM_
@@ -6376,6 +6441,18 @@ void LinearScan::unassignPhysReg(RegRecord* regRec, RefPosition* spillRefPositio
{
regRec->assignedInterval = regRec->previousInterval;
regRec->previousInterval = nullptr;
+#ifdef _TARGET_ARM_
+ // Update second half RegRecord of a double register for TYP_DOUBLE
+ if (regRec->assignedInterval->registerType == TYP_DOUBLE)
+ {
+ assert(isFloatRegType(regRec->registerType));
+ assert(genIsValidDoubleReg(regRec->regNum));
+
+ nextRegRec->assignedInterval = nextRegRec->previousInterval;
+ nextRegRec->previousInterval = nullptr;
+ }
+#endif // _TARGET_ARM_
+
#ifdef DEBUG
if (spill)
{
@@ -6392,6 +6469,18 @@ void LinearScan::unassignPhysReg(RegRecord* regRec, RefPosition* spillRefPositio
{
regRec->assignedInterval = nullptr;
regRec->previousInterval = nullptr;
+
+#ifdef _TARGET_ARM_
+ // Update second half RegRecord of a double register for TYP_DOUBLE
+ if (assignedInterval->registerType == TYP_DOUBLE)
+ {
+ assert(isFloatRegType(regRec->registerType));
+ assert(genIsValidDoubleReg(regRec->regNum));
+
+ nextRegRec->assignedInterval = nullptr;
+ nextRegRec->previousInterval = nullptr;
+ }
+#endif // _TARGET_ARM_
}
}
@@ -6505,6 +6594,45 @@ regNumber LinearScan::rotateBlockStartLocation(Interval* interval, regNumber tar
}
#endif // DEBUG
+#ifdef _TARGET_ARM_
+//--------------------------------------------------------------------------------------
+// isSecondHalfReg: Test if recRec is second half of double reigster
+// which is assigned to an interval.
+//
+// Arguments:
+// regRec - a register to be tested
+// interval - an interval which is assigned to some register
+//
+// Assumptions:
+// None
+//
+// Return Value:
+// True only if regRec is second half of assignedReg in interval
+//
+bool LinearScan::isSecondHalfReg(RegRecord* regRec, Interval* interval)
+{
+ RegRecord* assignedReg = interval->assignedReg;
+
+ if (assignedReg != nullptr && interval->registerType == TYP_DOUBLE)
+ {
+ // interval should have been allocated to a valid double register
+ assert(genIsValidDoubleReg(assignedReg->regNum));
+
+ // Find a second half RegRecord of double register
+ regNumber firstRegNum = assignedReg->regNum;
+ regNumber secondRegNum = REG_NEXT(firstRegNum);
+
+ assert(genIsValidFloatReg(secondRegNum) && !genIsValidDoubleReg(secondRegNum));
+
+ RegRecord* secondRegRec = getRegisterRecord(secondRegNum);
+
+ return secondRegRec == regRec;
+ }
+
+ return false;
+}
+#endif
+
//------------------------------------------------------------------------
// processBlockStartLocations: Update var locations on entry to 'currentBlock'
//
@@ -6703,6 +6831,7 @@ void LinearScan::processBlockStartLocations(BasicBlock* currentBlock, bool alloc
if (assignedInterval != nullptr)
{
assert(assignedInterval->isLocalVar || assignedInterval->isConstant);
+
if (!assignedInterval->isConstant && assignedInterval->assignedReg == physRegRecord)
{
assignedInterval->isActive = false;
@@ -6712,6 +6841,13 @@ void LinearScan::processBlockStartLocations(BasicBlock* currentBlock, bool alloc
}
inVarToRegMap[assignedInterval->getVarIndex(compiler)] = REG_STK;
}
+#ifdef _TARGET_ARM_
+ // Consider overlapping floating point register for TYP_DOUBLE
+ else if (!assignedInterval->isConstant && assignedInterval->registerType == TYP_DOUBLE)
+ {
+ assert(!assignedInterval->isActive || isSecondHalfReg(physRegRecord, assignedInterval));
+ }
+#endif // _TARGET_ARM_
else
{
// This interval may still be active, but was in another register in an
@@ -6839,6 +6975,9 @@ void LinearScan::freeRegister(RegRecord* physRegRecord)
// we wouldn't unnecessarily link separate live ranges to the same register.
if (nextRefPosition == nullptr || RefTypeIsDef(nextRefPosition->refType))
{
+#ifdef _TARGET_ARM_
+ assert((assignedInterval->registerType != TYP_DOUBLE) || genIsValidDoubleReg(physRegRecord->regNum));
+#endif // _TARGET_ARM_
unassignPhysReg(physRegRecord, nullptr);
}
}
@@ -7070,11 +7209,24 @@ void LinearScan::allocateRegisters()
// Otherwise, do nothing.
if (refType == RefTypeFixedReg)
{
- RegRecord* regRecord = currentRefPosition->getReg();
- if (regRecord->assignedInterval != nullptr && !regRecord->assignedInterval->isActive &&
- regRecord->assignedInterval->isConstant)
+ RegRecord* regRecord = currentRefPosition->getReg();
+ Interval* assignedInterval = regRecord->assignedInterval;
+
+ if (assignedInterval != nullptr && !assignedInterval->isActive && assignedInterval->isConstant)
{
regRecord->assignedInterval = nullptr;
+
+#ifdef _TARGET_ARM_
+ // Update overlapping floating point register for TYP_DOUBLE
+ if (assignedInterval->registerType == TYP_DOUBLE)
+ {
+ regRecord = getRegisterRecord(REG_NEXT(regRecord->regNum));
+ assignedInterval = regRecord->assignedInterval;
+
+ assert(assignedInterval != nullptr && !assignedInterval->isActive && assignedInterval->isConstant);
+ regRecord->assignedInterval = nullptr;
+ }
+#endif
}
INDEBUG(dumpLsraAllocationEvent(LSRA_EVENT_FIXED_REG, nullptr, currentRefPosition->assignedReg()));
continue;
@@ -7567,11 +7719,13 @@ void LinearScan::allocateRegisters()
if (currentRefPosition->delayRegFree)
{
delayRegsToFree |= assignedRegBit;
+
INDEBUG(dumpLsraAllocationEvent(LSRA_EVENT_LAST_USE_DELAYED));
}
else
{
regsToFree |= assignedRegBit;
+
INDEBUG(dumpLsraAllocationEvent(LSRA_EVENT_LAST_USE));
}
}
@@ -7911,6 +8065,18 @@ void LinearScan::resolveLocalRef(BasicBlock* block, GenTreePtr treeNode, RefPosi
interval->isActive = true;
physRegRecord->assignedInterval = interval;
interval->assignedReg = physRegRecord;
+#ifdef _TARGET_ARM_
+ // Update overlapping floating point register for TYP_DOUBLE
+ if (interval->registerType == TYP_DOUBLE)
+ {
+ assert(isFloatRegType(physRegRecord->registerType));
+
+ regNumber nextRegNum = REG_NEXT(physRegRecord->regNum);
+ RegRecord* nextPhysRegRecord = getRegisterRecord(nextRegNum);
+
+ nextPhysRegRecord->assignedInterval = interval;
+ }
+#endif
}
}
@@ -9943,12 +10109,11 @@ void TreeNodeInfo::Initialize(LinearScan* lsra, GenTree* node, LsraLocation loca
dstCandidates = genRegMask(node->gtRegNum);
}
- internalIntCount = 0;
- internalFloatCount = 0;
- isLocalDefUse = false;
- isHelperCallWithKills = false;
- isLsraAdded = false;
- definesAnyRegisters = false;
+ internalIntCount = 0;
+ internalFloatCount = 0;
+ isLocalDefUse = false;
+ isLsraAdded = false;
+ definesAnyRegisters = false;
setDstCandidates(lsra, dstCandidates);
srcCandsIndex = dstCandsIndex;
@@ -10373,10 +10538,6 @@ void TreeNodeInfo::dump(LinearScan* lsra)
{
printf(" I");
}
- if (isHelperCallWithKills)
- {
- printf(" H");
- }
if (isLsraAdded)
{
printf(" A");
diff --git a/src/jit/lsra.h b/src/jit/lsra.h
index b6f8379..f0a9d54 100644
--- a/src/jit/lsra.h
+++ b/src/jit/lsra.h
@@ -694,6 +694,10 @@ private:
void processBlockStartLocations(BasicBlock* current, bool allocationPass);
void processBlockEndLocations(BasicBlock* current);
+#ifdef _TARGET_ARM_
+ bool isSecondHalfReg(RegRecord* regRec, Interval* interval);
+#endif
+
RefType CheckBlockType(BasicBlock* block, BasicBlock* prevBlock);
// insert refpositions representing prolog zero-inits which will be added later
@@ -1131,7 +1135,7 @@ private:
int compareBlocksForSequencing(BasicBlock* block1, BasicBlock* block2, bool useBlockWeights);
BasicBlockList* blockSequenceWorkList;
bool blockSequencingDone;
- void addToBlockSequenceWorkList(BlockSet sequencedBlockSet, BasicBlock* block);
+ void addToBlockSequenceWorkList(BlockSet sequencedBlockSet, BasicBlock* block, BlockSet& predSet);
void removeFromBlockSequenceWorkList(BasicBlockList* listNode, BasicBlockList* prevNode);
BasicBlock* getNextCandidateFromWorkList();
diff --git a/src/jit/lsraarm.cpp b/src/jit/lsraarm.cpp
index e83f50c..0d1cfe6 100644
--- a/src/jit/lsraarm.cpp
+++ b/src/jit/lsraarm.cpp
@@ -229,8 +229,6 @@ void Lowering::TreeNodeInfoInit(GenTree* tree)
JITDUMP("TreeNodeInfoInit for: ");
DISPNODE(tree);
- NYI_IF(tree->TypeGet() == TYP_DOUBLE, "lowering double");
-
switch (tree->OperGet())
{
GenTree* op1;
diff --git a/src/jit/lsraarmarch.cpp b/src/jit/lsraarmarch.cpp
index 7d999d8..f661bab 100644
--- a/src/jit/lsraarmarch.cpp
+++ b/src/jit/lsraarmarch.cpp
@@ -784,15 +784,24 @@ void Lowering::TreeNodeInfoInitBlockStore(GenTreeBlk* blkNode)
if (blkNode->OperGet() == GT_STORE_OBJ)
{
// CopyObj
- NYI_ARM("GT_STORE_OBJ is needed of write barriers implementation");
-
-#ifdef _TARGET_ARM64_
-
// We don't need to materialize the struct size but we still need
// a temporary register to perform the sequence of loads and stores.
blkNode->gtLsraInfo.internalIntCount = 1;
+ if (size >= 2 * REGSIZE_BYTES)
+ {
+ // We will use ldp/stp to reduce code size and improve performance
+ // so we need to reserve an extra internal register
+ blkNode->gtLsraInfo.internalIntCount++;
+ }
+
+ // We can't use the special Write Barrier registers, so exclude them from the mask
+ regMaskTP internalIntCandidates = RBM_ALLINT & ~(RBM_WRITE_BARRIER_DST_BYREF | RBM_WRITE_BARRIER_SRC_BYREF);
+ blkNode->gtLsraInfo.setInternalCandidates(l, internalIntCandidates);
+
+ // If we have a dest address we want it in RBM_WRITE_BARRIER_DST_BYREF.
dstAddr->gtLsraInfo.setSrcCandidates(l, RBM_WRITE_BARRIER_DST_BYREF);
+
// If we have a source address we want it in REG_WRITE_BARRIER_SRC_BYREF.
// Otherwise, if it is a local, codegen will put its address in REG_WRITE_BARRIER_SRC_BYREF,
// which is killed by a StoreObj (and thus needn't be reserved).
@@ -800,8 +809,6 @@ void Lowering::TreeNodeInfoInitBlockStore(GenTreeBlk* blkNode)
{
srcAddrOrFill->gtLsraInfo.setSrcCandidates(l, RBM_WRITE_BARRIER_SRC_BYREF);
}
-
-#endif // _TARGET_ARM64_
}
else
{
@@ -824,7 +831,8 @@ void Lowering::TreeNodeInfoInitBlockStore(GenTreeBlk* blkNode)
if (size >= 2 * REGSIZE_BYTES)
{
- // Use ldp/stp to reduce code size and improve performance
+ // We will use ldp/stp to reduce code size and improve performance
+ // so we need to reserve an extra internal register
internalIntCount++;
}
diff --git a/src/jit/morph.cpp b/src/jit/morph.cpp
index f63496b..6928c3c 100644
--- a/src/jit/morph.cpp
+++ b/src/jit/morph.cpp
@@ -6099,7 +6099,7 @@ GenTreePtr Compiler::fgMorphStackArgForVarArgs(unsigned lclNum, var_types varTyp
* Transform the given GT_LCL_VAR tree for code generation.
*/
-GenTreePtr Compiler::fgMorphLocalVar(GenTreePtr tree)
+GenTreePtr Compiler::fgMorphLocalVar(GenTreePtr tree, bool forceRemorph)
{
noway_assert(tree->gtOper == GT_LCL_VAR);
@@ -6129,7 +6129,7 @@ GenTreePtr Compiler::fgMorphLocalVar(GenTreePtr tree)
/* If not during the global morphing phase bail */
- if (!fgGlobalMorph)
+ if (!fgGlobalMorph && !forceRemorph)
{
return tree;
}
@@ -6560,6 +6560,13 @@ GenTreePtr Compiler::fgMorphField(GenTreePtr tree, MorphAddrContext* mac)
GenTreePtr tlsRef = gtNewIconHandleNode(WIN32_TLS_SLOTS, GTF_ICON_TLS_HDL);
+ // Translate GTF_FLD_INITCLASS to GTF_ICON_INITCLASS
+ if ((tree->gtFlags & GTF_FLD_INITCLASS) != 0)
+ {
+ tree->gtFlags &= ~GTF_FLD_INITCLASS;
+ tlsRef->gtFlags |= GTF_ICON_INITCLASS;
+ }
+
tlsRef = gtNewOperNode(GT_IND, TYP_I_IMPL, tlsRef);
if (dllRef != nullptr)
@@ -6614,6 +6621,12 @@ GenTreePtr Compiler::fgMorphField(GenTreePtr tree, MorphAddrContext* mac)
FieldSeqNode* fieldSeq =
fieldMayOverlap ? FieldSeqStore::NotAField() : GetFieldSeqStore()->CreateSingleton(symHnd);
addr->gtIntCon.gtFieldSeq = fieldSeq;
+ // Translate GTF_FLD_INITCLASS to GTF_ICON_INITCLASS
+ if ((tree->gtFlags & GTF_FLD_INITCLASS) != 0)
+ {
+ tree->gtFlags &= ~GTF_FLD_INITCLASS;
+ addr->gtFlags |= GTF_ICON_INITCLASS;
+ }
tree->SetOper(GT_IND);
// The GTF_FLD_NULLCHECK is the same bit as GTF_IND_ARR_LEN.
@@ -6628,9 +6641,10 @@ GenTreePtr Compiler::fgMorphField(GenTreePtr tree, MorphAddrContext* mac)
else
#endif // _TARGET_64BIT_
{
- // Only volatile could be set, and it maps over
- noway_assert((tree->gtFlags & ~(GTF_FLD_VOLATILE | GTF_COMMON_MASK)) == 0);
- noway_assert(GTF_FLD_VOLATILE == GTF_IND_VOLATILE);
+ // Only volatile or classinit could be set, and they map over
+ noway_assert((tree->gtFlags & ~(GTF_FLD_VOLATILE | GTF_FLD_INITCLASS | GTF_COMMON_MASK)) == 0);
+ static_assert_no_msg(GTF_FLD_VOLATILE == GTF_CLS_VAR_VOLATILE);
+ static_assert_no_msg(GTF_FLD_INITCLASS == GTF_CLS_VAR_INITCLASS);
tree->SetOper(GT_CLS_VAR);
tree->gtClsVar.gtClsVarHnd = symHnd;
FieldSeqNode* fieldSeq =
@@ -6644,6 +6658,13 @@ GenTreePtr Compiler::fgMorphField(GenTreePtr tree, MorphAddrContext* mac)
{
GenTreePtr addr = gtNewIconHandleNode((size_t)pFldAddr, GTF_ICON_STATIC_HDL);
+ // Translate GTF_FLD_INITCLASS to GTF_ICON_INITCLASS
+ if ((tree->gtFlags & GTF_FLD_INITCLASS) != 0)
+ {
+ tree->gtFlags &= ~GTF_FLD_INITCLASS;
+ addr->gtFlags |= GTF_ICON_INITCLASS;
+ }
+
// There are two cases here, either the static is RVA based,
// in which case the type of the FIELD node is not a GC type
// and the handle to the RVA is a TYP_I_IMPL. Or the FIELD node is
@@ -8522,7 +8543,8 @@ GenTreePtr Compiler::fgMorphLeaf(GenTreePtr tree)
if (tree->gtOper == GT_LCL_VAR)
{
- return fgMorphLocalVar(tree);
+ const bool forceRemorph = false;
+ return fgMorphLocalVar(tree, forceRemorph);
}
#ifdef _TARGET_X86_
else if (tree->gtOper == GT_LCL_FLD)
@@ -13132,26 +13154,14 @@ GenTreePtr Compiler::fgMorphSmpOp(GenTreePtr tree, MorphAddrContext* mac)
varTypeIsStruct(tempTyp) || (tempTyp == TYP_BLK) || (tempTyp == TYP_LCLBLK);
const unsigned varSize = useExactSize ? varDsc->lvExactSize : genTypeSize(temp);
+ // Make sure we do not enregister this lclVar.
+ lvaSetVarDoNotEnregister(lclNum DEBUGARG(DNER_LocalField));
+
// If the size of the load is greater than the size of the lclVar, we cannot fold this access into
// a lclFld: the access represented by an lclFld node must begin at or after the start of the
// lclVar and must not extend beyond the end of the lclVar.
- if ((ival1 < 0) || ((ival1 + genTypeSize(typ)) > varSize))
- {
- lvaSetVarDoNotEnregister(lclNum DEBUGARG(DNER_LocalField));
- }
- else
+ if ((ival1 >= 0) && ((ival1 + genTypeSize(typ)) <= varSize))
{
- // Make sure we don't separately promote the fields of this struct.
- if (varDsc->lvRegStruct)
- {
- // We can enregister, but can't promote.
- varDsc->lvPromoted = false;
- }
- else
- {
- lvaSetVarDoNotEnregister(lclNum DEBUGARG(DNER_LocalField));
- }
-
// We will turn a GT_LCL_VAR into a GT_LCL_FLD with an gtLclOffs of 'ival'
// or if we already have a GT_LCL_FLD we will adjust the gtLclOffs by adding 'ival'
// Then we change the type of the GT_LCL_FLD to match the orginal GT_IND type.
@@ -13195,6 +13205,25 @@ GenTreePtr Compiler::fgMorphSmpOp(GenTreePtr tree, MorphAddrContext* mac)
DEBUG_DESTROY_NODE(op1); // GT_ADD or GT_ADDR
DEBUG_DESTROY_NODE(tree); // GT_IND
+ // If the result of the fold is a local var, we may need to perform further adjustments e.g. for
+ // normalization.
+ if (temp->OperIs(GT_LCL_VAR))
+ {
+#ifdef DEBUG
+ // We clear this flag on `temp` because `fgMorphLocalVar` may assert that this bit is clear
+ // and the node in question must have this bit set (as it has already been morphed).
+ temp->gtDebugFlags &= ~GTF_DEBUG_NODE_MORPHED;
+#endif // DEBUG
+ const bool forceRemorph = true;
+ temp = fgMorphLocalVar(temp, forceRemorph);
+#ifdef DEBUG
+ // We then set this flag on `temp` because `fgMorhpLocalVar` may not set it itself, and the
+ // caller of `fgMorphSmpOp` may assert that this flag is set on `temp` once this function
+ // returns.
+ temp->gtDebugFlags |= GTF_DEBUG_NODE_MORPHED;
+#endif // DEBUG
+ }
+
return temp;
}
@@ -13644,7 +13673,7 @@ GenTree* Compiler::fgMorphSmpOpOptional(GenTreeOp* tree)
GenTree* op2 = tree->gtOp2;
var_types typ = tree->TypeGet();
- if (GenTree::OperIsCommutative(oper))
+ if (fgGlobalMorph && GenTree::OperIsCommutative(oper))
{
/* Swap the operands so that the more expensive one is 'op1' */
@@ -13682,7 +13711,7 @@ GenTree* Compiler::fgMorphSmpOpOptional(GenTreeOp* tree)
/* Change "((x+icon)+y)" to "((x+y)+icon)"
Don't reorder floating-point operations */
- if ((oper == GT_ADD) && !tree->gtOverflow() && (op1->gtOper == GT_ADD) && !op1->gtOverflow() &&
+ if (fgGlobalMorph && (oper == GT_ADD) && !tree->gtOverflow() && (op1->gtOper == GT_ADD) && !op1->gtOverflow() &&
varTypeIsIntegralOrI(typ))
{
GenTreePtr ad2 = op1->gtOp.gtOp2;
diff --git a/src/jit/nodeinfo.h b/src/jit/nodeinfo.h
index 1937cc4..5f03da2 100644
--- a/src/jit/nodeinfo.h
+++ b/src/jit/nodeinfo.h
@@ -25,7 +25,6 @@ public:
dstCandsIndex = 0;
internalCandsIndex = 0;
isLocalDefUse = false;
- isHelperCallWithKills = false;
isLsraAdded = false;
isDelayFree = false;
hasDelayFreeSrc = false;
@@ -117,9 +116,6 @@ public:
// nodes, or top-level nodes that are non-void.
unsigned char isLocalDefUse : 1;
- // isHelperCallWithKills is set when this is a helper call that kills more than just its in/out regs.
- unsigned char isHelperCallWithKills : 1;
-
// Is this node added by LSRA, e.g. as a resolution or copy/reload move.
unsigned char isLsraAdded : 1;
diff --git a/src/jit/optimizer.cpp b/src/jit/optimizer.cpp
index 710dac5..1e50e53 100644
--- a/src/jit/optimizer.cpp
+++ b/src/jit/optimizer.cpp
@@ -2838,6 +2838,11 @@ void Compiler::optUnrollLoops()
// to outermost order
for (unsigned lnum = optLoopCount - 1; lnum != ~0U; --lnum)
{
+ // This is necessary due to an apparent analysis limitation since
+ // optLoopCount must be strictly greater than 0 upon entry and lnum
+ // cannot wrap due to the loop termination condition.
+ PREFAST_ASSUME(lnum != 0U - 1);
+
BasicBlock* block;
BasicBlock* head;
BasicBlock* bottom;
@@ -6003,7 +6008,9 @@ void Compiler::optHoistLoopExprsForBlock(BasicBlock* blk, unsigned lnum, LoopHoi
{
GenTreePtr stmtTree = stmt->gtStmtExpr;
bool hoistable;
- (void)optHoistLoopExprsForTree(stmtTree, lnum, hoistCtxt, &firstBlockAndBeforeSideEffect, &hoistable);
+ bool cctorDependent;
+ (void)optHoistLoopExprsForTree(stmtTree, lnum, hoistCtxt, &firstBlockAndBeforeSideEffect, &hoistable,
+ &cctorDependent);
if (hoistable)
{
// we will try to hoist the top-level stmtTree
@@ -6109,43 +6116,87 @@ bool Compiler::optIsProfitableToHoistableTree(GenTreePtr tree, unsigned lnum)
//
// This function returns true if 'tree' is a loop invariant expression.
-// It also sets '*pHoistable' to true if 'tree' can be hoisted into a loop PreHeader block
+// It also sets '*pHoistable' to true if 'tree' can be hoisted into a loop PreHeader block,
+// and sets '*pCctorDependent' if 'tree' is a function of a static field that must not be
+// hoisted (even if '*pHoistable' is true) unless a preceding corresponding cctor init helper
+// call is also hoisted.
//
-bool Compiler::optHoistLoopExprsForTree(
- GenTreePtr tree, unsigned lnum, LoopHoistContext* hoistCtxt, bool* pFirstBlockAndBeforeSideEffect, bool* pHoistable)
+bool Compiler::optHoistLoopExprsForTree(GenTreePtr tree,
+ unsigned lnum,
+ LoopHoistContext* hoistCtxt,
+ bool* pFirstBlockAndBeforeSideEffect,
+ bool* pHoistable,
+ bool* pCctorDependent)
{
// First do the children.
// We must keep track of whether each child node was hoistable or not
//
unsigned nChildren = tree->NumChildren();
bool childrenHoistable[GenTree::MAX_CHILDREN];
+ bool childrenCctorDependent[GenTree::MAX_CHILDREN];
// Initialize the array elements for childrenHoistable[] to false
for (unsigned i = 0; i < nChildren; i++)
{
- childrenHoistable[i] = false;
+ childrenHoistable[i] = false;
+ childrenCctorDependent[i] = false;
}
+ // Initclass CLS_VARs and IconHandles are the base cases of cctor dependent trees.
+ // In the IconHandle case, it's of course the dereference, rather than the constant itself, that is
+ // truly dependent on the cctor. So a more precise approach would be to separately propagate
+ // isCctorDependent and isAddressWhoseDereferenceWouldBeCctorDependent, but we don't for simplicity/throughput;
+ // the constant itself would be considered non-hoistable anyway, since optIsCSEcandidate returns
+ // false for constants.
+ bool treeIsCctorDependent = ((tree->OperIs(GT_CLS_VAR) && ((tree->gtFlags & GTF_CLS_VAR_INITCLASS) != 0)) ||
+ (tree->OperIs(GT_CNS_INT) && ((tree->gtFlags & GTF_ICON_INITCLASS) != 0)));
bool treeIsInvariant = true;
for (unsigned childNum = 0; childNum < nChildren; childNum++)
{
if (!optHoistLoopExprsForTree(tree->GetChild(childNum), lnum, hoistCtxt, pFirstBlockAndBeforeSideEffect,
- &childrenHoistable[childNum]))
+ &childrenHoistable[childNum], &childrenCctorDependent[childNum]))
{
treeIsInvariant = false;
}
+
+ if (childrenCctorDependent[childNum])
+ {
+ // Normally, a parent of a cctor-dependent tree is also cctor-dependent.
+ treeIsCctorDependent = true;
+
+ // Check for the case where we can stop propagating cctor-dependent upwards.
+ if (tree->OperIs(GT_COMMA) && (childNum == 1))
+ {
+ GenTreePtr op1 = tree->gtGetOp1();
+ if (op1->OperIs(GT_CALL))
+ {
+ GenTreeCall* call = op1->AsCall();
+ if ((call->gtCallType == CT_HELPER) &&
+ s_helperCallProperties.MayRunCctor(eeGetHelperNum(call->gtCallMethHnd)))
+ {
+ // Hoisting the comma is ok because it would hoist the initialization along
+ // with the static field reference.
+ treeIsCctorDependent = false;
+ // Hoisting the static field without hoisting the initialization would be
+ // incorrect, make sure we consider the field (which we flagged as
+ // cctor-dependent) non-hoistable.
+ noway_assert(!childrenHoistable[childNum]);
+ }
+ }
+ }
+ }
}
- // If all the children of "tree" are hoistable, then "tree" itself can be hoisted
- //
- bool treeIsHoistable = treeIsInvariant;
+ // If all the children of "tree" are hoistable, then "tree" itself can be hoisted,
+ // unless it has a static var reference that can't be hoisted past its cctor call.
+ bool treeIsHoistable = treeIsInvariant && !treeIsCctorDependent;
// But we must see if anything else prevents "tree" from being hoisted.
//
if (treeIsInvariant)
{
// Tree must be a suitable CSE candidate for us to be able to hoist it.
- treeIsHoistable = optIsCSEcandidate(tree);
+ treeIsHoistable &= optIsCSEcandidate(tree);
// If it's a call, it must be a helper call, and be pure.
// Further, if it may run a cctor, it must be labeled as "Hoistable"
@@ -6184,14 +6235,6 @@ bool Compiler::optHoistLoopExprsForTree(
treeIsHoistable = false;
}
}
- // Currently we must give up on reads from static variables (even if we are in the first block).
- //
- if (tree->OperGet() == GT_CLS_VAR)
- {
- // TODO-CQ: test that fails if we hoist GT_CLS_VAR: JIT\Directed\Languages\ComponentPascal\pi_r.exe
- // method Main
- treeIsHoistable = false;
- }
}
// Is the value of the whole tree loop invariant?
@@ -6285,7 +6328,8 @@ bool Compiler::optHoistLoopExprsForTree(
}
}
- *pHoistable = treeIsHoistable;
+ *pHoistable = treeIsHoistable;
+ *pCctorDependent = treeIsCctorDependent;
return treeIsInvariant;
}
diff --git a/src/jit/regalloc.cpp b/src/jit/regalloc.cpp
index 938f8e8..38967a4 100644
--- a/src/jit/regalloc.cpp
+++ b/src/jit/regalloc.cpp
@@ -1340,7 +1340,7 @@ RET:
while (iter.NextElem(this, &varNum))
{
// We'll need this for one of the calls...
- VarSetOps::ClearD(this, varAsSet);
+ VarSetOps::OldStyleClearD(this, varAsSet);
VarSetOps::AddElemD(this, varAsSet, varNum);
// If this varBit and lastUse?
@@ -6348,7 +6348,7 @@ void Compiler::rpPredictRegUse()
/* Zero the variable/register interference graph */
for (unsigned i = 0; i < REG_COUNT; i++)
{
- VarSetOps::ClearD(this, raLclRegIntf[i]);
+ VarSetOps::OldStyleClearD(this, raLclRegIntf[i]);
}
// if there are PInvoke calls and compLvFrameListRoot is enregistered,
diff --git a/src/jit/target.h b/src/jit/target.h
index f62d905..9fa5e33 100644
--- a/src/jit/target.h
+++ b/src/jit/target.h
@@ -1357,6 +1357,13 @@ typedef unsigned short regPairNoSmall; // arm: need 12 bits
#define RBM_WRITE_BARRIER RBM_R1
#endif
+ //In the ARM case, registers of write barrier use the normal argument registers.
+ #define REG_WRITE_BARRIER_SRC_BYREF REG_ARG_1
+ #define RBM_WRITE_BARRIER_SRC_BYREF RBM_ARG_1
+
+ #define REG_WRITE_BARRIER_DST_BYREF REG_ARG_0
+ #define RBM_WRITE_BARRIER_DST_BYREF RBM_ARG_0
+
// GenericPInvokeCalliHelper VASigCookie Parameter
#define REG_PINVOKE_COOKIE_PARAM REG_R4
#define RBM_PINVOKE_COOKIE_PARAM RBM_R4
@@ -1520,7 +1527,7 @@ typedef unsigned short regPairNoSmall; // arm: need 12 bits
#define FEATURE_STRUCTPROMOTE 1 // JIT Optimization to promote fields of structs into registers
#define FEATURE_MULTIREG_STRUCT_PROMOTE 1 // True when we want to promote fields of a multireg struct into registers
#define FEATURE_FASTTAILCALL 1 // Tail calls made as epilog+jmp
- #define FEATURE_TAILCALL_OPT 0 // opportunistic Tail calls (i.e. without ".tail" prefix) made as fast tail calls.
+ #define FEATURE_TAILCALL_OPT 1 // opportunistic Tail calls (i.e. without ".tail" prefix) made as fast tail calls.
#define FEATURE_SET_FLAGS 1 // Set to true to force the JIT to mark the trees with GTF_SET_FLAGS when the flags need to be set
#define FEATURE_MULTIREG_ARGS_OR_RET 1 // Support for passing and/or returning single values in more than one register
#define FEATURE_MULTIREG_ARGS 1 // Support for passing a single argument in more than one register
@@ -1573,7 +1580,7 @@ typedef unsigned short regPairNoSmall; // arm: need 12 bits
#define RBM_CALLEE_SAVED (RBM_INT_CALLEE_SAVED | RBM_FLT_CALLEE_SAVED)
#define RBM_CALLEE_TRASH (RBM_INT_CALLEE_TRASH | RBM_FLT_CALLEE_TRASH)
- #define RBM_CALLEE_TRASH_NOGC (RBM_R12|RBM_R13|RBM_R14|RBM_R15)
+ #define RBM_CALLEE_TRASH_NOGC (RBM_R12|RBM_R13|RBM_R14|RBM_R15|RBM_IP1)
#define REG_DEFAULT_HELPER_CALL_TARGET REG_R12
#define RBM_ALLINT (RBM_INT_CALLEE_SAVED | RBM_INT_CALLEE_TRASH)
@@ -1950,7 +1957,7 @@ inline bool genIsValidFloatReg(regNumber reg)
return reg >= REG_FP_FIRST && reg <= REG_FP_LAST;
}
-#if defined(LEGACY_BACKEND) && defined(_TARGET_ARM_)
+#ifdef _TARGET_ARM_
/*****************************************************************************
* Return true if the register is a valid floating point double register
@@ -1960,7 +1967,7 @@ inline bool genIsValidDoubleReg(regNumber reg)
return genIsValidFloatReg(reg) && (((reg - REG_FP_FIRST) & 0x1) == 0);
}
-#endif // defined(LEGACY_BACKEND) && defined(_TARGET_ARM_)
+#endif // _TARGET_ARM_
//-------------------------------------------------------------------------------------------
// hasFixedRetBuffReg:
diff --git a/src/md/ceefilegen/cceegen.cpp b/src/md/ceefilegen/cceegen.cpp
index 0cf0780..bd69c8d 100644
--- a/src/md/ceefilegen/cceegen.cpp
+++ b/src/md/ceefilegen/cceegen.cpp
@@ -38,22 +38,30 @@ HRESULT STDMETHODCALLTYPE CreateICeeGen(REFIID riid, void **pCeeGen)
HRESULT CCeeGen::CreateNewInstance(CCeeGen* & pGen) // static, public
{
- pGen = new CCeeGen();
- _ASSERTE(pGen != NULL);
- TESTANDRETURNMEMORY(pGen);
+ NewHolder<CCeeGen> pGenHolder(new CCeeGen());
+ _ASSERTE(pGenHolder != NULL);
+ TESTANDRETURNMEMORY(pGenHolder);
- pGen->m_peSectionMan = new PESectionMan;
- _ASSERTE(pGen->m_peSectionMan != NULL);
- TESTANDRETURNMEMORY(pGen->m_peSectionMan);
+ pGenHolder->m_peSectionMan = new PESectionMan;
+ _ASSERTE(pGenHolder->m_peSectionMan != NULL);
+ TESTANDRETURNMEMORY(pGenHolder->m_peSectionMan);
- HRESULT hr = pGen->m_peSectionMan->Init();
- TESTANDRETURNHR(hr);
+ HRESULT hr = pGenHolder->m_peSectionMan->Init();
+ if (FAILED(hr))
+ {
+ pGenHolder->Cleanup();
+ return hr;
+ }
- hr = pGen->Init();
- TESTANDRETURNHR(hr);
+ hr = pGenHolder->Init();
+ if (FAILED(hr))
+ {
+ // Init() calls Cleanup() on failure
+ return hr;
+ }
+ pGen = pGenHolder.Extract();
return hr;
-
}
STDMETHODIMP CCeeGen::QueryInterface(REFIID riid, void** ppv)
diff --git a/src/md/enc/mdinternalrw.cpp b/src/md/enc/mdinternalrw.cpp
index 02fb407..75c7939 100644
--- a/src/md/enc/mdinternalrw.cpp
+++ b/src/md/enc/mdinternalrw.cpp
@@ -2393,7 +2393,7 @@ HRESULT MDInternalRW::GetItemGuid( // return hresult
// Get the GUID, if any.
hr = GetCustomAttributeByName(tkObj, INTEROP_GUID_TYPE, (const void**)&pBlob, &cbBlob);
- if (hr != S_FALSE)
+ if (SUCCEEDED(hr) && hr != S_FALSE)
{
// Should be in format. Total length == 41
// <0x0001><0x24>01234567-0123-0123-0123-001122334455<0x0000>
diff --git a/src/mscorlib/Resources/Strings.resx b/src/mscorlib/Resources/Strings.resx
index 791d1ca..cbf969e8 100644
--- a/src/mscorlib/Resources/Strings.resx
+++ b/src/mscorlib/Resources/Strings.resx
@@ -1628,9 +1628,6 @@
<data name="ArgumentOutOfRange_ArrayLBAndLength" xml:space="preserve">
<value>Higher indices will exceed Int32.MaxValue because of large lower bound and/or length.</value>
</data>
- <data name="ArgumentOutOfRange_ArrayListInsert" xml:space="preserve">
- <value>Insertion index was out of range. Must be non-negative and less than or equal to size.</value>
- </data>
<data name="ArgumentOutOfRange_BadHourMinuteSecond" xml:space="preserve">
<value>Hour, Minute, and Second parameters describe an un-representable DateTime.</value>
</data>
@@ -3185,6 +3182,9 @@
<data name="PlatformNotSupported_WinRT" xml:space="preserve">
<value>Windows Runtime is not supported on this operating system.</value>
</data>
+ <data name="PlatformNotSupported_OverlappedIO" xml:space="preserve">
+ <value>This API is specific to the way in which Windows handles asynchronous I/O, and is not supported on this platform.</value>
+ </data>
<data name="Policy_CannotLoadSemiTrustAssembliesDuringInit" xml:space="preserve">
<value>All assemblies loaded as part of AppDomain initialization must be fully trusted.</value>
</data>
@@ -3287,6 +3287,9 @@
<data name="Serialization_DateTimeTicksOutOfRange" xml:space="preserve">
<value>Invalid serialized DateTime data. Ticks must be between DateTime.MinValue.Ticks and DateTime.MaxValue.Ticks.</value>
</data>
+ <data name="Serialization_DelegatesNotSupported" xml:space="preserve">
+ <value>Serializing delegates is not supported on this platform.</value>
+ </data>
<data name="Serialization_InsufficientDeserializationState" xml:space="preserve">
<value>Insufficient state to deserialize the object. Missing field '{0}'. More information is needed.</value>
</data>
diff --git a/src/mscorlib/System.Private.CoreLib.csproj b/src/mscorlib/System.Private.CoreLib.csproj
index df86533..513e002 100644
--- a/src/mscorlib/System.Private.CoreLib.csproj
+++ b/src/mscorlib/System.Private.CoreLib.csproj
@@ -20,6 +20,7 @@
<!-- This prevents the default MsBuild targets from referencing System.Core.dll -->
<AddAdditionalExplicitAssemblyReferences>false</AddAdditionalExplicitAssemblyReferences>
<!-- These prevent the default MsBuild targets from referencing System.dll and mscorlib.dll -->
+ <ExcludeMscorlibFacade>true</ExcludeMscorlibFacade>
<NoStdLib>true</NoStdLib>
<NoCompilerStandardLib>true</NoCompilerStandardLib>
<SubsystemVersion>6.00</SubsystemVersion>
@@ -86,11 +87,9 @@
<PropertyGroup Condition="'$(OsEnvironment)' == 'Unix'">
<DebugType>portable</DebugType>
</PropertyGroup>
-
<PropertyGroup Condition="'$(TargetsOSX)' == 'true'">
<DefineConstants>PLATFORM_OSX;$(DefineConstants)</DefineConstants>
</PropertyGroup>
-
<!-- Assembly attributes -->
<PropertyGroup>
<AssemblyName>System.Private.CoreLib</AssemblyName>
@@ -104,6 +103,7 @@
<AssemblyInfoLines Include="[assembly: System.Security.AllowPartiallyTrustedCallers]" />
<AssemblyInfoLines Include="[assembly: System.Runtime.InteropServices.ComVisible(false)]" />
<AssemblyInfoLines Include="[assembly: System.Resources.NeutralResourcesLanguage(&quot;en-US&quot;)]" />
+ <AssemblyInfoLines Include="[assembly: System.Runtime.InteropServices.DefaultDllImportSearchPathsAttribute(System.Runtime.InteropServices.DllImportSearchPath.AssemblyDirectory | System.Runtime.InteropServices.DllImportSearchPath.System32)]" />
</ItemGroup>
<!--
Helper Paths
@@ -152,7 +152,6 @@
<Compile Include="$(BclSourcesRoot)\System\Runtime\GcSettings.cs" />
</ItemGroup>
<ItemGroup>
- <Compile Include="$(BclSourcesRoot)\System\Collections\ArrayList.cs" />
<Compile Include="$(BclSourcesRoot)\System\Collections\Comparer.cs" />
<Compile Include="$(BclSourcesRoot)\System\Collections\CompatibleComparer.cs" />
<Compile Include="$(BclSourcesRoot)\System\Collections\ListDictionaryInternal.cs" />
@@ -173,6 +172,7 @@
<Compile Include="$(BclSourcesRoot)\System\Runtime\InteropServices\Marshal.cs" />
<Compile Include="$(BclSourcesRoot)\System\Runtime\InteropServices\MarshalDirectiveException.cs" />
<Compile Include="$(BclSourcesRoot)\System\Runtime\InteropServices\PInvokeMap.cs" />
+ <Compile Include="$(BclSourcesRoot)\System\Runtime\InteropServices\PInvokeMarshal.cs" />
<Compile Include="$(BclSourcesRoot)\System\Runtime\InteropServices\RuntimeEnvironment.cs" />
<Compile Include="$(BclSourcesRoot)\System\Runtime\InteropServices\SEHException.cs" />
<Compile Include="$(BclSourcesRoot)\System\Runtime\InteropServices\SafeBuffer.cs" />
@@ -314,10 +314,9 @@
<Compile Include="$(BclSourcesRoot)\System\IAppDomainPauseManager.cs" />
<Compile Include="$(BclSourcesRoot)\System\AppDomainAttributes.cs" />
<Compile Include="$(BclSourcesRoot)\System\AppDomainUnloadedException.cs" />
- <Compile Include="$(BclSourcesRoot)\System\ArgumentOutOfRangeException.cs" />
<Compile Include="$(BclSourcesRoot)\System\ArgIterator.cs" />
<Compile Include="$(BclSourcesRoot)\System\Attribute.cs" />
- <Compile Include="$(BclSourcesRoot)\System\BadImageFormatException.cs" />
+ <Compile Include="$(BclSourcesRoot)\System\BadImageFormatException.CoreCLR.cs" />
<Compile Include="$(BclSourcesRoot)\System\BitConverter.cs" />
<Compile Include="$(BclSourcesRoot)\System\Boolean.cs" />
<Compile Include="$(BclSourcesRoot)\System\Buffer.cs" />
@@ -326,11 +325,9 @@
<Compile Include="$(BclSourcesRoot)\System\Currency.cs" />
<Compile Include="$(BclSourcesRoot)\System\Decimal.cs" />
<Compile Include="$(BclSourcesRoot)\System\DefaultBinder.CanConvert.cs" />
- <Compile Include="$(BclSourcesRoot)\System\DelegateSerializationHolder.cs" />
<Compile Include="$(BclSourcesRoot)\System\Double.cs" />
<Compile Include="$(BclSourcesRoot)\System\Empty.cs" />
<Compile Include="$(BclSourcesRoot)\System\Enum.cs" />
- <Compile Include="$(BclSourcesRoot)\System\DllNotFoundException.cs" />
<Compile Include="$(BclSourcesRoot)\System\Environment.cs" />
<Compile Include="$(BclSourcesRoot)\System\GC.cs" />
<Compile Include="$(BclSourcesRoot)\System\Guid.cs" />
@@ -347,10 +344,7 @@
<Compile Include="$(BclSourcesRoot)\System\MissingMemberException.cs" />
<Compile Include="$(BclSourcesRoot)\System\NonSerializedAttribute.cs" />
<Compile Include="$(BclSourcesRoot)\System\Number.cs" />
- <Compile Include="$(BclSourcesRoot)\System\OperatingSystem.cs" />
- <Compile Include="$(BclSourcesRoot)\System\OperationCanceledException.cs" />
<Compile Include="$(BclSourcesRoot)\System\ParseNumbers.cs" />
- <Compile Include="$(BclSourcesRoot)\System\PlatformID.cs" />
<Compile Include="$(BclSourcesRoot)\System\ResId.cs" />
<Compile Include="$(BclSourcesRoot)\System\RtType.cs" />
<Compile Include="$(BclSourcesRoot)\System\RuntimeArgumentHandle.cs" />
@@ -403,7 +397,6 @@
<Compile Include="$(BclSourcesRoot)\System\Reflection\MdFieldInfo.cs" />
<Compile Include="$(BclSourcesRoot)\System\Reflection\MdImport.cs" />
<Compile Include="$(BclSourcesRoot)\System\Reflection\MemberInfo.Internal.cs" />
- <Compile Include="$(BclSourcesRoot)\System\Reflection\MemberSerializationStringGenerator.cs" />
<Compile Include="$(BclSourcesRoot)\System\Reflection\MethodBase.CoreCLR.cs" />
<Compile Include="$(BclSourcesRoot)\System\Reflection\MethodBody.cs" />
<Compile Include="$(BclSourcesRoot)\System\Reflection\RtFieldInfo.cs" />
@@ -478,10 +471,7 @@
<Compile Include="$(BclSourcesRoot)\System\Globalization\GregorianCalendar.cs" />
<Compile Include="$(BclSourcesRoot)\System\Globalization\GregorianCalendarHelper.cs" />
<Compile Include="$(BclSourcesRoot)\System\Globalization\IdnMapping.cs" />
- <Compile Include="$(BclSourcesRoot)\System\Globalization\NumberFormatInfo.cs" />
<Compile Include="$(BclSourcesRoot)\System\Globalization\RegionInfo.cs" />
- <Compile Include="$(BclSourcesRoot)\System\Globalization\SortKey.cs" />
- <Compile Include="$(BclSourcesRoot)\System\Globalization\StringInfo.cs" />
<Compile Include="$(BclSourcesRoot)\System\Globalization\TextElementEnumerator.cs" />
<Compile Include="$(BclSourcesRoot)\System\Globalization\TextInfo.cs" />
<Compile Include="$(BclSourcesRoot)\System\Globalization\TimeSpanFormat.cs" />
@@ -499,6 +489,7 @@
<Compile Include="$(BclSourcesRoot)\System\Threading\Monitor.cs" />
<Compile Include="$(BclSourcesRoot)\System\Threading\Mutex.cs" />
<Compile Include="$(BclSourcesRoot)\System\Threading\Overlapped.cs" />
+ <Compile Include="$(BclSourcesRoot)\System\Threading\PinnableBufferCache.cs" />
<Compile Include="$(BclSourcesRoot)\System\Threading\Semaphore.cs" />
<Compile Include="$(BclSourcesRoot)\System\Threading\Thread.cs" />
<Compile Include="$(BclSourcesRoot)\System\Threading\ThreadInterruptedException.cs" />
@@ -546,17 +537,13 @@
<Compile Include="$(BclSourcesRoot)\System\IO\Directory.cs" />
<Compile Include="$(BclSourcesRoot)\System\IO\SearchOption.cs" />
<Compile Include="$(BclSourcesRoot)\System\IO\DriveNotFoundException.cs" />
- <Compile Include="$(BclSourcesRoot)\System\IO\EncodingCache.cs" />
<Compile Include="$(BclSourcesRoot)\System\IO\File.cs" />
<Compile Include="$(BclSourcesRoot)\System\IO\FileLoadException.CoreCLR.cs" />
<Compile Include="$(BclSourcesRoot)\System\IO\FileNotFoundException.CoreCLR.cs" />
<Compile Include="$(BclSourcesRoot)\System\IO\IOException.cs" />
<Compile Include="$(BclSourcesRoot)\System\IO\MemoryStream.cs" />
- <Compile Include="$(BclSourcesRoot)\System\IO\PinnedBufferMemoryStream.cs" />
<Compile Include="$(BclSourcesRoot)\System\IO\Stream.cs" />
<Compile Include="$(BclSourcesRoot)\System\IO\UnmanagedMemoryAccessor.cs" />
- <Compile Include="$(BclSourcesRoot)\System\IO\UnmanagedMemoryStream.cs" />
- <Compile Include="$(BclSourcesRoot)\System\IO\UnmanagedMemoryStreamWrapper.cs" />
</ItemGroup>
<ItemGroup>
<Compile Include="$(BclSourcesRoot)\System\Security\DynamicSecurityMethodAttribute.cs" />
@@ -577,6 +564,8 @@
<Compile Include="$(BclSourcesRoot)\System\Diagnostics\Eventing\EventSource_CoreCLR.cs" />
<Compile Condition="'$(FeatureXplatEventSource)' == 'true'" Include="$(BclSourcesRoot)\System\Diagnostics\Eventing\XplatEventLogger.cs" />
<Compile Include="$(BclSourcesRoot)\System\Diagnostics\Eventing\FrameworkEventSource.cs" />
+ <Compile Condition="'$(FeaturePerfTracing)' == 'true'" Include="$(BclSourcesRoot)\System\Diagnostics\Eventing\EventPipe.cs" />
+ <Compile Condition="'$(FeaturePerfTracing)' == 'true'" Include="$(BclSourcesRoot)\System\Diagnostics\Eventing\EventPipeEventProvider.cs" />
</ItemGroup>
<ItemGroup>
<Compile Include="$(BclSourcesRoot)\System\Diagnostics\Contracts\Contracts.cs" />
@@ -602,9 +591,6 @@
<Compile Include="$(BclSourcesRoot)\System\Runtime\Serialization\SerializationInfo.cs" />
</ItemGroup>
<ItemGroup>
- <Compile Include="$(BclSourcesRoot)\System\Runtime\Remoting\ObjectHandle.cs" />
- </ItemGroup>
- <ItemGroup>
<Compile Include="$(BclSourcesRoot)\System\Text\DecoderNLS.cs" />
<Compile Include="$(BclSourcesRoot)\System\Text\DecoderBestFitFallback.cs" />
<Compile Include="$(BclSourcesRoot)\System\Text\DecoderExceptionFallback.cs" />
@@ -635,11 +621,9 @@
<Compile Include="$(BclSourcesRoot)\System\Resources\IResourceGroveler.cs" />
<Compile Include="$(BclSourcesRoot)\System\Resources\LooselyLinkedResourceReference.cs" />
<Compile Include="$(BclSourcesRoot)\System\Resources\ManifestBasedResourceGroveler.cs" />
- <Compile Include="$(BclSourcesRoot)\System\Resources\ResourceFallbackManager.cs" />
<Compile Include="$(BclSourcesRoot)\System\Resources\ResourceManager.cs" />
<Compile Include="$(BclSourcesRoot)\System\Resources\ResourceReader.cs" />
<Compile Include="$(BclSourcesRoot)\System\Resources\ResourceSet.cs" />
- <Compile Include="$(BclSourcesRoot)\System\Resources\RuntimeResourceSet.cs" />
</ItemGroup>
<ItemGroup>
<Compile Include="$(BclSourcesRoot)\System\Nullable.cs" />
@@ -662,36 +646,28 @@
<Compile Include="$(BclSourcesRoot)\Microsoft\Win32\SafeHandles\SafeFindHandle.cs" />
<Compile Include="$(BclSourcesRoot)\Microsoft\Win32\SafeHandles\SafeLibraryHandle.cs" />
<Compile Include="$(BclSourcesRoot)\Microsoft\Win32\SafeHandles\SafeWaitHandle.cs" />
- <Compile Include="$(BclSourcesRoot)\Microsoft\Win32\SafeHandles\Win32SafeHandles.cs" />
<Compile Condition="'$(FeatureWin32Registry)' == 'true'" Include="$(BclSourcesRoot)\Microsoft\Win32\SafeHandles\SafeRegistryHandle.cs" />
</ItemGroup>
<ItemGroup>
<Compile Include="$(BclSourcesRoot)\System\Numerics\Hashing\HashHelpers.cs" />
</ItemGroup>
<ItemGroup Condition="'$(TargetsUnix)' == 'true'">
- <Compile Include="$(BclSourcesRoot)\Interop\Unix\System.Globalization.Native\Interop.Collation.cs" />
<Compile Include="$(BclSourcesRoot)\Interop\Unix\System.Globalization.Native\Interop.ICU.cs" />
- <Compile Include="$(BclSourcesRoot)\System\Diagnostics\Debug.Unix.cs" />
- <Compile Include="$(BclSourcesRoot)\System\Globalization\CalendarData.Unix.cs" />
<Compile Include="$(BclSourcesRoot)\System\Globalization\CompareInfo.Unix.cs" />
- <Compile Include="$(BclSourcesRoot)\System\Globalization\CultureData.Unix.cs" />
<Compile Include="$(BclSourcesRoot)\System\Globalization\CultureInfo.Unix.cs" />
<Compile Include="$(BclSourcesRoot)\System\Globalization\EncodingTable.Unix.cs" />
<Compile Include="$(BclSourcesRoot)\System\Globalization\EncodingDataItem.Unix.cs" />
<Compile Include="$(BclSourcesRoot)\System\Globalization\GlobalizationMode.Unix.cs" />
- <Compile Include="$(BclSourcesRoot)\System\Globalization\HijriCalendar.Unix.cs" />
- <Compile Include="$(BclSourcesRoot)\System\Globalization\IdnMapping.Unix.cs" />
- <Compile Include="$(BclSourcesRoot)\System\Globalization\JapaneseCalendar.Unix.cs" />
<Compile Include="$(BclSourcesRoot)\System\Globalization\TextInfo.Unix.cs" />
<Compile Include="$(BclSourcesRoot)\System\IO\FileSystemEnumerable.cs" />
<Compile Include="$(BclSourcesRoot)\System\IO\TextReader.cs" />
<Compile Include="$(BclSourcesRoot)\System\IO\StreamReader.cs" />
<Compile Include="$(BclSourcesRoot)\System\Runtime\Versioning\CompatibilitySwitch.cs" />
<Compile Include="$(BclSourcesRoot)\System\Text\Normalization.Unix.cs" />
+ <Compile Include="$(BclSourcesRoot)\System\Threading\ClrThreadPoolBoundHandle.Unix.cs" />
<Compile Include="$(BclSourcesRoot)\System\TimeZoneInfo.Unix.cs" />
</ItemGroup>
<ItemGroup Condition="'$(TargetsWindows)' == 'true'">
- <Compile Include="$(BclSourcesRoot)\Interop\Windows\kernel32\Interop.Globalization.cs" />
<Compile Include="$(BclSourcesRoot)\Interop\Windows\Normaliz\Interop.Idna.cs" />
<Compile Include="$(BclSourcesRoot)\Interop\Windows\Normaliz\Interop.Normalization.cs" />
<Compile Include="$(BclSourcesRoot)\System\Diagnostics\Debug.Windows.cs" />
@@ -700,11 +676,10 @@
<Compile Include="$(BclSourcesRoot)\System\Globalization\CultureData.Windows.cs" />
<Compile Include="$(BclSourcesRoot)\System\Globalization\CultureInfo.Windows.cs" />
<Compile Include="$(BclSourcesRoot)\System\Globalization\GlobalizationMode.Windows.cs" />
- <Compile Include="$(BclSourcesRoot)\System\Globalization\HijriCalendar.Win32.cs" />
<Compile Include="$(BclSourcesRoot)\System\Globalization\IdnMapping.Windows.cs" />
- <Compile Include="$(BclSourcesRoot)\System\Globalization\JapaneseCalendar.Win32.cs" />
<Compile Include="$(BclSourcesRoot)\System\Globalization\TextInfo.Windows.cs" />
<Compile Include="$(BclSourcesRoot)\System\Text\Normalization.Windows.cs" />
+ <Compile Include="$(BclSourcesRoot)\System\Threading\ClrThreadPoolBoundHandle.Windows.cs" />
<Compile Include="$(BclSourcesRoot)\System\TimeZoneInfo.Win32.cs" />
</ItemGroup>
<!-- Include additional sources shared files in the compilation -->
@@ -713,7 +688,6 @@
<Compile Include="$(CommonPath)\Preprocessed\AssemblyRefs.g.cs" />
<!-- These files are shared with other framework components and don't live the same folder as the rest of them-->
<Compile Include="$(CommonPath)\NotImplemented.cs" />
- <Compile Include="$(CommonPath)\PinnableBufferCache.cs" />
<Compile Include="$(CommonPath)\System\SR.cs" />
<!-- Include Internals visible to file in the compilation -->
<Compile Include="$(BclSourcesRoot)\mscorlib.Friends.cs" />
@@ -753,9 +727,11 @@
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
<PropertyGroup>
<!-- Overwrite the key that we are going to use for signing -->
- <AssemblyOriginatorKeyFile>$(MSBuildThisFileDirectory)Tools\Signing\mscorlib.snk</AssemblyOriginatorKeyFile>
+ <AssemblyOriginatorKeyFile>$(ToolsDir)SilverlightPlatformPublicKey.snk</AssemblyOriginatorKeyFile>
+ <!-- Don't need a strong name signature because we only ship the native image -->
+ <StrongNameSig>None</StrongNameSig>
<!-- Use a different nativeresource file to avoid conflicts with mscorlib-->
<Win32Resource Condition="'$(GenerateNativeVersionInfo)'=='true'">$(IntermediateOutputPath)\System.Private.CoreLib.res</Win32Resource>
</PropertyGroup>
<Import Project="GenerateCompilerResponseFile.targets" />
-</Project>
+</Project> \ No newline at end of file
diff --git a/src/mscorlib/Tools/Signing/mscorlib.snk b/src/mscorlib/Tools/Signing/mscorlib.snk
deleted file mode 100644
index 60146e8..0000000
--- a/src/mscorlib/Tools/Signing/mscorlib.snk
+++ /dev/null
Binary files differ
diff --git a/src/mscorlib/src/Interop/Unix/System.Globalization.Native/Interop.Collation.cs b/src/mscorlib/shared/Interop/Unix/System.Globalization.Native/Interop.Collation.cs
index fe14560..79aedd7 100644
--- a/src/mscorlib/src/Interop/Unix/System.Globalization.Native/Interop.Collation.cs
+++ b/src/mscorlib/shared/Interop/Unix/System.Globalization.Native/Interop.Collation.cs
@@ -3,7 +3,6 @@
// See the LICENSE file in the project root for more information.
using System;
-using System.Diagnostics;
using System.Globalization;
using System.Runtime.InteropServices;
using System.Security;
@@ -61,8 +60,6 @@ internal static partial class Interop
protected override bool ReleaseHandle()
{
- Debug.Assert(!GlobalizationMode.Invariant);
-
CloseSortHandle(handle);
SetHandle(IntPtr.Zero);
return true;
diff --git a/src/mscorlib/shared/Interop/Windows/Interop.Libraries.cs b/src/mscorlib/shared/Interop/Windows/Interop.Libraries.cs
index 58bb12d..bf07a68 100644
--- a/src/mscorlib/shared/Interop/Windows/Interop.Libraries.cs
+++ b/src/mscorlib/shared/Interop/Windows/Interop.Libraries.cs
@@ -9,7 +9,6 @@ internal static partial class Interop
internal const string BCrypt = "BCrypt.dll";
internal const string Crypt32 = "crypt32.dll";
internal const string Kernel32 = "kernel32.dll";
- internal const string NtDll = "ntdll.dll";
internal const string OleAut32 = "oleaut32.dll";
}
}
diff --git a/src/mscorlib/src/Interop/Windows/kernel32/Interop.Globalization.cs b/src/mscorlib/shared/Interop/Windows/Kernel32/Interop.Globalization.cs
index 2bb349d..7d3287f 100644
--- a/src/mscorlib/src/Interop/Windows/kernel32/Interop.Globalization.cs
+++ b/src/mscorlib/shared/Interop/Windows/Kernel32/Interop.Globalization.cs
@@ -89,20 +89,20 @@ internal static partial class Interop
internal static extern bool GetUserPreferredUILanguages(uint dwFlags, out uint pulNumLanguages, char [] pwszLanguagesBuffer, ref uint pcchLanguagesBuffer);
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
- internal static extern int GetLocaleInfoEx(string lpLocaleName, uint LCType, IntPtr lpLCData, int cchData);
+ internal static extern int GetLocaleInfoEx(string lpLocaleName, uint LCType, void* lpLCData, int cchData);
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
- internal extern static bool EnumSystemLocalesEx(EnumLocalesProcEx lpLocaleEnumProcEx, uint dwFlags, IntPtr lParam, IntPtr reserved);
+ internal extern static bool EnumSystemLocalesEx(EnumLocalesProcEx lpLocaleEnumProcEx, uint dwFlags, void* lParam, IntPtr reserved);
- internal delegate BOOL EnumLocalesProcEx(IntPtr lpLocaleString, uint dwFlags, IntPtr lParam);
+ internal delegate BOOL EnumLocalesProcEx(char* lpLocaleString, uint dwFlags, void* lParam);
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
internal extern static int ResolveLocaleName(string lpNameToResolve, char* lpLocaleName, int cchLocaleName);
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
- internal extern static bool EnumTimeFormatsEx(EnumTimeFormatsProcEx lpTimeFmtEnumProcEx, string lpLocaleName, uint dwFlags, IntPtr lParam);
+ internal extern static bool EnumTimeFormatsEx(EnumTimeFormatsProcEx lpTimeFmtEnumProcEx, string lpLocaleName, uint dwFlags, void* lParam);
- internal delegate BOOL EnumTimeFormatsProcEx(IntPtr lpTimeFormatString, IntPtr lParam);
+ internal delegate BOOL EnumTimeFormatsProcEx(char* lpTimeFormatString, void* lParam);
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
internal extern static int GetCalendarInfoEx(string lpLocaleName, uint Calendar, IntPtr lpReserved, uint CalType, IntPtr lpCalData, int cchData, out int lpValue);
@@ -111,12 +111,12 @@ internal static partial class Interop
internal extern static int GetCalendarInfoEx(string lpLocaleName, uint Calendar, IntPtr lpReserved, uint CalType, IntPtr lpCalData, int cchData, IntPtr lpValue);
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
- internal extern static bool EnumCalendarInfoExEx(EnumCalendarInfoProcExEx pCalInfoEnumProcExEx, string lpLocaleName, uint Calendar, string lpReserved, uint CalType, IntPtr lParam);
+ internal extern static bool EnumCalendarInfoExEx(EnumCalendarInfoProcExEx pCalInfoEnumProcExEx, string lpLocaleName, uint Calendar, string lpReserved, uint CalType, void* lParam);
- internal delegate BOOL EnumCalendarInfoProcExEx(IntPtr lpCalendarInfoString, uint Calendar, IntPtr lpReserved, IntPtr lParam);
+ internal delegate BOOL EnumCalendarInfoProcExEx(char* lpCalendarInfoString, uint Calendar, IntPtr lpReserved, void* lParam);
[StructLayout(LayoutKind.Sequential)]
- internal struct NlsVersionInfoEx
+ internal struct NlsVersionInfoEx
{
internal int dwNLSVersionInfoSize;
internal int dwNLSVersion;
diff --git a/src/mscorlib/shared/Interop/Windows/Kernel32/Interop.SetErrorMode.cs b/src/mscorlib/shared/Interop/Windows/Kernel32/Interop.SetThreadErrorMode.cs
index 276f49c..123eb75 100644
--- a/src/mscorlib/shared/Interop/Windows/Kernel32/Interop.SetErrorMode.cs
+++ b/src/mscorlib/shared/Interop/Windows/Kernel32/Interop.SetThreadErrorMode.cs
@@ -8,8 +8,8 @@ internal partial class Interop
{
internal partial class Kernel32
{
- [DllImport(Libraries.Kernel32, SetLastError = false, EntryPoint = "SetErrorMode", ExactSpelling = true)]
- internal static extern uint SetErrorMode(uint newMode);
+ [DllImport(Libraries.Kernel32, SetLastError = true, ExactSpelling = true)]
+ internal static extern bool SetThreadErrorMode(uint dwNewMode, out uint lpOldMode);
internal const uint SEM_FAILCRITICALERRORS = 1;
}
diff --git a/src/mscorlib/shared/Interop/Windows/NtDll/Interop.ZeroMemory.cs b/src/mscorlib/shared/Interop/Windows/NtDll/Interop.ZeroMemory.cs
deleted file mode 100644
index 9bf7321..0000000
--- a/src/mscorlib/shared/Interop/Windows/NtDll/Interop.ZeroMemory.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System;
-using System.Runtime.InteropServices;
-using System.Security;
-
-internal partial class Interop
-{
- internal partial class NtDll
- {
- [DllImport(Libraries.NtDll, CharSet = CharSet.Unicode, EntryPoint = "RtlZeroMemory")]
- internal static extern void ZeroMemory(IntPtr address, UIntPtr length);
- }
-}
diff --git a/src/mscorlib/shared/Microsoft/Win32/SafeHandles/SafeFileHandle.Unix.cs b/src/mscorlib/shared/Microsoft/Win32/SafeHandles/SafeFileHandle.Unix.cs
index d13b536..f28f44f 100644
--- a/src/mscorlib/shared/Microsoft/Win32/SafeHandles/SafeFileHandle.Unix.cs
+++ b/src/mscorlib/shared/Microsoft/Win32/SafeHandles/SafeFileHandle.Unix.cs
@@ -4,6 +4,7 @@
using System;
using System.Diagnostics;
+using System.IO;
using System.Runtime.InteropServices;
namespace Microsoft.Win32.SafeHandles
@@ -38,18 +39,30 @@ namespace Microsoft.Win32.SafeHandles
internal static SafeFileHandle Open(string path, Interop.Sys.OpenFlags flags, int mode)
{
Debug.Assert(path != null);
+ SafeFileHandle handle = Interop.Sys.Open(path, flags, mode);
- // If we fail to open the file due to a path not existing, we need to know whether to blame
- // the file itself or its directory. If we're creating the file, then we blame the directory,
- // otherwise we blame the file.
- bool enoentDueToDirectory = (flags & Interop.Sys.OpenFlags.O_CREAT) != 0;
-
- // Open the file.
- SafeFileHandle handle = Interop.CheckIo(
- Interop.Sys.Open(path, flags, mode),
- path,
- isDirectory: enoentDueToDirectory,
- errorRewriter: e => (e.Error == Interop.Error.EISDIR) ? Interop.Error.EACCES.Info() : e);
+ if (handle.IsInvalid)
+ {
+ handle.Dispose();
+ Interop.ErrorInfo error = Interop.Sys.GetLastErrorInfo();
+
+ // If we fail to open the file due to a path not existing, we need to know whether to blame
+ // the file itself or its directory. If we're creating the file, then we blame the directory,
+ // otherwise we blame the file.
+ //
+ // When opening, we need to align with Windows, which considers a missing path to be
+ // FileNotFound only if the containing directory exists.
+
+ bool isDirectory = (error.Error == Interop.Error.ENOENT) &&
+ ((flags & Interop.Sys.OpenFlags.O_CREAT) != 0
+ || !DirectoryExists(Path.GetDirectoryName(PathInternal.TrimEndingDirectorySeparator(path))));
+
+ Interop.CheckIo(
+ error.Error,
+ path,
+ isDirectory,
+ errorRewriter: e => (e.Error == Interop.Error.EISDIR) ? Interop.Error.EACCES.Info() : e);
+ }
// Make sure it's not a directory; we do this after opening it once we have a file descriptor
// to avoid race conditions.
@@ -68,6 +81,31 @@ namespace Microsoft.Win32.SafeHandles
return handle;
}
+ private static bool DirectoryExists(string fullPath)
+ {
+ int fileType = Interop.Sys.FileTypes.S_IFDIR;
+
+ Interop.Sys.FileStatus fileinfo;
+ Interop.ErrorInfo errorInfo = default(Interop.ErrorInfo);
+
+ // First use stat, as we want to follow symlinks. If that fails, it could be because the symlink
+ // is broken, we don't have permissions, etc., in which case fall back to using LStat to evaluate
+ // based on the symlink itself.
+ if (Interop.Sys.Stat(fullPath, out fileinfo) < 0 &&
+ Interop.Sys.LStat(fullPath, out fileinfo) < 0)
+ {
+ errorInfo = Interop.Sys.GetLastErrorInfo();
+ return false;
+ }
+
+ // Something exists at this path. If the caller is asking for a directory, return true if it's
+ // a directory and false for everything else. If the caller is asking for a file, return false for
+ // a directory and true for everything else.
+ return
+ (fileType == Interop.Sys.FileTypes.S_IFDIR) ==
+ ((fileinfo.Mode & Interop.Sys.FileTypes.S_IFMT) == Interop.Sys.FileTypes.S_IFDIR);
+ }
+
/// <summary>Opens a SafeFileHandle for a file descriptor created by a provided delegate.</summary>
/// <param name="fdFunc">
/// The function that creates the file descriptor. Returns the file descriptor on success, or an invalid
diff --git a/src/mscorlib/shared/Microsoft/Win32/SafeHandles/SafeHandleMinusOneIsInvalid.cs b/src/mscorlib/shared/Microsoft/Win32/SafeHandles/SafeHandleMinusOneIsInvalid.cs
new file mode 100644
index 0000000..5415f2c
--- /dev/null
+++ b/src/mscorlib/shared/Microsoft/Win32/SafeHandles/SafeHandleMinusOneIsInvalid.cs
@@ -0,0 +1,19 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.InteropServices;
+
+namespace Microsoft.Win32.SafeHandles
+{
+ // Class of safe handle which uses only -1 as an invalid handle.
+ public abstract class SafeHandleMinusOneIsInvalid : SafeHandle
+ {
+ protected SafeHandleMinusOneIsInvalid(bool ownsHandle) : base(new IntPtr(-1), ownsHandle)
+ {
+ }
+
+ public override bool IsInvalid => handle == new IntPtr(-1);
+ }
+}
diff --git a/src/mscorlib/shared/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs b/src/mscorlib/shared/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs
new file mode 100644
index 0000000..8d0220b
--- /dev/null
+++ b/src/mscorlib/shared/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs
@@ -0,0 +1,19 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.InteropServices;
+
+namespace Microsoft.Win32.SafeHandles
+{
+ // Class of safe handle which uses 0 or -1 as an invalid handle.
+ public abstract class SafeHandleZeroOrMinusOneIsInvalid : SafeHandle
+ {
+ protected SafeHandleZeroOrMinusOneIsInvalid(bool ownsHandle) : base(IntPtr.Zero, ownsHandle)
+ {
+ }
+
+ public override bool IsInvalid => handle == IntPtr.Zero || handle == new IntPtr(-1);
+ }
+}
diff --git a/src/mscorlib/shared/System.Private.CoreLib.Shared.projitems b/src/mscorlib/shared/System.Private.CoreLib.Shared.projitems
index 3443a2b..e409be0 100644
--- a/src/mscorlib/shared/System.Private.CoreLib.Shared.projitems
+++ b/src/mscorlib/shared/System.Private.CoreLib.Shared.projitems
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
@@ -16,10 +16,13 @@
<ItemGroup>
<Compile Include="$(MSBuildThisFileDirectory)Microsoft\Win32\SafeHandles\CriticalHandleMinusOneIsInvalid.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)Microsoft\Win32\SafeHandles\CriticalHandleZeroOrMinusOneIsInvalid.cs"/>
+ <Compile Include="$(MSBuildThisFileDirectory)Microsoft\Win32\SafeHandles\SafeHandleMinusOneIsInvalid.cs"/>
+ <Compile Include="$(MSBuildThisFileDirectory)Microsoft\Win32\SafeHandles\SafeHandleZeroOrMinusOneIsInvalid.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)System\Action.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)System\ApplicationException.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)System\ArgumentException.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)System\ArgumentNullException.cs"/>
+ <Compile Include="$(MSBuildThisFileDirectory)System\ArgumentOutOfRangeException.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)System\ArithmeticException.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)System\ArrayTypeMismatchException.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)System\AssemblyLoadEventArgs.cs" />
@@ -27,6 +30,7 @@
<Compile Include="$(MSBuildThisFileDirectory)System\AsyncCallback.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)System\AttributeTargets.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)System\AttributeUsageAttribute.cs"/>
+ <Compile Include="$(MSBuildThisFileDirectory)System\BadImageFormatException.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)System\Buffers\ArrayPool.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)System\Buffers\ConfigurableArrayPool.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)System\Buffers\TlsOverPerCoreLockedStacksArrayPool.cs"/>
@@ -74,6 +78,7 @@
<Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\ConditionalAttribute.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Debug.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)System\DivideByZeroException.cs"/>
+ <Compile Include="$(MSBuildThisFileDirectory)System\DllNotFoundException.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)System\DuplicateWaitObjectException.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)System\EntryPointNotFoundException.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)System\EventArgs.cs"/>
@@ -107,9 +112,12 @@
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\JulianCalendar.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\KoreanCalendar.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\KoreanLunisolarCalendar.cs"/>
+ <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\NumberFormatInfo.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\NumberStyles.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\PersianCalendar.cs"/>
+ <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\SortKey.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\SortVersion.cs"/>
+ <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\StringInfo.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\TaiwanCalendar.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\TaiwanLunisolarCalendar.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\ThaiBuddhistCalendar.cs"/>
@@ -132,6 +140,7 @@
<Compile Include="$(MSBuildThisFileDirectory)System\InvalidProgramException.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)System\InvalidTimeZoneException.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)System\IO\DirectoryNotFoundException.cs"/>
+ <Compile Include="$(MSBuildThisFileDirectory)System\IO\EncodingCache.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)System\IO\EndOfStreamException.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)System\IO\Error.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)System\IO\FileAccess.cs"/>
@@ -144,8 +153,11 @@
<Compile Include="$(MSBuildThisFileDirectory)System\IO\Path.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)System\IO\PathInternal.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)System\IO\PathTooLongException.cs"/>
+ <Compile Include="$(MSBuildThisFileDirectory)System\IO\PinnedBufferMemoryStream.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)System\IO\SeekOrigin.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)System\IO\StreamHelpers.CopyValidation.cs"/>
+ <Compile Include="$(MSBuildThisFileDirectory)System\IO\UnmanagedMemoryStream.cs"/>
+ <Compile Include="$(MSBuildThisFileDirectory)System\IO\UnmanagedMemoryStreamWrapper.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)System\IObservable.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)System\IObserver.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)System\IProgress.cs"/>
@@ -162,6 +174,7 @@
<Compile Include="$(MSBuildThisFileDirectory)System\NullReferenceException.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)System\ObjectDisposedException.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)System\ObsoleteAttribute.cs"/>
+ <Compile Include="$(MSBuildThisFileDirectory)System\OperationCanceledException.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)System\OverflowException.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)System\ParamArrayAttribute.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)System\ParamsArray.cs"/>
@@ -188,6 +201,7 @@
<Compile Include="$(MSBuildThisFileDirectory)System\Reflection\AssemblyKeyNameAttribute.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Reflection\AssemblyMetadataAttribute.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Reflection\AssemblyNameFlags.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)System\Reflection\AssemblyNameFormatter.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Reflection\AssemblyProductAttribute.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Reflection\AssemblySignatureKeyAttribute.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Reflection\AssemblyTitleAttribute.cs" />
@@ -215,7 +229,6 @@
<Compile Include="$(MSBuildThisFileDirectory)System\Reflection\ManifestResourceInfo.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Reflection\MemberFilter.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Reflection\MemberInfo.cs" />
- <Compile Include="$(MSBuildThisFileDirectory)System\Reflection\MemberInfoSerializationHolder.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Reflection\MemberTypes.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Reflection\MethodAttributes.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Reflection\MethodBase.cs" />
@@ -252,7 +265,9 @@
<Compile Include="$(MSBuildThisFileDirectory)System\Resources\MissingManifestResourceException.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)System\Resources\MissingSatelliteAssemblyException.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)System\Resources\NeutralResourcesLanguageAttribute.cs"/>
+ <Compile Include="$(MSBuildThisFileDirectory)System\Resources\ResourceFallbackManager.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)System\Resources\ResourceTypeCode.cs"/>
+ <Compile Include="$(MSBuildThisFileDirectory)System\Resources\RuntimeResourceSet.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)System\Resources\SatelliteContractVersionAttribute.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)System\Resources\UltimateResourceFallbackLocation.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\CompilerServices\AccessedThroughPropertyAttribute.cs"/>
@@ -274,9 +289,10 @@
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\CompilerServices\FormattableStringFactory.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\CompilerServices\IAsyncStateMachine.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\CompilerServices\IndexerNameAttribute.cs"/>
- <Compile Include="$(MSBuildThisFileDirectory)System\Runtime\CompilerServices\InternalsVisibleToAttribute.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\CompilerServices\INotifyCompletion.cs"/>
+ <Compile Include="$(MSBuildThisFileDirectory)System\Runtime\CompilerServices\InternalsVisibleToAttribute.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\CompilerServices\IsConst.cs"/>
+ <Compile Include="$(MSBuildThisFileDirectory)System\Runtime\CompilerServices\IsByRefLikeAttribute.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\CompilerServices\IsVolatile.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\CompilerServices\IteratorStateMachineAttribute.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\CompilerServices\ITuple.cs"/>
@@ -354,9 +370,9 @@
<Compile Include="$(MSBuildThisFileDirectory)System\Text\EncodingProvider.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)System\Text\Normalization.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)System\Text\StringBuilder.cs"/>
+ <Compile Include="$(MSBuildThisFileDirectory)System\Text\UnicodeEncoding.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)System\Text\UTF32Encoding.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)System\Text\UTF8Encoding.cs"/>
- <Compile Include="$(MSBuildThisFileDirectory)System\Text\UnicodeEncoding.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)System\ThreadAttributes.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\AbandonedMutexException.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\ApartmentState.cs"/>
@@ -399,7 +415,6 @@
<Compile Include="$(MSBuildThisFileDirectory)System\UnauthorizedAccessException.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)System\UnhandledExceptionEventArgs.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)System\UnhandledExceptionEventHandler.cs"/>
- <Compile Include="$(MSBuildThisFileDirectory)System\UnitySerializationHolder.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)System\ValueTuple.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)System\Version.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)System\Void.cs"/>
@@ -411,6 +426,7 @@
<Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\EventProvider.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\EventSource.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\EventSourceException.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\IEventProvider.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\StubEnvironment.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\Winmeta.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\TraceLogging\ArrayTypeInfo.cs" />
@@ -465,6 +481,7 @@
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.GetLongPathNameW.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.GetTempFileNameW.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.GetTempPathW.cs"/>
+ <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.Globalization.cs" Condition="'$(EnableDummyGlobalizationImplementation)' != 'true'"/>
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.LockFile.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.OutputDebugString.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.ReadFile_SafeHandle_IntPtr.cs"/>
@@ -472,16 +489,19 @@
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.SECURITY_ATTRIBUTES.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.SecurityOptions.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.SetEndOfFile.cs"/>
- <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.SetErrorMode.cs"/>
+ <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.SetThreadErrorMode.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.SetFilePointerEx.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.WideCharToMultiByte.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.WriteFile_SafeHandle_IntPtr.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.WriteFile_SafeHandle_NativeOverlapped.cs"/>
- <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\NtDll\Interop.ZeroMemory.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\OleAut32\Interop.SysAllocStringLen.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\OleAut32\Interop.SysFreeString.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\OleAut32\Interop.SysStringLen.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)Microsoft\Win32\SafeHandles\SafeFileHandle.Windows.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\HijriCalendar.Win32.cs" Condition="'$(IsProjectNLibrary)' != 'true' and '$(EnableDummyGlobalizationImplementation)' != 'true'"/>
+ <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\HijriCalendar.WinRT.cs" Condition="'$(IsProjectNLibrary)' == 'true'"/>
+ <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\JapaneseCalendar.Win32.cs" Condition="'$(IsProjectNLibrary)' != 'true' and '$(EnableDummyGlobalizationImplementation)' != 'true'"/>
+ <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\JapaneseCalendar.WinRT.cs" Condition="'$(IsProjectNLibrary)' == 'true'"/>
<Compile Include="$(MSBuildThisFileDirectory)System\IO\FileStream.Win32.cs" Condition="'$(IsProjectNLibrary)' != 'true'" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\FileStream.Windows.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\FileStream.WinRT.cs" Condition="'$(IsProjectNLibrary)' == 'true'" />
@@ -500,6 +520,7 @@
<Compile Include="$(MSBuildThisFileDirectory)Interop\Unix\Interop.Libraries.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)Interop\Unix\System.Globalization.Native\Interop.Calendar.cs" Condition="'$(EnableDummyGlobalizationImplementation)' != 'true'"/>
<Compile Include="$(MSBuildThisFileDirectory)Interop\Unix\System.Globalization.Native\Interop.Casing.cs" Condition="'$(EnableDummyGlobalizationImplementation)' != 'true'"/>
+ <Compile Include="$(MSBuildThisFileDirectory)Interop\Unix\System.Globalization.Native\Interop.Collation.cs" Condition="'$(EnableDummyGlobalizationImplementation)' != 'true'"/>
<Compile Include="$(MSBuildThisFileDirectory)Interop\Unix\System.Globalization.Native\Interop.Idna.cs" Condition="'$(EnableDummyGlobalizationImplementation)' != 'true'"/>
<Compile Include="$(MSBuildThisFileDirectory)Interop\Unix\System.Globalization.Native\Interop.Locale.cs" Condition="'$(EnableDummyGlobalizationImplementation)' != 'true'"/>
<Compile Include="$(MSBuildThisFileDirectory)Interop\Unix\System.Globalization.Native\Interop.Normalization.cs" Condition="'$(EnableDummyGlobalizationImplementation)' != 'true'"/>
@@ -526,7 +547,13 @@
<Compile Include="$(MSBuildThisFileDirectory)Interop\Unix\System.Native\Interop.Unlink.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)Interop\Unix\System.Native\Interop.Write.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)Microsoft\Win32\SafeHandles\SafeFileHandle.Unix.cs"/>
+ <Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Debug.Unix.cs"/>
+ <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CalendarData.Unix.cs" Condition="'$(EnableDummyGlobalizationImplementation)' != 'true'"/>
+ <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CultureData.Unix.cs" Condition="'$(EnableDummyGlobalizationImplementation)' != 'true'"/>
+ <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\HijriCalendar.Unix.cs" Condition="'$(EnableDummyGlobalizationImplementation)' != 'true'"/>
+ <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\IdnMapping.Unix.cs" Condition="'$(EnableDummyGlobalizationImplementation)' != 'true'"/>
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\LocaleData.Unix.cs" Condition="'$(EnableDummyGlobalizationImplementation)' != 'true'"/>
+ <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\JapaneseCalendar.Unix.cs" Condition="'$(EnableDummyGlobalizationImplementation)' != 'true'"/>
<Compile Include="$(MSBuildThisFileDirectory)System\IO\FileStream.OSX.cs" Condition="'$(TargetsOSX)' == 'true'"/>
<Compile Include="$(MSBuildThisFileDirectory)System\IO\FileStream.Linux.cs" Condition="'$(TargetsOSX)' != 'true'"/>
<Compile Include="$(MSBuildThisFileDirectory)System\IO\FileStream.Unix.cs"/>
diff --git a/src/mscorlib/shared/System/ApplicationException.cs b/src/mscorlib/shared/System/ApplicationException.cs
index 900feb5..cb98902 100644
--- a/src/mscorlib/shared/System/ApplicationException.cs
+++ b/src/mscorlib/shared/System/ApplicationException.cs
@@ -23,7 +23,6 @@ namespace System
// ApplicationException extends but adds no new functionality to
// RecoverableException.
//
- [Serializable]
public class ApplicationException : Exception
{
// Creates a new ApplicationException with its message string set to
@@ -51,6 +50,9 @@ namespace System
HResult = __HResults.COR_E_APPLICATION;
}
- protected ApplicationException(SerializationInfo info, StreamingContext context) : base(info, context) { }
+ protected ApplicationException(SerializationInfo info, StreamingContext context) : base(info, context)
+ {
+ throw new PlatformNotSupportedException();
+ }
}
}
diff --git a/src/mscorlib/shared/System/ArgumentException.cs b/src/mscorlib/shared/System/ArgumentException.cs
index 96afbe1..de2d775 100644
--- a/src/mscorlib/shared/System/ArgumentException.cs
+++ b/src/mscorlib/shared/System/ArgumentException.cs
@@ -20,7 +20,6 @@ namespace System
// the contract of the method. Ideally it should give a meaningful error
// message describing what was wrong and which parameter is incorrect.
//
- [Serializable]
public class ArgumentException : SystemException
{
private String _paramName;
@@ -65,13 +64,12 @@ namespace System
protected ArgumentException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
- _paramName = info.GetString("ParamName");
+ throw new PlatformNotSupportedException();
}
public override void GetObjectData(SerializationInfo info, StreamingContext context)
{
base.GetObjectData(info, context);
- info.AddValue("ParamName", _paramName, typeof(String));
}
public override String Message
diff --git a/src/mscorlib/shared/System/ArgumentNullException.cs b/src/mscorlib/shared/System/ArgumentNullException.cs
index 3a86223..74b39fe 100644
--- a/src/mscorlib/shared/System/ArgumentNullException.cs
+++ b/src/mscorlib/shared/System/ArgumentNullException.cs
@@ -18,7 +18,6 @@ namespace System
// The ArgumentException is thrown when an argument
// is null when it shouldn't be.
//
- [Serializable]
public class ArgumentNullException : ArgumentException
{
// Creates a new ArgumentNullException with its message
@@ -48,6 +47,9 @@ namespace System
HResult = __HResults.E_POINTER;
}
- protected ArgumentNullException(SerializationInfo info, StreamingContext context) : base(info, context) { }
+ protected ArgumentNullException(SerializationInfo info, StreamingContext context) : base(info, context)
+ {
+ throw new PlatformNotSupportedException();
+ }
}
}
diff --git a/src/mscorlib/src/System/ArgumentOutOfRangeException.cs b/src/mscorlib/shared/System/ArgumentOutOfRangeException.cs
index 9083781..4721a50 100644
--- a/src/mscorlib/src/System/ArgumentOutOfRangeException.cs
+++ b/src/mscorlib/shared/System/ArgumentOutOfRangeException.cs
@@ -11,43 +11,27 @@
**
=============================================================================*/
-
-using System;
-using System.Runtime.Remoting;
-using System.Runtime.Serialization;
using System.Globalization;
-using System.Diagnostics.Contracts;
+using System.Runtime.Serialization;
namespace System
{
// The ArgumentOutOfRangeException is thrown when an argument
// is outside the legal range for that argument.
- [Serializable]
- public class ArgumentOutOfRangeException : ArgumentException, ISerializable
+ public class ArgumentOutOfRangeException : ArgumentException
{
- private static volatile String _rangeMessage;
- private Object m_actualValue;
-
- private static String RangeMessage
- {
- get
- {
- if (_rangeMessage == null)
- _rangeMessage = SR.Arg_ArgumentOutOfRangeException;
- return _rangeMessage;
- }
- }
+ private Object _actualValue;
// Creates a new ArgumentOutOfRangeException with its message
// string set to a default message explaining an argument was out of range.
public ArgumentOutOfRangeException()
- : base(RangeMessage)
+ : base(SR.Arg_ArgumentOutOfRangeException)
{
HResult = __HResults.COR_E_ARGUMENTOUTOFRANGE;
}
public ArgumentOutOfRangeException(String paramName)
- : base(RangeMessage, paramName)
+ : base(SR.Arg_ArgumentOutOfRangeException, paramName)
{
HResult = __HResults.COR_E_ARGUMENTOUTOFRANGE;
}
@@ -70,18 +54,29 @@ namespace System
public ArgumentOutOfRangeException(String paramName, Object actualValue, String message)
: base(message, paramName)
{
- m_actualValue = actualValue;
+ _actualValue = actualValue;
HResult = __HResults.COR_E_ARGUMENTOUTOFRANGE;
}
+ protected ArgumentOutOfRangeException(SerializationInfo info, StreamingContext context)
+ : base(info, context)
+ {
+ throw new PlatformNotSupportedException();
+ }
+
+ public override void GetObjectData(SerializationInfo info, StreamingContext context)
+ {
+ base.GetObjectData(info, context);
+ }
+
public override String Message
{
get
{
String s = base.Message;
- if (m_actualValue != null)
+ if (_actualValue != null)
{
- String valueMessage = SR.Format(SR.ArgumentOutOfRange_ActualValue, m_actualValue.ToString());
+ String valueMessage = SR.Format(SR.ArgumentOutOfRange_ActualValue, _actualValue.ToString());
if (s == null)
return valueMessage;
return s + Environment.NewLine + valueMessage;
@@ -96,23 +91,7 @@ namespace System
// want to avoid sticking printf's in their code.
public virtual Object ActualValue
{
- get { return m_actualValue; }
- }
-
- public override void GetObjectData(SerializationInfo info, StreamingContext context)
- {
- if (info == null)
- {
- throw new ArgumentNullException(nameof(info));
- }
- Contract.EndContractBlock();
- base.GetObjectData(info, context);
- info.AddValue("ActualValue", m_actualValue, typeof(Object));
- }
-
- protected ArgumentOutOfRangeException(SerializationInfo info, StreamingContext context) : base(info, context)
- {
- m_actualValue = info.GetValue("ActualValue", typeof(Object));
+ get { return _actualValue; }
}
}
}
diff --git a/src/mscorlib/shared/System/ArithmeticException.cs b/src/mscorlib/shared/System/ArithmeticException.cs
index 081ba45..2c8abe5 100644
--- a/src/mscorlib/shared/System/ArithmeticException.cs
+++ b/src/mscorlib/shared/System/ArithmeticException.cs
@@ -18,7 +18,6 @@ namespace System
// The ArithmeticException is thrown when overflow or underflow
// occurs.
//
- [Serializable]
public class ArithmeticException : SystemException
{
// Creates a new ArithmeticException with its message string set to
@@ -46,6 +45,9 @@ namespace System
HResult = __HResults.COR_E_ARITHMETIC;
}
- protected ArithmeticException(SerializationInfo info, StreamingContext context) : base(info, context) { }
+ protected ArithmeticException(SerializationInfo info, StreamingContext context) : base(info, context)
+ {
+ throw new PlatformNotSupportedException();
+ }
}
}
diff --git a/src/mscorlib/shared/System/ArrayTypeMismatchException.cs b/src/mscorlib/shared/System/ArrayTypeMismatchException.cs
index 3e941fd..d06a450 100644
--- a/src/mscorlib/shared/System/ArrayTypeMismatchException.cs
+++ b/src/mscorlib/shared/System/ArrayTypeMismatchException.cs
@@ -18,7 +18,6 @@ namespace System
// The ArrayMismatchException is thrown when an attempt to store
// an object of the wrong type within an array occurs.
//
- [Serializable]
public class ArrayTypeMismatchException : SystemException
{
// Creates a new ArrayMismatchException with its message string set to
@@ -46,6 +45,9 @@ namespace System
HResult = __HResults.COR_E_ARRAYTYPEMISMATCH;
}
- protected ArrayTypeMismatchException(SerializationInfo info, StreamingContext context) : base(info, context) { }
+ protected ArrayTypeMismatchException(SerializationInfo info, StreamingContext context) : base(info, context)
+ {
+ throw new PlatformNotSupportedException();
+ }
}
}
diff --git a/src/mscorlib/shared/System/AsyncCallback.cs b/src/mscorlib/shared/System/AsyncCallback.cs
index 5c49535..036d44a 100644
--- a/src/mscorlib/shared/System/AsyncCallback.cs
+++ b/src/mscorlib/shared/System/AsyncCallback.cs
@@ -12,6 +12,5 @@
namespace System
{
- [Serializable]
public delegate void AsyncCallback(IAsyncResult ar);
}
diff --git a/src/mscorlib/shared/System/AttributeTargets.cs b/src/mscorlib/shared/System/AttributeTargets.cs
index fdfa4ab..c33d19e 100644
--- a/src/mscorlib/shared/System/AttributeTargets.cs
+++ b/src/mscorlib/shared/System/AttributeTargets.cs
@@ -10,7 +10,6 @@ namespace System
// Enum used to indicate all the elements of the
// VOS it is valid to attach this element to.
[Flags]
- [Serializable]
public enum AttributeTargets
{
Assembly = 0x0001,
diff --git a/src/mscorlib/shared/System/AttributeUsageAttribute.cs b/src/mscorlib/shared/System/AttributeUsageAttribute.cs
index 6f9aeb2..219dc43 100644
--- a/src/mscorlib/shared/System/AttributeUsageAttribute.cs
+++ b/src/mscorlib/shared/System/AttributeUsageAttribute.cs
@@ -16,7 +16,6 @@ using System.Reflection;
namespace System
{
/* By default, attributes are inherited and multiple attributes are not allowed */
- [Serializable]
[AttributeUsage(AttributeTargets.Class, Inherited = true)]
public sealed class AttributeUsageAttribute : Attribute
{
diff --git a/src/mscorlib/src/System/BadImageFormatException.cs b/src/mscorlib/shared/System/BadImageFormatException.cs
index 42005cc..6bed5e9 100644
--- a/src/mscorlib/src/System/BadImageFormatException.cs
+++ b/src/mscorlib/shared/System/BadImageFormatException.cs
@@ -11,16 +11,13 @@
**
===========================================================*/
+using System.Globalization;
+using System.IO;
+using System.Runtime.Serialization;
+
namespace System
{
- using System;
- using System.Runtime.Serialization;
- using FileLoadException = System.IO.FileLoadException;
- using SecurityException = System.Security.SecurityException;
- using System.Globalization;
-
- [Serializable]
- public class BadImageFormatException : SystemException
+ public partial class BadImageFormatException : SystemException
{
private String _fileName; // The name of the corrupt PE file.
private String _fusionLog; // fusion log (when applicable)
@@ -56,6 +53,17 @@ namespace System
_fileName = fileName;
}
+ protected BadImageFormatException(SerializationInfo info, StreamingContext context)
+ : base(info, context)
+ {
+ throw new PlatformNotSupportedException();
+ }
+
+ public override void GetObjectData(SerializationInfo info, StreamingContext context)
+ {
+ base.GetObjectData(info, context);
+ }
+
public override String Message
{
get
@@ -70,7 +78,7 @@ namespace System
if (_message == null)
{
if ((_fileName == null) &&
- (HResult == System.__HResults.COR_E_EXCEPTION))
+ (HResult == __HResults.COR_E_EXCEPTION))
_message = SR.Arg_BadImageFormatException;
else
@@ -85,7 +93,7 @@ namespace System
public override String ToString()
{
- String s = GetType().FullName + ": " + Message;
+ String s = GetType().ToString() + ": " + Message;
if (_fileName != null && _fileName.Length != 0)
s += Environment.NewLine + SR.Format(SR.IO_FileName_Name, _fileName);
@@ -95,68 +103,22 @@ namespace System
if (StackTrace != null)
s += Environment.NewLine + StackTrace;
- try
- {
- if (FusionLog != null)
- {
- if (s == null)
- s = " ";
- s += Environment.NewLine;
- s += Environment.NewLine;
- s += FusionLog;
- }
- }
- catch (SecurityException)
- {
- }
- return s;
- }
-
- protected BadImageFormatException(SerializationInfo info, StreamingContext context) : base(info, context)
- {
- // Base class constructor will check info != null.
- _fileName = info.GetString("BadImageFormat_FileName");
- try
+ if (_fusionLog != null)
{
- _fusionLog = info.GetString("BadImageFormat_FusionLog");
+ if (s == null)
+ s = " ";
+ s += Environment.NewLine;
+ s += Environment.NewLine;
+ s += _fusionLog;
}
- catch
- {
- _fusionLog = null;
- }
- }
- private BadImageFormatException(String fileName, String fusionLog, int hResult)
- : base(null)
- {
- HResult = hResult;
- _fileName = fileName;
- _fusionLog = fusionLog;
- SetMessageField();
+ return s;
}
public String FusionLog
{
-#pragma warning disable CS0618 // Type or member is obsolete
-#pragma warning restore CS0618 // Type or member is obsolete
get { return _fusionLog; }
}
-
- public override void GetObjectData(SerializationInfo info, StreamingContext context)
- {
- // Serialize data for our base classes. base will verify info != null.
- base.GetObjectData(info, context);
-
- // Serialize data for this class
- info.AddValue("BadImageFormat_FileName", _fileName, typeof(String));
- try
- {
- info.AddValue("BadImageFormat_FusionLog", FusionLog, typeof(String));
- }
- catch (SecurityException)
- {
- }
- }
}
}
diff --git a/src/mscorlib/shared/System/CLSCompliantAttribute.cs b/src/mscorlib/shared/System/CLSCompliantAttribute.cs
index e03600d..d895b5a 100644
--- a/src/mscorlib/shared/System/CLSCompliantAttribute.cs
+++ b/src/mscorlib/shared/System/CLSCompliantAttribute.cs
@@ -13,7 +13,6 @@
namespace System
{
- [Serializable]
[AttributeUsage(AttributeTargets.All, Inherited = true, AllowMultiple = false)]
public sealed class CLSCompliantAttribute : Attribute
{
diff --git a/src/mscorlib/shared/System/Char.cs b/src/mscorlib/shared/System/Char.cs
index 2b3133a..3fad7a4 100644
--- a/src/mscorlib/shared/System/Char.cs
+++ b/src/mscorlib/shared/System/Char.cs
@@ -26,7 +26,7 @@ namespace System
//
// Member Variables
//
- internal char m_value;
+ private char m_value; // Do not rename (binary serialization)
//
// Public Constants
diff --git a/src/mscorlib/shared/System/CharEnumerator.cs b/src/mscorlib/shared/System/CharEnumerator.cs
index 4dbd5cd..ea9915a 100644
--- a/src/mscorlib/shared/System/CharEnumerator.cs
+++ b/src/mscorlib/shared/System/CharEnumerator.cs
@@ -17,7 +17,6 @@ using System.Collections.Generic;
namespace System
{
- [Serializable]
public sealed class CharEnumerator : IEnumerator, IEnumerator<char>, IDisposable, ICloneable
{
private String _str;
diff --git a/src/mscorlib/shared/System/Collections/Generic/KeyNotFoundException.cs b/src/mscorlib/shared/System/Collections/Generic/KeyNotFoundException.cs
index 1fca773..cdd6faf 100644
--- a/src/mscorlib/shared/System/Collections/Generic/KeyNotFoundException.cs
+++ b/src/mscorlib/shared/System/Collections/Generic/KeyNotFoundException.cs
@@ -7,7 +7,6 @@ using System.Runtime.Serialization;
namespace System.Collections.Generic
{
- [Serializable]
public class KeyNotFoundException : SystemException
{
public KeyNotFoundException()
@@ -28,6 +27,9 @@ namespace System.Collections.Generic
HResult = __HResults.COR_E_KEYNOTFOUND;
}
- protected KeyNotFoundException(SerializationInfo info, StreamingContext context) : base(info, context) { }
+ protected KeyNotFoundException(SerializationInfo info, StreamingContext context) : base(info, context)
+ {
+ throw new PlatformNotSupportedException();
+ }
}
}
diff --git a/src/mscorlib/shared/System/CurrentSystemTimeZone.cs b/src/mscorlib/shared/System/CurrentSystemTimeZone.cs
index 2d84839..3f17d6f 100644
--- a/src/mscorlib/shared/System/CurrentSystemTimeZone.cs
+++ b/src/mscorlib/shared/System/CurrentSystemTimeZone.cs
@@ -28,7 +28,6 @@ using System.Runtime.Versioning;
namespace System
{
[Obsolete("System.CurrentSystemTimeZone has been deprecated. Please investigate the use of System.TimeZoneInfo.Local instead.")]
- [Serializable]
internal partial class CurrentSystemTimeZone : TimeZone
{
// Standard offset in ticks to the Universal time if
diff --git a/src/mscorlib/shared/System/DBNull.cs b/src/mscorlib/shared/System/DBNull.cs
index 486eb72..4f4d64b 100644
--- a/src/mscorlib/shared/System/DBNull.cs
+++ b/src/mscorlib/shared/System/DBNull.cs
@@ -6,23 +6,17 @@ using System.Runtime.Serialization;
namespace System
{
- [Serializable]
public sealed class DBNull : ISerializable, IConvertible
{
private DBNull()
{
}
-
- private DBNull(SerializationInfo info, StreamingContext context)
- {
- throw new NotSupportedException(SR.NotSupported_DBNullSerial);
- }
-
+
public static readonly DBNull Value = new DBNull();
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
- UnitySerializationHolder.GetUnitySerializationInfo(info, UnitySerializationHolder.NullUnity, null, null);
+ throw new PlatformNotSupportedException();
}
public override string ToString()
diff --git a/src/mscorlib/shared/System/DataMisalignedException.cs b/src/mscorlib/shared/System/DataMisalignedException.cs
index b1991a0..ff5b29f 100644
--- a/src/mscorlib/shared/System/DataMisalignedException.cs
+++ b/src/mscorlib/shared/System/DataMisalignedException.cs
@@ -13,7 +13,6 @@ using System.Runtime.Serialization;
namespace System
{
- [Serializable]
public sealed class DataMisalignedException : SystemException
{
public DataMisalignedException()
@@ -33,7 +32,5 @@ namespace System
{
HResult = __HResults.COR_E_DATAMISALIGNED;
}
-
- internal DataMisalignedException(SerializationInfo info, StreamingContext context) : base(info, context) { }
}
}
diff --git a/src/mscorlib/shared/System/DateTimeKind.cs b/src/mscorlib/shared/System/DateTimeKind.cs
index 6b5e690..33c9bd9 100644
--- a/src/mscorlib/shared/System/DateTimeKind.cs
+++ b/src/mscorlib/shared/System/DateTimeKind.cs
@@ -7,7 +7,6 @@ namespace System
// This enum is used to indentify DateTime instances in cases when they are known to be in local time,
// UTC time or if this information has not been specified or is not applicable.
- [Serializable]
public enum DateTimeKind
{
Unspecified = 0,
diff --git a/src/mscorlib/shared/System/DayOfWeek.cs b/src/mscorlib/shared/System/DayOfWeek.cs
index 5d84257..f67d10e 100644
--- a/src/mscorlib/shared/System/DayOfWeek.cs
+++ b/src/mscorlib/shared/System/DayOfWeek.cs
@@ -13,7 +13,6 @@
namespace System
{
- [Serializable]
public enum DayOfWeek
{
Sunday = 0,
diff --git a/src/mscorlib/shared/System/DefaultBinder.cs b/src/mscorlib/shared/System/DefaultBinder.cs
index 3b46d5f..9adf702 100644
--- a/src/mscorlib/shared/System/DefaultBinder.cs
+++ b/src/mscorlib/shared/System/DefaultBinder.cs
@@ -8,8 +8,6 @@ using CultureInfo = System.Globalization.CultureInfo;
namespace System
{
- //Marked serializable even though it has no state.
- [Serializable]
#if CORECLR
internal
#else
diff --git a/src/mscorlib/shared/System/Diagnostics/ConditionalAttribute.cs b/src/mscorlib/shared/System/Diagnostics/ConditionalAttribute.cs
index d5bca6e..416625b 100644
--- a/src/mscorlib/shared/System/Diagnostics/ConditionalAttribute.cs
+++ b/src/mscorlib/shared/System/Diagnostics/ConditionalAttribute.cs
@@ -4,7 +4,6 @@
namespace System.Diagnostics
{
- [Serializable]
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = true)]
public sealed class ConditionalAttribute : Attribute
{
diff --git a/src/mscorlib/src/System/Diagnostics/Debug.Unix.cs b/src/mscorlib/shared/System/Diagnostics/Debug.Unix.cs
index 495f2f7..495f2f7 100644
--- a/src/mscorlib/src/System/Diagnostics/Debug.Unix.cs
+++ b/src/mscorlib/shared/System/Diagnostics/Debug.Unix.cs
diff --git a/src/mscorlib/shared/System/Diagnostics/Tracing/EventProvider.cs b/src/mscorlib/shared/System/Diagnostics/Tracing/EventProvider.cs
index e18574c..5292551 100644
--- a/src/mscorlib/shared/System/Diagnostics/Tracing/EventProvider.cs
+++ b/src/mscorlib/shared/System/Diagnostics/Tracing/EventProvider.cs
@@ -54,6 +54,7 @@ namespace System.Diagnostics.Tracing
// subclasses of EventProvider use when creating efficient (but unsafe) version of
// EventWrite. We do make it a nested type because we really don't expect anyone to use
// it except subclasses (and then only rarely).
+ [StructLayout(LayoutKind.Sequential)]
public struct EventData
{
internal unsafe ulong Ptr;
@@ -78,6 +79,7 @@ namespace System.Diagnostics.Tracing
private static bool m_setInformationMissing;
+ internal IEventProvider m_eventProvider; // The interface that implements the specific logging mechanism functions.
UnsafeNativeMethods.ManifestEtw.EtwEnableCallback m_etwCallback; // Trace Callback function
private long m_regHandle; // Trace Registration Handle
private byte m_level; // Tracing Level
@@ -119,6 +121,13 @@ namespace System.Diagnostics.Tracing
// EventSource has special logic to do this, no one else should be calling EventProvider.
internal EventProvider()
{
+#if PLATFORM_WINDOWS
+ m_eventProvider = new EtwEventProvider();
+#elif FEATURE_PERFTRACING
+ m_eventProvider = new EventPipeEventProvider();
+#else
+ m_eventProvider = new NoOpEventProvider();
+#endif
}
/// <summary>
@@ -429,7 +438,7 @@ namespace System.Diagnostics.Tracing
// However the framework version of EventSource DOES have ES_SESSION_INFO defined and thus
// does not have this issue.
-#if ES_SESSION_INFO || !ES_BUILD_STANDALONE
+#if (PLATFORM_WINDOWS && (ES_SESSION_INFO || !ES_BUILD_STANDALONE))
int buffSize = 256; // An initial guess that probably works most of the time.
byte* buffer;
for (; ; )
@@ -469,7 +478,7 @@ namespace System.Diagnostics.Tracing
providerInstance = (UnsafeNativeMethods.ManifestEtw.TRACE_PROVIDER_INSTANCE_INFO*)&structBase[providerInstance->NextOffset];
}
#else
-#if !ES_BUILD_PCL && !FEATURE_PAL // TODO command arguments don't work on PCL builds...
+#if !ES_BUILD_PCL && PLATFORM_WINDOWS // TODO command arguments don't work on PCL builds...
// This code is only used in the Nuget Package Version of EventSource. because
// the code above is using APIs baned from UWP apps.
//
@@ -553,7 +562,7 @@ namespace System.Diagnostics.Tracing
dataStart = 0;
if (filterData == null)
{
-#if (!ES_BUILD_PCL && !ES_BUILD_PN && !FEATURE_PAL)
+#if (!ES_BUILD_PCL && !ES_BUILD_PN && PLATFORM_WINDOWS)
string regKey = @"\Microsoft\Windows\CurrentVersion\Winevt\Publishers\{" + m_providerId + "}";
if (System.Runtime.InteropServices.Marshal.SizeOf(typeof(IntPtr)) == 8)
regKey = @"HKEY_LOCAL_MACHINE\Software" + @"\Wow6432Node" + regKey;
@@ -928,7 +937,7 @@ namespace System.Diagnostics.Tracing
// </SecurityKernel>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity", Justification = "Performance-critical code")]
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1045:DoNotPassTypesByReference")]
- internal unsafe bool WriteEvent(ref EventDescriptor eventDescriptor, Guid* activityID, Guid* childActivityID, params object[] eventPayload)
+ internal unsafe bool WriteEvent(ref EventDescriptor eventDescriptor, IntPtr eventHandle, Guid* activityID, Guid* childActivityID, params object[] eventPayload)
{
int status = 0;
@@ -1056,7 +1065,7 @@ namespace System.Diagnostics.Tracing
userDataPtr[refObjPosition[7]].Ptr = (ulong)v7;
}
- status = UnsafeNativeMethods.ManifestEtw.EventWriteTransferWrapper(m_regHandle, ref eventDescriptor, activityID, childActivityID, argCount, userData);
+ status = m_eventProvider.EventWriteTransferWrapper(m_regHandle, ref eventDescriptor, eventHandle, activityID, childActivityID, argCount, userData);
}
}
else
@@ -1082,7 +1091,7 @@ namespace System.Diagnostics.Tracing
}
}
- status = UnsafeNativeMethods.ManifestEtw.EventWriteTransferWrapper(m_regHandle, ref eventDescriptor, activityID, childActivityID, argCount, userData);
+ status = m_eventProvider.EventWriteTransferWrapper(m_regHandle, ref eventDescriptor, eventHandle, activityID, childActivityID, argCount, userData);
for (int i = 0; i < refObjIndex; ++i)
{
@@ -1124,7 +1133,7 @@ namespace System.Diagnostics.Tracing
// <CallsSuppressUnmanagedCode Name="UnsafeNativeMethods.ManifestEtw.EventWrite(System.Int64,EventDescriptor&,System.UInt32,System.Void*):System.UInt32" />
// </SecurityKernel>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1045:DoNotPassTypesByReference")]
- internal unsafe protected bool WriteEvent(ref EventDescriptor eventDescriptor, Guid* activityID, Guid* childActivityID, int dataCount, IntPtr data)
+ internal unsafe protected bool WriteEvent(ref EventDescriptor eventDescriptor, IntPtr eventHandle, Guid* activityID, Guid* childActivityID, int dataCount, IntPtr data)
{
if (childActivityID != null)
{
@@ -1135,7 +1144,7 @@ namespace System.Diagnostics.Tracing
(EventOpcode)eventDescriptor.Opcode == EventOpcode.Stop);
}
- int status = UnsafeNativeMethods.ManifestEtw.EventWriteTransferWrapper(m_regHandle, ref eventDescriptor, activityID, childActivityID, dataCount, (EventData*)data);
+ int status = m_eventProvider.EventWriteTransferWrapper(m_regHandle, ref eventDescriptor, eventHandle, activityID, childActivityID, dataCount, (EventData*)data);
if (status != 0)
{
@@ -1155,9 +1164,10 @@ namespace System.Diagnostics.Tracing
{
int status;
- status = UnsafeNativeMethods.ManifestEtw.EventWriteTransferWrapper(
+ status = m_eventProvider.EventWriteTransferWrapper(
m_regHandle,
ref eventDescriptor,
+ IntPtr.Zero,
activityID,
relatedActivityID,
dataCount,
@@ -1178,12 +1188,12 @@ namespace System.Diagnostics.Tracing
{
m_providerId = providerId;
m_etwCallback = enableCallback;
- return UnsafeNativeMethods.ManifestEtw.EventRegister(ref providerId, enableCallback, null, ref m_regHandle);
+ return m_eventProvider.EventRegister(ref providerId, enableCallback, null, ref m_regHandle);
}
private uint EventUnregister(long registrationHandle)
{
- return UnsafeNativeMethods.ManifestEtw.EventUnregister(registrationHandle);
+ return m_eventProvider.EventUnregister(registrationHandle);
}
static int[] nibblebits = { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4 };
@@ -1203,5 +1213,108 @@ namespace System.Diagnostics.Tracing
return idx;
}
}
+
+#if PLATFORM_WINDOWS
+
+ // A wrapper around the ETW-specific API calls.
+ internal sealed class EtwEventProvider : IEventProvider
+ {
+ // Register an event provider.
+ unsafe uint IEventProvider.EventRegister(
+ ref Guid providerId,
+ UnsafeNativeMethods.ManifestEtw.EtwEnableCallback enableCallback,
+ void* callbackContext,
+ ref long registrationHandle)
+ {
+ return UnsafeNativeMethods.ManifestEtw.EventRegister(
+ ref providerId,
+ enableCallback,
+ callbackContext,
+ ref registrationHandle);
+ }
+
+ // Unregister an event provider.
+ uint IEventProvider.EventUnregister(long registrationHandle)
+ {
+ return UnsafeNativeMethods.ManifestEtw.EventUnregister(registrationHandle);
+ }
+
+ // Write an event.
+ unsafe int IEventProvider.EventWriteTransferWrapper(
+ long registrationHandle,
+ ref EventDescriptor eventDescriptor,
+ IntPtr eventHandle,
+ Guid* activityId,
+ Guid* relatedActivityId,
+ int userDataCount,
+ EventProvider.EventData* userData)
+ {
+ return UnsafeNativeMethods.ManifestEtw.EventWriteTransferWrapper(
+ registrationHandle,
+ ref eventDescriptor,
+ activityId,
+ relatedActivityId,
+ userDataCount,
+ userData);
+ }
+
+ // Get or set the per-thread activity ID.
+ int IEventProvider.EventActivityIdControl(UnsafeNativeMethods.ManifestEtw.ActivityControl ControlCode, ref Guid ActivityId)
+ {
+ return UnsafeNativeMethods.ManifestEtw.EventActivityIdControl(
+ ControlCode,
+ ref ActivityId);
+ }
+
+ // Define an EventPipeEvent handle.
+ unsafe IntPtr IEventProvider.DefineEventHandle(uint eventID, string eventName, Int64 keywords, uint eventVersion, uint level, byte *pMetadata, uint metadataLength)
+ {
+ throw new System.NotSupportedException();
+ }
+ }
+
+#elif !FEATURE_PERFTRACING
+
+ internal sealed class NoOpEventProvider : IEventProvider
+ {
+ unsafe uint IEventProvider.EventRegister(
+ ref Guid providerId,
+ UnsafeNativeMethods.ManifestEtw.EtwEnableCallback enableCallback,
+ void* callbackContext,
+ ref long registrationHandle)
+ {
+ return 0;
+ }
+
+ uint IEventProvider.EventUnregister(long registrationHandle)
+ {
+ return 0;
+ }
+
+ unsafe int IEventProvider.EventWriteTransferWrapper(
+ long registrationHandle,
+ ref EventDescriptor eventDescriptor,
+ IntPtr eventHandle,
+ Guid* activityId,
+ Guid* relatedActivityId,
+ int userDataCount,
+ EventProvider.EventData* userData)
+ {
+ return 0;
+ }
+
+ int IEventProvider.EventActivityIdControl(UnsafeNativeMethods.ManifestEtw.ActivityControl ControlCode, ref Guid ActivityId)
+ {
+ return 0;
+ }
+
+ // Define an EventPipeEvent handle.
+ unsafe IntPtr IEventProvider.DefineEventHandle(uint eventID, string eventName, Int64 keywords, uint eventVersion, uint level, byte *pMetadata, uint metadataLength)
+ {
+ throw new System.NotSupportedException();
+ }
+ }
+
+#endif
}
diff --git a/src/mscorlib/shared/System/Diagnostics/Tracing/EventSource.cs b/src/mscorlib/shared/System/Diagnostics/Tracing/EventSource.cs
index cf4901d..3349c06 100644..100755
--- a/src/mscorlib/shared/System/Diagnostics/Tracing/EventSource.cs
+++ b/src/mscorlib/shared/System/Diagnostics/Tracing/EventSource.cs
@@ -4,16 +4,10 @@
// This program uses code hyperlinks available as part of the HyperAddin Visual Studio plug-in.
// It is available from http://www.codeplex.com/hyperAddin
-#if PLATFORM_WINDOWS
-
-#define FEATURE_MANAGED_ETW
-
-#if !ES_BUILD_STANDALONE && !CORECLR && !ES_BUILD_PN
+#if PLATFORM_WINDOWS && !ES_BUILD_STANDALONE && !CORECLR && !ES_BUILD_PN
#define FEATURE_ACTIVITYSAMPLING
#endif // !ES_BUILD_STANDALONE
-#endif // PLATFORM_WINDOWS
-
#if ES_BUILD_STANDALONE
#define FEATURE_MANAGED_ETW_CHANNELS
// #define FEATURE_ADVANCED_MANAGED_ETW_CHANNELS
@@ -692,6 +686,106 @@ namespace System.Diagnostics.Tracing
Initialize(eventSourceGuid, eventSourceName, traits);
}
+#if FEATURE_PERFTRACING
+ // Generate the serialized blobs that describe events for all strongly typed events (that is events that define strongly
+ // typed event methods. Dynamically defined events (that use Write) hare defined on the fly and are handled elsewhere.
+ private unsafe void DefineEventPipeEvents()
+ {
+ Debug.Assert(m_eventData != null);
+ Debug.Assert(m_provider != null);
+ int cnt = m_eventData.Length;
+ for (int i = 0; i < cnt; i++)
+ {
+ uint eventID = (uint)m_eventData[i].Descriptor.EventId;
+ if (eventID == 0)
+ continue;
+
+ string eventName = m_eventData[i].Name;
+ Int64 keywords = m_eventData[i].Descriptor.Keywords;
+ uint eventVersion = m_eventData[i].Descriptor.Version;
+ uint level = m_eventData[i].Descriptor.Level;
+
+ // evnetID : 4 bytes
+ // eventName : (eventName.Length + 1) * 2 bytes
+ // keywords : 8 bytes
+ // eventVersion : 4 bytes
+ // level : 4 bytes
+ // parameterCount : 4 bytes
+ uint metadataLength = 24 + ((uint)eventName.Length + 1) * 2;
+
+ // Increase the metadataLength for the types of all parameters.
+ metadataLength += (uint)m_eventData[i].Parameters.Length * 4;
+
+ // Increase the metadataLength for the names of all parameters.
+ foreach (var parameter in m_eventData[i].Parameters)
+ {
+ string parameterName = parameter.Name;
+ metadataLength = metadataLength + ((uint)parameterName.Length + 1) * 2;
+ }
+
+ byte[] metadata = new byte[metadataLength];
+
+ // Write metadata: evnetID, eventName, keywords, eventVersion, level, parameterCount, param1 type, param1 name...
+ fixed (byte *pMetadata = metadata)
+ {
+ uint offset = 0;
+ WriteToBuffer(pMetadata, metadataLength, ref offset, eventID);
+ fixed(char *pEventName = eventName)
+ {
+ WriteToBuffer(pMetadata, metadataLength, ref offset, (byte *)pEventName, ((uint)eventName.Length + 1) * 2);
+ }
+ WriteToBuffer(pMetadata, metadataLength, ref offset, keywords);
+ WriteToBuffer(pMetadata, metadataLength, ref offset, eventVersion);
+ WriteToBuffer(pMetadata, metadataLength, ref offset, level);
+ WriteToBuffer(pMetadata, metadataLength, ref offset, (uint)m_eventData[i].Parameters.Length);
+ foreach (var parameter in m_eventData[i].Parameters)
+ {
+ // Write parameter type.
+ WriteToBuffer(pMetadata, metadataLength, ref offset, (uint)Type.GetTypeCode(parameter.ParameterType));
+
+ // Write parameter name.
+ string parameterName = parameter.Name;
+ fixed (char *pParameterName = parameterName)
+ {
+ WriteToBuffer(pMetadata, metadataLength, ref offset, (byte *)pParameterName, ((uint)parameterName.Length + 1) * 2);
+ }
+ }
+ Debug.Assert(metadataLength == offset);
+ IntPtr eventHandle = m_provider.m_eventProvider.DefineEventHandle(eventID, eventName, keywords, eventVersion, level, pMetadata, metadataLength);
+ m_eventData[i].EventHandle = eventHandle;
+ }
+ }
+ }
+
+ // Copy src to buffer and modify the offset.
+ // Note: We know the buffer size ahead of time to make sure no buffer overflow.
+ private static unsafe void WriteToBuffer(byte *buffer, uint bufferLength, ref uint offset, byte *src, uint srcLength)
+ {
+ Debug.Assert(bufferLength >= (offset + srcLength));
+ for (int i = 0; i < srcLength; i++)
+ {
+ *(byte *)(buffer + offset + i) = *(byte *)(src + i);
+ }
+ offset += srcLength;
+ }
+
+ // Copy uint value to buffer.
+ private static unsafe void WriteToBuffer(byte *buffer, uint bufferLength, ref uint offset, uint value)
+ {
+ Debug.Assert(bufferLength >= (offset + 4));
+ *(uint *)(buffer + offset) = value;
+ offset += 4;
+ }
+
+ // Copy long value to buffer.
+ private static unsafe void WriteToBuffer(byte *buffer, uint bufferLength, ref uint offset, long value)
+ {
+ Debug.Assert(bufferLength >= (offset + 8));
+ *(long *)(buffer + offset) = value;
+ offset += 8;
+ }
+#endif
+
internal virtual void GetMetadata(out Guid eventSourceGuid, out string eventSourceName, out EventMetadata[] eventData, out byte[] manifestBytes)
{
//
@@ -1185,7 +1279,7 @@ namespace System.Diagnostics.Tracing
// by default the Descriptor.Keyword will have the perEventSourceSessionId bit
// mask set to 0x0f so, when all ETW sessions want the event we don't need to
// synthesize a new one
- if (!m_provider.WriteEvent(ref m_eventData[eventId].Descriptor, pActivityId, relatedActivityId, eventDataCount, (IntPtr)data))
+ if (!m_provider.WriteEvent(ref m_eventData[eventId].Descriptor, m_eventData[eventId].EventHandle, pActivityId, relatedActivityId, eventDataCount, (IntPtr)data))
ThrowEventSourceException(m_eventData[eventId].Name);
}
else
@@ -1205,7 +1299,7 @@ namespace System.Diagnostics.Tracing
m_eventData[eventId].Descriptor.Task,
unchecked((long)etwSessions.ToEventKeywords() | origKwd));
- if (!m_provider.WriteEvent(ref desc, pActivityId, relatedActivityId, eventDataCount, (IntPtr)data))
+ if (!m_provider.WriteEvent(ref desc, m_eventData[eventId].EventHandle, pActivityId, relatedActivityId, eventDataCount, (IntPtr)data))
ThrowEventSourceException(m_eventData[eventId].Name);
}
}
@@ -1235,7 +1329,7 @@ namespace System.Diagnostics.Tracing
#else
if (!SelfDescribingEvents)
{
- if (!m_provider.WriteEvent(ref m_eventData[eventId].Descriptor, pActivityId, relatedActivityId, eventDataCount, (IntPtr)data))
+ if (!m_provider.WriteEvent(ref m_eventData[eventId].Descriptor, m_eventData[eventId].EventHandle, pActivityId, relatedActivityId, eventDataCount, (IntPtr)data))
ThrowEventSourceException(m_eventData[eventId].Name);
}
else
@@ -1328,6 +1422,7 @@ namespace System.Diagnostics.Tracing
if (disposing)
{
#if FEATURE_MANAGED_ETW
+#if !FEATURE_PERFTRACING
// Send the manifest one more time to ensure circular buffers have a chance to get to this information
// even in scenarios with a high volume of ETW events.
if (m_eventSourceEnabled)
@@ -1340,6 +1435,7 @@ namespace System.Diagnostics.Tracing
{ } // If it fails, simply give up.
m_eventSourceEnabled = false;
}
+#endif
if (m_provider != null)
{
m_provider.Dispose();
@@ -1474,6 +1570,7 @@ namespace System.Diagnostics.Tracing
// Set m_provider, which allows this.
m_provider = provider;
+#if PLATFORM_WINDOWS
#if (!ES_BUILD_STANDALONE && !ES_BUILD_PN)
// API available on OS >= Win 8 and patched Win 7.
// Disable only for FrameworkEventSource to avoid recursion inside exception handling.
@@ -1492,8 +1589,8 @@ namespace System.Diagnostics.Tracing
metadataHandle.Free();
}
+#endif // PLATFORM_WINDOWS
#endif // FEATURE_MANAGED_ETW
-
Debug.Assert(!m_eventSourceEnabled); // We can't be enabled until we are completely initted.
// We are logically completely initialized at this point.
m_completelyInited = true;
@@ -1945,7 +2042,7 @@ namespace System.Diagnostics.Tracing
// by default the Descriptor.Keyword will have the perEventSourceSessionId bit
// mask set to 0x0f so, when all ETW sessions want the event we don't need to
// synthesize a new one
- if (!m_provider.WriteEvent(ref m_eventData[eventId].Descriptor, pActivityId, childActivityID, args))
+ if (!m_provider.WriteEvent(ref m_eventData[eventId].Descriptor, m_eventData[eventId].EventHandle, pActivityId, childActivityID, args))
ThrowEventSourceException(m_eventData[eventId].Name);
}
else
@@ -1962,7 +2059,7 @@ namespace System.Diagnostics.Tracing
m_eventData[eventId].Descriptor.Task,
unchecked((long)etwSessions.ToEventKeywords() | origKwd));
- if (!m_provider.WriteEvent(ref desc, pActivityId, childActivityID, args))
+ if (!m_provider.WriteEvent(ref desc, m_eventData[eventId].EventHandle, pActivityId, childActivityID, args))
ThrowEventSourceException(m_eventData[eventId].Name);
}
}
@@ -1992,7 +2089,7 @@ namespace System.Diagnostics.Tracing
#else
if (!SelfDescribingEvents)
{
- if (!m_provider.WriteEvent(ref m_eventData[eventId].Descriptor, pActivityId, childActivityID, args))
+ if (!m_provider.WriteEvent(ref m_eventData[eventId].Descriptor, m_eventData[eventId].EventHandle, pActivityId, childActivityID, args))
ThrowEventSourceException(m_eventData[eventId].Name);
}
else
@@ -2102,32 +2199,26 @@ namespace System.Diagnostics.Tracing
#endif //!ES_BUILD_PCL
}
- private int GetParamLenghtIncludingByteArray(ParameterInfo[] parameters)
+ unsafe private void WriteToAllListeners(int eventId, Guid* childActivityID, int eventDataCount, EventSource.EventData* data)
{
- int sum = 0;
- foreach (ParameterInfo info in parameters)
+ // We represent a byte[] as a integer denoting the length and then a blob of bytes in the data pointer. This causes a spurious
+ // warning because eventDataCount is off by one for the byte[] case since a byte[] has 2 items associated it. So we want to check
+ // that the number of parameters is correct against the byte[] case, but also we the args array would be one too long if
+ // we just used the modifiedParamCount here -- so we need both.
+ int paramCount = GetParameterCount(m_eventData[eventId]);
+ int modifiedParamCount = 0;
+ for (int i = 0; i < paramCount; i++)
{
- if (info.ParameterType == typeof(byte[]))
+ Type parameterType = GetDataType(m_eventData[eventId], i);
+ if (parameterType == typeof(byte[]))
{
- sum += 2;
+ modifiedParamCount += 2;
}
else
{
- sum++;
+ modifiedParamCount++;
}
}
-
- return sum;
- }
-
- unsafe private void WriteToAllListeners(int eventId, Guid* chil