summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rw-r--r--BuildToolsVersion.txt2
-rw-r--r--CONTRIBUTING.md7
-rw-r--r--Documentation/building/cross-building.md39
-rw-r--r--Documentation/building/freebsd-instructions.md8
-rw-r--r--Documentation/building/linux-instructions.md4
-rw-r--r--Documentation/project-docs/contributing-workflow.md2
-rw-r--r--Documentation/project-docs/contributing.md57
-rw-r--r--Documentation/project-docs/glossary.md7
-rw-r--r--THIRD-PARTY-NOTICES62
-rw-r--r--UpdateDependencies.ps156
-rw-r--r--build-packages.cmd9
-rwxr-xr-xbuild-packages.sh8
-rw-r--r--build.cmd16
-rwxr-xr-xbuild.sh33
-rwxr-xr-xclean.sh2
-rw-r--r--clrdefinitions.cmake7
-rw-r--r--cross/arm-softfp/tryrun.cmake4
-rw-r--r--cross/arm/tryrun.cmake4
-rw-r--r--cross/arm64/tryrun.cmake4
-rwxr-xr-xcross/build-rootfs.sh4
-rw-r--r--crosscomponents.cmake1
-rw-r--r--dir.props3
-rw-r--r--init-tools.cmd2
-rwxr-xr-xinit-tools.sh1
-rwxr-xr-xnetci.groovy92
-rwxr-xr-xpublish-packages.sh4
-rw-r--r--src/.nuget/Microsoft.NETCore.Jit/win/Microsoft.NETCore.Jit.pkgproj9
-rw-r--r--src/ToolBox/SOS/Strike/disasm.cpp12
-rw-r--r--src/ToolBox/SOS/Strike/disasm.h8
-rw-r--r--src/ToolBox/SOS/Strike/disasmARM.cpp6
-rw-r--r--src/ToolBox/SOS/Strike/disasmARM64.cpp6
-rw-r--r--src/ToolBox/SOS/Strike/exts.h5
-rw-r--r--src/ToolBox/SOS/Strike/strike.cpp39
-rw-r--r--src/ToolBox/SOS/Strike/util.cpp16
-rw-r--r--src/coreclr/hosts/unixcoreruncommon/coreruncommon.cpp24
-rw-r--r--src/debug/daccess/daccess.cpp6
-rw-r--r--src/debug/daccess/enummem.cpp5
-rw-r--r--src/debug/daccess/nidump.cpp13
-rw-r--r--src/debug/daccess/request.cpp2
-rw-r--r--src/gc/env/gcenv.base.h30
-rw-r--r--src/gc/env/gcenv.ee.h3
-rw-r--r--src/gc/env/gcenv.sync.h9
-rw-r--r--src/gc/gc.cpp1242
-rw-r--r--src/gc/gcpriv.h7
-rw-r--r--src/gc/gcscan.cpp65
-rw-r--r--src/gc/sample/gcenv.ee.cpp25
-rw-r--r--src/gc/sample/gcenv.unix.cpp450
-rw-r--r--src/gc/sample/gcenv.windows.cpp5
-rw-r--r--src/gcdump/gcdump.cpp11
-rw-r--r--src/gcdump/gcdumpnonx86.cpp15
-rw-r--r--src/gcinfo/CMakeLists.txt1
-rw-r--r--src/gcinfo/dbggcinfoencoder.cpp981
-rw-r--r--src/gcinfo/gcinfo.settings.targets1
-rw-r--r--src/gcinfo/gcinfodumper.cpp14
-rw-r--r--src/gcinfo/gcinfoencoder.cpp84
-rw-r--r--src/inc/dbggcinfodecoder.h343
-rw-r--r--src/inc/dbggcinfoencoder.h469
-rw-r--r--src/inc/eetwain.h10
-rw-r--r--src/inc/gcdecoder.cpp2
-rw-r--r--src/inc/gcdump.h15
-rw-r--r--src/inc/gcinfo.h249
-rw-r--r--src/inc/gcinfodecoder.h29
-rw-r--r--src/inc/gcinfodumper.h4
-rw-r--r--src/inc/gcinfoencoder.h8
-rw-r--r--src/inc/gcinfotypes.h270
-rw-r--r--src/inc/llvm/Dwarf.def393
-rw-r--r--src/inc/llvm/Dwarf.h711
-rw-r--r--src/inc/llvm/ELF.h1273
-rw-r--r--src/inc/volatile.h8
-rw-r--r--src/jit/CMakeLists.txt2
-rw-r--r--src/jit/assertionprop.cpp4
-rw-r--r--src/jit/block.cpp2
-rw-r--r--src/jit/block.h6
-rwxr-xr-xsrc/jit/codegen.h3
-rw-r--r--src/jit/codegenarm.cpp2
-rwxr-xr-xsrc/jit/codegencommon.cpp39
-rw-r--r--src/jit/codegeninterface.h3
-rw-r--r--src/jit/codegenlegacy.cpp9
-rw-r--r--src/jit/codegenlinear.h1
-rwxr-xr-xsrc/jit/codegenxarch.cpp651
-rw-r--r--src/jit/compiler.cpp616
-rw-r--r--src/jit/compiler.h67
-rw-r--r--src/jit/compiler.hpp12
-rw-r--r--src/jit/decomposelongs.cpp1289
-rw-r--r--src/jit/decomposelongs.h63
-rw-r--r--src/jit/emitxarch.cpp43
-rw-r--r--src/jit/flowgraph.cpp81
-rw-r--r--src/jit/gcencode.cpp8
-rw-r--r--src/jit/gentree.cpp259
-rw-r--r--src/jit/gentree.h69
-rw-r--r--src/jit/gtlist.h2
-rw-r--r--src/jit/gtstructs.h2
-rw-r--r--src/jit/importer.cpp31
-rw-r--r--src/jit/inline.cpp19
-rw-r--r--src/jit/inline.h20
-rw-r--r--src/jit/inlinepolicy.cpp147
-rw-r--r--src/jit/inlinepolicy.h26
-rw-r--r--src/jit/jit.settings.targets2
-rw-r--r--src/jit/jitgcinfo.h4
-rw-r--r--src/jit/lclvars.cpp30
-rw-r--r--[-rwxr-xr-x]src/jit/lower.cpp1049
-rw-r--r--src/jit/lower.h68
-rw-r--r--src/jit/lowerxarch.cpp301
-rw-r--r--src/jit/lsra.cpp165
-rw-r--r--src/jit/lsra.h59
-rwxr-xr-x[-rw-r--r--]src/jit/morph.cpp538
-rw-r--r--src/jit/optcse.cpp47
-rw-r--r--src/jit/rationalize.cpp621
-rw-r--r--src/jit/rationalize.h35
-rw-r--r--src/jit/simdcodegenxarch.cpp4
-rw-r--r--src/jit/target.h13
-rw-r--r--src/jit/unwind.h1
-rw-r--r--src/jit/unwindarm.cpp4
-rw-r--r--src/md/compiler/disp.cpp2
-rw-r--r--src/mscorlib/Tools/BclRewriter/BclRewriter.targets15
-rw-r--r--src/mscorlib/corefx/System/Globalization/Calendar.cs6
-rw-r--r--src/mscorlib/corefx/System/Globalization/CultureInfo.cs2
-rw-r--r--src/mscorlib/corefx/System/Globalization/DateTimeFormatInfo.cs2
-rw-r--r--src/mscorlib/corefx/System/Globalization/NumberFormatInfo.cs2
-rw-r--r--src/mscorlib/corefx/System/Globalization/TextInfo.cs4
-rw-r--r--src/mscorlib/model.xml767
-rw-r--r--src/mscorlib/mscorlib.shared.sources.props4
-rw-r--r--src/mscorlib/ref/mscorlib.cs3
-rw-r--r--src/mscorlib/src/Internal/Runtime/Augments/EnvironmentAugments.cs21
-rw-r--r--src/mscorlib/src/System/AccessViolationException.cs2
-rw-r--r--src/mscorlib/src/System/AggregateException.cs2
-rw-r--r--src/mscorlib/src/System/AppDomain.cs6
-rw-r--r--src/mscorlib/src/System/AppDomainUnloadedException.cs4
-rw-r--r--src/mscorlib/src/System/ApplicationException.cs4
-rw-r--r--src/mscorlib/src/System/ArgumentException.cs4
-rw-r--r--src/mscorlib/src/System/ArgumentNullException.cs7
-rw-r--r--src/mscorlib/src/System/ArgumentOutOfRangeException.cs4
-rw-r--r--src/mscorlib/src/System/ArithmeticException.cs7
-rw-r--r--src/mscorlib/src/System/ArrayTypeMismatchException.cs4
-rw-r--r--src/mscorlib/src/System/AsyncCallback.cs2
-rw-r--r--src/mscorlib/src/System/BadImageFormatException.cs2
-rw-r--r--src/mscorlib/src/System/CannotUnloadAppDomainException.cs2
-rw-r--r--src/mscorlib/src/System/Char.cs18
-rw-r--r--src/mscorlib/src/System/Collections/Comparer.cs6
-rw-r--r--src/mscorlib/src/System/Collections/Concurrent/ConcurrentDictionary.cs2
-rw-r--r--src/mscorlib/src/System/Collections/Concurrent/ConcurrentQueue.cs2
-rw-r--r--src/mscorlib/src/System/Collections/Concurrent/ConcurrentStack.cs2
-rw-r--r--src/mscorlib/src/System/Collections/Generic/Comparer.cs18
-rw-r--r--src/mscorlib/src/System/Collections/Generic/Dictionary.cs2
-rw-r--r--src/mscorlib/src/System/Collections/Generic/EqualityComparer.cs8
-rw-r--r--src/mscorlib/src/System/Collections/Generic/KeyNotFoundException.cs4
-rw-r--r--src/mscorlib/src/System/Collections/Generic/List.cs29
-rw-r--r--src/mscorlib/src/System/Collections/Hashtable.cs34
-rw-r--r--src/mscorlib/src/System/ContextMarshalException.cs2
-rw-r--r--src/mscorlib/src/System/DBNull.cs4
-rw-r--r--src/mscorlib/src/System/DataMisalignedException.cs4
-rw-r--r--src/mscorlib/src/System/DateTime.cs9
-rw-r--r--src/mscorlib/src/System/DateTimeOffset.cs11
-rw-r--r--src/mscorlib/src/System/Decimal.cs9
-rw-r--r--src/mscorlib/src/System/Delegate.cs2
-rw-r--r--src/mscorlib/src/System/DelegateSerializationHolder.cs2
-rw-r--r--src/mscorlib/src/System/Diagnostics/Eventing/ActivityTracker.cs2
-rw-r--r--src/mscorlib/src/System/Diagnostics/Eventing/EventSourceException.cs2
-rw-r--r--src/mscorlib/src/System/Diagnostics/Stacktrace.cs42
-rw-r--r--src/mscorlib/src/System/Diagnostics/log.cs4
-rw-r--r--src/mscorlib/src/System/DivideByZeroException.cs2
-rw-r--r--src/mscorlib/src/System/DllNotFoundException.cs7
-rw-r--r--src/mscorlib/src/System/DuplicateWaitObjectException.cs4
-rw-r--r--src/mscorlib/src/System/Empty.cs2
-rw-r--r--src/mscorlib/src/System/EntryPointNotFoundException.cs7
-rw-r--r--src/mscorlib/src/System/EventHandler.cs4
-rw-r--r--src/mscorlib/src/System/Exception.cs24
-rw-r--r--src/mscorlib/src/System/ExecutionEngineException.cs2
-rw-r--r--src/mscorlib/src/System/FieldAccessException.cs7
-rw-r--r--src/mscorlib/src/System/FormatException.cs2
-rw-r--r--src/mscorlib/src/System/Globalization/Calendar.cs2
-rw-r--r--src/mscorlib/src/System/Globalization/CompareInfo.cs5
-rw-r--r--src/mscorlib/src/System/Globalization/CultureInfo.cs12
-rw-r--r--src/mscorlib/src/System/Globalization/CultureNotFoundException.cs2
-rw-r--r--src/mscorlib/src/System/Globalization/DateTimeFormat.cs2
-rw-r--r--src/mscorlib/src/System/Globalization/DateTimeFormatInfo.cs6
-rw-r--r--src/mscorlib/src/System/Globalization/GregorianCalendar.cs4
-rw-r--r--src/mscorlib/src/System/Globalization/RegionInfo.cs10
-rw-r--r--src/mscorlib/src/System/Globalization/SortKey.cs7
-rw-r--r--src/mscorlib/src/System/Globalization/StringInfo.cs5
-rw-r--r--src/mscorlib/src/System/Globalization/TextElementEnumerator.cs4
-rw-r--r--src/mscorlib/src/System/Globalization/TextInfo.cs15
-rw-r--r--src/mscorlib/src/System/IO/DirectoryNotFoundException.cs2
-rw-r--r--src/mscorlib/src/System/IO/DriveInfo.cs7
-rw-r--r--src/mscorlib/src/System/IO/DriveNotFoundException.cs4
-rw-r--r--src/mscorlib/src/System/IO/EndOfStreamException.cs4
-rw-r--r--src/mscorlib/src/System/IO/FileLoadException.cs4
-rw-r--r--src/mscorlib/src/System/IO/FileNotFoundException.cs4
-rw-r--r--src/mscorlib/src/System/IO/FileSystemInfo.cs12
-rw-r--r--src/mscorlib/src/System/IO/IOException.cs4
-rw-r--r--src/mscorlib/src/System/IO/PathTooLongException.cs4
-rw-r--r--src/mscorlib/src/System/IO/Stream.cs60
-rw-r--r--src/mscorlib/src/System/IndexOutOfRangeException.cs2
-rw-r--r--src/mscorlib/src/System/InsufficientExecutionStackException.cs2
-rw-r--r--src/mscorlib/src/System/InsufficientMemoryException.cs2
-rw-r--r--src/mscorlib/src/System/IntPtr.cs89
-rw-r--r--src/mscorlib/src/System/InvalidCastException.cs4
-rw-r--r--src/mscorlib/src/System/InvalidOperationException.cs4
-rw-r--r--src/mscorlib/src/System/InvalidProgramException.cs4
-rw-r--r--src/mscorlib/src/System/InvalidTimeZoneException.cs4
-rw-r--r--src/mscorlib/src/System/Lazy.cs19
-rw-r--r--src/mscorlib/src/System/MemberAccessException.cs4
-rw-r--r--src/mscorlib/src/System/MethodAccessException.cs7
-rw-r--r--src/mscorlib/src/System/MissingFieldException.cs4
-rw-r--r--src/mscorlib/src/System/MissingMemberException.cs5
-rw-r--r--src/mscorlib/src/System/MissingMethodException.cs4
-rw-r--r--src/mscorlib/src/System/MulticastDelegate.cs4
-rw-r--r--src/mscorlib/src/System/MulticastNotSupportedException.cs4
-rw-r--r--src/mscorlib/src/System/NotFiniteNumberException.cs4
-rw-r--r--src/mscorlib/src/System/NotImplementedException.cs4
-rw-r--r--src/mscorlib/src/System/NotSupportedException.cs4
-rw-r--r--src/mscorlib/src/System/NullReferenceException.cs4
-rw-r--r--src/mscorlib/src/System/ObjectDisposedException.cs4
-rw-r--r--src/mscorlib/src/System/OperatingSystem.cs2
-rw-r--r--src/mscorlib/src/System/OperationCanceledException.cs2
-rw-r--r--src/mscorlib/src/System/OutOfMemoryException.cs2
-rw-r--r--src/mscorlib/src/System/OverflowException.cs4
-rw-r--r--src/mscorlib/src/System/PlatformNotSupportedException.cs4
-rw-r--r--src/mscorlib/src/System/RankException.cs4
-rw-r--r--src/mscorlib/src/System/Reflection/AmbiguousMatchException.cs4
-rw-r--r--src/mscorlib/src/System/Reflection/Assembly.cs24
-rw-r--r--src/mscorlib/src/System/Reflection/AssemblyName.cs21
-rw-r--r--src/mscorlib/src/System/Reflection/ConstructorInfo.cs4
-rw-r--r--src/mscorlib/src/System/Reflection/CustomAttributeFormatException.cs4
-rw-r--r--src/mscorlib/src/System/Reflection/Emit/EnumBuilder.cs8
-rw-r--r--src/mscorlib/src/System/Reflection/Emit/GenericTypeParameterBuilder.cs8
-rw-r--r--src/mscorlib/src/System/Reflection/Emit/ModuleBuilder.cs3
-rw-r--r--src/mscorlib/src/System/Reflection/Emit/SymbolType.cs70
-rw-r--r--src/mscorlib/src/System/Reflection/Emit/TypeBuilder.cs10
-rw-r--r--src/mscorlib/src/System/Reflection/Emit/TypeBuilderInstantiation.cs8
-rw-r--r--src/mscorlib/src/System/Reflection/EventInfo.cs4
-rw-r--r--src/mscorlib/src/System/Reflection/FieldInfo.cs6
-rw-r--r--src/mscorlib/src/System/Reflection/InvalidFilterCriteriaException.cs4
-rw-r--r--src/mscorlib/src/System/Reflection/MemberFilter.cs6
-rw-r--r--src/mscorlib/src/System/Reflection/MemberInfoSerializationHolder.cs4
-rw-r--r--src/mscorlib/src/System/Reflection/MethodInfo.cs2
-rw-r--r--src/mscorlib/src/System/Reflection/Missing.cs9
-rw-r--r--src/mscorlib/src/System/Reflection/Module.cs2
-rw-r--r--src/mscorlib/src/System/Reflection/ParameterInfo.cs2
-rw-r--r--src/mscorlib/src/System/Reflection/Pointer.cs10
-rw-r--r--src/mscorlib/src/System/Reflection/PropertyInfo.cs2
-rw-r--r--src/mscorlib/src/System/Reflection/ReflectionTypeLoadException.cs4
-rw-r--r--src/mscorlib/src/System/Reflection/StrongNameKeyPair.cs4
-rw-r--r--src/mscorlib/src/System/Reflection/TargetException.cs4
-rw-r--r--src/mscorlib/src/System/Reflection/TargetInvocationException.cs4
-rw-r--r--src/mscorlib/src/System/Reflection/TargetParameterCountException.cs4
-rw-r--r--src/mscorlib/src/System/Reflection/TypeFilter.cs6
-rw-r--r--src/mscorlib/src/System/Resources/MissingManifestResourceException.cs4
-rw-r--r--src/mscorlib/src/System/Resources/MissingSatelliteAssemblyException.cs4
-rw-r--r--src/mscorlib/src/System/Resources/ResourceManager.cs2
-rw-r--r--src/mscorlib/src/System/RtType.cs4
-rw-r--r--src/mscorlib/src/System/Runtime/InteropServices/COMException.cs2
-rw-r--r--src/mscorlib/src/System/Runtime/InteropServices/ExternalException.cs4
-rw-r--r--src/mscorlib/src/System/Runtime/InteropServices/InvalidComObjectException.cs4
-rw-r--r--src/mscorlib/src/System/Runtime/InteropServices/InvalidOleVariantTypeException.cs7
-rw-r--r--src/mscorlib/src/System/Runtime/InteropServices/MarshalDirectiveException.cs4
-rw-r--r--src/mscorlib/src/System/Runtime/InteropServices/SEHException.cs4
-rw-r--r--src/mscorlib/src/System/Runtime/InteropServices/SafeArrayRankMismatchException.cs7
-rw-r--r--src/mscorlib/src/System/Runtime/InteropServices/SafeArrayTypeMismatchException.cs7
-rw-r--r--src/mscorlib/src/System/Runtime/Serialization/IDeserializationCallback.cs3
-rw-r--r--src/mscorlib/src/System/Runtime/Serialization/ISerializable.cs2
-rw-r--r--src/mscorlib/src/System/Runtime/Serialization/SerializationException.cs7
-rw-r--r--src/mscorlib/src/System/Runtime/Serialization/SerializationInfo.cs2
-rw-r--r--src/mscorlib/src/System/RuntimeHandles.cs64
-rw-r--r--src/mscorlib/src/System/Security/HostProtectionException.cs5
-rw-r--r--src/mscorlib/src/System/Security/PermissionSet.cs15
-rw-r--r--src/mscorlib/src/System/Security/Permissions/SiteIdentityPermission.cs4
-rw-r--r--src/mscorlib/src/System/Security/Permissions/URLIdentityPermission.cs7
-rw-r--r--src/mscorlib/src/System/Security/Permissions/ZoneIdentityPermission.cs4
-rw-r--r--src/mscorlib/src/System/Security/Policy/Evidence.cs2
-rw-r--r--src/mscorlib/src/System/Security/SecurityException.cs5
-rw-r--r--src/mscorlib/src/System/Security/Util/TokenBasedSet.cs2
-rw-r--r--src/mscorlib/src/System/Security/Util/URLString.cs4
-rw-r--r--src/mscorlib/src/System/Security/VerificationException.cs5
-rw-r--r--src/mscorlib/src/System/StackOverflowException.cs4
-rw-r--r--src/mscorlib/src/System/String.cs316
-rw-r--r--src/mscorlib/src/System/SystemException.cs4
-rw-r--r--src/mscorlib/src/System/Text/ASCIIEncoding.cs328
-rw-r--r--src/mscorlib/src/System/Text/BaseCodePageEncoding.cs2
-rw-r--r--src/mscorlib/src/System/Text/CodePageEncoding.cs14
-rw-r--r--src/mscorlib/src/System/Text/DBCSCodePageEncoding.cs2
-rw-r--r--src/mscorlib/src/System/Text/DecoderExceptionFallback.cs2
-rw-r--r--src/mscorlib/src/System/Text/DecoderNLS.cs7
-rw-r--r--src/mscorlib/src/System/Text/EncoderExceptionFallback.cs2
-rw-r--r--src/mscorlib/src/System/Text/EncoderNLS.cs7
-rw-r--r--src/mscorlib/src/System/Text/Encoding.cs20
-rw-r--r--src/mscorlib/src/System/Text/EncodingForwarder.cs339
-rw-r--r--src/mscorlib/src/System/Text/EncodingNLS.cs320
-rw-r--r--src/mscorlib/src/System/Text/GB18030Encoding.cs4
-rw-r--r--src/mscorlib/src/System/Text/ISCIIEncoding.cs7
-rw-r--r--src/mscorlib/src/System/Text/Latin1Encoding.cs9
-rw-r--r--src/mscorlib/src/System/Text/MLangCodePageEncoding.cs23
-rw-r--r--src/mscorlib/src/System/Text/SBCSCodePageEncoding.cs2
-rw-r--r--src/mscorlib/src/System/Text/StringBuilder.cs8
-rw-r--r--src/mscorlib/src/System/Text/SurrogateEncoder.cs7
-rw-r--r--src/mscorlib/src/System/Text/UTF32Encoding.cs318
-rw-r--r--src/mscorlib/src/System/Text/UTF7Encoding.cs347
-rw-r--r--src/mscorlib/src/System/Text/UTF8Encoding.cs336
-rw-r--r--src/mscorlib/src/System/Text/UnicodeEncoding.cs334
-rw-r--r--src/mscorlib/src/System/Threading/AbandonedMutexException.cs4
-rw-r--r--src/mscorlib/src/System/Threading/ExecutionContext.cs4
-rw-r--r--src/mscorlib/src/System/Threading/LockRecursionException.cs2
-rw-r--r--src/mscorlib/src/System/Threading/SemaphoreFullException.cs4
-rw-r--r--src/mscorlib/src/System/Threading/SynchronizationLockException.cs4
-rw-r--r--src/mscorlib/src/System/Threading/Tasks/TaskCanceledException.cs2
-rw-r--r--src/mscorlib/src/System/Threading/Tasks/TaskSchedulerException.cs2
-rw-r--r--src/mscorlib/src/System/Threading/ThreadAbortException.cs2
-rw-r--r--src/mscorlib/src/System/Threading/ThreadInterruptedException.cs2
-rw-r--r--src/mscorlib/src/System/Threading/ThreadStartException.cs2
-rw-r--r--src/mscorlib/src/System/Threading/ThreadStateException.cs4
-rw-r--r--src/mscorlib/src/System/Threading/WaitHandleCannotBeOpenedException.cs2
-rw-r--r--src/mscorlib/src/System/TimeZoneInfo.cs28
-rw-r--r--src/mscorlib/src/System/TimeZoneNotFoundException.cs2
-rw-r--r--src/mscorlib/src/System/TimeoutException.cs4
-rw-r--r--src/mscorlib/src/System/TypeAccessException.cs2
-rw-r--r--src/mscorlib/src/System/TypeInitializationException.cs4
-rw-r--r--src/mscorlib/src/System/TypeLoadException.cs4
-rw-r--r--src/mscorlib/src/System/TypeUnloadedException.cs4
-rw-r--r--src/mscorlib/src/System/UIntPtr.cs27
-rw-r--r--src/mscorlib/src/System/UnauthorizedAccessException.cs4
-rw-r--r--src/mscorlib/src/System/UnhandledExceptionEventHandler.cs10
-rw-r--r--src/mscorlib/src/System/UnitySerializationHolder.cs2
-rw-r--r--src/mscorlib/src/System/WeakReference.cs8
-rw-r--r--src/mscorlib/src/System/WeakReferenceOfT.cs8
-rw-r--r--src/pal/inc/pal.h90
-rw-r--r--src/pal/src/config.h.in1
-rw-r--r--src/pal/src/configure.cmake28
-rw-r--r--src/pal/src/exception/machexception.cpp35
-rw-r--r--src/pal/src/exception/seh-unwind.cpp150
-rw-r--r--src/pal/src/exception/seh.cpp76
-rw-r--r--src/pal/src/exception/signal.cpp71
-rw-r--r--src/pal/src/include/pal/seh.hpp24
-rw-r--r--src/pal/src/include/pal/virtual.h7
-rw-r--r--src/pal/src/loader/module.cpp16
-rw-r--r--src/pal/src/map/virtual.cpp244
-rw-r--r--src/pal/tests/palsuite/exception_handling/pal_sxs/test1/dlltest1.cpp2
-rw-r--r--src/pal/tests/palsuite/exception_handling/pal_sxs/test1/dlltest2.cpp2
-rw-r--r--src/sign.builds14
-rw-r--r--src/vm/CMakeLists.txt2
-rw-r--r--src/vm/assemblyspec.cpp23
-rw-r--r--src/vm/codeman.cpp79
-rw-r--r--src/vm/codeman.h35
-rw-r--r--src/vm/coreassemblyspec.cpp22
-rw-r--r--src/vm/crossgen/CMakeLists.txt1
-rw-r--r--src/vm/crossgen/wks_crossgen.nativeproj1
-rw-r--r--src/vm/dac/dacwks.targets1
-rw-r--r--src/vm/dbggcinfodecoder.cpp932
-rw-r--r--src/vm/debughelp.cpp10
-rw-r--r--src/vm/ecalllist.h8
-rw-r--r--src/vm/eedbginterfaceimpl.cpp6
-rw-r--r--src/vm/eetwain.cpp63
-rw-r--r--src/vm/exceptionhandling.cpp89
-rw-r--r--src/vm/exceptionhandling.h21
-rw-r--r--src/vm/exceptmacros.h24
-rw-r--r--src/vm/fieldmarshaler.cpp26
-rw-r--r--src/vm/gccover.cpp20
-rw-r--r--src/vm/gccover.h2
-rw-r--r--src/vm/gcenv.ee.cpp111
-rw-r--r--src/vm/gcinfodecoder.cpp61
-rw-r--r--src/vm/ilmarshalers.cpp16
-rw-r--r--src/vm/object.cpp25
-rw-r--r--src/vm/object.h2
-rw-r--r--src/vm/olevariant.cpp109
-rw-r--r--src/vm/olevariant.h53
-rw-r--r--src/vm/stackwalk.h7
-rw-r--r--src/vm/stubhelpers.cpp16
-rw-r--r--src/vm/synch.cpp99
-rw-r--r--src/vm/synch.h8
-rw-r--r--src/vm/wks/CMakeLists.txt2
-rw-r--r--src/vm/wks/wks.targets1
-rwxr-xr-xsync.sh6
-rw-r--r--tests/arm64/Tests.lst18
-rw-r--r--tests/buildtest.cmd46
-rw-r--r--tests/dir.props20
-rw-r--r--tests/issues.targets68
-rw-r--r--tests/runtest.proj4
-rwxr-xr-xtests/runtest.sh2
-rwxr-xr-xtests/scripts/arm32_ci_script.sh428
-rw-r--r--tests/src/Interop/CMakeLists.txt1
-rw-r--r--tests/src/Interop/MarshalAPI/MarshalStructure/MarshalStructure.cs165
-rw-r--r--tests/src/Interop/MarshalAPI/MarshalStructure/MarshalStructure.csproj47
-rw-r--r--tests/src/Interop/MarshalAPI/MarshalStructure/project.json44
-rw-r--r--tests/src/Interop/SizeConst/CMakeLists.txt11
-rw-r--r--tests/src/Interop/SizeConst/SizeConstNative.cpp12
-rw-r--r--tests/src/Interop/SizeConst/SizeConstTest.cs47
-rw-r--r--tests/src/Interop/SizeConst/SizeConstTest.csproj48
-rw-r--r--tests/src/Interop/SizeConst/project.json44
-rw-r--r--tests/src/JIT/Regression/JitBlue/GitHub_6238/GitHub_6238.cs46
-rw-r--r--tests/src/JIT/Regression/JitBlue/GitHub_6238/GitHub_6238.csproj40
-rw-r--r--tests/src/JIT/Regression/JitBlue/GitHub_6238/app.config27
-rw-r--r--tests/src/JIT/Regression/JitBlue/GitHub_6238/project.json45
-rw-r--r--tests/src/JIT/Regression/JitBlue/GitHub_6239/GitHub_6239.cs46
-rw-r--r--tests/src/JIT/Regression/JitBlue/GitHub_6239/GitHub_6239.csproj40
-rw-r--r--tests/src/JIT/Regression/JitBlue/GitHub_6239/app.config27
-rw-r--r--tests/src/JIT/Regression/JitBlue/GitHub_6239/project.json45
-rw-r--r--tests/testsFailingOutsideWindows.txt4
-rw-r--r--tests/testsRunningInsideARM.txt22
-rw-r--r--tests/testsUnsupportedOutsideWindows.txt1
-rw-r--r--tests/x86_jit32_issues.targets10
-rw-r--r--tests/x86_legacy_backend_issues.targets8
401 files changed, 12432 insertions, 10175 deletions
diff --git a/.gitignore b/.gitignore
index d5765607a0..dbd3dd677d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -198,6 +198,9 @@ FakesAssemblies/
# C/C++ extension for Visual Studio Code
browse.VC.db
+# Local settings folder for Visual Studio Code
+.vscode/
+
### MonoDevelop ###
*.pidb
diff --git a/BuildToolsVersion.txt b/BuildToolsVersion.txt
index 33cf4e352d..f03b16e558 100644
--- a/BuildToolsVersion.txt
+++ b/BuildToolsVersion.txt
@@ -1 +1 @@
-1.0.25-prerelease-00507-05
+1.0.26-prerelease-00625-01
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000000..2637b25cc0
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,7 @@
+# Contributing
+
+See [Contributing](Documentation/project-docs/contributing.md) for information about coding styles, source structure, making pull requests, and more.
+
+# Developers
+
+See the [Developer Guide](Documentation/project-docs/developer-guide.md) for details about developing in this repo.
diff --git a/Documentation/building/cross-building.md b/Documentation/building/cross-building.md
index 30e8a08562..ba268678e9 100644
--- a/Documentation/building/cross-building.md
+++ b/Documentation/building/cross-building.md
@@ -95,4 +95,43 @@ The output is at bin/Product/<BuildOS>.arm.Debug/mscorlib.dll.
(console) ARMv7 Thumb Mono/.Net assembly, for MS Windows
```
+Building coreclr for Linux ARM Emulator
+=======================================
+It is possible to build coreclr binaries (native and mscorlib.dll) and run coreclr unit tests on the Linux ARM Emulator (latest version provided here: [#3805](https://github.com/dotnet/coreclr/issues/3805)).
+The `tests/scripts/arm32_ci_script.sh` script does this.
+
+The following instructions assume that:
+* You have set up the extracted emulator at `/opt/linux-arm-emulator` (such that `/opt/linux-arm-emulator/platform/rootfs-t30.ext4` exists)
+The emulator rootfs is of 4GB size by default. But to enable testing of coreclr binaries on the emulator, you need to resize the rootfs (to atleast 7GB) using the instructions given in the `doc/RESIZE-IMAGE.txt` file of the extracted emulator.
+* The mount path for the emulator rootfs is `/opt/linux-arm-emulator-root` (change this path if you have a working directory at this path).
+
+All the following instructions are for the Release mode. Change the commands and files accordingly for the Debug mode.
+
+To just build libcoreclr and mscorlib for the Linux ARM Emulator, run the following command:
+```
+prajwal@ubuntu ~/coreclr $ ./tests/scripts/arm32_ci_script.sh \
+ --emulatorPath=/opt/linux-arm-emulator \
+ --mountPath=/opt/linux-arm-emulator-root \
+ --buildConfig=Release \
+ --skipTests
+```
+
+The Linux ARM Emulator is based on soft floating point and thus the native binaries in coreclr are built for the arm-softfp architecture. The coreclr binaries generated by the above command (native and mscorlib) can be found at `~/coreclr/bin/Product/Linux.arm-softfp.Release`.
+
+To build libcoreclr and mscorlib, and run selected coreclr unit tests on the emulator, do the following:
+* Download the latest Coreclr unit test binaries (or build on Windows) from here: [Debug](http://dotnet-ci.cloudapp.net/job/dotnet_coreclr/job/master/job/debug_windows_nt_bld/lastSuccessfulBuild/artifact/bin/tests/tests.zip) and [Release](http://dotnet-ci.cloudapp.net/job/dotnet_coreclr/job/master/job/release_windows_nt_bld/lastSuccessfulBuild/artifact/bin/tests/tests.zip).
+Setup the binaries at `~/coreclr/bin/tests/Windows_NT.x64.Release`.
+* Build corefx binaries for the Emulator as given [here](https://github.com/dotnet/corefx/blob/master/Documentation/building/cross-building.md#building-corefx-for-linux-arm-emulator).
+Setup these binaries at `~/corefx/bin/Linux.arm-softfp.Release`, `~/corefx/bin/Linux.AnyCPU.Release`, `~/corefx/bin/Unix.AnyCPU.Release`, and `~/corefx/bin/AnyOS.AnyCPU.Release`.
+* Run the following command (change value of `--testDirFile` argument to the file containing your selection of tests):
+```
+prajwal@ubuntu ~/coreclr $ ./tests/scripts/arm32_ci_script.sh \
+ --emulatorPath=/opt/linux-arm-emulator \
+ --mountPath=/opt/linux-arm-emulator-root \
+ --buildConfig=Release \
+ --testRootDir=~/coreclr/bin/tests/Windows_NT.x64.Release \
+ --coreFxNativeBinDir=~/corefx/bin/Linux.arm-softfp.Release \
+ --coreFxBinDir="~/corefx/bin/Linux.AnyCPU.Release;~/corefx/bin/Unix.AnyCPU.Release;~/corefx/bin/AnyOS.AnyCPU.Release" \
+ --testDirFile=~/coreclr/tests/testsRunningInsideARM.txt
+```
diff --git a/Documentation/building/freebsd-instructions.md b/Documentation/building/freebsd-instructions.md
index a921a8b270..0eb902762d 100644
--- a/Documentation/building/freebsd-instructions.md
+++ b/Documentation/building/freebsd-instructions.md
@@ -67,6 +67,14 @@ janhenke@freebsd-frankfurt:~/git/coreclr % ./build.sh
Note: FreeBSD 10.1-RELEASE system's Clang/LLVM is 3.4, the minimum version to compile CoreCLR runtime is 3.5. See [Note on Clang/LLVM versions](#note-on-clangllvm-versions).
+If the build fails with errors about resolving LLVM-components, the default Clang-version assumed (3.5) may not be appropriate for your system.
+Override it using the following syntax. In this example LLVM 3.6 is used:
+
+```sh
+janhenke@freebsd-frankfurt:~/git/coreclr % ./build.sh clang3.6
+```
+
+
After the build is completed, there should some files placed in `bin/Product/FreeBSD.x64.Debug`. The ones we are interested in are:
* `corerun`: The command line host. This program loads and starts the CoreCLR runtime and passes the managed program you want to run to it.
diff --git a/Documentation/building/linux-instructions.md b/Documentation/building/linux-instructions.md
index 02f00dd3de..e79b145242 100644
--- a/Documentation/building/linux-instructions.md
+++ b/Documentation/building/linux-instructions.md
@@ -121,8 +121,8 @@ lgs@ubuntu wget http://llvm.org/releases/3.6.2/llvm-3.6.2.src.tar.xz
lgs@ubuntu tar xJf llvm-3.6.2.src.tar.xz
lgs@ubuntu cd ./llvm-3.6.2.src/tools/
lgs@ubuntu wget http://llvm.org/releases/3.6.2/cfe-3.6.2.src.tar.xz
-lgs@ubuntu tar xJf cfe-3.6.2.src.tar.xz\
-lgs@ubuntu mv cfe-3.6.2 clang
+lgs@ubuntu tar xJf cfe-3.6.2.src.tar.xz
+lgs@ubuntu mv cfe-3.6.2.src clang
```
Second, expand the coverage of the upstream patch by:
diff --git a/Documentation/project-docs/contributing-workflow.md b/Documentation/project-docs/contributing-workflow.md
index f15631b0fd..5c91a49bae 100644
--- a/Documentation/project-docs/contributing-workflow.md
+++ b/Documentation/project-docs/contributing-workflow.md
@@ -6,7 +6,7 @@ You can contribute to .NET Core with issues and PRs. Simply filing issues for pr
Getting Started
===============
-If you are looking at getting your feet wet with some simple (but still beneficial) changes, check out _up for grabs_ issues on the [CoreCLR](https://github.com/dotnet/coreclr/labels/up for grabs) and [CoreFX](https://github.com/dotnet/corefx/labels/up for grabs) repos.
+If you are looking at getting your feet wet with some simple (but still beneficial) changes, check out _up for grabs_ issues on the [CoreCLR](https://github.com/dotnet/coreclr/labels/up-for-grabs) and [CoreFX](https://github.com/dotnet/corefx/labels/up%20for%20grabs) repos.
For new ideas, please always start with an issue before starting development of an implementation. See [project priorities](project-priorities.md) to understand the Microsoft team's approach to engagement on general improvements to the product. Use [CODE_OWNERS.TXT](https://github.com/dotnet/coreclr/blob/master/CODE_OWNERS.TXT) to find relevant maintainers and @ mention them to ask for feedback on your issue.
diff --git a/Documentation/project-docs/contributing.md b/Documentation/project-docs/contributing.md
index e0d0560625..f099bf93bf 100644
--- a/Documentation/project-docs/contributing.md
+++ b/Documentation/project-docs/contributing.md
@@ -6,7 +6,7 @@ The .NET Core team maintains several guidelines for contributing to the .NET Cor
Contribution Guidelines
=======================
-- [Licensing](#copyright) describes the licensing practices for the project.
+- [Copyright](#copyright) describes the licensing practices for the project.
- [General Contribution Guidance](#general-contribution-guidance) describes general contribution guidance, including more subjective stylistic guidelines.
- [Contribution Bar](#contribution-bar) describes the bar that the team uses to accept changes.
- [Contribution Workflow](contributing-workflow.md) describes the workflow that the team uses for considering and accepting changes.
@@ -82,7 +82,7 @@ Contributing Ports
We encourage ports of CoreCLR to other platforms. Linux and OS X ports are in progress and have a lot of momentum behind them. There is also interest in a [FreeBSD port](https://github.com/dotnet/coreclr/issues/455) (and OpenBSD and NetBSD).
-Ports have a weaker contribution bar, since they do not contribute to compatibility risk with existing Microsoft products on Windows. For ports, we are primarily looking for functionaly correct implementations.
+Ports have a weaker contribution bar, since they do not contribute to compatibility risk with existing Microsoft products on Windows. For ports, we are primarily looking for functionally correct implementations.
Contributing to mscorlib library
--------------------------------
@@ -96,17 +96,26 @@ Most managed code changes should be made in the [CoreFX](https://github.com/dotn
Please see [Breaking Changes](https://github.com/dotnet/corefx/blob/master/Documentation/coding-guidelines/breaking-changes.md) to understand our requirements on changes that could impact compatibility. Please pay the most attention to changes that affect the [Public Contract](https://github.com/dotnet/corefx/blob/master/Documentation/coding-guidelines/breaking-changes.md#bucket-1-public-contract). We will not accept changes that break compatibility.
-Licensing
+Copyright
=========
-The .NET Core project sources are licensed as [MIT](../../LICENSE.TXT). The project contains source from other projects that may be licensed differently, which are called out in [3rd party notices](../../THIRD-PARTY-NOTICES).
+The .NET Core copyright is held by ".NET Foundation and Contributors". See [.NET Foundation](http://www.dotnetfoundation.org/).
-.NET Core binaries are produced and licensed separately. Microsoft produces a distribution of .NET Core licensed under the [.NET Library License](https://www.microsoft.com/net/dotnet_library_license.htm). Other groups or companies may produce their own distributions of .NET Core.
+Source License
+--------------
-Copyright
----------
+The .NET Core project uses multiple licenses for the various project repositories. Most projects use the [MIT License](https://opensource.org/licenses/MIT) for code and the [Creative Commons Attribution 4.0 International Public License (CC-BY)](https://creativecommons.org/licenses/by/4.0/) license for documentation. The [Apache 2 License](https://opensource.org/licenses/Apache-2.0) is also used.
-The .NET Core project copyright is held by ".NET Foundation and Contributors" except where otherwise called out (see [3rd party notices](../../THIRD-PARTY-NOTICES)). Please read the [.NET Core license](../../LICENSE.TXT) to review the copyright.
+See the license file at the root of project repositories for the specific license, such as with the following examples:
+
+- [CoreCLR](https://github.com/dotnet/coreclr/blob/master/LICENSE.TXT) [(MIT)](https://opensource.org/licenses/MIT).
+- [Roslyn](https://github.com/dotnet/roslyn/blob/master/License.txt) [(Apache 2)](https://opensource.org/licenses/Apache-2.0).
+- [core-docs](https://github.com/dotnet/core-docs/blob/master/license.txt) [(CC-BY)](https://creativecommons.org/licenses/by/4.0/).
+
+Binary License
+--------------
+
+Microsoft produces a distribution of .NET Core licensed under the [.NET Library License](https://www.microsoft.com/net/dotnet_library_license.htm). Other groups or companies may produce their own distributions of .NET Core.
File Headers
------------
@@ -119,13 +128,39 @@ The following file header is the used for .NET Core. Please use it for new files
// See the LICENSE file in the project root for more information.
```
-The addition of existing files from other projects is handled on a case by case basis.
+- See [class.cpp](../../src/vm/class.cpp) for an example of the header in a C++ file.
+- See [List.cs](https://github.com/dotnet/corefx/blob/master/src/System.Collections/src/System/Collections/Generic/List.cs) for an example of the header in a C# file.
+
+Copying Files from Other Projects
+---------------------------------
+
+.NET Core uses some files from other projects, typically where a binary distribution does not exist or would be inconvenient.
+
+The following rules must be followed for PRs that include files from another project:
+
+- The license of the file is [permissive](https://en.wikipedia.org/wiki/Permissive_free_software_licence).
+- The license of the file is left in-tact.
+- The contribution is correctly attributed in the [3rd party notices](../../THIRD-PARTY-NOTICES) file in the repository, as needed.
+
+See [IdnMapping.cs](../../src/mscorlib/src/System/Globalization/IdnMapping.cs) for an example of a file copied from another project and attributed in the [CoreCLR 3rd party notices](../../THIRD-PARTY-NOTICES) file.
+
+Porting Files from Other Projects
+---------------------------------
+
+There are many good algorithms implemented in other languages that would benefit the .NET Core project. The rules for porting a Java file to C# , for example, are the same as would be used for copying the same file, as described above.
+
+[Clean-room](https://en.wikipedia.org/wiki/Clean_room_design) implementations of existing algorithms that are not permissively licensed will generally not be accepted. If you want to create or nominate such an implementation, please create an issue to discuss the idea.
Contributor License Agreement
-----------------------------
-You must sign a [.NET Foundation Contribution License Agreement (CLA)](http://cla2.dotnetfoundation.org) before your PR will be merged. This a one-time requirement for projects in the .NET Foundation. You can read more about [Contribution License Agreements (CLA)](http://en.wikipedia.org/wiki/Contributor_License_Agreement) on wikipedia.
+You must sign a [.NET Foundation Contribution License Agreement (CLA)](http://cla2.dotnetfoundation.org) before your PR will be merged. This is a one-time requirement for projects in the .NET Foundation. You can read more about [Contribution License Agreements (CLA)](http://en.wikipedia.org/wiki/Contributor_License_Agreement) on Wikipedia.
-Signing the CLA is super simple and can be done in less than a minute.
+The agreement: [net-foundation-contribution-license-agreement.pdf](https://cla2.dotnetfoundation.org/cladoc/net-foundation-contribution-license-agreement.pdf)
You don't have to do this up-front. You can simply clone, fork, and submit your pull-request as usual. When your pull-request is created, it is classified by a CLA bot. If the change is trivial (e.g. you just fixed a typo), then the PR is labelled with `cla-not-required`. Otherwise it's classified as `cla-required`. Once you signed a CLA, the current and all future pull-requests will be labelled as `cla-signed`.
+
+Patents
+=======
+
+Microsoft has issued a [Patent Promise for .NET Libraries and Runtime Components](https://github.com/dotnet/coreclr/blob/master/PATENTS.TXT).
diff --git a/Documentation/project-docs/glossary.md b/Documentation/project-docs/glossary.md
index 176da1da74..19609049a7 100644
--- a/Documentation/project-docs/glossary.md
+++ b/Documentation/project-docs/glossary.md
@@ -5,13 +5,18 @@ This glossary defines terms, both common and more niche, that are important to u
As much as possible, we should link to the most authoritative and recent source of information for a term. That approach should be the most helpful for people who want to learn more about a topic.
-* CLR: Common Language Runtime
+* BOTR: Book Of The Runtime.
+* CLR: Common Language Runtime.
* COMPlus: An early name for the .NET platform, back when it was envisioned as a successor to the COM platform (hence, "COM+"). Used in various places in the CLR infrastructure, most prominently as a common prefix for the names of internal configuration settings. Note that this is different from the product that eventually ended up being named [COM+](https://msdn.microsoft.com/en-us/library/windows/desktop/ms685978.aspx).
* COR: [Common Object Runtime](http://www.danielmoth.com/Blog/mscorlibdll.aspx). The name of .NET before it was named .NET.
* DAC: Data Access Component. An abstraction layer over the internal structures in the runtime.
* EE: Execution Engine.
+* GC: [Garbage Collector](https://github.com/dotnet/coreclr/blob/master/Documentation/botr/garbage-collection.md).
+* JIT: [Just-in-Time](https://github.com/dotnet/coreclr/blob/master/Documentation/botr/ryujit-overview.md) compiler. RyuJIT is the code name for the next generation Just-in-Time(aka "JIT") for the .NET runtime.
* LCG: Lightweight Code Generation. An early name for [dynamic methods](https://github.com/dotnet/coreclr/blob/master/src/mscorlib/src/System/Reflection/Emit/DynamicMethod.cs).
+* NGen: Native Image Generator.
* PAL: [Platform Adaptation Layer](http://archive.oreilly.com/pub/a/dotnet/2002/03/04/rotor.html). Provides an abstraction layer between the runtime and the operating system
+* PE: Portable Executable.
* ProjectN: Codename for the first version of [.NET Native for UWP](https://msdn.microsoft.com/en-us/vstudio/dotnetnative.aspx).
* ReadyToRun: A flavor of native images - command line switch of [crossgen](https://github.com/dotnet/coreclr/blob/master/src/tools/crossgen/crossgen.cpp). We do plan to add docs as part of [#227](https://github.com/dotnet/coreclr/issues/227).
* Redhawk: Codename for experimental minimal managed code runtime that evolved into [CoreRT](https://github.com/dotnet/corert/).
diff --git a/THIRD-PARTY-NOTICES b/THIRD-PARTY-NOTICES
index 9f51a37de5..accca3aad0 100644
--- a/THIRD-PARTY-NOTICES
+++ b/THIRD-PARTY-NOTICES
@@ -39,3 +39,65 @@ TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+License notice for The LLVM Compiler Infrastructure
+---------------------------------------------------
+==============================================================================
+LLVM Release License
+==============================================================================
+University of Illinois/NCSA
+Open Source License
+
+Copyright (c) 2003-2015 University of Illinois at Urbana-Champaign.
+All rights reserved.
+
+Developed by:
+
+ LLVM Team
+
+ University of Illinois at Urbana-Champaign
+
+ http://llvm.org
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal with
+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:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimers.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimers in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the names of the LLVM Team, University of Illinois at
+ Urbana-Champaign, nor the names of its contributors may be used to
+ endorse or promote products derived from this Software without specific
+ prior written permission.
+
+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
+CONTRIBUTORS 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 WITH THE
+SOFTWARE.
+
+License notice for Bit Twiddling Hacks
+--------------------------------------
+
+Bit Twiddling Hacks
+
+By Sean Eron Anderson
+seander@cs.stanford.edu
+
+Individually, the code snippets here are in the public domain (unless otherwise
+noted) — feel free to use them however you please. The aggregate collection and
+descriptions are © 1997-2005 Sean Eron Anderson. The code and descriptions are
+distributed in the hope that they will be useful, but WITHOUT ANY WARRANTY and
+without even the implied warranty of merchantability or fitness for a particular
+purpose.
+
diff --git a/UpdateDependencies.ps1 b/UpdateDependencies.ps1
index 102dd4ee8c..8fee1b9bef 100644
--- a/UpdateDependencies.ps1
+++ b/UpdateDependencies.ps1
@@ -22,6 +22,16 @@ param(
$LatestVersion = Invoke-WebRequest $VersionFileUrl -UseBasicParsing
$LatestVersion = $LatestVersion.ToString().Trim()
+if ($DirPropsVersionElements -contains 'CoreClrExpectedPrerelease')
+{
+ # Also get list of all package versions, relative to the given prerelease version url.
+ $LatestPackagesListUrl = $VersionFileUrl -Replace 'Latest.txt', 'Latest_Packages.txt'
+ $LatestPackagesList = Invoke-WebRequest $LatestPackagesListUrl -UseBasicParsing
+ $LatestCoreCLRPackage = $LatestPackagesList -split "`n" | ?{ $_.StartsWith('Microsoft.NETCore.Runtime.CoreCLR') }
+ $LatestCoreCLRVersion = ($LatestCoreCLRPackage -split ' ')[1].Trim()
+}
+
+
# Make a nicely formatted string of the dir props version elements. Short names, joined by commas.
$DirPropsVersionNames = ($DirPropsVersionElements | %{ $_ -replace 'ExpectedPrerelease', '' }) -join ', '
@@ -34,22 +44,41 @@ function UpdateValidDependencyVersionsFile
return $false
}
- $DirPropsPath = "$PSScriptRoot\dir.props"
-
- $DirPropsContent = Get-Content $DirPropsPath | % {
- $line = $_
- $DirPropsVersionElements | % {
- $line = $line -replace `
- "<$_>.*</$_>", `
- "<$_>$LatestVersion</$_>"
- }
- $line
+ $DirPropsPaths = @("$PSScriptRoot\dir.props", "$PSScriptRoot\tests\dir.props")
+
+ $DirPropsPaths | %{
+ $DirPropsContent = Get-Content $_ | %{
+ $line = $_
+
+ $DirPropsVersionElements | %{
+ $line = $line -replace `
+ "<$_>.*</$_>", `
+ "<$_>$LatestVersion</$_>"
+ }
+
+ if ($LatestCoreCLRVersion)
+ {
+ $line = $line -replace `
+ "<CoreClrPackageVersion>.*<", `
+ "<CoreClrPackageVersion>$LatestCoreCLRVersion<"
+ }
+
+ $line
+ }
+ Set-Content $_ $DirPropsContent
}
- Set-Content $DirPropsPath $DirPropsContent
return $true
}
+# Updates all the project.json files with out of date version numbers
+function RunUpdatePackageDependencyVersions
+{
+ cmd /c $PSScriptRoot\tests\buildtest.cmd updateinvalidpackages | Out-Host
+
+ return $LASTEXITCODE -eq 0
+}
+
# Creates a Pull Request for the updated version numbers
function CreatePullRequest
{
@@ -113,6 +142,11 @@ if (!(UpdateValidDependencyVersionsFile))
Exit -1
}
+if (!(RunUpdatePackageDependencyVersions))
+{
+ Exit -1
+}
+
if (!(CreatePullRequest))
{
Exit -1
diff --git a/build-packages.cmd b/build-packages.cmd
index 5429581956..3552ab2ae8 100644
--- a/build-packages.cmd
+++ b/build-packages.cmd
@@ -51,6 +51,15 @@ if NOT [!ERRORLEVEL!]==[0] (
exit /b 1
)
+rem Build the TargetingPack package
+set __msbuildArgs="%__ProjectDir%\src\.nuget\Microsoft.TargetingPack.Private.CoreCLR\Microsoft.TargetingPack.Private.CoreCLR.pkgproj" !allargs!
+echo msbuild.exe %__msbuildArgs% !options! >> %packagesLog%
+call msbuild.exe %__msbuildArgs% !options!
+if NOT [!ERRORLEVEL!]==[0] (
+ echo ERROR: An error occurred while building packages, see %packagesLog% for more details.
+ exit /b 1
+)
+
echo Done Building Packages.
exit /b
diff --git a/build-packages.sh b/build-packages.sh
index 0403c3f1f0..238958eefd 100755
--- a/build-packages.sh
+++ b/build-packages.sh
@@ -121,7 +121,7 @@ $__ProjectRoot/init-tools.sh
echo "Generating nuget packages for "$__BuildOS
# Invoke MSBuild
- $__ProjectRoot/Tools/corerun "$__MSBuildPath" /nologo "$__ProjectRoot/src/.nuget/Microsoft.NETCore.Runtime.CoreCLR/Microsoft.NETCore.Runtime.CoreCLR.builds" /verbosity:minimal "/fileloggerparameters:Verbosity=normal;LogFile=$binclashlog" /t:Build /p:__BuildOS=$__BuildOS /p:__BuildArch=$__BuildArch /p:__BuildType=$__BuildType /p:__IntermediatesDir=$__IntermediatesDir /p:BuildNugetPackage=false /p:UseSharedCompilation=false
+ $__ProjectRoot/Tools/dotnetcli/dotnet "$__MSBuildPath" /nologo "$__ProjectRoot/src/.nuget/Microsoft.NETCore.Runtime.CoreCLR/Microsoft.NETCore.Runtime.CoreCLR.builds" /verbosity:minimal "/fileloggerparameters:Verbosity=normal;LogFile=$binclashlog" /t:Build /p:__BuildOS=$__BuildOS /p:__BuildArch=$__BuildArch /p:__BuildType=$__BuildType /p:__IntermediatesDir=$__IntermediatesDir /p:BuildNugetPackage=false /p:UseSharedCompilation=false
if [ $? -ne 0 ]; then
echo -e "\nAn error occurred. Aborting build-packages.sh ." >> $build_packages_log
@@ -130,7 +130,7 @@ if [ $? -ne 0 ]; then
fi
# Build the JIT packages
- $__ProjectRoot/Tools/corerun "$__MSBuildPath" /nologo "$__ProjectRoot/src/.nuget/Microsoft.NETCore.Jit/Microsoft.NETCore.Jit.builds" /verbosity:minimal "/fileloggerparameters:Verbosity=normal;LogFile=$binclashlog" /t:Build /p:__BuildOS=$__BuildOS /p:__BuildArch=$__BuildArch /p:__BuildType=$__BuildType /p:__IntermediatesDir=$__IntermediatesDir /p:BuildNugetPackage=false /p:UseSharedCompilation=false
+ $__ProjectRoot/Tools/dotnetcli/dotnet "$__MSBuildPath" /nologo "$__ProjectRoot/src/.nuget/Microsoft.NETCore.Jit/Microsoft.NETCore.Jit.builds" /verbosity:minimal "/fileloggerparameters:Verbosity=normal;LogFile=$binclashlog" /t:Build /p:__BuildOS=$__BuildOS /p:__BuildArch=$__BuildArch /p:__BuildType=$__BuildType /p:__IntermediatesDir=$__IntermediatesDir /p:BuildNugetPackage=false /p:UseSharedCompilation=false
if [ $? -ne 0 ]; then
echo -e "\nAn error occurred. Aborting build-packages.sh ." >> $build_packages_log
@@ -139,7 +139,7 @@ if [ $? -ne 0 ]; then
fi
# Build the ILAsm package
- $__ProjectRoot/Tools/corerun "$__MSBuildPath" /nologo "$__ProjectRoot/src/.nuget/Microsoft.NETCore.ILAsm/Microsoft.NETCore.ILAsm.builds" /verbosity:minimal "/fileloggerparameters:Verbosity=normal;LogFile=$binclashlog" /t:Build /p:__BuildOS=$__BuildOS /p:__BuildArch=$__BuildArch /p:__BuildType=$__BuildType /p:__IntermediatesDir=$__IntermediatesDir /p:BuildNugetPackage=false /p:UseSharedCompilation=false
+ $__ProjectRoot/Tools/dotnetcli/dotnet "$__MSBuildPath" /nologo "$__ProjectRoot/src/.nuget/Microsoft.NETCore.ILAsm/Microsoft.NETCore.ILAsm.builds" /verbosity:minimal "/fileloggerparameters:Verbosity=normal;LogFile=$binclashlog" /t:Build /p:__BuildOS=$__BuildOS /p:__BuildArch=$__BuildArch /p:__BuildType=$__BuildType /p:__IntermediatesDir=$__IntermediatesDir /p:BuildNugetPackage=false /p:UseSharedCompilation=false
if [ $? -ne 0 ]; then
echo -e "\nAn error occurred. Aborting build-packages.sh ." >> $build_packages_log
@@ -148,7 +148,7 @@ if [ $? -ne 0 ]; then
fi
# Build the ILDAsm package
- $__ProjectRoot/Tools/corerun "$__MSBuildPath" /nologo "$__ProjectRoot/src/.nuget/Microsoft.NETCore.ILDAsm/Microsoft.NETCore.ILDAsm.builds" /verbosity:minimal "/fileloggerparameters:Verbosity=normal;LogFile=$binclashlog" /t:Build /p:__BuildOS=$__BuildOS /p:__BuildArch=$__BuildArch /p:__BuildType=$__BuildType /p:__IntermediatesDir=$__IntermediatesDir /p:BuildNugetPackage=false /p:UseSharedCompilation=false
+ $__ProjectRoot/Tools/dotnetcli/dotnet "$__MSBuildPath" /nologo "$__ProjectRoot/src/.nuget/Microsoft.NETCore.ILDAsm/Microsoft.NETCore.ILDAsm.builds" /verbosity:minimal "/fileloggerparameters:Verbosity=normal;LogFile=$binclashlog" /t:Build /p:__BuildOS=$__BuildOS /p:__BuildArch=$__BuildArch /p:__BuildType=$__BuildType /p:__IntermediatesDir=$__IntermediatesDir /p:BuildNugetPackage=false /p:UseSharedCompilation=false
if [ $? -ne 0 ]; then
echo -e "\nAn error occurred. Aborting build-packages.sh ." >> $build_packages_log
diff --git a/build.cmd b/build.cmd
index 0e4b1c4540..5439ca551f 100644
--- a/build.cmd
+++ b/build.cmd
@@ -46,6 +46,7 @@ set "__LogsDir=%__RootBinDir%\Logs"
set __CleanBuild=
set __CoreLibOnly=
+set __CoreLibAlsoNativeImage=
set __ConfigureOnly=
set __SkipConfigure=
set __SkipCoreLibBuild=
@@ -112,6 +113,7 @@ if /i "%1" == "netbsdmscorlib" (set __CoreLibOnly=1&set __BuildOS=NetBSD&se
if /i "%1" == "osxmscorlib" (set __CoreLibOnly=1&set __BuildOS=OSX&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop)
if /i "%1" == "windowsmscorlib" (set __CoreLibOnly=1&set __BuildOS=Windows_NT&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop)
+if /i "%1" == "nativemscorlib" (set __CoreLibAlsoNativeImage=1&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop)
if /i "%1" == "vs2015" (set __VSVersion=%1&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop)
if /i "%1" == "configureonly" (set __ConfigureOnly=1&set __SkipCoreLibBuild=1&set __SkipBuildPackages=1&set __SkipTestBuild=1&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop)
if /i "%1" == "skipconfigure" (set __SkipConfigure=1&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop)
@@ -203,8 +205,6 @@ set __msbuildCleanBuildArgs=/t:rebuild
:: Cleanup the previous output for the selected configuration
if exist "%__BinDir%" rd /s /q "%__BinDir%"
if exist "%__IntermediatesDir%" rd /s /q "%__IntermediatesDir%"
-if exist "%__TestBinDir%" rd /s /q "%__TestBinDir%"
-if exist "%__TestIntermediatesDir%" rd /s /q "%__TestIntermediatesDir%"
if exist "%__LogsDir%" del /f /q "%__LogsDir%\*_%__BuildOS%__%__BuildArch%__%__BuildType%.*"
if exist "%__ProjectDir%\Tools" rd /s /q "%__ProjectDir%\Tools"
@@ -499,12 +499,15 @@ if errorlevel 1 (
echo %__BuildLog%
echo %__BuildWrn%
echo %__BuildErr%
+ type %__BuildErr%
exit /b 1
)
if defined __CoreLibOnly (
echo %__MsgPrefix%System.Private.CoreLib successfully built.
- exit /b 0
+ if not defined __CoreLibAlsoNativeImage (
+ exit /b 0
+ )
)
echo %__MsgPrefix%Generating native image of System.Private.CoreLib for %__BuildOS%.%__BuildArch%.%__BuildType%
@@ -515,6 +518,7 @@ set "__CrossgenExe=%__CrossComponentBinDir%\crossgen.exe"
if NOT %errorlevel% == 0 (
echo %__MsgPrefix%Error: CrossGen System.Private.CoreLib build failed. Refer to the build log file for details:
echo %__CrossGenCoreLibLog%
+ type %__CrossGenCoreLibLog%
exit /b 1
)
@@ -526,9 +530,14 @@ set "__CrossgenExe=%__CrossComponentBinDir%\crossgen.exe"
if NOT %errorlevel% == 0 (
echo %__MsgPrefix%Error: CrossGen mscorlib facade build failed. Refer to the build log file for details:
echo %__CrossGenCoreLibLog%
+ type %__CrossGenCoreLibLog%
exit /b 1
)
+if defined __CoreLibAlsoNativeImage (
+ exit /b 0
+)
+
:SkipCoreLibBuild
:GenerateNuget
@@ -716,6 +725,7 @@ echo mscorlib version: one of freebsdmscorlib, linuxmscorlib, netbsdmscorlib, os
echo or windowsmscorlib. If one of these is passed, only System.Private.CoreLib is built,
echo for the specified platform ^(FreeBSD, Linux, NetBSD, OS X or Windows,
echo respectively^).
+echo add nativemscorlib to go further and build the native image for designated mscorlib.
echo priority ^<N^> : specify a set of test that will be built and run, with priority N.
echo sequential: force a non-parallel build ^(default is to build in parallel
echo using all processors^).
diff --git a/build.sh b/build.sh
index fe4c0b01ce..6b6cf2df5e 100755
--- a/build.sh
+++ b/build.sh
@@ -1,6 +1,29 @@
#!/usr/bin/env bash
-PYTHON=${PYTHON:-python}
+# resolve python-version to use
+if [ "$PYTHON" == "" ] ; then
+ if which python >/dev/null 2>&1
+ then
+ PYTHON=python
+ elif which python2 >/dev/null 2>&1
+ then
+ PYTHON=python2
+ elif which python2.7 >/dev/null 2>&1
+ then
+ PYTHON=python2.7
+ else
+ echo "Unable to locate build-dependency python2.x!" 1>&2
+ exit 1
+ fi
+fi
+
+# validate python-dependency
+# useful in case of explicitly set option.
+if ! which $PYTHON > /dev/null 2>&1
+then
+ echo "Unable to locate build-dependency python2.x ($PYTHON)!" 1>&2
+ exit 1
+fi
usage()
{
@@ -154,8 +177,8 @@ build_coreclr()
__versionSourceFile=$__IntermediatesDir/version.cpp
if [ $__SkipGenerateVersion == 0 ]; then
"$__ProjectRoot/init-tools.sh" > "$__ProjectRoot/init-tools.log"
- echo "Running: \"$__ProjectRoot/Tools/corerun\" \"$__ProjectRoot/Tools/MSBuild.exe\" \"$__ProjectRoot/build.proj\" /v:minimal /t:GenerateVersionSourceFile /p:NativeVersionSourceFile=$__versionSourceFile /p:GenerateVersionSourceFile=true /v:minimal $__OfficialBuildIdArg"
- "$__ProjectRoot/Tools/corerun" "$__ProjectRoot/Tools/MSBuild.exe" "$__ProjectRoot/build.proj" /v:minimal /t:GenerateVersionSourceFile /p:NativeVersionSourceFile=$__versionSourceFile /p:GenerateVersionSourceFile=true /v:minimal $__OfficialBuildIdArg
+ echo "Running: \"$__ProjectRoot/Tools/dotnetcli/dotnet\" \"$__ProjectRoot/Tools/MSBuild.exe\" \"$__ProjectRoot/build.proj\" /v:minimal /t:GenerateVersionSourceFile /p:NativeVersionSourceFile=$__versionSourceFile /p:GenerateVersionSourceFile=true /v:minimal $__OfficialBuildIdArg"
+ "$__ProjectRoot/Tools/dotnetcli/dotnet" "$__ProjectRoot/Tools/MSBuild.exe" "$__ProjectRoot/build.proj" /v:minimal /t:GenerateVersionSourceFile /p:NativeVersionSourceFile=$__versionSourceFile /p:GenerateVersionSourceFile=true /v:minimal $__OfficialBuildIdArg
else
__versionSourceLine="static char sccsid[] __attribute__((used)) = \"@(#)No version information produced\";"
echo $__versionSourceLine > $__versionSourceFile
@@ -289,7 +312,7 @@ build_CoreLib()
echo "Commencing build of managed components for $__BuildOS.$__BuildArch.$__BuildType"
# Invoke MSBuild
- $__ProjectRoot/Tools/corerun "$__MSBuildPath" /nologo "$__ProjectRoot/build.proj" /verbosity:minimal "/fileloggerparameters:Verbosity=normal;LogFile=$__LogsDir/System.Private.CoreLib_$__BuildOS__$__BuildArch__$__BuildType.log" /t:Build /p:__BuildOS=$__BuildOS /p:__BuildArch=$__BuildArch /p:__BuildType=$__BuildType /p:__IntermediatesDir=$__IntermediatesDir /p:__RootBinDir=$__RootBinDir /p:BuildNugetPackage=false /p:UseSharedCompilation=false ${__SignTypeReal}
+ $__ProjectRoot/Tools/dotnetcli/dotnet "$__MSBuildPath" /nologo "$__ProjectRoot/build.proj" /verbosity:minimal "/fileloggerparameters:Verbosity=normal;LogFile=$__LogsDir/System.Private.CoreLib_$__BuildOS__$__BuildArch__$__BuildType.log" /t:Build /p:__BuildOS=$__BuildOS /p:__BuildArch=$__BuildArch /p:__BuildType=$__BuildType /p:__IntermediatesDir=$__IntermediatesDir /p:__RootBinDir=$__RootBinDir /p:BuildNugetPackage=false /p:UseSharedCompilation=false ${__SignTypeReal}
if [ $? -ne 0 ]; then
echo "Failed to build managed components."
@@ -335,7 +358,7 @@ generate_NugetPackages()
echo "Generating nuget packages for "$__BuildOS
# Build the packages
- $__ProjectRoot/Tools/corerun "$__MSBuildPath" /nologo "$__ProjectRoot/src/.nuget/packages.builds" /verbosity:minimal "/fileloggerparameters:Verbosity=normal;LogFile=$__LogsDir/Nuget_$__BuildOS__$__BuildArch__$__BuildType.log" /t:Build /p:__BuildOS=$__BuildOS /p:__BuildArch=$__BuildArch /p:__BuildType=$__BuildType /p:__IntermediatesDir=$__IntermediatesDir /p:__RootBinDir=$__RootBinDir /p:BuildNugetPackage=false /p:UseSharedCompilation=false
+ $__ProjectRoot/Tools/dotnetcli/dotnet "$__MSBuildPath" /nologo "$__ProjectRoot/src/.nuget/packages.builds" /verbosity:minimal "/fileloggerparameters:Verbosity=normal;LogFile=$__LogsDir/Nuget_$__BuildOS__$__BuildArch__$__BuildType.log" /t:Build /p:__BuildOS=$__BuildOS /p:__BuildArch=$__BuildArch /p:__BuildType=$__BuildType /p:__IntermediatesDir=$__IntermediatesDir /p:__RootBinDir=$__RootBinDir /p:BuildNugetPackage=false /p:UseSharedCompilation=false
if [ $? -ne 0 ]; then
echo "Failed to generate Nuget packages."
diff --git a/clean.sh b/clean.sh
index 8d88bd27f2..dacb5e2986 100755
--- a/clean.sh
+++ b/clean.sh
@@ -25,7 +25,7 @@ if [ $# == 0 ]; then
clean_packages=true
fi
-while [[ $# > 0 ]]
+while [[ $# -gt 0 ]]
do
opt="$1"
case $opt in
diff --git a/clrdefinitions.cmake b/clrdefinitions.cmake
index 3785f633b9..5ff9be4647 100644
--- a/clrdefinitions.cmake
+++ b/clrdefinitions.cmake
@@ -132,13 +132,6 @@ add_definitions(-DFEATURE_MANAGED_ETW_CHANNELS)
add_definitions(-DFEATURE_MAIN_CLR_MODULE_USES_CORE_NAME)
add_definitions(-DFEATURE_MERGE_CULTURE_SUPPORT_AND_ENGINE)
-if(CLR_CMAKE_TARGET_ARCH_ARM64)
- # TODO_DJIT: Remove this as part of enabling cross-compiling standalone JIT binary.
- if (NOT CLR_CMAKE_PLATFORM_UNIX)
- set(FEATURE_MERGE_JIT_AND_ENGINE 1)
- endif(NOT CLR_CMAKE_PLATFORM_UNIX)
-endif(CLR_CMAKE_TARGET_ARCH_ARM64)
-
if(FEATURE_MERGE_JIT_AND_ENGINE)
# Disable the following for UNIX altjit on Windows
add_definitions(-DFEATURE_MERGE_JIT_AND_ENGINE)
diff --git a/cross/arm-softfp/tryrun.cmake b/cross/arm-softfp/tryrun.cmake
index 2721d08491..26a30e5e40 100644
--- a/cross/arm-softfp/tryrun.cmake
+++ b/cross/arm-softfp/tryrun.cmake
@@ -34,10 +34,6 @@ SET( HAVE_MMAP_DEV_ZERO_EXITCODE
0
CACHE STRING "Result from TRY_RUN" FORCE)
-SET( MMAP_DOESNOT_ALLOW_REMAP_EXITCODE
- 1
- CACHE STRING "Result from TRY_RUN" FORCE)
-
SET( ONE_SHARED_MAPPING_PER_FILEREGION_PER_PROCESS_EXITCODE
1
CACHE STRING "Result from TRY_RUN" FORCE)
diff --git a/cross/arm/tryrun.cmake b/cross/arm/tryrun.cmake
index 2721d08491..26a30e5e40 100644
--- a/cross/arm/tryrun.cmake
+++ b/cross/arm/tryrun.cmake
@@ -34,10 +34,6 @@ SET( HAVE_MMAP_DEV_ZERO_EXITCODE
0
CACHE STRING "Result from TRY_RUN" FORCE)
-SET( MMAP_DOESNOT_ALLOW_REMAP_EXITCODE
- 1
- CACHE STRING "Result from TRY_RUN" FORCE)
-
SET( ONE_SHARED_MAPPING_PER_FILEREGION_PER_PROCESS_EXITCODE
1
CACHE STRING "Result from TRY_RUN" FORCE)
diff --git a/cross/arm64/tryrun.cmake b/cross/arm64/tryrun.cmake
index d8a95a6387..1751ac5250 100644
--- a/cross/arm64/tryrun.cmake
+++ b/cross/arm64/tryrun.cmake
@@ -34,10 +34,6 @@ SET( HAVE_MMAP_DEV_ZERO_EXITCODE
0
CACHE STRING "Result from TRY_RUN" FORCE)
-SET( MMAP_DOESNOT_ALLOW_REMAP_EXITCODE
- 1
- CACHE STRING "Result from TRY_RUN" FORCE)
-
SET( ONE_SHARED_MAPPING_PER_FILEREGION_PER_PROCESS_EXITCODE
1
CACHE STRING "Result from TRY_RUN" FORCE)
diff --git a/cross/build-rootfs.sh b/cross/build-rootfs.sh
index dc093b8675..b786420405 100755
--- a/cross/build-rootfs.sh
+++ b/cross/build-rootfs.sh
@@ -52,12 +52,12 @@ for i in "$@"
__UbuntuCodeName=jessie
;;
vivid)
- if [ __UbuntuCodeName != "jessie" ]; then
+ if [ "$__UbuntuCodeName" != "jessie" ]; then
__UbuntuCodeName=vivid
fi
;;
wily)
- if [ __UbuntuCodeName != "jessie" ]; then
+ if [ "$__UbuntuCodeName" != "jessie" ]; then
__UbuntuCodeName=wily
fi
;;
diff --git a/crosscomponents.cmake b/crosscomponents.cmake
index 158173e307..e0d5c1a939 100644
--- a/crosscomponents.cmake
+++ b/crosscomponents.cmake
@@ -5,4 +5,5 @@ set (CLR_CROSS_COMPONENTS_LIST
mscordaccore
mscordbi
sos
+ clrjit
)
diff --git a/dir.props b/dir.props
index 809d5eb877..9adde779fd 100644
--- a/dir.props
+++ b/dir.props
@@ -63,6 +63,7 @@
<ToolsDir Condition="'$(ToolsDir)'==''">$(ProjectDir)Tools/</ToolsDir>
<DotnetCliPath Condition="'$(DotnetCliPath)'==''">$(ToolsDir)dotnetcli/</DotnetCliPath>
+ <OverrideToolHost>$(DotnetCliPath)dotnet</OverrideToolHost>
<BuildToolsSemaphore Condition="'$(BuildToolsSemaphore)' == ''">$(ToolsDir)Microsoft.DotNet.Build.Tasks.dll</BuildToolsSemaphore>
<TestWorkingDir>$(__TestWorkingDir)\</TestWorkingDir>
@@ -152,7 +153,7 @@
<ProjectUrl>https://dot.net</ProjectUrl>
<!-- PreReleaseSuffix for packages published from closed build (e.g. CoreCLR for Arm32, APISet, etc) -->
- <ExternalExpectedPrerelease>beta-24306-00</ExternalExpectedPrerelease>
+ <ExternalExpectedPrerelease>beta-24325-00</ExternalExpectedPrerelease>
<!-- On Windows, MSbuild still runs against Desktop FX while it runs on .NET Core on non-Windows. this requires
pulling in different packaging dependencies.
diff --git a/init-tools.cmd b/init-tools.cmd
index abc34f9aa6..1bdf2a89a5 100644
--- a/init-tools.cmd
+++ b/init-tools.cmd
@@ -44,7 +44,7 @@ if exist "%DOTNET_CMD%" goto :afterdotnetrestore
echo Installing dotnet cli...
if NOT exist "%DOTNET_PATH%" mkdir "%DOTNET_PATH%"
set /p DOTNET_VERSION=< "%~dp0DotnetCLIVersion.txt"
-set DOTNET_ZIP_NAME=dotnet-dev-win-x64.%DOTNET_VERSION%.zip
+if [%PROCESSOR_ARCHITECTURE%]==[x86] (set DOTNET_ZIP_NAME=dotnet-dev-win-x86.%DOTNET_VERSION%.zip) else (set DOTNET_ZIP_NAME=dotnet-dev-win-x64.%DOTNET_VERSION%.zip)
set DOTNET_REMOTE_PATH=https://dotnetcli.blob.core.windows.net/dotnet/preview/Binaries/%DOTNET_VERSION%/%DOTNET_ZIP_NAME%
set DOTNET_LOCAL_PATH=%DOTNET_PATH%%DOTNET_ZIP_NAME%
echo Installing '%DOTNET_REMOTE_PATH%' to '%DOTNET_LOCAL_PATH%' >> "%INIT_TOOLS_LOG%"
diff --git a/init-tools.sh b/init-tools.sh
index 0c56966223..e6966cc2f0 100755
--- a/init-tools.sh
+++ b/init-tools.sh
@@ -116,7 +116,6 @@ if [ ! -e $__PROJECT_JSON_FILE ]; then
# On ubuntu 14.04, /bin/sh (symbolic link) calls /bin/dash by default.
$__BUILD_TOOLS_PATH/init-tools.sh $__scriptpath $__DOTNET_CMD $__TOOLRUNTIME_DIR
- chmod a+x $__TOOLRUNTIME_DIR/corerun
else
echo "$__PROJECT_JSON_FILE found. Skipping .NET CLI installation."
fi
diff --git a/netci.groovy b/netci.groovy
index 3647dca6c7..3787e54a4d 100755
--- a/netci.groovy
+++ b/netci.groovy
@@ -1,7 +1,6 @@
// Import the utility functionality.
-import jobs.generation.Utilities;
-import jobs.generation.JobReport;
+import jobs.generation.*
// The input project name (e.g. dotnet/coreclr)
def project = GithubProject
@@ -493,7 +492,14 @@ def static addTriggers(def job, def branch, def isPR, def architecture, def os,
case 'gcstress0x3':
if (os != 'CentOS7.1' && !(os in bidailyCrossList)) {
assert (os == 'Windows_NT') || (os in Constants.crossList)
- Utilities.addPeriodicTrigger(job, '@weekly')
+ if (architecture == 'arm64') {
+ assert (os == 'Windows_NT')
+ Utilities.addPeriodicTrigger(job, '@daily')
+ addEmailPublisher(job, 'dotnetonarm64@microsoft.com')
+ }
+ else {
+ Utilities.addPeriodicTrigger(job, '@weekly')
+ }
}
break
case 'gcstress0xc':
@@ -554,7 +560,7 @@ def static addTriggers(def job, def branch, def isPR, def architecture, def os,
case 'Ubuntu16.04':
assert !isFlowJob
assert scenario == 'default'
- Utilities.addGithubPRTriggerForBranch(job, branch, "${os} ${architecture} ${configuration} Build", '(?i).*test\\W+${os}\\W+.*')
+ Utilities.addGithubPRTriggerForBranch(job, branch, "${os} ${architecture} ${configuration} Build", "(?i).*test\\W+${os}\\W+.*")
break
case 'Ubuntu':
case 'OSX':
@@ -1768,11 +1774,24 @@ combinedScenarios.each { scenario ->
def armemul_path = '/opt/linux-arm-emulator'
def armrootfs_mountpath = '/opt/linux-arm-emulator-root'
- // Call the ARM emulator build script to cross build using the ARM emulator rootfs
- buildCommands += "./tests/scripts/arm32_ci_script.sh --emulatorPath=${armemul_path} --mountPath=${armrootfs_mountpath} --buildConfig=${lowerConfiguration}"
+ // Unzip the Windows test binaries first. Exit with 0
+ buildCommands += "unzip -q -o ./bin/tests/tests.zip -d ./bin/tests/Windows_NT.x64.${configuration} || exit 0"
+ // Unpack the corefx binaries
+ buildCommands += "tar -xf ./bin/build.tar.gz"
- // Basic archiving of the build, no pal tests
+ // Call the ARM emulator build script to cross build and test using the ARM emulator rootfs
+ buildCommands += """./tests/scripts/arm32_ci_script.sh \\
+ --emulatorPath=${armemul_path} \\
+ --mountPath=${armrootfs_mountpath} \\
+ --buildConfig=${lowerConfiguration} \\
+ --testRootDir=./bin/tests/Windows_NT.x64.${configuration} \\
+ --coreFxNativeBinDir=./bin/Linux.arm-softfp.${configuration} \\
+ --coreFxBinDir=\"./bin/Linux.AnyCPU.${configuration};./bin/Unix.AnyCPU.${configuration};./bin/AnyOS.AnyCPU.${configuration}\" \\
+ --testDirFile=./tests/testsRunningInsideARM.txt"""
+
+
+ // Basic archiving of the build
Utilities.addArchival(newJob, "bin/Product/**")
break
}
@@ -1796,6 +1815,35 @@ combinedScenarios.each { scenario ->
}
}
else {
+ // Setup corefx and Windows test binaries for Linux ARM Emulator Build
+ if (isLinuxEmulatorBuild) {
+ // Define the Windows Tests and Corefx build job names
+ def WindowTestsName = projectFolder + '/' +
+ Utilities.getFullJobName(project,
+ getJobName(lowerConfiguration,
+ 'x64' ,
+ 'windows_nt',
+ 'default',
+ true),
+ false)
+ def corefxFolder = Utilities.getFolderName('dotnet/corefx') + '/' +
+ Utilities.getFolderName(branch)
+
+ // Copy the Windows test binaries and the Corefx build binaries
+ copyArtifacts(WindowTestsName) {
+ excludePatterns('**/testResults.xml', '**/*.ni.dll')
+ buildSelector {
+ latestSuccessful(true)
+ }
+ }
+ copyArtifacts("${corefxFolder}/linuxarmemulator_cross_${lowerConfiguration}") {
+ includePatterns('bin/build.tar.gz')
+ buildSelector {
+ latestSuccessful(true)
+ }
+ }
+ }
+
buildCommands.each { buildCommand ->
shell(buildCommand)
}
@@ -2092,15 +2140,17 @@ combinedScenarios.each { scenario ->
// Unzip the tests first. Exit with 0
shell("unzip -q -o ./clr/bin/tests/tests.zip -d ./clr/bin/tests/Windows_NT.${architecture}.${configuration} || exit 0")
- shell("ls clr/bin")
// Get corefx
shell("git clone https://github.com/dotnet/corefx fx")
- shell("ls")
- shell("pwd")
+
// Build Linux corefx
shell("./fx/build.sh x64 release Linux skiptests")
- // Check contents of bin directory - this can be removed after we confirm everything is as expected
- shell("ls ./fx/bin")
+
+ def testEnvOpt = ""
+ def scriptFileName = "\$WORKSPACE/set_stress_test_env.sh"
+ def createScriptCmds = genStressModeScriptStep(os, scenario, Constants.jitStressModeScenarios['heapverify1'], scriptFileName)
+ shell("${createScriptCmds}")
+ testEnvOpt = "--test-env=" + scriptFileName
// Run corefx tests
shell("""./fx/run-test.sh \\
@@ -2121,12 +2171,19 @@ combinedScenarios.each { scenario ->
--coreFxNativeBinDir=\"\$(pwd)/fx/bin/${osGroup}.${architecture}.Release\" \\
--crossgen --runcrossgentests""")
- // Run coreclr tests w/ server GC enabled & produce coverage reports
+ // Run coreclr tests w/ server GC & HeapVerify enabled
shell("""./clr/tests/runtest.sh \\
--testRootDir=\"\$(pwd)/clr/bin/tests/Windows_NT.${architecture}.${configuration}\" \\
--testNativeBinDir=\"\$(pwd)/clr/bin/obj/${osGroup}.${architecture}.${configuration}/tests\" \\
--coreOverlayDir=\"\$(pwd)/clr/bin/tests/Windows_NT.${architecture}.${configuration}/Tests/coreoverlay\" \\
- --useServerGC --coreclr-coverage \\
+ --useServerGC ${testEnvOpt}""")
+
+ // Run long-running coreclr GC tests & produce coverage reports
+ shell("""./clr/tests/runtest.sh \\
+ --testRootDir=\"\$(pwd)/clr/bin/tests/Windows_NT.${architecture}.${configuration}\" \\
+ --testNativeBinDir=\"\$(pwd)/clr/bin/obj/${osGroup}.${architecture}.${configuration}/tests\" \\
+ --coreOverlayDir=\"\$(pwd)/clr/bin/tests/Windows_NT.${architecture}.${configuration}/Tests/coreoverlay\" \\
+ --long-gc --playlist=\"\$(pwd)/clr/tests/longRunningGcTests.txt\" --coreclr-coverage\\
--coreclr-objs=\"\$(pwd)/clr/bin/obj/${osGroup}.${architecture}.${configuration}\" \\
--coreclr-src=\"\$(pwd)/clr/src\" \\
--coverage-output-dir=\"\${WORKSPACE}/coverage\" """)
@@ -2195,6 +2252,13 @@ combinedScenarios.each { scenario ->
addEmailPublisher(newJob, 'clrcoverage@microsoft.com')
}
+ // Experimental: If on Ubuntu 14.04, then attempt to pull in crash dump links
+ if (os in ['Ubuntu']) {
+ SummaryBuilder summaries = new SummaryBuilder()
+ summaries.addLinksSummaryFromFile('Crash dumps from this run:', 'dumplings.txt')
+ summaries.emit(newJob)
+ }
+
setMachineAffinity(newJob, os, architecture)
Utilities.standardJobSetup(newJob, project, isPR, "*/${branch}")
// Set timeouts to 240.
diff --git a/publish-packages.sh b/publish-packages.sh
index a7e5cec43a..555a590256 100755
--- a/publish-packages.sh
+++ b/publish-packages.sh
@@ -57,8 +57,8 @@ echo "Running init-tools.sh"
$working_tree_root/init-tools.sh
echo "Publishing packages..."
-echo -e "\n$working_tree_root/Tools/corerun $working_tree_root/Tools/MSBuild.exe $working_tree_root/src/publish.proj $options $*" /p:__BuildOS=$__BuildOS >> $publish_log
-$working_tree_root/Tools/corerun $working_tree_root/Tools/MSBuild.exe $working_tree_root/src/publish.proj $options $* /p:__BuildOS=$__BuildOS
+echo -e "\n$working_tree_root/Tools/dotnetcli/dotnet $working_tree_root/Tools/MSBuild.exe $working_tree_root/src/publish.proj $options $*" /p:__BuildOS=$__BuildOS >> $publish_log
+$working_tree_root/Tools/dotnetcli/dotnet $working_tree_root/Tools/MSBuild.exe $working_tree_root/src/publish.proj $options $* /p:__BuildOS=$__BuildOS
if [ $? -ne 0 ]
then
echo -e "\nPackage publishing failed. Aborting." >> $publish_log
diff --git a/src/.nuget/Microsoft.NETCore.Jit/win/Microsoft.NETCore.Jit.pkgproj b/src/.nuget/Microsoft.NETCore.Jit/win/Microsoft.NETCore.Jit.pkgproj
index fd799b10dd..cda00784ad 100644
--- a/src/.nuget/Microsoft.NETCore.Jit/win/Microsoft.NETCore.Jit.pkgproj
+++ b/src/.nuget/Microsoft.NETCore.Jit/win/Microsoft.NETCore.Jit.pkgproj
@@ -9,9 +9,13 @@
</PropertyGroup>
<ItemGroup>
<ArchitectureSpecificNativeFile Include="$(BinDir)clrjit.dll" />
+ <CrossArchitectureSpecificNativeFile Include="$(BinDir)$(CrossTargetComponentFolder)\clrjit.dll" />
<File Include="@(ArchitectureSpecificNativeFile)">
<TargetPath>runtimes/$(PackageTargetRuntime)/native</TargetPath>
</File>
+ <File Condition="'$(HasCrossTargetComponents)' == 'true'" Include="@(CrossArchitectureSpecificNativeFile)">
+ <TargetPath>runtimes/$(CrossTargetComponentFolder)_$(PackagePlatform)/native</TargetPath>
+ </File>
</ItemGroup>
<ItemGroup>
<!-- prevent accidental inclusion in AOT projects. -->
@@ -22,10 +26,15 @@
<ArchitectureSpecificNativeSymbol Include="@(ArchitectureSpecificNativeFile -> '%(RelativeDir)PDB\%(FileName).pdb')" />
<AdditionalSymbolPackageExcludes Include="%2A%2A\%2A.dll" />
<ArchitectureSpecificNativeSymbol Include="..\_.pdb" />
+ <CrossArchitectureSpecificNativeSymbol Condition="'$(HasCrossTargetComponents)' == 'true'" Include="@(CrossArchitectureSpecificNativeFile -> '%(RelativeDir)PDB\%(FileName).pdb')" />
<File Include="@(ArchitectureSpecificNativeSymbol)">
<TargetPath>runtimes/$(PackageTargetRuntime)/native</TargetPath>
<IsSymbolFile>true</IsSymbolFile>
</File>
+ <File Condition="'$(HasCrossTargetComponents)' == 'true'" Include="@(CrossArchitectureSpecificNativeSymbol)">
+ <TargetPath>runtimes/$(CrossTargetComponentFolder)_$(PackagePlatform)/native</TargetPath>
+ <IsSymbolFile>true</IsSymbolFile>
+ </File>
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
</Project>
diff --git a/src/ToolBox/SOS/Strike/disasm.cpp b/src/ToolBox/SOS/Strike/disasm.cpp
index 097f4cd14c..e141f8038f 100644
--- a/src/ToolBox/SOS/Strike/disasm.cpp
+++ b/src/ToolBox/SOS/Strike/disasm.cpp
@@ -9,6 +9,7 @@
// ==--==
#include "strike.h"
+#include "gcinfo.h"
#include "util.h"
#include <dbghelp.h>
#include <limits.h>
@@ -1058,10 +1059,11 @@ void PrintNothing (const char *fmt, ...)
///
/// Dump X86 GCInfo header and table
///
-void X86Machine::DumpGCInfo(BYTE* pTable, unsigned methodSize, printfFtn gcPrintf, bool encBytes, bool bPrintHeader) const
+void X86Machine::DumpGCInfo(GCInfoToken gcInfoToken, unsigned methodSize, printfFtn gcPrintf, bool encBytes, bool bPrintHeader) const
{
X86GCDump::InfoHdr header;
- X86GCDump::GCDump gcDump(encBytes, 5, true);
+ X86GCDump::GCDump gcDump(gcInfoToken.Version, encBytes, 5, true);
+ BYTE* pTable = dac_cast<PTR_BYTE>(gcInfoToken.Info);
if (bPrintHeader)
{
gcDump.gcPrintf = gcPrintf;
@@ -1107,17 +1109,17 @@ LPCSTR AMD64Machine::s_SPName = "RSP";
///
/// Dump AMD64 GCInfo table
///
-void AMD64Machine::DumpGCInfo(BYTE* pTable, unsigned methodSize, printfFtn gcPrintf, bool encBytes, bool bPrintHeader) const
+void AMD64Machine::DumpGCInfo(GCInfoToken gcInfoToken, unsigned methodSize, printfFtn gcPrintf, bool encBytes, bool bPrintHeader) const
{
if (bPrintHeader)
{
ExtOut("Pointer table:\n");
}
- GCDump gcDump(encBytes, 5, true);
+ GCDump gcDump(gcInfoToken.Version, encBytes, 5, true);
gcDump.gcPrintf = gcPrintf;
- gcDump.DumpGCTable(pTable, methodSize, 0);
+ gcDump.DumpGCTable(dac_cast<PTR_BYTE>(gcInfoToken.Info), methodSize, 0);
}
#endif // SOS_TARGET_AMD64
diff --git a/src/ToolBox/SOS/Strike/disasm.h b/src/ToolBox/SOS/Strike/disasm.h
index 6972c39ccb..59fc168a6e 100644
--- a/src/ToolBox/SOS/Strike/disasm.h
+++ b/src/ToolBox/SOS/Strike/disasm.h
@@ -159,7 +159,7 @@ public:
virtual void GetGCRegisters(LPCSTR** regNames, unsigned int* cntRegs) const
{ _ASSERTE(cntRegs != NULL); *regNames = s_GCRegs; *cntRegs = _countof(s_GCRegs); }
- virtual void DumpGCInfo(BYTE* pTable, unsigned methodSize, printfFtn gcPrintf, bool encBytes, bool bPrintHeader) const;
+ virtual void DumpGCInfo(GCInfoToken gcInfoToken, unsigned methodSize, printfFtn gcPrintf, bool encBytes, bool bPrintHeader) const;
private:
X86Machine() {}
@@ -225,7 +225,7 @@ public:
virtual void GetGCRegisters(LPCSTR** regNames, unsigned int* cntRegs) const
{ _ASSERTE(cntRegs != NULL); *regNames = s_GCRegs; *cntRegs = _countof(s_GCRegs); }
- virtual void DumpGCInfo(BYTE* pTable, unsigned methodSize, printfFtn gcPrintf, bool encBytes, bool bPrintHeader) const;
+ virtual void DumpGCInfo(GCInfoToken gcInfoToken, unsigned methodSize, printfFtn gcPrintf, bool encBytes, bool bPrintHeader) const;
private:
ARMMachine() {}
@@ -293,7 +293,7 @@ public:
virtual void GetGCRegisters(LPCSTR** regNames, unsigned int* cntRegs) const
{ _ASSERTE(cntRegs != NULL); *regNames = s_GCRegs; *cntRegs = _countof(s_GCRegs); }
- virtual void DumpGCInfo(BYTE* pTable, unsigned methodSize, printfFtn gcPrintf, bool encBytes, bool bPrintHeader) const;
+ virtual void DumpGCInfo(GCInfoToken gcInfoToken, unsigned methodSize, printfFtn gcPrintf, bool encBytes, bool bPrintHeader) const;
private:
AMD64Machine() {}
@@ -357,7 +357,7 @@ public:
virtual void GetGCRegisters(LPCSTR** regNames, unsigned int* cntRegs) const
{ _ASSERTE(cntRegs != NULL); *regNames = s_GCRegs; *cntRegs = _countof(s_GCRegs);}
- virtual void DumpGCInfo(BYTE* pTable, unsigned methodSize, printfFtn gcPrintf, bool encBytes, bool bPrintHeader) const;
+ virtual void DumpGCInfo(GCInfoToken gcInfoToken, unsigned methodSize, printfFtn gcPrintf, bool encBytes, bool bPrintHeader) const;
private:
ARM64Machine() {}
diff --git a/src/ToolBox/SOS/Strike/disasmARM.cpp b/src/ToolBox/SOS/Strike/disasmARM.cpp
index 80dce71890..a82d4b9b65 100644
--- a/src/ToolBox/SOS/Strike/disasmARM.cpp
+++ b/src/ToolBox/SOS/Strike/disasmARM.cpp
@@ -607,7 +607,7 @@ BOOL ARMMachine::GetExceptionContext (TADDR stack, TADDR PC, TADDR *cxrAddr, CRO
///
/// Dump ARM GCInfo table
///
-void ARMMachine::DumpGCInfo(BYTE* pTable, unsigned methodSize, printfFtn gcPrintf, bool encBytes, bool bPrintHeader) const
+void ARMMachine::DumpGCInfo(GCInfoToken gcInfoToken, unsigned methodSize, printfFtn gcPrintf, bool encBytes, bool bPrintHeader) const
{
#ifndef FEATURE_PAL
if (bPrintHeader)
@@ -615,10 +615,10 @@ void ARMMachine::DumpGCInfo(BYTE* pTable, unsigned methodSize, printfFtn gcPrint
ExtOut("Pointer table:\n");
}
- ARMGCDump::GCDump gcDump(encBytes, 5, true);
+ ARMGCDump::GCDump gcDump(gcInfoToken.Version, encBytes, 5, true);
gcDump.gcPrintf = gcPrintf;
- gcDump.DumpGCTable(pTable, methodSize, 0);
+ gcDump.DumpGCTable(dac_cast<PTR_BYTE>(gcInfoToken.Info), methodSize, 0);
#endif // !FEATURE_PAL
}
diff --git a/src/ToolBox/SOS/Strike/disasmARM64.cpp b/src/ToolBox/SOS/Strike/disasmARM64.cpp
index 2c581bc946..4ac8c59105 100644
--- a/src/ToolBox/SOS/Strike/disasmARM64.cpp
+++ b/src/ToolBox/SOS/Strike/disasmARM64.cpp
@@ -377,16 +377,16 @@ BOOL ARM64Machine::GetExceptionContext (TADDR stack, TADDR PC, TADDR *cxrAddr, C
///
/// Dump ARM GCInfo table
///
-void ARM64Machine::DumpGCInfo(BYTE* pTable, unsigned methodSize, printfFtn gcPrintf, bool encBytes, bool bPrintHeader) const
+void ARM64Machine::DumpGCInfo(GCInfoToken gcInfoToken, unsigned methodSize, printfFtn gcPrintf, bool encBytes, bool bPrintHeader) const
{
if (bPrintHeader)
{
ExtOut("Pointer table:\n");
}
- ARM64GCDump::GCDump gcDump(encBytes, 5, true);
+ ARM64GCDump::GCDump gcDump(gcInfoToken.Version, encBytes, 5, true);
gcDump.gcPrintf = gcPrintf;
- gcDump.DumpGCTable(pTable, methodSize, 0);
+ gcDump.DumpGCTable(dac_cast<PTR_BYTE>(gcInfoToken.Info), methodSize, 0);
}
diff --git a/src/ToolBox/SOS/Strike/exts.h b/src/ToolBox/SOS/Strike/exts.h
index baef6d7084..36b5230c37 100644
--- a/src/ToolBox/SOS/Strike/exts.h
+++ b/src/ToolBox/SOS/Strike/exts.h
@@ -23,7 +23,6 @@
#pragma warning(disable:4430) // missing type specifier: C++ doesn't support default-int
#endif
#include "strike.h"
-
#include <wdbgexts.h>
#include <dbgeng.h>
#include <stdio.h>
@@ -43,6 +42,8 @@
// the DAC to read the DAC-ized data structures.
#include "daccess.h"
+#include "gcinfo.h"
+
// Convert between CLRDATA_ADDRESS and TADDR.
#define TO_TADDR(cdaddr) ((TADDR)(cdaddr))
#define TO_CDADDR(taddr) ((CLRDATA_ADDRESS)(LONG_PTR)(taddr))
@@ -386,7 +387,7 @@ public:
typedef void (*printfFtn)(const char* fmt, ...);
// Dumps the GCInfo
- virtual void DumpGCInfo(BYTE* pTable, unsigned methodSize, printfFtn gcPrintf, bool encBytes, bool bPrintHeader) const = 0;
+ virtual void DumpGCInfo(GCInfoToken gcInfoToken, unsigned methodSize, printfFtn gcPrintf, bool encBytes, bool bPrintHeader) const = 0;
protected:
IMachine() {}
diff --git a/src/ToolBox/SOS/Strike/strike.cpp b/src/ToolBox/SOS/Strike/strike.cpp
index 024293c2a4..df4a18443f 100644
--- a/src/ToolBox/SOS/Strike/strike.cpp
+++ b/src/ToolBox/SOS/Strike/strike.cpp
@@ -2229,13 +2229,13 @@ size_t FormatGeneratedException (DWORD_PTR dataPtr,
__out_ecount_opt(bufferLength) WCHAR *wszBuffer,
size_t bufferLength,
BOOL bAsync,
- BOOL bNestedCase=FALSE,
- BOOL bLineNumbers=FALSE)
+ BOOL bNestedCase = FALSE,
+ BOOL bLineNumbers = FALSE)
{
UINT count = bytes / sizeof(StackTraceElement);
size_t Length = 0;
- if (wszBuffer && bufferLength>0)
+ if (wszBuffer && bufferLength > 0)
{
wszBuffer[0] = L'\0';
}
@@ -2243,7 +2243,7 @@ size_t FormatGeneratedException (DWORD_PTR dataPtr,
// Buffer is calculated for sprintf below (" %p %p %S\n");
WCHAR wszLineBuffer[mdNameLen + 8 + sizeof(size_t)*2 + MAX_LONGPATH + 8];
- if (count==0)
+ if (count == 0)
{
return 0;
}
@@ -2307,22 +2307,13 @@ size_t FormatGeneratedException (DWORD_PTR dataPtr,
{
char filename[MAX_LONGPATH+1] = "";
ULONG linenum = 0;
- if (bLineNumbers
- && FAILED(GetLineByOffset(TO_CDADDR(ste.ip),
- &linenum,
- filename,
- _countof(filename))))
- {
- bLineNumbers = FALSE;
- }
-
- if (!bLineNumbers)
+ if (bLineNumbers && SUCCEEDED(GetLineByOffset(TO_CDADDR(ste.ip), &linenum, filename, _countof(filename))))
{
- swprintf_s(wszLineBuffer, _countof(wszLineBuffer), W(" %s\n"), so.String());
+ swprintf_s(wszLineBuffer, _countof(wszLineBuffer), W(" %s [%S @ %d]\n"), so.String(), filename, linenum);
}
else
{
- swprintf_s(wszLineBuffer, _countof(wszLineBuffer), W(" %s [%S @ %d]\n"), so.String(), filename, linenum);
+ swprintf_s(wszLineBuffer, _countof(wszLineBuffer), W(" %s\n"), so.String());
}
Length += _wcslen(wszLineBuffer);
@@ -7116,9 +7107,13 @@ DECLARE_API(bpmd)
// did we get dll and type name or file:line#? Search for a colon in the first arg
// to see if it is in fact a file:line#
CHAR* pColon = strchr(DllName.data, ':');
+#ifndef FEATURE_PAL
+ if (FAILED(g_ExtSymbols->GetModuleByModuleName(MAIN_CLR_MODULE_NAME_A, 0, NULL, NULL))) {
+#else
if (FAILED(g_ExtSymbols->GetModuleByModuleName(MAIN_CLR_DLL_NAME_A, 0, NULL, NULL))) {
- ExtOut("File name:Line number not supported\n");
- fBadParam = true;
+#endif
+ ExtOut("%s not loaded yet\n", MAIN_CLR_DLL_NAME_A);
+ return Status;
}
if(NULL != pColon)
@@ -8022,10 +8017,10 @@ DECLARE_API(GCInfo)
// Mutable table pointer since we need to pass the appropriate
// offset into the table to DumpGCTable.
- BYTE *pTable = table;
+ GCInfoToken gcInfoToken = { table, GCINFO_VERSION };
unsigned int methodSize = (unsigned int)codeHeaderData.MethodSize;
- g_targetMachine->DumpGCInfo(pTable, methodSize, ExtOut, true /*encBytes*/, true /*bPrintHeader*/);
+ g_targetMachine->DumpGCInfo(gcInfoToken, methodSize, ExtOut, true /*encBytes*/, true /*bPrintHeader*/);
return Status;
}
@@ -8106,8 +8101,8 @@ void DecodeGCTableEntry (const char *fmt, ...)
VOID CALLBACK DumpGCTableFiberEntry (LPVOID pvGCEncodingInfo)
{
GCEncodingInfo *pInfo = (GCEncodingInfo*)pvGCEncodingInfo;
-
- g_targetMachine->DumpGCInfo(pInfo->table, pInfo->methodSize, DecodeGCTableEntry, false /*encBytes*/, false /*bPrintHeader*/);
+ GCInfoToken gcInfoToken = { pInfo, GCINFO_VERSION };
+ g_targetMachine->DumpGCInfo(gcInfoToken, pInfo->methodSize, DecodeGCTableEntry, false /*encBytes*/, false /*bPrintHeader*/);
pInfo->fDoneDecoding = true;
SwitchToFiber(pInfo->pvMainFiber);
diff --git a/src/ToolBox/SOS/Strike/util.cpp b/src/ToolBox/SOS/Strike/util.cpp
index bdf5be25e6..16c382dd0f 100644
--- a/src/ToolBox/SOS/Strike/util.cpp
+++ b/src/ToolBox/SOS/Strike/util.cpp
@@ -6229,16 +6229,20 @@ HRESULT SymbolReader::LoadCoreCLR()
{
HRESULT Status = S_OK;
- std::string absolutePath, coreClrPath;
- absolutePath = g_ExtServices->GetCoreClrDirectory();
- GetDirectory(absolutePath.c_str(), coreClrPath);
+ std::string absolutePath;
+ std::string coreClrPath = g_ExtServices->GetCoreClrDirectory();
+ if (!GetAbsolutePath(coreClrPath.c_str(), absolutePath))
+ {
+ ExtErr("Error: fail to convert CLR files path to absolute path \n");
+ return E_FAIL;
+ }
coreClrPath.append("/");
coreClrPath.append(coreClrDll);
coreclrLib = dlopen(coreClrPath.c_str(), RTLD_NOW | RTLD_LOCAL);
if (coreclrLib == nullptr)
{
- fprintf(stderr, "Error: Fail to load %s\n", coreClrPath.c_str());
+ ExtErr("Error: Fail to load %s\n", coreClrPath.c_str());
return E_FAIL;
}
void *hostHandle;
@@ -6270,7 +6274,7 @@ HRESULT SymbolReader::LoadCoreCLR()
if (!GetEntrypointExecutableAbsolutePath(entryPointExecutablePath))
{
- perror("Could not get full path to current executable");
+ ExtErr("Could not get full path to current executable");
return E_FAIL;
}
@@ -6280,7 +6284,7 @@ HRESULT SymbolReader::LoadCoreCLR()
propertyKeys, propertyValues, &hostHandle, &domainId);
if (Status != S_OK)
{
- fprintf(stderr, "Error: Fail to initialize CoreCLR\n");
+ ExtErr("Error: Fail to initialize CoreCLR\n");
return Status;
}
diff --git a/src/coreclr/hosts/unixcoreruncommon/coreruncommon.cpp b/src/coreclr/hosts/unixcoreruncommon/coreruncommon.cpp
index 92581faa64..b4c54ca6e3 100644
--- a/src/coreclr/hosts/unixcoreruncommon/coreruncommon.cpp
+++ b/src/coreclr/hosts/unixcoreruncommon/coreruncommon.cpp
@@ -16,7 +16,11 @@
#include <string>
#include <string.h>
#include <sys/stat.h>
-#ifdef HAVE_SYS_SYSCTL_H
+#if defined(__FreeBSD__)
+#include <sys/types.h>
+#include <sys/param.h>
+#endif
+#if defined(HAVE_SYS_SYSCTL_H) || defined(__FreeBSD__)
#include <sys/sysctl.h>
#endif
#include "coreruncommon.h"
@@ -75,6 +79,24 @@ bool GetEntrypointExecutableAbsolutePath(std::string& entrypointExecutable)
result = true;
}
}
+#elif defined (__FreeBSD__)
+ static const int name[] = {
+ CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1
+ };
+ char path[PATH_MAX];
+ size_t len;
+
+ len = sizeof(path);
+ if (sysctl(name, 4, path, &len, nullptr, 0) == 0)
+ {
+ entrypointExecutable.assign(path);
+ result = true;
+ }
+ else
+ {
+ // ENOMEM
+ result = false;
+ }
#elif defined(__NetBSD__) && defined(KERN_PROC_PATHNAME)
static const int name[] = {
CTL_KERN, KERN_PROC_ARGS, -1, KERN_PROC_PATHNAME,
diff --git a/src/debug/daccess/daccess.cpp b/src/debug/daccess/daccess.cpp
index 4f500d9e6a..ba3995b1f7 100644
--- a/src/debug/daccess/daccess.cpp
+++ b/src/debug/daccess/daccess.cpp
@@ -2339,7 +2339,7 @@ namespace serialization { namespace bin {
};
template <typename _Ty>
- class is_blittable<_Ty, typename std::enable_if<std::is_arithmetic<_Ty>::value>::type>
+ struct is_blittable<_Ty, typename std::enable_if<std::is_arithmetic<_Ty>::value>::type>
: std::true_type
{ // determines whether _Ty is blittable
};
@@ -2347,7 +2347,7 @@ namespace serialization { namespace bin {
// allow types to declare themselves blittable by including a static bool
// member "is_blittable".
template <typename _Ty>
- class is_blittable<_Ty, typename std::enable_if<_Ty::is_blittable>::type>
+ struct is_blittable<_Ty, typename std::enable_if<_Ty::is_blittable>::type>
: std::true_type
{ // determines whether _Ty is blittable
};
@@ -6012,7 +6012,7 @@ ClrDataAccess::GetMethodExtents(MethodDesc* methodDesc,
EECodeInfo codeInfo(methodStart);
_ASSERTE(codeInfo.IsValid());
- TADDR codeSize = codeInfo.GetCodeManager()->GetFunctionSize(codeInfo.GetGCInfo());
+ TADDR codeSize = codeInfo.GetCodeManager()->GetFunctionSize(codeInfo.GetGCInfoToken());
*extents = new (nothrow) METH_EXTENTS;
if (!*extents)
diff --git a/src/debug/daccess/enummem.cpp b/src/debug/daccess/enummem.cpp
index f88fb628ba..068c2f2b13 100644
--- a/src/debug/daccess/enummem.cpp
+++ b/src/debug/daccess/enummem.cpp
@@ -979,10 +979,11 @@ HRESULT ClrDataAccess::EnumMemWalkStackHelper(CLRDataEnumMemoryFlags flags,
codeInfo.GetJitManager()->IsFilterFunclet(&codeInfo);
// The stackwalker needs GC info to find the parent 'stack pointer' or PSP
- PTR_BYTE pGCInfo = dac_cast<PTR_BYTE>(codeInfo.GetGCInfo());
+ GCInfoToken gcInfoToken = codeInfo.GetGCInfoToken();
+ PTR_BYTE pGCInfo = dac_cast<PTR_BYTE>(gcInfoToken.Info);
if (pGCInfo != NULL)
{
- GcInfoDecoder gcDecoder(pGCInfo, DECODE_PSP_SYM, 0);
+ GcInfoDecoder gcDecoder(gcInfoToken, DECODE_PSP_SYM, 0);
DacEnumMemoryRegion(dac_cast<TADDR>(pGCInfo), gcDecoder.GetNumBytesRead(), true);
}
}
diff --git a/src/debug/daccess/nidump.cpp b/src/debug/daccess/nidump.cpp
index 6de9ec0b94..d151a54212 100644
--- a/src/debug/daccess/nidump.cpp
+++ b/src/debug/daccess/nidump.cpp
@@ -3093,7 +3093,8 @@ void NativeImageDumper::DumpCompleteMethod(PTR_Module module, MethodIterator& mi
unsigned gcInfoSize = UINT_MAX;
//parse GCInfo for size information.
- PTR_CBYTE gcInfo = dac_cast<PTR_CBYTE>(mi.GetGCInfo());
+ GCInfoToken gcInfoToken = mi.GetGCInfoToken();
+ PTR_CBYTE gcInfo = dac_cast<PTR_CBYTE>(gcInfoToken.Info);
void (* stringOutFn)(const char *, ...);
IF_OPT(GC_INFO)
@@ -3108,10 +3109,10 @@ void NativeImageDumper::DumpCompleteMethod(PTR_Module module, MethodIterator& mi
{
PTR_CBYTE curGCInfoPtr = gcInfo;
g_holdStringOutData.Clear();
- GCDump gcDump;
+ GCDump gcDump(gcInfoToken.Version);
gcDump.gcPrintf = stringOutFn;
#if !defined(_TARGET_X86_) && defined(USE_GC_INFO_DECODER)
- GcInfoDecoder gcInfoDecoder(curGCInfoPtr, DECODE_CODE_LENGTH, 0);
+ GcInfoDecoder gcInfoDecoder(gcInfoToken, DECODE_CODE_LENGTH, 0);
methodSize = gcInfoDecoder.GetCodeLength();
#endif
@@ -3119,7 +3120,7 @@ void NativeImageDumper::DumpCompleteMethod(PTR_Module module, MethodIterator& mi
#ifdef _TARGET_X86_
InfoHdr hdr;
stringOutFn( "method info Block:\n" );
- curGCInfoPtr += gcDump.DumpInfoHdr(curGCInfoPtr, &hdr, &methodSize, 0);
+ curGCInfoPtr += gcDump.DumpInfoHdr(PTR_CBYTE(gcInfoToken.Info), &hdr, &methodSize, 0);
stringOutFn( "\n" );
#endif
@@ -9436,10 +9437,10 @@ void NativeImageDumper::DumpReadyToRunMethod(PCODE pEntryPoint, PTR_RUNTIME_FUNC
{
PTR_CBYTE curGCInfoPtr = gcInfo;
g_holdStringOutData.Clear();
- GCDump gcDump;
+ GCDump gcDump(GCINFO_VERSION);
gcDump.gcPrintf = stringOutFn;
#if !defined(_TARGET_X86_) && defined(USE_GC_INFO_DECODER)
- GcInfoDecoder gcInfoDecoder(curGCInfoPtr, DECODE_CODE_LENGTH, 0);
+ GcInfoDecoder gcInfoDecoder({ curGCInfoPtr, GCINFO_VERSION }, DECODE_CODE_LENGTH, 0);
methodSize = gcInfoDecoder.GetCodeLength();
#endif
diff --git a/src/debug/daccess/request.cpp b/src/debug/daccess/request.cpp
index 9e864769c4..62dd5f51f9 100644
--- a/src/debug/daccess/request.cpp
+++ b/src/debug/daccess/request.cpp
@@ -1148,7 +1148,7 @@ ClrDataAccess::GetCodeHeaderData(CLRDATA_ADDRESS ip, struct DacpCodeHeaderData *
codeHeaderData->MethodStart =
(CLRDATA_ADDRESS) codeInfo.GetStartAddress();
- size_t methodSize = codeInfo.GetCodeManager()->GetFunctionSize(codeInfo.GetGCInfo());
+ size_t methodSize = codeInfo.GetCodeManager()->GetFunctionSize(codeInfo.GetGCInfoToken());
_ASSERTE(FitsIn<DWORD>(methodSize));
codeHeaderData->MethodSize = static_cast<DWORD>(methodSize);
diff --git a/src/gc/env/gcenv.base.h b/src/gc/env/gcenv.base.h
index 329ac6e1dc..97f1661b0d 100644
--- a/src/gc/env/gcenv.base.h
+++ b/src/gc/env/gcenv.base.h
@@ -176,6 +176,12 @@ typedef DWORD (WINAPI *PTHREAD_START_ROUTINE)(void* lpThreadParameter);
#endif // _MSC_VER
+typedef struct _PROCESSOR_NUMBER {
+ uint16_t Group;
+ uint8_t Number;
+ uint8_t Reserved;
+} PROCESSOR_NUMBER, *PPROCESSOR_NUMBER;
+
#endif // _INC_WINDOWS
// -----------------------------------------------------------------------------------------------------------
@@ -463,13 +469,6 @@ public:
static HANDLE GetFinalizerEvent();
};
-#ifdef FEATURE_REDHAWK
-typedef uint32_t (__stdcall *BackgroundCallback)(void* pCallbackContext);
-REDHAWK_PALIMPORT bool REDHAWK_PALAPI PalStartBackgroundGCThread(BackgroundCallback callback, void* pCallbackContext);
-#endif // FEATURE_REDHAWK
-
-void DestroyThread(Thread * pThread);
-
bool IsGCSpecialThread();
inline bool dbgOnly_IsSpecialEEThread()
@@ -607,4 +606,21 @@ public:
};
#endif // STRESS_HEAP
+class NumaNodeInfo
+{
+public:
+ static bool CanEnableGCNumaAware();
+ static void GetGroupForProcessor(uint16_t processor_number, uint16_t * group_number, uint16_t * group_processor_number);
+ static bool GetNumaProcessorNodeEx(PPROCESSOR_NUMBER proc_no, uint16_t * node_no);
+};
+
+class CPUGroupInfo
+{
+public:
+ static bool CanEnableGCCPUGroups();
+ static uint32_t GetNumActiveProcessors();
+ static void GetGroupForProcessor(uint16_t processor_number, uint16_t * group_number, uint16_t * group_processor_number);
+};
+
+
#endif // __GCENV_BASE_INCLUDED__
diff --git a/src/gc/env/gcenv.ee.h b/src/gc/env/gcenv.ee.h
index 42f47c4b18..0c1fd4988a 100644
--- a/src/gc/env/gcenv.ee.h
+++ b/src/gc/env/gcenv.ee.h
@@ -74,13 +74,12 @@ public:
static void EnablePreemptiveGC(Thread * pThread);
static void DisablePreemptiveGC(Thread * pThread);
- static void SetGCSpecial(Thread * pThread);
static alloc_context * GetAllocContext(Thread * pThread);
static bool CatchAtSafePoint(Thread * pThread);
static void GcEnumAllocContexts(enum_alloc_context_func* fn, void* param);
- static bool CreateBackgroundThread(Thread** thread, GCBackgroundThreadFunction threadStart, void* arg);
+ static Thread* CreateBackgroundThread(GCBackgroundThreadFunction threadStart, void* arg);
};
#endif // __GCENV_EE_H__
diff --git a/src/gc/env/gcenv.sync.h b/src/gc/env/gcenv.sync.h
index 5e3486ae27..d6bee05a19 100644
--- a/src/gc/env/gcenv.sync.h
+++ b/src/gc/env/gcenv.sync.h
@@ -128,10 +128,11 @@ public:
class CLREventStatic
{
public:
- void CreateManualEvent(bool bInitialState);
- void CreateAutoEvent(bool bInitialState);
- void CreateOSManualEvent(bool bInitialState);
- void CreateOSAutoEvent(bool bInitialState);
+ bool CreateAutoEventNoThrow(bool bInitialState);
+ bool CreateManualEventNoThrow(bool bInitialState);
+ bool CreateOSAutoEventNoThrow(bool bInitialState);
+ bool CreateOSManualEventNoThrow(bool bInitialState);
+
void CloseEvent();
bool IsValid() const;
bool Set();
diff --git a/src/gc/gc.cpp b/src/gc/gc.cpp
index 024c87a66f..33004211e2 100644
--- a/src/gc/gc.cpp
+++ b/src/gc/gc.cpp
@@ -690,9 +690,8 @@ public:
// for an OS event on a managed thread.
// But we are not sure if this plays well in the hosting
// environment.
- //join_struct.joined_event[i].CreateOSManualEvent(FALSE);
- join_struct.joined_event[i].CreateManualEvent(FALSE);
- if (!join_struct.joined_event[i].IsValid())
+ //join_struct.joined_event[i].CreateOSManualEventNoThrow(FALSE);
+ if (!join_struct.joined_event[i].CreateManualEventNoThrow(FALSE))
return FALSE;
}
}
@@ -1221,13 +1220,11 @@ BOOL recursive_gc_sync::init ()
gc_background_running = FALSE;
foreground_gate = 0;
- foreground_complete.CreateOSAutoEvent(FALSE);
- if (!foreground_complete.IsValid())
+ if (!foreground_complete.CreateOSAutoEventNoThrow(FALSE))
{
goto error;
}
- foreground_allowed.CreateManualEvent(FALSE);
- if (!foreground_allowed.IsValid())
+ if (!foreground_allowed.CreateManualEventNoThrow(FALSE))
{
goto error;
}
@@ -2274,7 +2271,7 @@ SPTR_IMPL_NS(PTR_gc_heap, SVR, gc_heap, g_heaps);
size_t* gc_heap::g_promoted;
#ifdef MH_SC_MARK
-BOOL* gc_heap::g_mark_stack_busy;
+int* gc_heap::g_mark_stack_busy;
#endif //MH_SC_MARK
@@ -2533,8 +2530,6 @@ gc_history_per_heap gc_heap::bgc_data_per_heap;
BOOL gc_heap::bgc_thread_running;
-CLREvent gc_heap::background_gc_create_event;
-
CLRCriticalSection gc_heap::bgc_threads_timeout_cs;
CLREvent gc_heap::gc_lh_block_event;
@@ -4926,7 +4921,7 @@ public:
return TRUE;
}
- static void init_cpu_mapping(gc_heap *heap, int heap_number)
+ static void init_cpu_mapping(gc_heap * /*heap*/, int heap_number)
{
if (GCToOSInterface::CanGetCurrentProcessorNumber())
{
@@ -4947,8 +4942,10 @@ public:
sniff_buffer[(1 + heap_number*n_sniff_buffers + sniff_index)*HS_CACHE_LINE_SIZE] &= 1;
}
- static int select_heap(alloc_context* acontext, int hint)
+ static int select_heap(alloc_context* acontext, int /*hint*/)
{
+ UNREFERENCED_PARAMETER(acontext); // only referenced by dprintf
+
if (GCToOSInterface::CanGetCurrentProcessorNumber())
return proc_no_to_heap_no[GCToOSInterface::GetCurrentProcessorNumber() % gc_heap::n_heaps];
@@ -5071,13 +5068,11 @@ uint8_t heap_select::numa_node_to_heap_map[MAX_SUPPORTED_CPUS+4];
BOOL gc_heap::create_thread_support (unsigned number_of_heaps)
{
BOOL ret = FALSE;
- gc_start_event.CreateOSManualEvent (FALSE);
- if (!gc_start_event.IsValid())
+ if (!gc_start_event.CreateOSManualEventNoThrow (FALSE))
{
goto cleanup;
}
- ee_suspend_event.CreateOSAutoEvent (FALSE);
- if (!ee_suspend_event.IsValid())
+ if (!ee_suspend_event.CreateOSAutoEventNoThrow (FALSE))
{
goto cleanup;
}
@@ -5110,7 +5105,7 @@ void gc_heap::destroy_thread_support ()
}
}
-#if !defined(FEATURE_REDHAWK) && !defined(FEATURE_PAL)
+#if !defined(FEATURE_PAL)
void set_thread_group_affinity_for_heap(int heap_number, GCThreadAffinity* affinity)
{
affinity->Group = GCThreadAffinity::None;
@@ -5190,7 +5185,7 @@ void set_thread_affinity_mask_for_heap(int heap_number, GCThreadAffinity* affini
}
}
}
-#endif // !FEATURE_REDHAWK && !FEATURE_CORECLR
+#endif // !FEATURE_PAL
bool gc_heap::create_gc_thread ()
{
@@ -5200,7 +5195,7 @@ bool gc_heap::create_gc_thread ()
affinity.Group = GCThreadAffinity::None;
affinity.Processor = GCThreadAffinity::None;
-#if !defined(FEATURE_REDHAWK) && !defined(FEATURE_PAL)
+#if !defined(FEATURE_PAL)
if (!gc_thread_no_affinitize_p)
{
//We are about to set affinity for GC threads, it is a good place to setup NUMA and
@@ -5211,7 +5206,7 @@ bool gc_heap::create_gc_thread ()
else
set_thread_affinity_mask_for_heap(heap_number, &affinity);
}
-#endif // !FEATURE_REDHAWK && !FEATURE_PAL
+#endif // !FEATURE_PAL
return GCToOSInterface::CreateThread(gc_thread_stub, this, &affinity);
}
@@ -7141,7 +7136,7 @@ int gc_heap::grow_brick_card_tables (uint8_t* start,
dprintf (GC_TABLE_LOG, ("Table alloc for %Id bytes: [%Ix, %Ix[",
alloc_size, (size_t)mem, (size_t)((uint8_t*)mem+alloc_size)));
- {
+ {
// mark array will be committed separately (per segment).
size_t commit_size = alloc_size - ms;
@@ -9940,13 +9935,11 @@ gc_heap::init_semi_shared()
segment_standby_list = 0;
- full_gc_approach_event.CreateManualEvent(FALSE);
- if (!full_gc_approach_event.IsValid())
+ if (!full_gc_approach_event.CreateManualEventNoThrow(FALSE))
{
goto cleanup;
}
- full_gc_end_event.CreateManualEvent(FALSE);
- if (!full_gc_end_event.IsValid())
+ if (!full_gc_end_event.CreateManualEventNoThrow(FALSE))
{
goto cleanup;
}
@@ -10279,8 +10272,7 @@ gc_heap::init_gc_heap (int h_number)
memset (&oom_info, 0, sizeof (oom_info));
memset (&fgm_result, 0, sizeof (fgm_result));
- gc_done_event.CreateManualEvent(FALSE);
- if (!gc_done_event.IsValid())
+ if (!gc_done_event.CreateManualEventNoThrow(FALSE))
{
return 0;
}
@@ -13189,7 +13181,7 @@ try_again:
org_hp->alloc_context_count--;
max_hp->alloc_context_count++;
acontext->alloc_heap = GCHeap::GetHeap(max_hp->heap_number);
-#if !defined(FEATURE_REDHAWK) && !defined(FEATURE_PAL)
+#if !defined(FEATURE_PAL)
if (CPUGroupInfo::CanEnableGCCPUGroups())
{ //only set ideal processor when max_hp and org_hp are in the same cpu
//group. DO NOT MOVE THREADS ACROSS CPU GROUPS
@@ -13223,7 +13215,7 @@ try_again:
org_hp->heap_number));
}
}
-#endif // !FEATURE_REDHAWK && !FEATURE_PAL
+#endif // !FEATURE_PAL
dprintf (3, ("Switching context %p (home heap %d) ",
acontext,
acontext->home_heap->pGenGCHeap->heap_number));
@@ -13242,7 +13234,7 @@ try_again:
acontext->alloc_count++;
}
-gc_heap* gc_heap::balance_heaps_loh (alloc_context* acontext, size_t size)
+gc_heap* gc_heap::balance_heaps_loh (alloc_context* acontext, size_t /*size*/)
{
gc_heap* org_hp = acontext->alloc_heap->pGenGCHeap;
//dprintf (1, ("LA: %Id", size));
@@ -15350,21 +15342,6 @@ void gc_heap::gc1()
assert (ephemeral_high == heap_segment_reserved (ephemeral_heap_segment));
#endif //BACKGROUND_GC
- int bottom_gen = 0;
-#ifdef BACKGROUND_GC
- if (settings.concurrent)
- {
- bottom_gen = max_generation;
- }
-#endif //BACKGROUND_GC
- {
- for (int gen_number = bottom_gen; gen_number <= max_generation+1; gen_number++)
- {
- dynamic_data* dd = dynamic_data_of (gen_number);
- dd_new_allocation(dd) = dd_gc_new_allocation (dd);
- }
- }
-
if (fgn_maxgen_percent)
{
if (settings.condemned_generation == (max_generation - 1))
@@ -16319,474 +16296,457 @@ void gc_heap::init_records()
int gc_heap::garbage_collect (int n)
{
- //TODO BACKGROUND_GC remove these when ready
-#ifndef NO_CATCH_HANDLERS
- PAL_TRY
-#endif //NO_CATCH_HANDLERS
- {
- //reset the number of alloc contexts
- alloc_contexts_used = 0;
+ //reset the number of alloc contexts
+ alloc_contexts_used = 0;
- fix_allocation_contexts (TRUE);
+ fix_allocation_contexts (TRUE);
#ifdef MULTIPLE_HEAPS
- clear_gen0_bricks();
+ clear_gen0_bricks();
#endif //MULTIPLE_HEAPS
- if ((settings.pause_mode == pause_no_gc) && current_no_gc_region_info.minimal_gc_p)
- {
+ if ((settings.pause_mode == pause_no_gc) && current_no_gc_region_info.minimal_gc_p)
+ {
#ifdef MULTIPLE_HEAPS
- gc_t_join.join(this, gc_join_minimal_gc);
- if (gc_t_join.joined())
- {
+ gc_t_join.join(this, gc_join_minimal_gc);
+ if (gc_t_join.joined())
+ {
#endif //MULTIPLE_HEAPS
#ifdef MULTIPLE_HEAPS
- // this is serialized because we need to get a segment
- for (int i = 0; i < n_heaps; i++)
- {
- if (!(g_heaps[i]->expand_soh_with_minimal_gc()))
- current_no_gc_region_info.start_status = start_no_gc_no_memory;
- }
-#else
- if (!expand_soh_with_minimal_gc())
+ // this is serialized because we need to get a segment
+ for (int i = 0; i < n_heaps; i++)
+ {
+ if (!(g_heaps[i]->expand_soh_with_minimal_gc()))
current_no_gc_region_info.start_status = start_no_gc_no_memory;
+ }
+#else
+ if (!expand_soh_with_minimal_gc())
+ current_no_gc_region_info.start_status = start_no_gc_no_memory;
#endif //MULTIPLE_HEAPS
- update_collection_counts_for_no_gc();
+ update_collection_counts_for_no_gc();
#ifdef MULTIPLE_HEAPS
- gc_t_join.restart();
- }
+ gc_t_join.restart();
+ }
#endif //MULTIPLE_HEAPS
- goto done;
- }
+ goto done;
+ }
- init_records();
- memset (&fgm_result, 0, sizeof (fgm_result));
+ init_records();
+ memset (&fgm_result, 0, sizeof (fgm_result));
- settings.reason = gc_trigger_reason;
- verify_pinned_queue_p = FALSE;
+ settings.reason = gc_trigger_reason;
+ verify_pinned_queue_p = FALSE;
#if defined(ENABLE_PERF_COUNTERS) || defined(FEATURE_EVENT_TRACE)
num_pinned_objects = 0;
#endif //ENABLE_PERF_COUNTERS || FEATURE_EVENT_TRACE
#ifdef STRESS_HEAP
- if (settings.reason == reason_gcstress)
- {
- settings.reason = reason_induced;
- settings.stress_induced = TRUE;
- }
+ if (settings.reason == reason_gcstress)
+ {
+ settings.reason = reason_induced;
+ settings.stress_induced = TRUE;
+ }
#endif // STRESS_HEAP
#ifdef MULTIPLE_HEAPS
- //align all heaps on the max generation to condemn
- dprintf (3, ("Joining for max generation to condemn"));
- condemned_generation_num = generation_to_condemn (n,
- &blocking_collection,
- &elevation_requested,
- FALSE);
- gc_t_join.join(this, gc_join_generation_determined);
- if (gc_t_join.joined())
+ //align all heaps on the max generation to condemn
+ dprintf (3, ("Joining for max generation to condemn"));
+ condemned_generation_num = generation_to_condemn (n,
+ &blocking_collection,
+ &elevation_requested,
+ FALSE);
+ gc_t_join.join(this, gc_join_generation_determined);
+ if (gc_t_join.joined())
#endif //MULTIPLE_HEAPS
- {
+ {
#ifdef TRACE_GC
- int gc_count = (int)dd_collection_count (dynamic_data_of (0));
- if (gc_count >= g_pConfig->GetGCtraceStart())
- trace_gc = 1;
- if (gc_count >= g_pConfig->GetGCtraceEnd())
- trace_gc = 0;
+ int gc_count = (int)dd_collection_count (dynamic_data_of (0));
+ if (gc_count >= g_pConfig->GetGCtraceStart())
+ trace_gc = 1;
+ if (gc_count >= g_pConfig->GetGCtraceEnd())
+ trace_gc = 0;
#endif //TRACE_GC
#ifdef MULTIPLE_HEAPS
#if !defined(SEG_MAPPING_TABLE) && !defined(FEATURE_BASICFREEZE)
- //delete old slots from the segment table
- seg_table->delete_old_slots();
+ //delete old slots from the segment table
+ seg_table->delete_old_slots();
#endif //!SEG_MAPPING_TABLE && !FEATURE_BASICFREEZE
- for (int i = 0; i < n_heaps; i++)
+ for (int i = 0; i < n_heaps; i++)
+ {
+ //copy the card and brick tables
+ if (g_card_table != g_heaps[i]->card_table)
{
- //copy the card and brick tables
- if (g_card_table != g_heaps[i]->card_table)
- {
- g_heaps[i]->copy_brick_card_table();
- }
+ g_heaps[i]->copy_brick_card_table();
+ }
- g_heaps[i]->rearrange_large_heap_segments();
- if (!recursive_gc_sync::background_running_p())
- {
- g_heaps[i]->rearrange_small_heap_segments();
- }
+ g_heaps[i]->rearrange_large_heap_segments();
+ if (!recursive_gc_sync::background_running_p())
+ {
+ g_heaps[i]->rearrange_small_heap_segments();
}
+ }
#else //MULTIPLE_HEAPS
#ifdef BACKGROUND_GC
- //delete old slots from the segment table
+ //delete old slots from the segment table
#if !defined(SEG_MAPPING_TABLE) && !defined(FEATURE_BASICFREEZE)
- seg_table->delete_old_slots();
+ seg_table->delete_old_slots();
#endif //!SEG_MAPPING_TABLE && !FEATURE_BASICFREEZE
- rearrange_large_heap_segments();
- if (!recursive_gc_sync::background_running_p())
- {
- rearrange_small_heap_segments();
- }
+ rearrange_large_heap_segments();
+ if (!recursive_gc_sync::background_running_p())
+ {
+ rearrange_small_heap_segments();
+ }
#endif //BACKGROUND_GC
- // check for card table growth
- if (g_card_table != card_table)
- copy_brick_card_table();
+ // check for card table growth
+ if (g_card_table != card_table)
+ copy_brick_card_table();
#endif //MULTIPLE_HEAPS
- BOOL should_evaluate_elevation = FALSE;
- BOOL should_do_blocking_collection = FALSE;
+ BOOL should_evaluate_elevation = FALSE;
+ BOOL should_do_blocking_collection = FALSE;
#ifdef MULTIPLE_HEAPS
- int gen_max = condemned_generation_num;
- for (int i = 0; i < n_heaps; i++)
- {
- if (gen_max < g_heaps[i]->condemned_generation_num)
- gen_max = g_heaps[i]->condemned_generation_num;
- if ((!should_evaluate_elevation) && (g_heaps[i]->elevation_requested))
- should_evaluate_elevation = TRUE;
- if ((!should_do_blocking_collection) && (g_heaps[i]->blocking_collection))
- should_do_blocking_collection = TRUE;
- }
+ int gen_max = condemned_generation_num;
+ for (int i = 0; i < n_heaps; i++)
+ {
+ if (gen_max < g_heaps[i]->condemned_generation_num)
+ gen_max = g_heaps[i]->condemned_generation_num;
+ if ((!should_evaluate_elevation) && (g_heaps[i]->elevation_requested))
+ should_evaluate_elevation = TRUE;
+ if ((!should_do_blocking_collection) && (g_heaps[i]->blocking_collection))
+ should_do_blocking_collection = TRUE;
+ }
- settings.condemned_generation = gen_max;
+ settings.condemned_generation = gen_max;
//logically continues after GC_PROFILING.
#else //MULTIPLE_HEAPS
- settings.condemned_generation = generation_to_condemn (n,
- &blocking_collection,
- &elevation_requested,
- FALSE);
- should_evaluate_elevation = elevation_requested;
- should_do_blocking_collection = blocking_collection;
-#endif //MULTIPLE_HEAPS
-
- settings.condemned_generation = joined_generation_to_condemn (
- should_evaluate_elevation,
- settings.condemned_generation,
- &should_do_blocking_collection
- STRESS_HEAP_ARG(n)
- );
+ settings.condemned_generation = generation_to_condemn (n,
+ &blocking_collection,
+ &elevation_requested,
+ FALSE);
+ should_evaluate_elevation = elevation_requested;
+ should_do_blocking_collection = blocking_collection;
+#endif //MULTIPLE_HEAPS
- STRESS_LOG1(LF_GCROOTS|LF_GC|LF_GCALLOC, LL_INFO10,
- "condemned generation num: %d\n", settings.condemned_generation);
+ settings.condemned_generation = joined_generation_to_condemn (
+ should_evaluate_elevation,
+ settings.condemned_generation,
+ &should_do_blocking_collection
+ STRESS_HEAP_ARG(n)
+ );
- record_gcs_during_no_gc();
+ STRESS_LOG1(LF_GCROOTS|LF_GC|LF_GCALLOC, LL_INFO10,
+ "condemned generation num: %d\n", settings.condemned_generation);
- if (settings.condemned_generation > 1)
- settings.promotion = TRUE;
+ record_gcs_during_no_gc();
+
+ if (settings.condemned_generation > 1)
+ settings.promotion = TRUE;
#ifdef HEAP_ANALYZE
- // At this point we've decided what generation is condemned
- // See if we've been requested to analyze survivors after the mark phase
- if (AnalyzeSurvivorsRequested(settings.condemned_generation))
- {
- heap_analyze_enabled = TRUE;
- }
+ // At this point we've decided what generation is condemned
+ // See if we've been requested to analyze survivors after the mark phase
+ if (AnalyzeSurvivorsRequested(settings.condemned_generation))
+ {
+ heap_analyze_enabled = TRUE;
+ }
#endif // HEAP_ANALYZE
#ifdef GC_PROFILING
- // If we're tracking GCs, then we need to walk the first generation
- // before collection to track how many items of each class has been
- // allocated.
- UpdateGenerationBounds();
- GarbageCollectionStartedCallback(settings.condemned_generation, settings.reason == reason_induced);
- {
- BEGIN_PIN_PROFILER(CORProfilerTrackGC());
- size_t profiling_context = 0;
+ // If we're tracking GCs, then we need to walk the first generation
+ // before collection to track how many items of each class has been
+ // allocated.
+ UpdateGenerationBounds();
+ GarbageCollectionStartedCallback(settings.condemned_generation, settings.reason == reason_induced);
+ {
+ BEGIN_PIN_PROFILER(CORProfilerTrackGC());
+ size_t profiling_context = 0;
#ifdef MULTIPLE_HEAPS
- int hn = 0;
- for (hn = 0; hn < gc_heap::n_heaps; hn++)
- {
- gc_heap* hp = gc_heap::g_heaps [hn];
+ int hn = 0;
+ for (hn = 0; hn < gc_heap::n_heaps; hn++)
+ {
+ gc_heap* hp = gc_heap::g_heaps [hn];
- // When we're walking objects allocated by class, then we don't want to walk the large
- // object heap because then it would count things that may have been around for a while.
- hp->walk_heap (&AllocByClassHelper, (void *)&profiling_context, 0, FALSE);
- }
-#else
// When we're walking objects allocated by class, then we don't want to walk the large
// object heap because then it would count things that may have been around for a while.
- gc_heap::walk_heap (&AllocByClassHelper, (void *)&profiling_context, 0, FALSE);
+ hp->walk_heap (&AllocByClassHelper, (void *)&profiling_context, 0, FALSE);
+ }
+#else
+ // When we're walking objects allocated by class, then we don't want to walk the large
+ // object heap because then it would count things that may have been around for a while.
+ gc_heap::walk_heap (&AllocByClassHelper, (void *)&profiling_context, 0, FALSE);
#endif //MULTIPLE_HEAPS
- // Notify that we've reached the end of the Gen 0 scan
- g_profControlBlock.pProfInterface->EndAllocByClass(&profiling_context);
- END_PIN_PROFILER();
- }
+ // Notify that we've reached the end of the Gen 0 scan
+ g_profControlBlock.pProfInterface->EndAllocByClass(&profiling_context);
+ END_PIN_PROFILER();
+ }
#endif // GC_PROFILING
#ifdef BACKGROUND_GC
- if ((settings.condemned_generation == max_generation) &&
- (recursive_gc_sync::background_running_p()))
- {
- //TODO BACKGROUND_GC If we just wait for the end of gc, it won't woork
- // because we have to collect 0 and 1 properly
- // in particular, the allocation contexts are gone.
- // For now, it is simpler to collect max_generation-1
- settings.condemned_generation = max_generation - 1;
- dprintf (GTC_LOG, ("bgc - 1 instead of 2"));
- }
+ if ((settings.condemned_generation == max_generation) &&
+ (recursive_gc_sync::background_running_p()))
+ {
+ //TODO BACKGROUND_GC If we just wait for the end of gc, it won't woork
+ // because we have to collect 0 and 1 properly
+ // in particular, the allocation contexts are gone.
+ // For now, it is simpler to collect max_generation-1
+ settings.condemned_generation = max_generation - 1;
+ dprintf (GTC_LOG, ("bgc - 1 instead of 2"));
+ }
- if ((settings.condemned_generation == max_generation) &&
- (should_do_blocking_collection == FALSE) &&
- gc_can_use_concurrent &&
- !temp_disable_concurrent_p &&
- ((settings.pause_mode == pause_interactive) || (settings.pause_mode == pause_sustained_low_latency)))
- {
- keep_bgc_threads_p = TRUE;
- c_write (settings.concurrent, TRUE);
- }
+ if ((settings.condemned_generation == max_generation) &&
+ (should_do_blocking_collection == FALSE) &&
+ gc_can_use_concurrent &&
+ !temp_disable_concurrent_p &&
+ ((settings.pause_mode == pause_interactive) || (settings.pause_mode == pause_sustained_low_latency)))
+ {
+ keep_bgc_threads_p = TRUE;
+ c_write (settings.concurrent, TRUE);
+ }
#endif //BACKGROUND_GC
- settings.gc_index = (uint32_t)dd_collection_count (dynamic_data_of (0)) + 1;
+ settings.gc_index = (uint32_t)dd_collection_count (dynamic_data_of (0)) + 1;
- // Call the EE for start of GC work
- // just one thread for MP GC
- GCToEEInterface::GcStartWork (settings.condemned_generation,
- max_generation);
+ // Call the EE for start of GC work
+ // just one thread for MP GC
+ GCToEEInterface::GcStartWork (settings.condemned_generation,
+ max_generation);
- // TODO: we could fire an ETW event to say this GC as a concurrent GC but later on due to not being able to
- // create threads or whatever, this could be a non concurrent GC. Maybe for concurrent GC we should fire
- // it in do_background_gc and if it failed to be a CGC we fire it in gc1... in other words, this should be
- // fired in gc1.
- do_pre_gc();
+ // TODO: we could fire an ETW event to say this GC as a concurrent GC but later on due to not being able to
+ // create threads or whatever, this could be a non concurrent GC. Maybe for concurrent GC we should fire
+ // it in do_background_gc and if it failed to be a CGC we fire it in gc1... in other words, this should be
+ // fired in gc1.
+ do_pre_gc();
#ifdef MULTIPLE_HEAPS
- gc_start_event.Reset();
- //start all threads on the roots.
- dprintf(3, ("Starting all gc threads for gc"));
- gc_t_join.restart();
+ gc_start_event.Reset();
+ //start all threads on the roots.
+ dprintf(3, ("Starting all gc threads for gc"));
+ gc_t_join.restart();
#endif //MULTIPLE_HEAPS
- }
+ }
+ {
+ int gen_num_for_data = max_generation + 1;
+ for (int i = 0; i <= gen_num_for_data; i++)
{
- int gen_num_for_data = max_generation + 1;
- for (int i = 0; i <= gen_num_for_data; i++)
- {
- gc_data_per_heap.gen_data[i].size_before = generation_size (i);
- generation* gen = generation_of (i);
- gc_data_per_heap.gen_data[i].free_list_space_before = generation_free_list_space (gen);
- gc_data_per_heap.gen_data[i].free_obj_space_before = generation_free_obj_space (gen);
- }
+ gc_data_per_heap.gen_data[i].size_before = generation_size (i);
+ generation* gen = generation_of (i);
+ gc_data_per_heap.gen_data[i].free_list_space_before = generation_free_list_space (gen);
+ gc_data_per_heap.gen_data[i].free_obj_space_before = generation_free_obj_space (gen);
}
- descr_generations (TRUE);
+ }
+ descr_generations (TRUE);
// descr_card_table();
#ifdef NO_WRITE_BARRIER
- fix_card_table();
+ fix_card_table();
#endif //NO_WRITE_BARRIER
#ifdef VERIFY_HEAP
- if ((g_pConfig->GetHeapVerifyLevel() & EEConfig::HEAPVERIFY_GC) &&
- !(g_pConfig->GetHeapVerifyLevel() & EEConfig::HEAPVERIFY_POST_GC_ONLY))
- {
- verify_heap (TRUE);
- }
- if (g_pConfig->GetHeapVerifyLevel() & EEConfig::HEAPVERIFY_BARRIERCHECK)
- checkGCWriteBarrier();
+ if ((g_pConfig->GetHeapVerifyLevel() & EEConfig::HEAPVERIFY_GC) &&
+ !(g_pConfig->GetHeapVerifyLevel() & EEConfig::HEAPVERIFY_POST_GC_ONLY))
+ {
+ verify_heap (TRUE);
+ }
+ if (g_pConfig->GetHeapVerifyLevel() & EEConfig::HEAPVERIFY_BARRIERCHECK)
+ checkGCWriteBarrier();
#endif // VERIFY_HEAP
#ifdef BACKGROUND_GC
- if (settings.concurrent)
- {
- // We need to save the settings because we'll need to restore it after each FGC.
- assert (settings.condemned_generation == max_generation);
- settings.compaction = FALSE;
- saved_bgc_settings = settings;
+ if (settings.concurrent)
+ {
+ // We need to save the settings because we'll need to restore it after each FGC.
+ assert (settings.condemned_generation == max_generation);
+ settings.compaction = FALSE;
+ saved_bgc_settings = settings;
#ifdef MULTIPLE_HEAPS
- if (heap_number == 0)
- {
- for (int i = 0; i < n_heaps; i++)
- {
- prepare_bgc_thread (g_heaps[i]);
- }
- dprintf (2, ("setting bgc_threads_sync_event"));
- bgc_threads_sync_event.Set();
- }
- else
+ if (heap_number == 0)
+ {
+ for (int i = 0; i < n_heaps; i++)
{
- bgc_threads_sync_event.Wait(INFINITE, FALSE);
- dprintf (2, ("bgc_threads_sync_event is signalled"));
+ prepare_bgc_thread (g_heaps[i]);
}
+ dprintf (2, ("setting bgc_threads_sync_event"));
+ bgc_threads_sync_event.Set();
+ }
+ else
+ {
+ bgc_threads_sync_event.Wait(INFINITE, FALSE);
+ dprintf (2, ("bgc_threads_sync_event is signalled"));
+ }
#else
- prepare_bgc_thread(0);
+ prepare_bgc_thread(0);
#endif //MULTIPLE_HEAPS
#ifdef MULTIPLE_HEAPS
- gc_t_join.join(this, gc_join_start_bgc);
- if (gc_t_join.joined())
+ gc_t_join.join(this, gc_join_start_bgc);
+ if (gc_t_join.joined())
#endif //MULTIPLE_HEAPS
- {
- do_concurrent_p = TRUE;
- do_ephemeral_gc_p = FALSE;
+ {
+ do_concurrent_p = TRUE;
+ do_ephemeral_gc_p = FALSE;
#ifdef MULTIPLE_HEAPS
- dprintf(2, ("Joined to perform a background GC"));
+ dprintf(2, ("Joined to perform a background GC"));
- for (int i = 0; i < n_heaps; i++)
+ for (int i = 0; i < n_heaps; i++)
+ {
+ gc_heap* hp = g_heaps[i];
+ if (!(hp->bgc_thread) || !hp->commit_mark_array_bgc_init (hp->mark_array))
{
- gc_heap* hp = g_heaps[i];
- if (!(hp->bgc_thread) || !hp->commit_mark_array_bgc_init (hp->mark_array))
- {
- do_concurrent_p = FALSE;
- break;
- }
- else
- {
- hp->background_saved_lowest_address = hp->lowest_address;
- hp->background_saved_highest_address = hp->highest_address;
- }
+ do_concurrent_p = FALSE;
+ break;
}
-#else
- do_concurrent_p = (!!bgc_thread && commit_mark_array_bgc_init (mark_array));
- if (do_concurrent_p)
+ else
{
- background_saved_lowest_address = lowest_address;
- background_saved_highest_address = highest_address;
+ hp->background_saved_lowest_address = hp->lowest_address;
+ hp->background_saved_highest_address = hp->highest_address;
}
+ }
+#else
+ do_concurrent_p = (!!bgc_thread && commit_mark_array_bgc_init (mark_array));
+ if (do_concurrent_p)
+ {
+ background_saved_lowest_address = lowest_address;
+ background_saved_highest_address = highest_address;
+ }
#endif //MULTIPLE_HEAPS
- if (do_concurrent_p)
- {
+ if (do_concurrent_p)
+ {
#ifdef FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP
- SoftwareWriteWatch::EnableForGCHeap();
+ SoftwareWriteWatch::EnableForGCHeap();
#endif //FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP
#ifdef MULTIPLE_HEAPS
- for (int i = 0; i < n_heaps; i++)
- g_heaps[i]->current_bgc_state = bgc_initialized;
+ for (int i = 0; i < n_heaps; i++)
+ g_heaps[i]->current_bgc_state = bgc_initialized;
#else
- current_bgc_state = bgc_initialized;
+ current_bgc_state = bgc_initialized;
#endif //MULTIPLE_HEAPS
- int gen = check_for_ephemeral_alloc();
- // always do a gen1 GC before we start BGC.
- // This is temporary for testing purpose.
- //int gen = max_generation - 1;
- dont_restart_ee_p = TRUE;
- if (gen == -1)
- {
- // If we decide to not do a GC before the BGC we need to
- // restore the gen0 alloc context.
+ int gen = check_for_ephemeral_alloc();
+ // always do a gen1 GC before we start BGC.
+ // This is temporary for testing purpose.
+ //int gen = max_generation - 1;
+ dont_restart_ee_p = TRUE;
+ if (gen == -1)
+ {
+ // If we decide to not do a GC before the BGC we need to
+ // restore the gen0 alloc context.
#ifdef MULTIPLE_HEAPS
- for (int i = 0; i < n_heaps; i++)
- {
- generation_allocation_pointer (g_heaps[i]->generation_of (0)) = 0;
- generation_allocation_limit (g_heaps[i]->generation_of (0)) = 0;
- }
+ for (int i = 0; i < n_heaps; i++)
+ {
+ generation_allocation_pointer (g_heaps[i]->generation_of (0)) = 0;
+ generation_allocation_limit (g_heaps[i]->generation_of (0)) = 0;
+ }
#else
- generation_allocation_pointer (youngest_generation) = 0;
- generation_allocation_limit (youngest_generation) = 0;
+ generation_allocation_pointer (youngest_generation) = 0;
+ generation_allocation_limit (youngest_generation) = 0;
#endif //MULTIPLE_HEAPS
- }
- else
- {
- do_ephemeral_gc_p = TRUE;
+ }
+ else
+ {
+ do_ephemeral_gc_p = TRUE;
- settings.init_mechanisms();
- settings.condemned_generation = gen;
- settings.gc_index = (size_t)dd_collection_count (dynamic_data_of (0)) + 2;
- do_pre_gc();
+ settings.init_mechanisms();
+ settings.condemned_generation = gen;
+ settings.gc_index = (size_t)dd_collection_count (dynamic_data_of (0)) + 2;
+ do_pre_gc();
- // TODO BACKGROUND_GC need to add the profiling stuff here.
- dprintf (GTC_LOG, ("doing gen%d before doing a bgc", gen));
- }
+ // TODO BACKGROUND_GC need to add the profiling stuff here.
+ dprintf (GTC_LOG, ("doing gen%d before doing a bgc", gen));
+ }
- //clear the cards so they don't bleed in gen 1 during collection
- // shouldn't this always be done at the beginning of any GC?
- //clear_card_for_addresses (
- // generation_allocation_start (generation_of (0)),
- // heap_segment_allocated (ephemeral_heap_segment));
+ //clear the cards so they don't bleed in gen 1 during collection
+ // shouldn't this always be done at the beginning of any GC?
+ //clear_card_for_addresses (
+ // generation_allocation_start (generation_of (0)),
+ // heap_segment_allocated (ephemeral_heap_segment));
- if (!do_ephemeral_gc_p)
- {
- do_background_gc();
- }
- }
- else
+ if (!do_ephemeral_gc_p)
{
- settings.compaction = TRUE;
- c_write (settings.concurrent, FALSE);
+ do_background_gc();
}
+ }
+ else
+ {
+ settings.compaction = TRUE;
+ c_write (settings.concurrent, FALSE);
+ }
#ifdef MULTIPLE_HEAPS
- gc_t_join.restart();
+ gc_t_join.restart();
#endif //MULTIPLE_HEAPS
- }
+ }
- if (do_concurrent_p)
- {
- // At this point we are sure we'll be starting a BGC, so save its per heap data here.
- // global data is only calculated at the end of the GC so we don't need to worry about
- // FGCs overwriting it.
- memset (&bgc_data_per_heap, 0, sizeof (bgc_data_per_heap));
- memcpy (&bgc_data_per_heap, &gc_data_per_heap, sizeof(gc_data_per_heap));
+ if (do_concurrent_p)
+ {
+ // At this point we are sure we'll be starting a BGC, so save its per heap data here.
+ // global data is only calculated at the end of the GC so we don't need to worry about
+ // FGCs overwriting it.
+ memset (&bgc_data_per_heap, 0, sizeof (bgc_data_per_heap));
+ memcpy (&bgc_data_per_heap, &gc_data_per_heap, sizeof(gc_data_per_heap));
- if (do_ephemeral_gc_p)
- {
- dprintf (2, ("GC threads running, doing gen%d GC", settings.condemned_generation));
+ if (do_ephemeral_gc_p)
+ {
+ dprintf (2, ("GC threads running, doing gen%d GC", settings.condemned_generation));
- gen_to_condemn_reasons.init();
- gen_to_condemn_reasons.set_condition (gen_before_bgc);
- gc_data_per_heap.gen_to_condemn_reasons.init (&gen_to_condemn_reasons);
- gc1();
+ gen_to_condemn_reasons.init();
+ gen_to_condemn_reasons.set_condition (gen_before_bgc);
+ gc_data_per_heap.gen_to_condemn_reasons.init (&gen_to_condemn_reasons);
+ gc1();
#ifdef MULTIPLE_HEAPS
- gc_t_join.join(this, gc_join_bgc_after_ephemeral);
- if (gc_t_join.joined())
+ gc_t_join.join(this, gc_join_bgc_after_ephemeral);
+ if (gc_t_join.joined())
#endif //MULTIPLE_HEAPS
- {
+ {
#ifdef MULTIPLE_HEAPS
- do_post_gc();
+ do_post_gc();
#endif //MULTIPLE_HEAPS
- settings = saved_bgc_settings;
- assert (settings.concurrent);
+ settings = saved_bgc_settings;
+ assert (settings.concurrent);
- do_background_gc();
+ do_background_gc();
#ifdef MULTIPLE_HEAPS
- gc_t_join.restart();
+ gc_t_join.restart();
#endif //MULTIPLE_HEAPS
- }
}
}
- else
- {
- dprintf (2, ("couldn't create BGC threads, reverting to doing a blocking GC"));
- gc1();
- }
}
else
-#endif //BACKGROUND_GC
{
+ dprintf (2, ("couldn't create BGC threads, reverting to doing a blocking GC"));
gc1();
}
+ }
+ else
+#endif //BACKGROUND_GC
+ {
+ gc1();
+ }
#ifndef MULTIPLE_HEAPS
- allocation_running_time = (size_t)GCToOSInterface::GetLowPrecisionTimeStamp();
- allocation_running_amount = dd_new_allocation (dynamic_data_of (0));
- fgn_last_alloc = dd_new_allocation (dynamic_data_of (0));
+ allocation_running_time = (size_t)GCToOSInterface::GetLowPrecisionTimeStamp();
+ allocation_running_amount = dd_new_allocation (dynamic_data_of (0));
+ fgn_last_alloc = dd_new_allocation (dynamic_data_of (0));
#endif //MULTIPLE_HEAPS
done:
- if (settings.pause_mode == pause_no_gc)
- allocate_for_no_gc_after_gc();
- }
-
- //TODO BACKGROUND_GC remove these when ready
-#ifndef NO_CATCH_HANDLERS
-
- PAL_EXCEPT_FILTER(CheckException, NULL)
- {
- _ASSERTE(!"Exception during garbage_collect()");
- EEPOLICY_HANDLE_FATAL_ERROR(CORINFO_EXCEPTION_GC);
- }
- PAL_ENDTRY
-#endif //NO_CATCH_HANDLERS
+ if (settings.pause_mode == pause_no_gc)
+ allocate_for_no_gc_after_gc();
int gn = settings.condemned_generation;
return gn;
@@ -17804,8 +17764,8 @@ gc_heap::mark_steal()
if (((size_t)o > 4) && !partial_object_p (o))
{
//this is a normal object, not a partial mark tuple
- //success = (FastInterlockCompareExchangePointer (&ref_mark_stack (hp, level), 0, o)==o);
- success = (FastInterlockCompareExchangePointer (&ref_mark_stack (hp, level), 4, o)==o);
+ //success = (Interlocked::CompareExchangePointer (&ref_mark_stack (hp, level), 0, o)==o);
+ success = (Interlocked::CompareExchangePointer (&ref_mark_stack (hp, level), (uint8_t*)4, o)==o);
#ifdef SNOOP_STATS
snoop_stat.interlocked_count++;
if (success)
@@ -17840,7 +17800,7 @@ gc_heap::mark_steal()
if (o && start)
{
//steal the object
- success = (FastInterlockCompareExchangePointer (&ref_mark_stack (hp, level+1), stolen, next)==next);
+ success = (Interlocked::CompareExchangePointer (&ref_mark_stack (hp, level+1), (uint8_t*)stolen, next)==next);
#ifdef SNOOP_STATS
snoop_stat.interlocked_count++;
if (success)
@@ -23345,13 +23305,8 @@ uint8_t* tree_search (uint8_t* tree, uint8_t* old_address)
#ifdef FEATURE_BASICFREEZE
bool gc_heap::frozen_object_p (Object* obj)
{
-#ifdef MULTIPLE_HEAPS
- ptrdiff_t delta = 0;
- heap_segment* pSegment = segment_of ((uint8_t*)obj, delta);
-#else //MULTIPLE_HEAPS
heap_segment* pSegment = gc_heap::find_segment ((uint8_t*)obj, FALSE);
_ASSERTE(pSegment);
-#endif //MULTIPLE_HEAPS
return heap_segment_read_only_p(pSegment);
}
@@ -23368,6 +23323,7 @@ void gc_heap::relocate_address (uint8_t** pold_address THREAD_NUMBER_DCL)
if (!((old_address >= gc_low) && (old_address < gc_high)))
#ifdef MULTIPLE_HEAPS
{
+ UNREFERENCED_PARAMETER(thread);
if (old_address == 0)
return;
gc_heap* hp = heap_of (old_address);
@@ -24844,60 +24800,6 @@ void gc_heap::compact_phase (int condemned_gen_number,
dprintf(2,("---- End of Compact phase ----"));
}
-#ifndef FEATURE_REDHAWK
-// This function is the filter function for the "__except" setup in the server and
-// concurrent gc thread base (gc_heap::gc_thread_stub()) in gc.cpp. If an
-// exception leaks out during GC, or from the implementation of gc_thread_function,
-// this filter will be invoked and we will kick in our unhandled exception processing
-// without relying on the OS UEF invocation mechanism.
-//
-// Also, any exceptions that escape out of the GC thread are fatal. Thus, once
-// we do our unhandled exception processing, we shall failfast.
-inline int32_t GCUnhandledExceptionFilter(EXCEPTION_POINTERS* pExceptionPointers, void* pv)
-{
- WRAPPER_NO_CONTRACT;
-
- int32_t result = CLRVectoredExceptionHandler(pExceptionPointers);
- if (result == EXCEPTION_CONTINUE_EXECUTION)
- {
- // Since VEH has asked to continue execution, lets do that...
- return result;
- }
-
- if ((pExceptionPointers->ExceptionRecord->ExceptionCode == STATUS_BREAKPOINT) ||
- (pExceptionPointers->ExceptionRecord->ExceptionCode == STATUS_SINGLE_STEP))
- {
- // We dont want to fail fast on debugger exceptions
- return result;
- }
-
- // VEH shouldnt be returning EXCEPTION_EXECUTE_HANDLER for a fault
- // in the GC thread!
- _ASSERTE(result != EXCEPTION_EXECUTE_HANDLER);
-
- // Exceptions in GC threads are fatal - invoke our unhandled exception
- // processing...
- result = InternalUnhandledExceptionFilter_Worker(pExceptionPointers);
-
-#ifdef FEATURE_UEF_CHAINMANAGER
- if (g_pUEFManager && (result == EXCEPTION_CONTINUE_SEARCH))
- {
- // Since the "UEF" of this runtime instance didnt handle the exception,
- // invoke the other registered UEF callbacks as well
- result = g_pUEFManager->InvokeUEFCallbacks(pExceptionPointers);
- }
-#endif // FEATURE_UEF_CHAINMANAGER
-
- // ...and then proceed to failfast.
- EEPOLICY_HANDLE_FATAL_ERROR(CORINFO_EXCEPTION_GC);
- _ASSERTE(!"We shouldnt reach here incase of exceptions in GC threads!");
-
- // Returning this will ensure our filter handler gets executed so that
- // it can failfast the runtime.
- return EXCEPTION_EXECUTE_HANDLER;
-}
-#endif // FEATURE_REDHAWK
-
#ifdef MULTIPLE_HEAPS
#ifdef _MSC_VER
@@ -24925,23 +24827,10 @@ void __stdcall gc_heap::gc_thread_stub (void* arg)
#endif //BACKGROUND_GC
}
#endif // FEATURE_REDHAWK
-#ifndef NO_CATCH_HANDLERS
- PAL_TRY
- {
-#endif // NO_CATCH_HANDLERS
- gc_heap* heap = (gc_heap*)arg;
- _alloca (256*heap->heap_number);
- heap->gc_thread_function();
-#ifndef NO_CATCH_HANDLERS
- }
- PAL_EXCEPT_FILTER(GCUnhandledExceptionFilter, NULL)
- {
- ASSERTE(!"Exception caught escaping out of the GC thread!");
- EEPOLICY_HANDLE_FATAL_ERROR(CORINFO_EXCEPTION_GC);
- }
- PAL_ENDTRY;
-#endif // NO_CATCH_HANDLERS
+ gc_heap* heap = (gc_heap*)arg;
+ _alloca (256*heap->heap_number);
+ heap->gc_thread_function();
}
#ifdef _MSC_VER
#pragma warning(pop)
@@ -24958,42 +24847,7 @@ void __stdcall gc_heap::gc_thread_stub (void* arg)
uint32_t __stdcall gc_heap::bgc_thread_stub (void* arg)
{
gc_heap* heap = (gc_heap*)arg;
-
- // TODO: need to check if we are still fine for these APIs:
- // Thread::BeginThreadAffinity
- // Thread::EndThreadAffinity()
- // since now GC threads can be managed threads.
- ClrFlsSetThreadType (ThreadType_GC);
- assert (heap->bgc_thread != NULL);
- GCToEEInterface::SetGCSpecial(heap->bgc_thread);
- STRESS_LOG_RESERVE_MEM (GC_STRESSLOG_MULTIPLY);
-
- // We commit the thread's entire stack to ensure we're robust in low memory conditions.
- /*
- BOOL fSuccess = Thread::CommitThreadStack();
-
- if (!fSuccess)
- {
- // For background GC we revert to doing a blocking GC.
- return 0;
- }
- */
-
-#ifndef NO_CATCH_HANDLERS
- PAL_TRY
- {
-#endif // NO_CATCH_HANDLERS
- return heap->bgc_thread_function();
-
-#ifndef NO_CATCH_HANDLERS
- }
- PAL_EXCEPT_FILTER(GCUnhandledExceptionFilter, NULL)
- {
- ASSERTE(!"Exception caught escaping out of the GC thread!");
- EEPOLICY_HANDLE_FATAL_ERROR(CORINFO_EXCEPTION_GC);
- }
- PAL_ENDTRY;
-#endif // NO_CATCH_HANDLERS
+ return heap->bgc_thread_function();
}
#ifdef _MSC_VER
#pragma warning(pop)
@@ -26773,62 +26627,29 @@ BOOL gc_heap::create_bgc_thread(gc_heap* gh)
//dprintf (2, ("Creating BGC thread"));
- if (GCToEEInterface::CreateBackgroundThread(&gh->bgc_thread, gh->bgc_thread_stub, gh))
- {
- dprintf (2, ("waiting for the thread to reach its main loop"));
- // In chk builds this can easily time out since
- // now we need to set the thread up into a managed thead.
- // And since it's a managed thread we also need to make sure that we don't
- // clean up here and are still executing code on that thread (it'll
- // trigger all sorts of asserts.
- //uint32_t res = gh->background_gc_create_event.Wait(20,FALSE);
- uint32_t res = gh->background_gc_create_event.Wait(INFINITE,FALSE);
- if (res == WAIT_TIMEOUT)
- {
- dprintf (2, ("waiting for the thread to reach its main loop Timeout."));
- goto cleanup;
- }
- if (!gh->bgc_thread_running)
- {
- dprintf(2, ("background GC thread failed to start."));
- goto cleanup;
- }
- //dprintf (2, ("waiting for the thread to reach its main loop Done."));
-
- return TRUE;
- }
+ gh->bgc_thread = GCToEEInterface::CreateBackgroundThread(gh->bgc_thread_stub, gh);
+ gh->bgc_thread_running = (gh->bgc_thread != NULL);
-cleanup:
-
- if (gh->bgc_thread)
- {
- gh->bgc_thread = 0;
- }
-
- return FALSE;
+ return gh->bgc_thread_running;
}
BOOL gc_heap::create_bgc_threads_support (int number_of_heaps)
{
BOOL ret = FALSE;
dprintf (3, ("Creating concurrent GC thread for the first time"));
- background_gc_done_event.CreateManualEvent(TRUE);
- if (!background_gc_done_event.IsValid())
+ if (!background_gc_done_event.CreateManualEventNoThrow(TRUE))
{
goto cleanup;
}
- bgc_threads_sync_event.CreateManualEvent(FALSE);
- if (!bgc_threads_sync_event.IsValid())
+ if (!bgc_threads_sync_event.CreateManualEventNoThrow(FALSE))
{
goto cleanup;
}
- ee_proceed_event.CreateAutoEvent(FALSE);
- if (!ee_proceed_event.IsValid())
+ if (!ee_proceed_event.CreateAutoEventNoThrow(FALSE))
{
goto cleanup;
}
- bgc_start_event.CreateManualEvent(FALSE);
- if (!bgc_start_event.IsValid())
+ if (!bgc_start_event.CreateManualEventNoThrow(FALSE))
{
goto cleanup;
}
@@ -26871,14 +26692,7 @@ BOOL gc_heap::create_bgc_thread_support()
BOOL ret = FALSE;
uint8_t** parr;
- gc_lh_block_event.CreateManualEvent(FALSE);
- if (!gc_lh_block_event.IsValid())
- {
- goto cleanup;
- }
-
- background_gc_create_event.CreateAutoEvent(FALSE);
- if (!background_gc_create_event.IsValid())
+ if (!gc_lh_block_event.CreateManualEventNoThrow(FALSE))
{
goto cleanup;
}
@@ -26902,10 +26716,6 @@ cleanup:
{
gc_lh_block_event.CloseEvent();
}
- if (background_gc_create_event.IsValid())
- {
- background_gc_create_event.CloseEvent();
- }
}
return ret;
@@ -26987,7 +26797,6 @@ void gc_heap::kill_gc_thread()
// In the first stage, we do minimum work, and call ExitProcess at the end.
// In the secodn stage, we have the Loader lock and only one thread is
// alive. Hence we do not need to kill gc thread.
- DestroyThread (bgc_thread);
background_gc_done_event.CloseEvent();
gc_lh_block_event.CloseEvent();
bgc_start_event.CloseEvent();
@@ -27004,28 +26813,11 @@ uint32_t gc_heap::bgc_thread_function()
dprintf (3, ("gc_thread thread starting..."));
BOOL do_exit = FALSE;
- Thread* thread_to_destroy = 0;
-
-#ifndef FEATURE_REDHAWK
- // see comments in create_bgc_thread - we need
- // to make sure that thread doesn't clean up this thread
- // while we run code here.
- if (!bgc_thread->HasStarted(FALSE))
- {
- dprintf (2, ("HasStarted failed"));
- bgc_thread_running = FALSE;
- background_gc_create_event.Set();
- return 0;
- }
-#endif //FEATURE_REDHAWK
- bgc_thread_running = TRUE;
Thread* current_thread = GetThread();
BOOL cooperative_mode = TRUE;
bgc_thread_id.SetToCurrentThread();
dprintf (1, ("bgc_thread_id is set to %x", (uint32_t)GCToOSInterface::GetCurrentThreadIdForLogging()));
- //this also indicates that the thread is ready.
- background_gc_create_event.Set();
while (1)
{
// Wait for work to do...
@@ -27065,10 +26857,6 @@ uint32_t gc_heap::bgc_thread_function()
{
dprintf (2, ("GC thread exiting"));
bgc_thread_running = FALSE;
- // We can't call DestroyThread here 'cause EnterCriticalSection
- // increases the thread's m_dwLockCount and DestroyThread will
- // assert if the lock count is not 0.
- thread_to_destroy = bgc_thread;
bgc_thread = 0;
bgc_thread_id.Clear();
do_exit = TRUE;
@@ -27172,11 +26960,6 @@ uint32_t gc_heap::bgc_thread_function()
//gc_heap::disable_preemptive (current_thread, TRUE);
}
- if (thread_to_destroy)
- {
- DestroyThread(thread_to_destroy);
- }
-
FireEtwGCTerminateConcurrentThread_V1(GetClrInstanceId());
dprintf (3, ("bgc_thread thread exiting"));
@@ -29960,6 +29743,7 @@ size_t gc_heap::compute_in (int gen_number)
}
dd_gc_new_allocation (dd) -= in;
+ dd_new_allocation (dd) = dd_gc_new_allocation (dd);
gc_history_per_heap* current_gc_data_per_heap = get_gc_data_per_heap();
gc_generation_data* gen_data = &(current_gc_data_per_heap->gen_data[gen_number]);
@@ -30132,6 +29916,8 @@ void gc_heap::compute_new_dynamic_data (int gen_number)
gen_data->npinned_surv = dd_survived_size (dd) - dd_pinned_survived_size (dd);
dd_gc_new_allocation (dd) = dd_desired_allocation (dd);
+ dd_new_allocation (dd) = dd_gc_new_allocation (dd);
+
//update counter
dd_promoted_size (dd) = out;
if (gen_number == max_generation)
@@ -30147,6 +29933,7 @@ void gc_heap::compute_new_dynamic_data (int gen_number)
dd_desired_allocation (dd) = desired_new_allocation (dd, out, max_generation+1, 0);
dd_gc_new_allocation (dd) = Align (dd_desired_allocation (dd),
get_alignment_constant (FALSE));
+ dd_new_allocation (dd) = dd_gc_new_allocation (dd);
gen_data = &(current_gc_data_per_heap->gen_data[max_generation+1]);
gen_data->size_after = total_gen_size;
@@ -33730,7 +33517,10 @@ HRESULT GCHeap::Initialize ()
return E_OUTOFMEMORY;
}
- WaitForGCEvent->CreateManualEvent(TRUE);
+ if (!WaitForGCEvent->CreateManualEventNoThrow(TRUE))
+ {
+ return E_FAIL;
+ }
StompWriteBarrierResize(true, false);
@@ -34207,112 +33997,106 @@ BOOL GCHeap::StressHeap(alloc_context * acontext)
return FALSE;
}
- EX_TRY
- {
-
#ifndef MULTIPLE_HEAPS
- static int32_t OneAtATime = -1;
+ static int32_t OneAtATime = -1;
- if (acontext == 0)
- acontext = generation_alloc_context (pGenGCHeap->generation_of(0));
+ if (acontext == 0)
+ acontext = generation_alloc_context (pGenGCHeap->generation_of(0));
- // Only bother with this if the stress level is big enough and if nobody else is
- // doing it right now. Note that some callers are inside the AllocLock and are
- // guaranteed synchronized. But others are using AllocationContexts and have no
- // particular synchronization.
- //
- // For this latter case, we want a very high-speed way of limiting this to one
- // at a time. A secondary advantage is that we release part of our StressObjs
- // buffer sparingly but just as effectively.
+ // Only bother with this if the stress level is big enough and if nobody else is
+ // doing it right now. Note that some callers are inside the AllocLock and are
+ // guaranteed synchronized. But others are using AllocationContexts and have no
+ // particular synchronization.
+ //
+ // For this latter case, we want a very high-speed way of limiting this to one
+ // at a time. A secondary advantage is that we release part of our StressObjs
+ // buffer sparingly but just as effectively.
- if (Interlocked::Increment(&OneAtATime) == 0 &&
- !TrackAllocations()) // Messing with object sizes can confuse the profiler (see ICorProfilerInfo::GetObjectSize)
- {
- StringObject* str;
+ if (Interlocked::Increment(&OneAtATime) == 0 &&
+ !TrackAllocations()) // Messing with object sizes can confuse the profiler (see ICorProfilerInfo::GetObjectSize)
+ {
+ StringObject* str;
- // If the current string is used up
- if (ObjectFromHandle(m_StressObjs[m_CurStressObj]) == 0)
+ // If the current string is used up
+ if (ObjectFromHandle(m_StressObjs[m_CurStressObj]) == 0)
+ {
+ // Populate handles with strings
+ int i = m_CurStressObj;
+ while(ObjectFromHandle(m_StressObjs[i]) == 0)
{
- // Populate handles with strings
- int i = m_CurStressObj;
- while(ObjectFromHandle(m_StressObjs[i]) == 0)
+ _ASSERTE(m_StressObjs[i] != 0);
+ unsigned strLen = (LARGE_OBJECT_SIZE - 32) / sizeof(WCHAR);
+ unsigned strSize = PtrAlign(StringObject::GetSize(strLen));
+
+ // update the cached type handle before allocating
+ SetTypeHandleOnThreadForAlloc(TypeHandle(g_pStringClass));
+ str = (StringObject*) pGenGCHeap->allocate (strSize, acontext);
+ if (str)
{
- _ASSERTE(m_StressObjs[i] != 0);
- unsigned strLen = (LARGE_OBJECT_SIZE - 32) / sizeof(WCHAR);
- unsigned strSize = PtrAlign(StringObject::GetSize(strLen));
-
- // update the cached type handle before allocating
- SetTypeHandleOnThreadForAlloc(TypeHandle(g_pStringClass));
- str = (StringObject*) pGenGCHeap->allocate (strSize, acontext);
- if (str)
- {
- str->SetMethodTable (g_pStringClass);
- str->SetStringLength (strLen);
+ str->SetMethodTable (g_pStringClass);
+ str->SetStringLength (strLen);
#if CHECK_APP_DOMAIN_LEAKS
- if (g_pConfig->AppDomainLeaks())
- str->SetAppDomain();
+ if (g_pConfig->AppDomainLeaks() && str->SetAppDomainNoThrow())
+ {
#endif
StoreObjectInHandle(m_StressObjs[i], ObjectToOBJECTREF(str));
+#if CHECK_APP_DOMAIN_LEAKS
}
- i = (i + 1) % NUM_HEAP_STRESS_OBJS;
- if (i == m_CurStressObj) break;
+#endif
}
-
- // advance the current handle to the next string
- m_CurStressObj = (m_CurStressObj + 1) % NUM_HEAP_STRESS_OBJS;
+ i = (i + 1) % NUM_HEAP_STRESS_OBJS;
+ if (i == m_CurStressObj) break;
}
- // Get the current string
- str = (StringObject*) OBJECTREFToObject(ObjectFromHandle(m_StressObjs[m_CurStressObj]));
- if (str)
+ // advance the current handle to the next string
+ m_CurStressObj = (m_CurStressObj + 1) % NUM_HEAP_STRESS_OBJS;
+ }
+
+ // Get the current string
+ str = (StringObject*) OBJECTREFToObject(ObjectFromHandle(m_StressObjs[m_CurStressObj]));
+ if (str)
+ {
+ // Chop off the end of the string and form a new object out of it.
+ // This will 'free' an object at the begining of the heap, which will
+ // force data movement. Note that we can only do this so many times.
+ // before we have to move on to the next string.
+ unsigned sizeOfNewObj = (unsigned)Align(min_obj_size * 31);
+ if (str->GetStringLength() > sizeOfNewObj / sizeof(WCHAR))
{
- // Chop off the end of the string and form a new object out of it.
- // This will 'free' an object at the begining of the heap, which will
- // force data movement. Note that we can only do this so many times.
- // before we have to move on to the next string.
- unsigned sizeOfNewObj = (unsigned)Align(min_obj_size * 31);
- if (str->GetStringLength() > sizeOfNewObj / sizeof(WCHAR))
- {
- unsigned sizeToNextObj = (unsigned)Align(size(str));
- uint8_t* freeObj = ((uint8_t*) str) + sizeToNextObj - sizeOfNewObj;
- pGenGCHeap->make_unused_array (freeObj, sizeOfNewObj);
- str->SetStringLength(str->GetStringLength() - (sizeOfNewObj / sizeof(WCHAR)));
- }
- else
- {
- // Let the string itself become garbage.
- // will be realloced next time around
- StoreObjectInHandle(m_StressObjs[m_CurStressObj], 0);
- }
+ unsigned sizeToNextObj = (unsigned)Align(size(str));
+ uint8_t* freeObj = ((uint8_t*) str) + sizeToNextObj - sizeOfNewObj;
+ pGenGCHeap->make_unused_array (freeObj, sizeOfNewObj);
+ str->SetStringLength(str->GetStringLength() - (sizeOfNewObj / sizeof(WCHAR)));
+ }
+ else
+ {
+ // Let the string itself become garbage.
+ // will be realloced next time around
+ StoreObjectInHandle(m_StressObjs[m_CurStressObj], 0);
}
}
- Interlocked::Decrement(&OneAtATime);
+ }
+ Interlocked::Decrement(&OneAtATime);
#endif // !MULTIPLE_HEAPS
- if (IsConcurrentGCEnabled())
- {
- int rgen = StressRNG(10);
+ if (IsConcurrentGCEnabled())
+ {
+ int rgen = StressRNG(10);
- // gen0:gen1:gen2 distribution: 40:40:20
- if (rgen >= 8)
- rgen = 2;
- else if (rgen >= 4)
- rgen = 1;
- else
- rgen = 0;
+ // gen0:gen1:gen2 distribution: 40:40:20
+ if (rgen >= 8)
+ rgen = 2;
+ else if (rgen >= 4)
+ rgen = 1;
+ else
+ rgen = 0;
- GarbageCollectTry (rgen, FALSE, collection_gcstress);
- }
- else
- {
- GarbageCollect(max_generation, FALSE, collection_gcstress);
- }
+ GarbageCollectTry (rgen, FALSE, collection_gcstress);
}
- EX_CATCH
+ else
{
- _ASSERTE (!"Exception happens during StressHeap");
+ GarbageCollect(max_generation, FALSE, collection_gcstress);
}
- EX_END_CATCH(RethrowTerminalExceptions)
return TRUE;
}
@@ -35345,151 +35129,139 @@ GCHeap::GarbageCollectGeneration (unsigned int gen, gc_reason reason)
int gc_start = GetCycleCount32();
#endif //COUNT_CYCLES
-#if defined ( _DEBUG) && defined (CATCH_GC)
- __try
-#endif // _DEBUG && CATCH_GC
- {
#ifdef TRACE_GC
#ifdef COUNT_CYCLES
- AllocDuration += GetCycleCount32() - AllocStart;
+ AllocDuration += GetCycleCount32() - AllocStart;
#else
- AllocDuration += clock() - AllocStart;
+ AllocDuration += clock() - AllocStart;
#endif //COUNT_CYCLES
#endif //TRACE_GC
- gc_heap::g_low_memory_status = (reason == reason_lowmemory) ||
- (reason == reason_lowmemory_blocking) ||
- g_bLowMemoryFromHost;
+ gc_heap::g_low_memory_status = (reason == reason_lowmemory) ||
+ (reason == reason_lowmemory_blocking) ||
+ g_bLowMemoryFromHost;
- if (g_bLowMemoryFromHost)
- reason = reason_lowmemory_host;
+ if (g_bLowMemoryFromHost)
+ reason = reason_lowmemory_host;
- gc_trigger_reason = reason;
+ gc_trigger_reason = reason;
#ifdef MULTIPLE_HEAPS
- for (int i = 0; i < gc_heap::n_heaps; i++)
- {
- gc_heap::g_heaps[i]->reset_gc_done();
- }
+ for (int i = 0; i < gc_heap::n_heaps; i++)
+ {
+ gc_heap::g_heaps[i]->reset_gc_done();
+ }
#else
- gc_heap::reset_gc_done();
+ gc_heap::reset_gc_done();
#endif //MULTIPLE_HEAPS
- gc_heap::gc_started = TRUE;
+ gc_heap::gc_started = TRUE;
- {
- init_sync_log_stats();
+ {
+ init_sync_log_stats();
#ifndef MULTIPLE_HEAPS
- cooperative_mode = gc_heap::enable_preemptive (current_thread);
+ cooperative_mode = gc_heap::enable_preemptive (current_thread);
- dprintf (2, ("Suspending EE"));
- BEGIN_TIMING(suspend_ee_during_log);
- GCToEEInterface::SuspendEE(GCToEEInterface::SUSPEND_FOR_GC);
- END_TIMING(suspend_ee_during_log);
- gc_heap::proceed_with_gc_p = gc_heap::should_proceed_with_gc();
- gc_heap::disable_preemptive (current_thread, cooperative_mode);
- if (gc_heap::proceed_with_gc_p)
- pGenGCHeap->settings.init_mechanisms();
- else
- gc_heap::update_collection_counts_for_no_gc();
+ dprintf (2, ("Suspending EE"));
+ BEGIN_TIMING(suspend_ee_during_log);
+ GCToEEInterface::SuspendEE(GCToEEInterface::SUSPEND_FOR_GC);
+ END_TIMING(suspend_ee_during_log);
+ gc_heap::proceed_with_gc_p = gc_heap::should_proceed_with_gc();
+ gc_heap::disable_preemptive (current_thread, cooperative_mode);
+ if (gc_heap::proceed_with_gc_p)
+ pGenGCHeap->settings.init_mechanisms();
+ else
+ gc_heap::update_collection_counts_for_no_gc();
#endif //!MULTIPLE_HEAPS
- }
+ }
- // MAP_EVENT_MONITORS(EE_MONITOR_GARBAGE_COLLECTIONS, NotifyEvent(EE_EVENT_TYPE_GC_STARTED, 0));
+// MAP_EVENT_MONITORS(EE_MONITOR_GARBAGE_COLLECTIONS, NotifyEvent(EE_EVENT_TYPE_GC_STARTED, 0));
#ifdef TRACE_GC
#ifdef COUNT_CYCLES
- unsigned start;
- unsigned finish;
- start = GetCycleCount32();
+ unsigned start;
+ unsigned finish;
+ start = GetCycleCount32();
#else
- clock_t start;
- clock_t finish;
- start = clock();
+ clock_t start;
+ clock_t finish;
+ start = clock();
#endif //COUNT_CYCLES
- PromotedObjectCount = 0;
+ PromotedObjectCount = 0;
#endif //TRACE_GC
- unsigned int condemned_generation_number = gen;
+ unsigned int condemned_generation_number = gen;
- // We want to get a stack from the user thread that triggered the GC
- // instead of on the GC thread which is the case for Server GC.
- // But we are doing it for Workstation GC as well to be uniform.
- FireEtwGCTriggered((int) reason, GetClrInstanceId());
+ // We want to get a stack from the user thread that triggered the GC
+ // instead of on the GC thread which is the case for Server GC.
+ // But we are doing it for Workstation GC as well to be uniform.
+ FireEtwGCTriggered((int) reason, GetClrInstanceId());
#ifdef MULTIPLE_HEAPS
- GcCondemnedGeneration = condemned_generation_number;
-
- cooperative_mode = gc_heap::enable_preemptive (current_thread);
+ GcCondemnedGeneration = condemned_generation_number;
- BEGIN_TIMING(gc_during_log);
- gc_heap::ee_suspend_event.Set();
- gc_heap::wait_for_gc_done();
- END_TIMING(gc_during_log);
+ cooperative_mode = gc_heap::enable_preemptive (current_thread);
- gc_heap::disable_preemptive (current_thread, cooperative_mode);
+ BEGIN_TIMING(gc_during_log);
+ gc_heap::ee_suspend_event.Set();
+ gc_heap::wait_for_gc_done();
+ END_TIMING(gc_during_log);
- condemned_generation_number = GcCondemnedGeneration;
+ gc_heap::disable_preemptive (current_thread, cooperative_mode);
+
+ condemned_generation_number = GcCondemnedGeneration;
#else
- if (gc_heap::proceed_with_gc_p)
- {
- BEGIN_TIMING(gc_during_log);
- pGenGCHeap->garbage_collect (condemned_generation_number);
- END_TIMING(gc_during_log);
- }
+ if (gc_heap::proceed_with_gc_p)
+ {
+ BEGIN_TIMING(gc_during_log);
+ pGenGCHeap->garbage_collect (condemned_generation_number);
+ END_TIMING(gc_during_log);
+ }
#endif //MULTIPLE_HEAPS
#ifdef TRACE_GC
#ifdef COUNT_CYCLES
- finish = GetCycleCount32();
+ finish = GetCycleCount32();
#else
- finish = clock();
+ finish = clock();
#endif //COUNT_CYCLES
- GcDuration += finish - start;
- dprintf (3,
- ("<GC# %d> Condemned: %d, Duration: %d, total: %d Alloc Avg: %d, Small Objects:%d Large Objects:%d",
- VolatileLoad(&pGenGCHeap->settings.gc_index), condemned_generation_number,
- finish - start, GcDuration,
- AllocCount ? (AllocDuration / AllocCount) : 0,
- AllocSmallCount, AllocBigCount));
- AllocCount = 0;
- AllocDuration = 0;
+ GcDuration += finish - start;
+ dprintf (3,
+ ("<GC# %d> Condemned: %d, Duration: %d, total: %d Alloc Avg: %d, Small Objects:%d Large Objects:%d",
+ VolatileLoad(&pGenGCHeap->settings.gc_index), condemned_generation_number,
+ finish - start, GcDuration,
+ AllocCount ? (AllocDuration / AllocCount) : 0,
+ AllocSmallCount, AllocBigCount));
+ AllocCount = 0;
+ AllocDuration = 0;
#endif // TRACE_GC
#ifdef BACKGROUND_GC
- // We are deciding whether we should fire the alloc wait end event here
- // because in begin_foreground we could be calling end_foreground
- // if we need to retry.
- if (gc_heap::alloc_wait_event_p)
- {
- hpt->fire_alloc_wait_event_end (awr_fgc_wait_for_bgc);
- gc_heap::alloc_wait_event_p = FALSE;
- }
+ // We are deciding whether we should fire the alloc wait end event here
+ // because in begin_foreground we could be calling end_foreground
+ // if we need to retry.
+ if (gc_heap::alloc_wait_event_p)
+ {
+ hpt->fire_alloc_wait_event_end (awr_fgc_wait_for_bgc);
+ gc_heap::alloc_wait_event_p = FALSE;
+ }
#endif //BACKGROUND_GC
#ifndef MULTIPLE_HEAPS
#ifdef BACKGROUND_GC
- if (!gc_heap::dont_restart_ee_p)
- {
+ if (!gc_heap::dont_restart_ee_p)
+ {
#endif //BACKGROUND_GC
- BEGIN_TIMING(restart_ee_during_log);
- GCToEEInterface::RestartEE(TRUE);
- END_TIMING(restart_ee_during_log);
+ BEGIN_TIMING(restart_ee_during_log);
+ GCToEEInterface::RestartEE(TRUE);
+ END_TIMING(restart_ee_during_log);
#ifdef BACKGROUND_GC
- }
+ }
#endif //BACKGROUND_GC
#endif //!MULTIPLE_HEAPS
- }
-#if defined (_DEBUG) && defined (CATCH_GC)
- __except (CheckException(GetExceptionInformation(), NULL))
- {
- _ASSERTE(!"Exception during GarbageCollectGeneration()");
- }
-#endif // _DEBUG && CATCH_GC
-
#ifdef COUNT_CYCLES
printf ("GC: %d Time: %d\n", GcCondemnedGeneration,
GetCycleCount32() - gc_start);
@@ -35652,7 +35424,7 @@ int GCHeap::GetHomeHeapNumber ()
{
if (pThread)
{
- GCHeap *hp = pThread->GetAllocContext()->home_heap;
+ GCHeap *hp = GCToEEInterface::GetAllocContext(pThread)->home_heap;
if (hp == gc_heap::g_heaps[i]->vm_heap) return i;
}
}
diff --git a/src/gc/gcpriv.h b/src/gc/gcpriv.h
index ec0c8324f4..03a23454a0 100644
--- a/src/gc/gcpriv.h
+++ b/src/gc/gcpriv.h
@@ -128,8 +128,6 @@ inline void FATAL_GC_ERROR()
//#define TRACE_GC //debug trace gc operation
//#define SIMPLE_DPRINTF
-//#define CATCH_GC //catches exception during GC
-
//#define TIME_GC //time allocation and garbage collection
//#define TIME_WRITE_WATCH //time GetWriteWatch and ResetWriteWatch calls
//#define COUNT_CYCLES //Use cycle counter for timing
@@ -156,8 +154,6 @@ inline void FATAL_GC_ERROR()
#define END_TIMING_CYCLES(x)
#endif //SYNCHRONIZATION_STATS || STAGE_STATS
-#define NO_CATCH_HANDLERS //to debug gc1, remove the catch handlers
-
/* End of optional features */
#ifdef GC_CONFIG_DRIVEN
@@ -3108,9 +3104,6 @@ protected:
PER_HEAP_ISOLATED
CLREvent background_gc_done_event;
- PER_HEAP
- CLREvent background_gc_create_event;
-
PER_HEAP_ISOLATED
CLREvent ee_proceed_event;
diff --git a/src/gc/gcscan.cpp b/src/gc/gcscan.cpp
index 79ba2dc045..42989e0414 100644
--- a/src/gc/gcscan.cpp
+++ b/src/gc/gcscan.cpp
@@ -19,7 +19,6 @@
#include "gc.h"
#include "objecthandle.h"
-//#define CATCH_GC //catches exception during GC
#ifdef DACCESS_COMPILE
SVAL_IMPL_INIT(int32_t, GCScan, m_GcStructuresInvalidCnt, 1);
#else //DACCESS_COMPILE
@@ -168,20 +167,7 @@ void GCScan::GcShortWeakPtrScan(promote_func* fn, int condemned, int max_gen,
void GCScan::GcScanRoots(promote_func* fn, int condemned, int max_gen,
ScanContext* sc)
{
-#if defined ( _DEBUG) && defined (CATCH_GC)
- //note that we can't use EX_TRY because the gc_thread isn't known
- PAL_TRY
-#endif // _DEBUG && CATCH_GC
- {
- GCToEEInterface::GcScanRoots(fn, condemned, max_gen, sc);
- }
-#if defined ( _DEBUG) && defined (CATCH_GC)
- PAL_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
- {
- _ASSERTE (!"We got an exception during scan roots");
- }
- PAL_ENDTRY
-#endif //_DEBUG
+ GCToEEInterface::GcScanRoots(fn, condemned, max_gen, sc);
}
/*
@@ -192,33 +178,18 @@ void GCScan::GcScanRoots(promote_func* fn, int condemned, int max_gen,
void GCScan::GcScanHandles (promote_func* fn, int condemned, int max_gen,
ScanContext* sc)
{
-
-#if defined ( _DEBUG) && defined (CATCH_GC)
- //note that we can't use EX_TRY because the gc_thread isn't known
- PAL_TRY
-#endif // _DEBUG && CATCH_GC
+ STRESS_LOG1(LF_GC|LF_GCROOTS, LL_INFO10, "GcScanHandles (Promotion Phase = %d)\n", sc->promotion);
+ if (sc->promotion)
{
- STRESS_LOG1(LF_GC|LF_GCROOTS, LL_INFO10, "GcScanHandles (Promotion Phase = %d)\n", sc->promotion);
- if (sc->promotion)
- {
- Ref_TracePinningRoots(condemned, max_gen, sc, fn);
- Ref_TraceNormalRoots(condemned, max_gen, sc, fn);
- }
- else
- {
- Ref_UpdatePointers(condemned, max_gen, sc, fn);
- Ref_UpdatePinnedPointers(condemned, max_gen, sc, fn);
- Ref_ScanDependentHandlesForRelocation(condemned, max_gen, sc, fn);
- }
+ Ref_TracePinningRoots(condemned, max_gen, sc, fn);
+ Ref_TraceNormalRoots(condemned, max_gen, sc, fn);
}
-
-#if defined ( _DEBUG) && defined (CATCH_GC)
- PAL_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ else
{
- _ASSERTE (!"We got an exception during scan roots");
+ Ref_UpdatePointers(condemned, max_gen, sc, fn);
+ Ref_UpdatePinnedPointers(condemned, max_gen, sc, fn);
+ Ref_ScanDependentHandlesForRelocation(condemned, max_gen, sc, fn);
}
- PAL_ENDTRY
-#endif //_DEBUG
}
@@ -232,22 +203,8 @@ void GCScan::GcScanHandlesForProfilerAndETW (int max_gen, ScanContext* sc)
{
LIMITED_METHOD_CONTRACT;
-#if defined ( _DEBUG) && defined (CATCH_GC)
- //note that we can't use EX_TRY because the gc_thread isn't known
- PAL_TRY
-#endif // _DEBUG && CATCH_GC
- {
- LOG((LF_GC|LF_GCROOTS, LL_INFO10, "Profiler Root Scan Phase, Handles\n"));
- Ref_ScanPointersForProfilerAndETW(max_gen, (uintptr_t)sc);
- }
-
-#if defined ( _DEBUG) && defined (CATCH_GC)
- PAL_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
- {
- _ASSERTE (!"We got an exception during scan roots for the profiler");
- }
- PAL_ENDTRY
-#endif //_DEBUG
+ LOG((LF_GC|LF_GCROOTS, LL_INFO10, "Profiler Root Scan Phase, Handles\n"));
+ Ref_ScanPointersForProfilerAndETW(max_gen, (uintptr_t)sc);
}
/*
diff --git a/src/gc/sample/gcenv.ee.cpp b/src/gc/sample/gcenv.ee.cpp
index 11befab1b9..330564a380 100644
--- a/src/gc/sample/gcenv.ee.cpp
+++ b/src/gc/sample/gcenv.ee.cpp
@@ -11,28 +11,36 @@
EEConfig * g_pConfig;
-void CLREventStatic::CreateManualEvent(bool bInitialState)
+bool CLREventStatic::CreateManualEventNoThrow(bool bInitialState)
{
m_hEvent = CreateEventW(NULL, TRUE, bInitialState, NULL);
m_fInitialized = true;
+
+ return IsValid();
}
-void CLREventStatic::CreateAutoEvent(bool bInitialState)
+bool CLREventStatic::CreateAutoEventNoThrow(bool bInitialState)
{
m_hEvent = CreateEventW(NULL, FALSE, bInitialState, NULL);
m_fInitialized = true;
+
+ return IsValid();
}
-void CLREventStatic::CreateOSManualEvent(bool bInitialState)
+bool CLREventStatic::CreateOSManualEventNoThrow(bool bInitialState)
{
m_hEvent = CreateEventW(NULL, TRUE, bInitialState, NULL);
m_fInitialized = true;
+
+ return IsValid();
}
-void CLREventStatic::CreateOSAutoEvent(bool bInitialState)
+bool CLREventStatic::CreateOSAutoEventNoThrow(bool bInitialState)
{
m_hEvent = CreateEventW(NULL, FALSE, bInitialState, NULL);
m_fInitialized = true;
+
+ return IsValid();
}
void CLREventStatic::CloseEvent()
@@ -176,11 +184,6 @@ void GCToEEInterface::DisablePreemptiveGC(Thread * pThread)
pThread->DisablePreemptiveGC();
}
-void GCToEEInterface::SetGCSpecial(Thread * pThread)
-{
- pThread->SetGCSpecial(true);
-}
-
alloc_context * GCToEEInterface::GetAllocContext(Thread * pThread)
{
return pThread->GetAllocContext();
@@ -212,10 +215,10 @@ void GCToEEInterface::SyncBlockCachePromotionsGranted(int /*max_gen*/)
{
}
-bool GCToEEInterface::CreateBackgroundThread(Thread** thread, GCBackgroundThreadFunction threadStart, void* arg)
+Thread* GCToEEInterface::CreateBackgroundThread(GCBackgroundThreadFunction threadStart, void* arg)
{
// TODO: Implement for background GC
- return false;
+ return NULL;
}
void FinalizerThread::EnableFinalization()
diff --git a/src/gc/sample/gcenv.unix.cpp b/src/gc/sample/gcenv.unix.cpp
index 515820650b..a5e9e83ee2 100644
--- a/src/gc/sample/gcenv.unix.cpp
+++ b/src/gc/sample/gcenv.unix.cpp
@@ -11,452 +11,4 @@
#include "gcenv.h"
#include "gc.h"
-#include <sys/mman.h>
-#include <sys/time.h>
-
-int32_t FastInterlockIncrement(int32_t volatile *lpAddend)
-{
- return __sync_add_and_fetch(lpAddend, 1);
-}
-
-int32_t FastInterlockDecrement(int32_t volatile *lpAddend)
-{
- return __sync_sub_and_fetch(lpAddend, 1);
-}
-
-int32_t FastInterlockExchange(int32_t volatile *Target, int32_t Value)
-{
- return __sync_swap(Target, Value);
-}
-
-int32_t FastInterlockCompareExchange(int32_t volatile *Destination, int32_t Exchange, int32_t Comperand)
-{
- return __sync_val_compare_and_swap(Destination, Comperand, Exchange);
-}
-
-int32_t FastInterlockExchangeAdd(int32_t volatile *Addend, int32_t Value)
-{
- return __sync_fetch_and_add(Addend, Value);
-}
-
-void * _FastInterlockExchangePointer(void * volatile *Target, void * Value)
-{
- return __sync_swap(Target, Value);
-}
-
-void * _FastInterlockCompareExchangePointer(void * volatile *Destination, void * Exchange, void * Comperand)
-{
- return __sync_val_compare_and_swap(Destination, Comperand, Exchange);
-}
-
-void FastInterlockOr(uint32_t volatile *p, uint32_t msk)
-{
- __sync_fetch_and_or(p, msk);
-}
-
-void FastInterlockAnd(uint32_t volatile *p, uint32_t msk)
-{
- __sync_fetch_and_and(p, msk);
-}
-
-
-void UnsafeInitializeCriticalSection(CRITICAL_SECTION * lpCriticalSection)
-{
- pthread_mutex_init(&lpCriticalSection->mutex, NULL);
-}
-
-void UnsafeEEEnterCriticalSection(CRITICAL_SECTION *lpCriticalSection)
-{
- pthread_mutex_lock(&lpCriticalSection->mutex);
-}
-
-void UnsafeEELeaveCriticalSection(CRITICAL_SECTION * lpCriticalSection)
-{
- pthread_mutex_unlock(&lpCriticalSection->mutex);
-}
-
-void UnsafeDeleteCriticalSection(CRITICAL_SECTION *lpCriticalSection)
-{
- pthread_mutex_destroy(&lpCriticalSection->mutex);
-}
-
-#if 0
-void CLREventStatic::CreateManualEvent(bool bInitialState)
-{
- // TODO: Implement
- m_fInitialized = true;
-}
-
-void CLREventStatic::CreateAutoEvent(bool bInitialState)
-{
- // TODO: Implement
- m_fInitialized = true;
-}
-
-void CLREventStatic::CreateOSManualEvent(bool bInitialState)
-{
- CreateManualEvent(bInitialState);
-}
-
-void CLREventStatic::CreateOSAutoEvent (bool bInitialState)
-{
- CreateAutoEvent(bInitialState);
-}
-
-void CLREventStatic::CloseEvent()
-{
- if (m_fInitialized)
- {
- // TODO: Implement
- m_fInitialized = false;
- }
-}
-
-bool CLREventStatic::IsValid() const
-{
- return m_fInitialized;
-}
-
-bool CLREventStatic::Set()
-{
- if (!m_fInitialized)
- return false;
- // TODO: Implement
- return true;
-}
-
-bool CLREventStatic::Reset()
-{
- if (!m_fInitialized)
- return false;
- // TODO: Implement
- return true;
-}
-
-uint32_t CLREventStatic::Wait(uint32_t dwMilliseconds, bool bAlertable)
-{
- DWORD result = WAIT_FAILED;
-
- if (m_fInitialized)
- {
- bool disablePreemptive = false;
- Thread * pCurThread = GetThread();
-
- if (NULL != pCurThread)
- {
- if (pCurThread->PreemptiveGCDisabled())
- {
- pCurThread->EnablePreemptiveGC();
- disablePreemptive = true;
- }
- }
-
- // TODO: Implement
- result = WAIT_OBJECT_0;
-
- if (disablePreemptive)
- {
- pCurThread->DisablePreemptiveGC();
- }
- }
-
- return result;
-}
-#endif // 0
-
-void DestroyThread(Thread * pThread)
-{
- // TODO: implement
-}
-
-bool __SwitchToThread(uint32_t dwSleepMSec, uint32_t dwSwitchCount)
-{
- return sched_yield() == 0;
-}
-
-static int W32toUnixAccessControl(uint32_t flProtect)
-{
- int prot = 0;
-
- switch (flProtect & 0xff)
- {
- case PAGE_NOACCESS:
- prot = PROT_NONE;
- break;
- case PAGE_READWRITE:
- prot = PROT_READ | PROT_WRITE;
- break;
- default:
- _ASSERTE(false);
- break;
- }
- return prot;
-}
-
-MethodTable * g_pFreeObjectMethodTable;
-
-GCSystemInfo g_SystemInfo;
-
-void InitializeSystemInfo()
-{
- // TODO: Implement
- g_SystemInfo.dwNumberOfProcessors = 4;
-
- g_SystemInfo.dwPageSize = OS_PAGE_SIZE;
- g_SystemInfo.dwAllocationGranularity = OS_PAGE_SIZE;
-}
-
-int32_t g_TrapReturningThreads;
-
-bool g_fFinalizerRunOnShutDown;
-
-#if 0
-#ifdef _MSC_VER
-__declspec(thread)
-#else
-__thread
-#endif
-Thread * pCurrentThread;
-
-Thread * GetThread()
-{
- return pCurrentThread;
-}
-
-Thread * g_pThreadList = NULL;
-
-Thread * ThreadStore::GetThreadList(Thread * pThread)
-{
- if (pThread == NULL)
- return g_pThreadList;
-
- return pThread->m_pNext;
-}
-
-void ThreadStore::AttachCurrentThread(bool fAcquireThreadStoreLock)
-{
- // TODO: Locks
-
- Thread * pThread = new Thread();
- pThread->GetAllocContext()->init();
- pCurrentThread = pThread;
-
- pThread->m_pNext = g_pThreadList;
- g_pThreadList = pThread;
-}
-#endif // 0
-void DestroyThread(Thread * pThread)
-{
- // TODO: Implement
-}
-
-#if 0
-void GCToEEInterface::SuspendEE(GCToEEInterface::SUSPEND_REASON reason)
-{
- GCHeap::GetGCHeap()->SetGCInProgress(TRUE);
-
- // TODO: Implement
-}
-
-void GCToEEInterface::RestartEE(bool bFinishedGC)
-{
- // TODO: Implement
-
- GCHeap::GetGCHeap()->SetGCInProgress(FALSE);
-}
-
-void GCToEEInterface::GcScanRoots(promote_func* fn, int condemned, int max_gen, ScanContext* sc)
-{
- // TODO: Implement - Scan stack roots
-}
-
-void GCToEEInterface::GcStartWork(int condemned, int max_gen)
-{
-}
-
-void GCToEEInterface::AfterGcScanRoots(int condemned, int max_gen, ScanContext* sc)
-{
-}
-
-void GCToEEInterface::GcBeforeBGCSweepWork()
-{
-}
-
-void GCToEEInterface::GcDone(int condemned)
-{
-}
-
-void FinalizerThread::EnableFinalization()
-{
- // Signal to finalizer thread that there are objects to finalize
- // TODO: Implement for finalization
-}
-
-bool PalStartBackgroundGCThread(BackgroundCallback callback, void* pCallbackContext)
-{
- // TODO: Implement for background GC
- return false;
-}
-
-bool IsGCSpecialThread()
-{
- // TODO: Implement for background GC
- return false;
-}
-
-#endif // 0
-
-WINBASEAPI
-UINT
-WINAPI
-GetWriteWatch(
- DWORD dwFlags,
- PVOID lpBaseAddress,
- SIZE_T dwRegionSize,
- PVOID *lpAddresses,
- uintptr_t * lpdwCount,
- uint32_t * lpdwGranularity
- )
-{
- // TODO: Implement for background GC
- *lpAddresses = NULL;
- *lpdwCount = 0;
- // Until it is implemented, return non-zero value as an indicator of failure
- return 1;
-}
-
-WINBASEAPI
-UINT
-WINAPI
-ResetWriteWatch(
- LPVOID lpBaseAddress,
- SIZE_T dwRegionSize
- )
-{
- // TODO: Implement for background GC
- // Until it is implemented, return non-zero value as an indicator of failure
- return 1;
-}
-
-const int tccSecondsToMillieSeconds = 1000;
-const int tccSecondsToMicroSeconds = 1000000;
-const int tccMillieSecondsToMicroSeconds = 1000; // 10^3
-
-WINBASEAPI
-DWORD
-WINAPI
-GetTickCount()
-{
- // TODO: More efficient, platform-specific implementation
- struct timeval tv;
- if (gettimeofday(&tv, NULL) == -1)
- {
- _ASSERTE(!"gettimeofday() failed");
- return 0;
- }
- return (tv.tv_sec * tccSecondsToMillieSeconds) + (tv.tv_usec / tccMillieSecondsToMicroSeconds);
-}
-
-WINBASEAPI
-BOOL
-WINAPI
-QueryPerformanceCounter(LARGE_INTEGER *lpPerformanceCount)
-{
- // TODO: More efficient, platform-specific implementation
- struct timeval tv;
- if (gettimeofday(&tv, NULL) == -1)
- {
- _ASSERTE(!"gettimeofday() failed");
- return FALSE;
- }
- lpPerformanceCount->QuadPart =
- (int64_t) tv.tv_sec * (int64_t) tccSecondsToMicroSeconds + (int64_t) tv.tv_usec;
- return TRUE;
-}
-
-WINBASEAPI
-BOOL
-WINAPI
-QueryPerformanceFrequency(LARGE_INTEGER *lpFrequency)
-{
- lpFrequency->QuadPart = (int64_t) tccSecondsToMicroSeconds;
- return TRUE;
-}
-
-WINBASEAPI
-DWORD
-WINAPI
-GetCurrentThreadId(
- void)
-{
- // TODO: Implement
- return 1;
-}
-
-WINBASEAPI
-void
-WINAPI
-YieldProcessor()
-{
- // TODO: Implement
-}
-
-WINBASEAPI
-void
-WINAPI
-DebugBreak()
-{
- // TODO: Implement
-}
-
-WINBASEAPI
-void
-WINAPI
-MemoryBarrier()
-{
- // TODO: Implement
-}
-
-// File I/O - Used for tracking only
-
-WINBASEAPI
-BOOL
-WINAPI
-FlushFileBuffers(
- HANDLE hFile)
-{
- // TODO: Reimplement callers using CRT
- return FALSE;
-}
-
-WINBASEAPI
-BOOL
-WINAPI
-WriteFile(
- HANDLE hFile,
- LPCVOID lpBuffer,
- DWORD nNumberOfBytesToWrite,
- DWORD * lpNumberOfBytesWritten,
- PVOID lpOverlapped)
-{
- // TODO: Reimplement callers using CRT
- return FALSE;
-}
-
-WINBASEAPI
-BOOL
-WINAPI
-CloseHandle(
- HANDLE hObject)
-{
- // TODO: Reimplement callers using CRT
- return FALSE;
-}
-
-WINBASEAPI
-DWORD
-WINAPI
-GetLastError()
-{
- return 1;
-}
+// TODO: Implement
diff --git a/src/gc/sample/gcenv.windows.cpp b/src/gc/sample/gcenv.windows.cpp
index 1324bd3869..e35af6b6a0 100644
--- a/src/gc/sample/gcenv.windows.cpp
+++ b/src/gc/sample/gcenv.windows.cpp
@@ -455,8 +455,3 @@ void CLRCriticalSection::Leave()
{
::LeaveCriticalSection(&m_cs);
}
-
-void DestroyThread(Thread * pThread)
-{
- // TODO: implement
-}
diff --git a/src/gcdump/gcdump.cpp b/src/gcdump/gcdump.cpp
index d2fda049fc..1c512c88e0 100644
--- a/src/gcdump/gcdump.cpp
+++ b/src/gcdump/gcdump.cpp
@@ -18,8 +18,9 @@
-GCDump::GCDump(bool encBytes, unsigned maxEncBytes, bool dumpCodeOffs)
- : fDumpEncBytes (encBytes ),
+GCDump::GCDump(UINT32 gcInfoVer, bool encBytes, unsigned maxEncBytes, bool dumpCodeOffs)
+ : gcInfoVersion (gcInfoVer),
+ fDumpEncBytes (encBytes ),
cMaxEncBytes (maxEncBytes ),
fDumpCodeOffsets(dumpCodeOffs)
{
@@ -32,7 +33,7 @@ GCDump::GCDump(bool encBytes, unsigned maxEncBytes, bool dumpCodeOffs)
* Display the byte encodings for the given range of the GC tables.
*/
-PTR_CBYTE GCDump::DumpEncoding(PTR_CBYTE table, int cDumpBytes)
+PTR_CBYTE GCDump::DumpEncoding(PTR_CBYTE gcInfoBlock, int cDumpBytes)
{
_ASSERTE((cDumpBytes >= 0) && (cMaxEncBytes < 256));
@@ -42,7 +43,7 @@ PTR_CBYTE GCDump::DumpEncoding(PTR_CBYTE table, int cDumpBytes)
unsigned count;
int cBytesLeft;
- for (count = cMaxEncBytes, cBytesLeft = cDumpBytes, pCurPos = table;
+ for (count = cMaxEncBytes, cBytesLeft = cDumpBytes, pCurPos = gcInfoBlock;
count > 0;
count--, pCurPos++, cBytesLeft--)
{
@@ -60,7 +61,7 @@ PTR_CBYTE GCDump::DumpEncoding(PTR_CBYTE table, int cDumpBytes)
gcPrintf("| ");
}
- return table + cDumpBytes;
+ return gcInfoBlock + cDumpBytes;
}
/*****************************************************************************/
diff --git a/src/gcdump/gcdumpnonx86.cpp b/src/gcdump/gcdumpnonx86.cpp
index 8167d3abd8..53e16ffbff 100644
--- a/src/gcdump/gcdumpnonx86.cpp
+++ b/src/gcdump/gcdumpnonx86.cpp
@@ -78,8 +78,9 @@ PCSTR GetRegName (UINT32 regnum)
/*****************************************************************************/
-GCDump::GCDump(bool encBytes, unsigned maxEncBytes, bool dumpCodeOffs)
- : fDumpEncBytes (encBytes ),
+GCDump::GCDump(UINT32 gcInfoVer, bool encBytes, unsigned maxEncBytes, bool dumpCodeOffs)
+ : gcInfoVersion(gcInfoVer),
+ fDumpEncBytes (encBytes ),
cMaxEncBytes (maxEncBytes ),
fDumpCodeOffsets(dumpCodeOffs)
{
@@ -270,11 +271,12 @@ BOOL StackSlotStateChangeCallback (
}
-size_t GCDump::DumpGCTable(PTR_CBYTE table,
+size_t GCDump::DumpGCTable(PTR_CBYTE gcInfoBlock,
unsigned methodSize,
bool verifyGCTables)
{
- GcInfoDecoder hdrdecoder(table,
+ GCInfoToken gcInfoToken = { dac_cast<PTR_VOID>(gcInfoBlock), gcInfoVersion };
+ GcInfoDecoder hdrdecoder(gcInfoToken,
(GcInfoDecoderFlags)( DECODE_SECURITY_OBJECT
| DECODE_GS_COOKIE
| DECODE_CODE_LENGTH
@@ -439,7 +441,7 @@ size_t GCDump::DumpGCTable(PTR_CBYTE table,
UINT32 cbEncodedMethodSize = hdrdecoder.GetCodeLength();
gcPrintf("Code size: %x\n", cbEncodedMethodSize);
- GcInfoDumper dumper(table);
+ GcInfoDumper dumper(gcInfoToken);
GcInfoDumpState state;
state.LastCodeOffset = -1;
@@ -520,6 +522,3 @@ void GCDump::DumpPtrsInFrame(PTR_CBYTE infoBlock,
#define VALIDATE_ROOT(isInterior, hCallBack, pObjRef) ((void)0)
#include "../vm/gcinfodecoder.cpp"
#include "../gcinfo/gcinfodumper.cpp"
-#ifdef VERIFY_GCINFO
-#include "../vm/dbggcinfodecoder.cpp"
-#endif
diff --git a/src/gcinfo/CMakeLists.txt b/src/gcinfo/CMakeLists.txt
index 11857184e3..016e1e273f 100644
--- a/src/gcinfo/CMakeLists.txt
+++ b/src/gcinfo/CMakeLists.txt
@@ -3,7 +3,6 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON)
set( GCINFO_SOURCES
arraylist.cpp
gcinfoencoder.cpp
- dbggcinfoencoder.cpp
)
if(CLR_CMAKE_PLATFORM_ARCH_I386)
diff --git a/src/gcinfo/dbggcinfoencoder.cpp b/src/gcinfo/dbggcinfoencoder.cpp
deleted file mode 100644
index 98480cf26d..0000000000
--- a/src/gcinfo/dbggcinfoencoder.cpp
+++ /dev/null
@@ -1,981 +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.
-/*****************************************************************************
- *
- * GC Information Encoding API
- *
- * This is an older well-tested implementation
- * now used to verify the real encoding
- * Define VERIFY_GCINFO to enable the verification
- *
- */
-
-#ifdef VERIFY_GCINFO
-
-#include "dbggcinfoencoder.h"
-#include "gcinfoencoder.h"
-
-
-namespace DbgGcInfo {
-
-
-#ifdef _DEBUG
- #ifndef LOGGING
- #define LOGGING
- #endif
-#endif
-#include "log.h"
-
-
-void *GcInfoEncoder::LifetimeTransitionAllocator::Alloc (void *context, SIZE_T cb)
-{
- GcInfoEncoder *pGcInfoEncoder = CONTAINING_RECORD(context, GcInfoEncoder, m_LifetimeTransitions);
- return pGcInfoEncoder->m_pAllocator->Alloc(cb);
-}
-
-void GcInfoEncoder::LifetimeTransitionAllocator::Free (void *context, void *pv)
-{
-#ifdef MUST_CALL_JITALLOCATOR_FREE
- GcInfoEncoder *pGcInfoEncoder = CONTAINING_RECORD(context, GcInfoEncoder, m_LifetimeTransitions);
- pGcInfoEncoder->m_pAllocator->Free(pv);
-#endif
-}
-
-
-BitStreamWriter::MemoryBlockList::MemoryBlockList()
- : m_head(nullptr),
- m_tail(nullptr)
-{
-}
-
-BitStreamWriter::MemoryBlock* BitStreamWriter::MemoryBlockList::AppendNew(IJitAllocator* allocator, size_t bytes)
-{
- auto* memBlock = reinterpret_cast<MemoryBlock*>(allocator->Alloc(sizeof(MemoryBlock) + bytes));
- memBlock->m_next = nullptr;
-
- if (m_tail != nullptr)
- {
- _ASSERTE(m_head != nullptr);
- m_tail->m_next = memBlock;
- }
- else
- {
- _ASSERTE(m_head == nullptr);
- m_head = memBlock;
- }
-
- m_tail = memBlock;
- return memBlock;
-}
-
-void BitStreamWriter::MemoryBlockList::Dispose(IJitAllocator* allocator)
-{
-#ifdef MUST_CALL_JITALLOCATOR_FREE
- for (MemoryBlock* block = m_head, *next; block != nullptr; block = next)
- {
- next = block->m_next;
- allocator->Free(block);
- }
- m_head = nullptr;
- m_tail = nullptr;
-#endif
-}
-
-
-void BitStreamWriter::AllocMemoryBlock()
-{
- _ASSERTE( IS_ALIGNED( m_MemoryBlockSize, sizeof( size_t ) ) );
- m_FullyInterruptibleInfoWriter( pJitAllocator ),
- m_LifetimeTransitions( pJitAllocator )
-{
- _ASSERTE( pCorJitInfo != NULL );
- _ASSERTE( pMethodInfo != NULL );
- _ASSERTE( pJitAllocator != NULL );
-
- m_pCorJitInfo = pCorJitInfo;
- m_pMethodInfo = pMethodInfo;
- m_pAllocator = pJitAllocator;
-
-#ifdef _DEBUG
- CORINFO_METHOD_HANDLE methodHandle = pMethodInfo->ftn;
-
- // Get the name of the current method along with the enclosing class
- // or module name.
- m_MethodName = (char *)
- pCorJitInfo->getMethodName(methodHandle, (const char **)&m_ModuleName);
-#endif
-
-
- m_MappingTableSize = m_MappingTableInitialSize;
- m_SlotMappings = (GcSlotDesc*) m_pAllocator->Alloc( m_MappingTableSize*sizeof(GcSlotDesc) );
- m_NumSlotMappings = 0;
-#if 0
-#ifdef PARTIALLY_INTERRUPTIBLE_GC_SUPPORTED
- m_NumSafePointsWithGcState = 0;
-#endif
-#endif
-
- m_SecurityObjectStackSlot = NO_SECURITY_OBJECT;
- m_PSPSymStackSlot = NO_PSP_SYM;
- m_GenericsInstContextStackSlot = NO_GENERICS_INST_CONTEXT;
- m_StackBaseRegister = NO_STACK_BASE_REGISTER;
- m_SizeOfEditAndContinuePreservedArea = NO_SIZE_OF_EDIT_AND_CONTINUE_PRESERVED_AREA;
- m_IsVarArg = false;
- m_LastInterruptibleRangeStopOffset = 0;
- m_NumInterruptibleRanges = 0;
-
-#ifdef _DEBUG
- m_IsMappingTableFrozen = FALSE;
- m_CodeLength = 0;
-#ifdef FIXED_STACK_PARAMETER_SCRATCH_AREA
- m_SizeOfStackOutgoingAndScratchArea = -1;
-#endif // FIXED_STACK_PARAMETER_SCRATCH_AREA
-#endif //_DEBUG
-}
-
-GcSlotId GcInfoEncoder::GetRegisterSlotId( UINT32 regNum, GcSlotFlags flags )
-{
- // We could lookup an existing identical slot in the mapping table (via some hashtable mechanism).
- // We just create duplicates for now.
-
-#ifdef _DEBUG
- _ASSERTE( !m_IsMappingTableFrozen );
-#endif
-
- if( m_NumSlotMappings == m_MappingTableSize )
- {
- GrowMappingTable();
- }
- _ASSERTE( m_NumSlotMappings < m_MappingTableSize );
-
- m_SlotMappings[ m_NumSlotMappings ].IsRegister = 1;
- m_SlotMappings[ m_NumSlotMappings ].Slot.RegisterNumber = regNum;
- m_SlotMappings[ m_NumSlotMappings ].IsInterior = ( flags & GC_SLOT_INTERIOR ) ? 1 : 0;
- m_SlotMappings[ m_NumSlotMappings ].IsPinned = ( flags & GC_SLOT_PINNED ) ? 1 : 0;
-
- GcSlotId newSlotId;
- newSlotId = m_NumSlotMappings++;
- return newSlotId;
-}
-
-GcSlotId GcInfoEncoder::GetStackSlotId( INT32 spOffset, GcSlotFlags flags, GcStackSlotBase spBase )
-{
- // We could lookup an existing identical slot in the mapping table (via some hashtable mechanism).
- // We just create duplicates for now.
-
-#ifdef _DEBUG
- _ASSERTE( !m_IsMappingTableFrozen );
-#endif
-
- if( m_NumSlotMappings == m_MappingTableSize )
- {
- GrowMappingTable();
- }
- _ASSERTE( m_NumSlotMappings < m_MappingTableSize );
-
- // Not valid to reference anything below the current stack pointer
- _ASSERTE(GC_SP_REL != spBase || spOffset >= 0);
-
- m_SlotMappings[ m_NumSlotMappings ].IsRegister = 0;
- m_SlotMappings[ m_NumSlotMappings ].Slot.Stack.SpOffset = spOffset;
- m_SlotMappings[ m_NumSlotMappings ].Slot.Stack.Base = spBase;
- m_SlotMappings[ m_NumSlotMappings ].IsInterior = ( flags & GC_SLOT_INTERIOR ) ? 1 : 0;
- m_SlotMappings[ m_NumSlotMappings ].IsPinned = ( flags & GC_SLOT_PINNED ) ? 1 : 0;
-
- GcSlotId newSlotId;
- newSlotId = m_NumSlotMappings++;
- return newSlotId;
-}
-
-void GcInfoEncoder::GrowMappingTable()
-{
- m_MappingTableSize *= 2;
- GcSlotDesc* newMappingTable = (GcSlotDesc*) m_pAllocator->Alloc( m_MappingTableSize * sizeof(GcSlotDesc) );
- memcpy( newMappingTable, m_SlotMappings, m_NumSlotMappings * sizeof(GcSlotDesc) );
-
-#ifdef MUST_CALL_JITALLOCATOR_FREE
- m_pAllocator->Free( m_SlotMappings );
-#endif
-
- m_SlotMappings = newMappingTable;
-}
-
-GcSlotSet::GcSlotSet( GcInfoEncoder* pEncoder )
-{
-#ifdef _DEBUG
- _ASSERTE( pEncoder->m_IsMappingTableFrozen );
-#endif
-
- m_pEncoder = pEncoder;
- m_NumBytes = ( pEncoder->m_NumSlotMappings + 7 ) / 8;
- m_Data = (BYTE*) pEncoder->m_pAllocator->Alloc( m_NumBytes );
-}
-
-// Copy constructor
-GcSlotSet::GcSlotSet( GcSlotSet & other )
-{
- m_pEncoder = other.m_pEncoder;
- m_NumBytes = other.m_NumBytes;
- m_Data = (BYTE*) other.m_pEncoder->m_pAllocator->Alloc( m_NumBytes );
- memcpy( m_Data, other.m_Data, m_NumBytes);
-}
-
-void GcSlotSet::Add( GcSlotId slotId )
-{
- _ASSERTE( slotId < m_pEncoder->m_NumSlotMappings );
- m_Data[ slotId / 8 ] |= 1 << ( slotId % 8 );
-}
-
-void GcSlotSet::Remove( GcSlotId slotId )
-{
- _ASSERTE( slotId < m_pEncoder->m_NumSlotMappings );
- m_Data[ slotId / 8 ] &= ~( 1 << ( slotId % 8 ) );
-}
-
-// Not used
-#if 0
-
-void GcSlotSet::Add( GcSlotSet & other )
-{
- _ASSERTE( m_pEncoder == other.m_pEncoder );
-
- for( int i=0; i<m_NumBytes; i++ )
- {
- m_Data[ i ] |= other.m_Data[ i ];
- }
-}
-
-void GcSlotSet::Subtract( GcSlotSet & other )
-{
- _ASSERTE( m_pEncoder == other.m_pEncoder );
-
- for( int i=0; i<m_NumBytes; i++ )
- {
- m_Data[ i ] &= ~( other.m_Data[ i ] );
- }
-}
-
-void GcSlotSet::Intersect( GcSlotSet & other )
-{
- _ASSERTE( m_pEncoder == other.m_pEncoder );
-
- for( int i=0; i<m_NumBytes; i++ )
- {
- m_Data[ i ] &= other.m_Data[ i ];
- }
-}
-
-#endif // unused
-
-
-void GcInfoEncoder::FinalizeSlotIds()
-{
-#ifdef _DEBUG
- m_IsMappingTableFrozen = TRUE;
-#endif
-}
-
-
-#if 0
-#ifdef PARTIALLY_INTERRUPTIBLE_GC_SUPPORTED
-
-void GcInfoEncoder::DefineGcStateAtSafePoint(
- UINT32 instructionOffset,
- GcSlotSet &liveSlots
- )
-{
-#ifdef _DEBUG
- _ASSERTE( m_IsMappingTableFrozen );
-#endif
-
-#ifdef _DEBUG
- // Verify that any slot is not reported multiple times. This is O(n^2) but it executes only under _DEBUG
- for( INT32 i1=0; i1<((INT32)m_NumSlotMappings)-1; i1++ )
- {
- BYTE isLive1 = liveSlots.m_Data[ i1 / 8 ] & ( 1 << ( i1 % 8 ) );
- if( isLive1 )
- for( UINT32 i2=i1+1; i2<m_NumSlotMappings; i2++ )
- {
- BYTE isLive2 = liveSlots.m_Data[ i2 / 8 ] & ( 1 << ( i2 % 8 ) );
- if( isLive2 )
- {
- if( m_SlotMappings[ i1 ].IsRegister && m_SlotMappings[ i2 ].IsRegister )
- {
- _ASSERTE( m_SlotMappings[ i1 ].Slot.RegisterNumber != m_SlotMappings[ i2 ].Slot.RegisterNumber );
- }
- else if( !m_SlotMappings[ i1 ].IsRegister && !m_SlotMappings[ i2 ].IsRegister )
- {
- _ASSERTE( m_SlotMappings[ i1 ].Slot.SpOffset != m_SlotMappings[ i2 ].Slot.SpOffset );
- }
- }
- }
- }
-#endif
-
- m_PartiallyInterruptibleInfoWriter.Write( instructionOffset, 32 );
-
- UINT32 i;
- for( i=0; i<m_NumSlotMappings/8; i++ )
- m_PartiallyInterruptibleInfoWriter.Write( liveSlots.m_Data[ i ], 8 );
-
- if( m_NumSlotMappings % 8 > 0 )
- m_PartiallyInterruptibleInfoWriter.Write( liveSlots.m_Data[ i ], m_NumSlotMappings % 8 );
-
- m_NumSafePointsWithGcState++;
-}
-
-#endif // PARTIALLY_INTERRUPTIBLE_GC_SUPPORTED
-#endif
-
-void GcInfoEncoder::DefineInterruptibleRange( UINT32 startInstructionOffset, UINT32 length )
-{
- UINT32 stopInstructionOffset = startInstructionOffset + length;
-
- size_t normStartDelta = NORMALIZE_CODE_OFFSET(startInstructionOffset) - NORMALIZE_CODE_OFFSET(m_LastInterruptibleRangeStopOffset);
- size_t normStopDelta = NORMALIZE_CODE_OFFSET(stopInstructionOffset) - NORMALIZE_CODE_OFFSET(startInstructionOffset);
- _ASSERTE(normStopDelta > 0);
-
- m_LastInterruptibleRangeStopOffset = startInstructionOffset + length;
-
- m_NumInterruptibleRanges++;
-
- m_FullyInterruptibleInfoWriter.EncodeVarLengthUnsigned(normStartDelta, INTERRUPTIBLE_RANGE_DELTA_ENCBASE);
-
- m_FullyInterruptibleInfoWriter.EncodeVarLengthUnsigned(normStopDelta-1, INTERRUPTIBLE_RANGE_DELTA_ENCBASE );
-}
-
-
-///////////////////////////////////////////////////////////////////////////
-// Tracking information
-///////////////////////////////////////////////////////////////////////////
-
-
-//
-// For inputs, pass zero as offset
-//
-
-void GcInfoEncoder::SetSlotState(
- UINT32 instructionOffset,
- GcSlotId slotId,
- GcSlotState slotState
- )
-{
- LifetimeTransition transition;
-
- transition.SlotDesc = m_SlotMappings[ slotId ];
- transition.CodeOffset = instructionOffset;
- transition.BecomesLive = ( slotState == GC_SLOT_LIVE );
-
- *( m_LifetimeTransitions.Append() ) = transition;
-}
-
-
-void GcInfoEncoder::SetIsVarArg()
-{
- m_IsVarArg = true;
-}
-
-void GcInfoEncoder::SetCodeLength( UINT32 length )
-{
- _ASSERTE( length > 0 );
- _ASSERTE( m_CodeLength == 0 || m_CodeLength == length );
- m_CodeLength = length;
-}
-
-
-void GcInfoEncoder::SetSecurityObjectStackSlot( INT32 spOffset )
-{
- _ASSERTE( spOffset != NO_SECURITY_OBJECT );
- _ASSERTE( m_SecurityObjectStackSlot == NO_SECURITY_OBJECT || m_SecurityObjectStackSlot == spOffset );
- m_SecurityObjectStackSlot = spOffset;
-}
-
-void GcInfoEncoder::SetPSPSymStackSlot( INT32 spOffsetPSPSym )
-{
- _ASSERTE( spOffsetPSPSym != NO_PSP_SYM );
- _ASSERTE( m_PSPSymStackSlot == NO_PSP_SYM || m_PSPSymStackSlot == spOffsetPSPSym );
-
- m_PSPSymStackSlot = spOffsetPSPSym;
-}
-
-void GcInfoEncoder::SetGenericsInstContextStackSlot( INT32 spOffsetGenericsContext )
-{
- _ASSERTE( spOffsetGenericsContext != NO_GENERICS_INST_CONTEXT);
- _ASSERTE( m_GenericsInstContextStackSlot == NO_GENERICS_INST_CONTEXT || m_GenericsInstContextStackSlot == spOffsetGenericsContext );
-
- m_GenericsInstContextStackSlot = spOffsetGenericsContext;
-}
-
-void GcInfoEncoder::SetStackBaseRegister( UINT32 regNum )
-{
- _ASSERTE( regNum != NO_STACK_BASE_REGISTER );
- _ASSERTE( m_StackBaseRegister == NO_STACK_BASE_REGISTER || m_StackBaseRegister == regNum );
- m_StackBaseRegister = regNum;
-}
-
-void GCInfoEncoder::SetSizeOfEditAndContinuePreservedArea( UINT32 slots )
-{
- _ASSERTE( regNum != NO_SIZE_OF_EDIT_AND_CONTINUE_PRESERVED_AREA );
- _ASSERTE( m_SizeOfEditAndContinuePreservedArea == NO_SIZE_OF_EDIT_AND_CONTINUE_PRESERVED_AREA );
- m_SizeOfEditAndContinuePreservedArea = slots;
-}
-
-
-
-#ifdef FIXED_STACK_PARAMETER_SCRATCH_AREA
-void GcInfoEncoder::SetSizeOfStackOutgoingAndScratchArea( UINT32 size )
-{
- _ASSERTE( size != -1 );
- _ASSERTE( m_SizeOfStackOutgoingAndScratchArea == -1 || m_SizeOfStackOutgoingAndScratchArea == size );
- m_SizeOfStackOutgoingAndScratchArea = size;
-}
-#endif // FIXED_STACK_PARAMETER_SCRATCH_AREA
-
-
-int __cdecl CompareLifetimeTransitionsForQsort(const void* p1, const void* p2)
-{
- const GcInfoEncoder::LifetimeTransition* pFirst = (const GcInfoEncoder::LifetimeTransition*) p1;
- const GcInfoEncoder::LifetimeTransition* pSecond = (const GcInfoEncoder::LifetimeTransition*) p2;
-
- // All registers come before all stack slots
- if( pFirst->SlotDesc.IsRegister && !pSecond->SlotDesc.IsRegister ) return -1;
- if( !pFirst->SlotDesc.IsRegister && pSecond->SlotDesc.IsRegister ) return 1;
-
- // Then sort them by slot
- if( pFirst->SlotDesc.IsRegister )
- {
- _ASSERTE( pSecond->SlotDesc.IsRegister );
- if( pFirst->SlotDesc.Slot.RegisterNumber < pSecond->SlotDesc.Slot.RegisterNumber ) return -1;
- if( pFirst->SlotDesc.Slot.RegisterNumber > pSecond->SlotDesc.Slot.RegisterNumber ) return 1;
- }
- else
- {
- _ASSERTE( !pSecond->SlotDesc.IsRegister );
- if( pFirst->SlotDesc.Slot.Stack.SpOffset < pSecond->SlotDesc.Slot.Stack.SpOffset ) return -1;
- if( pFirst->SlotDesc.Slot.Stack.SpOffset > pSecond->SlotDesc.Slot.Stack.SpOffset ) return 1;
-
- // This is arbitrary, but we want to make sure they are considered separate slots
- if( pFirst->SlotDesc.Slot.Stack.Base < pSecond->SlotDesc.Slot.Stack.Base ) return -1;
- if( pFirst->SlotDesc.Slot.Stack.Base > pSecond->SlotDesc.Slot.Stack.Base ) return 1;
- }
-
- // Then sort them by code offset
- size_t firstOffset = pFirst->CodeOffset;
- size_t secondOffset = pSecond->CodeOffset;
- if( firstOffset < secondOffset ) return -1;
- if( firstOffset > secondOffset ) return 1;
-
- //
- // Same slot and offset. We put all the going-live transition first
- // so that the encoder will skip the remaining transitions and
- // the going-live transitions take precedence
- //
- _ASSERTE( ( pFirst->BecomesLive == 0 ) || ( pFirst->BecomesLive == 1 ) );
- _ASSERTE( ( pSecond->BecomesLive == 0 ) || ( pSecond->BecomesLive == 1 ) );
- return ( pSecond->BecomesLive - pFirst->BecomesLive );
-}
-
-
-void GcInfoEncoder::Build()
-{
- SIZE_T i;
-
- ///////////////////////////////////////////////////////////////////////
- // Method header
- ///////////////////////////////////////////////////////////////////////
-
- m_HeaderInfoWriter.Write( ( m_IsVarArg ? 1 : 0 ), 1 );
-
- if(m_SecurityObjectStackSlot != NO_SECURITY_OBJECT)
- {
- m_HeaderInfoWriter.Write( 1, 1 );
- m_HeaderInfoWriter.EncodeVarLengthSigned(NORMALIZE_STACK_SLOT(m_SecurityObjectStackSlot), SECURITY_OBJECT_STACK_SLOT_ENCBASE);
- }
- else
- {
- m_HeaderInfoWriter.Write( 0, 1 );
- }
-
- if (m_PSPSymStackSlot != NO_PSP_SYM)
- {
- m_HeaderInfoWriter.Write( 1, 1 );
- m_HeaderInfoWriter.EncodeVarLengthSigned(NORMALIZE_STACK_SLOT(m_PSPSymStackSlot), PSP_SYM_STACK_SLOT_ENCBASE);
- }
- else
- {
- m_HeaderInfoWriter.Write( 0, 1 );
- }
-
- if (m_GenericsInstContextStackSlot != NO_GENERICS_INST_CONTEXT)
- {
- m_HeaderInfoWriter.Write( 1, 1 );
- m_HeaderInfoWriter.EncodeVarLengthSigned(NORMALIZE_STACK_SLOT(m_GenericsInstContextStackSlot), GENERICS_INST_CONTEXT_STACK_SLOT_ENCBASE);
- }
- else
- {
- m_HeaderInfoWriter.Write( 0, 1 );
- }
-
- _ASSERTE( m_CodeLength > 0 );
- m_HeaderInfoWriter.EncodeVarLengthUnsigned(NORMALIZE_CODE_LENGTH(m_CodeLength), CODE_LENGTH_ENCBASE);
-
- if(m_StackBaseRegister != NO_STACK_BASE_REGISTER)
- {
- m_HeaderInfoWriter.Write( 1, 1 );
- m_HeaderInfoWriter.EncodeVarLengthUnsigned(NORMALIZE_STACK_BASE_REGISTER(m_StackBaseRegister), STACK_BASE_REGISTER_ENCBASE);
- }
- else
- {
- m_HeaderInfoWriter.Write( 0, 1 );
- }
-
- if(m_SizeOfEditAndContinuePreservedArea != NO_SIZE_OF_EDIT_AND_CONTINUE_PRESERVED_AREA)
- {
- m_HeaderInfoWriter.Write( 1, 1 );
- m_HeaderInfoWriter.EncodeVarLengthUnsigned(m_SizeOfEditAndContinuePreservedArea, SIZE_OF_EDIT_AND_CONTINUE_PRESERVED_AREA_ENCBASE);
- }
- else
- {
- m_HeaderInfoWriter.Write( 0, 1 );
- }
-
-#ifdef FIXED_STACK_PARAMETER_SCRATCH_AREA
- _ASSERTE( m_SizeOfStackOutgoingAndScratchArea != -1 );
- m_HeaderInfoWriter.EncodeVarLengthUnsigned(NORMALIZE_SIZE_OF_STACK_AREA(m_SizeOfStackOutgoingAndScratchArea), SIZE_OF_STACK_AREA_ENCBASE);
-#endif // FIXED_STACK_PARAMETER_SCRATCH_AREA
-
-
- ///////////////////////////////////////////////////////////////////////
- // Fully-interruptible: encode number of interruptible ranges
- ///////////////////////////////////////////////////////////////////////
-
- m_HeaderInfoWriter.EncodeVarLengthUnsigned(NORMALIZE_NUM_INTERRUPTIBLE_RANGES(m_NumInterruptibleRanges), NUM_INTERRUPTIBLE_RANGES_ENCBASE);
-
-#if 0
-#ifdef PARTIALLY_INTERRUPTIBLE_GC_SUPPORTED
-
- ///////////////////////////////////////////////////////////////////////
- // Partially-interruptible: Encode call sites
- ///////////////////////////////////////////////////////////////////////
-
- m_HeaderInfoWriter.Write( m_NumSafePointsWithGcState, sizeof( m_NumSafePointsWithGcState ) * 8 );
-
- if( m_NumSafePointsWithGcState > 0 )
- {
- m_HeaderInfoWriter.Write( m_NumSlotMappings, sizeof( m_NumSlotMappings ) * 8 );
-
- ///////////////////////////////////////////////////////////////////////
- // Partially-interruptible: Encode slot mappings
- ///////////////////////////////////////////////////////////////////////
-
- // Assert that we can write a GcSlotDesc with a single call to BitStreamWriter.Write()
- _ASSERTE( sizeof( GcSlotDesc ) <= sizeof( size_t ) );
- for( UINT32 i=0; i<m_NumSlotMappings; i++ )
- {
- size_t data = 0;
- *( (GcSlotDesc*) &data ) = m_SlotMappings[ i ];
- m_PartiallyInterruptibleInfoWriter.Write( data, sizeof( GcSlotDesc ) * 8 );
- }
- }
-
-#endif // PARTIALLY_INTERRUPTIBLE_GC_SUPPORTED
-#endif
-
- ///////////////////////////////////////////////////////////////////////
- // Fully-interruptible: Encode lifetime transitions
- ///////////////////////////////////////////////////////////////////////
-
- m_rgSortedTransitions = (LifetimeTransition*)m_pAllocator->Alloc(m_LifetimeTransitions.Count() * sizeof(LifetimeTransition));
- m_LifetimeTransitions.CopyTo(m_rgSortedTransitions);
-
- // Sort them first
- size_t numTransitions = m_LifetimeTransitions.Count();
- qsort(m_rgSortedTransitions, numTransitions, sizeof(LifetimeTransition), CompareLifetimeTransitionsForQsort);
-
- //------------------------------------------------------------------
- // Count registers and stack slots
- //------------------------------------------------------------------
-
- int numRegisters = 0;
- int numStackSlots = 0;
-
- if(numTransitions > 0)
- {
- i = 1;
- if(m_rgSortedTransitions[ 0 ].SlotDesc.IsRegister)
- {
- numRegisters++;
-
- for( ; i < numTransitions; i++ )
- {
- if(!(m_rgSortedTransitions[ i ].SlotDesc.IsRegister))
- {
- numStackSlots++;
- i++;
- break;
- }
- _ASSERTE(m_rgSortedTransitions[ i-1 ].SlotDesc.IsRegister);
- if((m_rgSortedTransitions[ i ].SlotDesc.Slot.RegisterNumber) != (m_rgSortedTransitions[ i-1 ].SlotDesc.Slot.RegisterNumber))
- numRegisters++;
- }
- }
- else
- {
- numStackSlots++;
- }
-
- for( ; i < numTransitions; i++ )
- {
- _ASSERTE(!(m_rgSortedTransitions[ i-1 ].SlotDesc.IsRegister));
- if((m_rgSortedTransitions[ i ].SlotDesc.Slot.Stack) != (m_rgSortedTransitions[ i-1 ].SlotDesc.Slot.Stack))
- numStackSlots++;
- }
- }
-
-
- size_t __registerSize = 0;
- size_t __stackSlotSize = 0;
- size_t __transitionSize = 0;
- size_t __numTransitions = 0;
-
-
- //------------------------------------------------------------------
- // Encode registers
- //------------------------------------------------------------------
-
- i = 0;
-
- m_FullyInterruptibleInfoWriter.EncodeVarLengthUnsigned(numRegisters, NUM_REGISTERS_ENCBASE);
-
- UINT32 lastNormRegNum = 0;
-
- for( int j=0; j < numRegisters; j++ )
- {
- _ASSERTE(m_rgSortedTransitions[ i ].SlotDesc.IsRegister);
-
- UINT32 currentRegNum = m_rgSortedTransitions[ i ].SlotDesc.Slot.RegisterNumber;
-
- // Encode slot identification
- UINT32 currentNormRegNum = NORMALIZE_REGISTER(currentRegNum);
- if( j == 0 )
- __registerSize += m_FullyInterruptibleInfoWriter.EncodeVarLengthUnsigned(currentNormRegNum, REGISTER_ENCBASE);
- else
- __registerSize += m_FullyInterruptibleInfoWriter.EncodeVarLengthUnsigned(currentNormRegNum - lastNormRegNum - 1, REGISTER_DELTA_ENCBASE);
- lastNormRegNum = currentNormRegNum;
-
- LifetimeTransition* pLastEncodedTransition = NULL;
-
- for( ; i < numTransitions; i++)
- {
- LifetimeTransition* pTransition = &(m_rgSortedTransitions[ i ]);
-
- if( !(pTransition->SlotDesc.IsRegister) || (pTransition->SlotDesc.Slot.RegisterNumber != currentRegNum))
- break;
-
- if( (pLastEncodedTransition == NULL) )
- {
- // Skip initial going-dead transitions (if any)
- if(!pTransition->BecomesLive)
- continue;
-
- // Encode first going-live transition
- size_t normCodeOffset = NORMALIZE_CODE_OFFSET(pTransition->CodeOffset)+1; // Leave 0 available as terminator
- __transitionSize += m_FullyInterruptibleInfoWriter.EncodeVarLengthUnsigned(normCodeOffset, NORM_CODE_OFFSET_DELTA_ENCBASE);
-
- __transitionSize += EncodeFullyInterruptibleSlotFlags(pTransition->SlotDesc);
-
- __numTransitions++;
- }
- else
- {
- _ASSERTE(pLastEncodedTransition->SlotDesc.IsRegister && pLastEncodedTransition->SlotDesc.Slot.RegisterNumber == currentRegNum);
-
- // Skip transitions on identical offsets
- // If there are multiple transitions on the same code offset, we'll encode the first one only
- _ASSERTE(i > 0);
- LifetimeTransition* pPrevTransition = &(m_rgSortedTransitions[ i-1 ]);
- if( (pPrevTransition->CodeOffset == pTransition->CodeOffset) )
- {
- _ASSERTE((!pPrevTransition->BecomesLive || !pTransition->BecomesLive) ||
- (pPrevTransition->SlotDesc.IsInterior == pTransition->SlotDesc.IsInterior) &&
- (pPrevTransition->SlotDesc.IsPinned == pTransition->SlotDesc.IsPinned));
- continue;
- }
-
- // Also skip redundant transitions
- if( (pLastEncodedTransition->BecomesLive == pTransition->BecomesLive) &&
- (pLastEncodedTransition->SlotDesc.IsInterior == pTransition->SlotDesc.IsInterior) &&
- (pLastEncodedTransition->SlotDesc.IsPinned == pTransition->SlotDesc.IsPinned) )
- continue;
-
- // Encode transition
- size_t normCodeOffsetDelta = NORMALIZE_CODE_OFFSET(pTransition->CodeOffset) - NORMALIZE_CODE_OFFSET(pLastEncodedTransition->CodeOffset);
- _ASSERTE(normCodeOffsetDelta != 0); // Leave 0 available as terminator
- __transitionSize += m_FullyInterruptibleInfoWriter.EncodeVarLengthUnsigned(normCodeOffsetDelta, NORM_CODE_OFFSET_DELTA_ENCBASE);
-
- if(pTransition->BecomesLive)
- {
- m_FullyInterruptibleInfoWriter.Write(1, 1);
- __transitionSize += EncodeFullyInterruptibleSlotFlags(pTransition->SlotDesc) + 1;
- }
- else
- {
- m_FullyInterruptibleInfoWriter.Write(0, 1);
- __transitionSize++;
- }
-
- __numTransitions++;
- }
-
- pLastEncodedTransition = pTransition;
- }
-
- // Encode termination for this slot
- m_FullyInterruptibleInfoWriter.EncodeVarLengthUnsigned(0, NORM_CODE_OFFSET_DELTA_ENCBASE);
- }
-
-
- //------------------------------------------------------------------
- // Encode stack slots
- //------------------------------------------------------------------
-
- m_FullyInterruptibleInfoWriter.EncodeVarLengthUnsigned(numStackSlots, NUM_STACK_SLOTS_ENCBASE);
-
- INT32 lastNormStackSlot = 0;
-
- for( int j=0; j < numStackSlots; j++ )
- {
- _ASSERTE(!m_rgSortedTransitions[ i ].SlotDesc.IsRegister);
-
- GcStackSlot currentStackSlot = m_rgSortedTransitions[ i ].SlotDesc.Slot.Stack;
-
- // Encode slot identification
- INT32 currentNormStackSlot = NORMALIZE_STACK_SLOT(currentStackSlot.SpOffset);
- if( j == 0 )
- __stackSlotSize += m_FullyInterruptibleInfoWriter.EncodeVarLengthSigned(currentNormStackSlot, STACK_SLOT_ENCBASE);
- else
- __stackSlotSize += m_FullyInterruptibleInfoWriter.EncodeVarLengthUnsigned(currentNormStackSlot - lastNormStackSlot, STACK_SLOT_DELTA_ENCBASE);
- lastNormStackSlot = currentNormStackSlot;
- _ASSERTE((currentStackSlot.Base & ~3) == 0);
- m_FullyInterruptibleInfoWriter.Write(currentStackSlot.Base, 2);
- __stackSlotSize += 2;
-
- LifetimeTransition* pLastEncodedTransition = NULL;
-
- for( ; i < numTransitions; i++)
- {
- LifetimeTransition* pTransition = &(m_rgSortedTransitions[ i ]);
-
- _ASSERTE(!pTransition->SlotDesc.IsRegister);
-
- if(pTransition->SlotDesc.Slot.Stack != currentStackSlot)
- break;
-
- if( (pLastEncodedTransition == NULL) )
- {
- // Skip initial going-dead transitions (if any)
- if(!pTransition->BecomesLive)
- continue;
-
- // Encode first going-live transition
- size_t normCodeOffset = NORMALIZE_CODE_OFFSET(pTransition->CodeOffset)+1; // Leave 0 available as terminator
- __transitionSize += m_FullyInterruptibleInfoWriter.EncodeVarLengthUnsigned(normCodeOffset, NORM_CODE_OFFSET_DELTA_ENCBASE);
-
- __transitionSize += EncodeFullyInterruptibleSlotFlags(pTransition->SlotDesc);
-
- __numTransitions++;
- }
- else
- {
- _ASSERTE(!(pLastEncodedTransition->SlotDesc.IsRegister) && pLastEncodedTransition->SlotDesc.Slot.Stack == currentStackSlot);
-
- // Skip transitions on identical offsets
- // If there are multiple transitions on the same code offset, we'll encode the first one only
- _ASSERTE(i > 0);
- LifetimeTransition* pPrevTransition = &(m_rgSortedTransitions[ i-1 ]);
- if( (pPrevTransition->CodeOffset == pTransition->CodeOffset) )
- {
- _ASSERTE((!pPrevTransition->BecomesLive || !pTransition->BecomesLive) ||
- (pPrevTransition->SlotDesc.IsInterior == pTransition->SlotDesc.IsInterior) &&
- (pPrevTransition->SlotDesc.IsPinned == pTransition->SlotDesc.IsPinned));
- continue;
- }
-
- // Also skip redundant transitions
- if( (pLastEncodedTransition->BecomesLive == pTransition->BecomesLive) &&
- (pLastEncodedTransition->SlotDesc.IsInterior == pTransition->SlotDesc.IsInterior) &&
- (pLastEncodedTransition->SlotDesc.IsPinned == pTransition->SlotDesc.IsPinned) )
- continue;
-
- // Encode transition
- size_t normCodeOffsetDelta = NORMALIZE_CODE_OFFSET(pTransition->CodeOffset) - NORMALIZE_CODE_OFFSET(pLastEncodedTransition->CodeOffset);
- _ASSERTE(normCodeOffsetDelta != 0); // Leave 0 available as terminator
- __transitionSize += m_FullyInterruptibleInfoWriter.EncodeVarLengthUnsigned(normCodeOffsetDelta, NORM_CODE_OFFSET_DELTA_ENCBASE);
-
- if(pTransition->BecomesLive)
- {
- m_FullyInterruptibleInfoWriter.Write(1, 1);
- __transitionSize += EncodeFullyInterruptibleSlotFlags(pTransition->SlotDesc) + 1;
- }
- else
- {
- m_FullyInterruptibleInfoWriter.Write(0, 1);
- __transitionSize++;
- }
-
- __numTransitions++;
- }
-
- pLastEncodedTransition = pTransition;
- }
-
- // Encode termination for this slot
- __transitionSize += m_FullyInterruptibleInfoWriter.EncodeVarLengthUnsigned(0, NORM_CODE_OFFSET_DELTA_ENCBASE);
- }
-
-}
-
-size_t GcInfoEncoder::GetByteCount()
-{
- return m_HeaderInfoWriter.GetByteCount() +
-#if 0
-#ifdef PARTIALLY_INTERRUPTIBLE_GC_SUPPORTED
- m_PartiallyInterruptibleInfoWriter.GetByteCount() +
-#endif // PARTIALLY_INTERRUPTIBLE_GC_SUPPORTED
-#endif
- m_FullyInterruptibleInfoWriter.GetByteCount();
-}
-
-//
-// Write encoded information to its final destination and frees temporary buffers.
-// The encoder shouldn't be used anymore after calling this method.
-//
-BYTE* GcInfoEncoder::Emit(BYTE* destBuffer)
-{
- size_t cbGcInfoSize = GetByteCount();
-
- _ASSERTE( destBuffer );
-
- m_HeaderInfoWriter.CopyTo( destBuffer );
- destBuffer += m_HeaderInfoWriter.GetByteCount();
- m_HeaderInfoWriter.Dispose();
-
-#if 0
-#ifdef PARTIALLY_INTERRUPTIBLE_GC_SUPPORTED
- m_PartiallyInterruptibleInfoWriter.CopyTo( destBuffer );
- destBuffer += m_PartiallyInterruptibleInfoWriter.GetByteCount();
- m_PartiallyInterruptibleInfoWriter.Dispose();
-#endif // PARTIALLY_INTERRUPTIBLE_GC_SUPPORTED
-#endif
-
- m_FullyInterruptibleInfoWriter.CopyTo( destBuffer );
- m_FullyInterruptibleInfoWriter.Dispose();
-
- return destBuffer;
-}
-
-void * GcInfoEncoder::eeAllocGCInfo (size_t blockSize)
-{
- return m_pCorJitInfo->allocGCInfo((ULONG)blockSize);
-}
-
-
-BitStreamWriter::BitStreamWriter( IJitAllocator* pAllocator )
-{
- m_pAllocator = pAllocator;
- m_BitCount = 0;
-#ifdef _DEBUG
- m_MemoryBlocksCount = 0;
-#endif
-
- // We are going to need at least one memory block, so we pre-allocate it
- AllocMemoryBlock();
- InitCurrentSlot();
-}
-
-//
-// bit 0 is the least significative bit
-// The stream encodes the first come bit in the least significant bit of each byte
-//
-void BitStreamWriter::Write( size_t data, int count )
-{
- _ASSERTE( count > 0 );
- _ASSERT( count <= sizeof( size_t )*8 );
-
- // Increment it now as we change count later on
- m_BitCount += count;
-
- if( count > m_FreeBitsInCurrentSlot )
- {
- if( m_FreeBitsInCurrentSlot > 0 )
- {
- WriteInCurrentSlot( data, m_FreeBitsInCurrentSlot );
- count -= m_FreeBitsInCurrentSlot;
- data >>= m_FreeBitsInCurrentSlot;
- }
-
- _ASSERTE( count > 0 );
-
- // Initialize the next slot
- if( ++m_pCurrentSlot >= m_OutOfBlockSlot )
- {
- // Get a new memory block
- AllocMemoryBlock();
- }
-
- InitCurrentSlot();
-
- // Write the remainder
- WriteInCurrentSlot( data, count );
- m_FreeBitsInCurrentSlot -= count;
- }
- else
- {
- WriteInCurrentSlot( data, count );
- m_FreeBitsInCurrentSlot -= count;
- // if m_FreeBitsInCurrentSlot becomes 0 a nwe slot will initialized on the next request
- }
-}
-
-
-void BitStreamWriter::CopyTo( BYTE* buffer )
-{
- int i,c;
- BYTE* source = NULL;
-
- MemoryBlock* pMemBlock = m_MemoryBlocks.Head();
- _ASSERTE( pMemBlockDesc != NULL );
- while (pMemBlock->Next() != NULL)
- {
- source = (BYTE*) pMemBlock->Contents;
- // @TODO: use memcpy instead
- for( i = 0; i < m_MemoryBlockSize; i++ )
- {
- *( buffer++ ) = *( source++ );
- }
-
- pMemBlock = pMemBlock->Next();
- }
-
- source = (BYTE*) pMemBlock->Contents;
- // The number of bytes to copy in the last block
- c = (int) ((BYTE*) ( m_pCurrentSlot + 1 ) - source - m_FreeBitsInCurrentSlot/8);
- _ASSERTE( c >= 0 );
- // @TODO: use memcpy instead
- for( i = 0; i < c; i++ )
- {
- *( buffer++ ) = *( source++ );
- }
-
-}
-
-void BitStreamWriter::Dispose()
-{
- m_MemoryBlocks.Dispose(m_pAllocator);
-}
-
-}
-
-#endif // VERIFY_GCINFO
-
diff --git a/src/gcinfo/gcinfo.settings.targets b/src/gcinfo/gcinfo.settings.targets
index f600e2a904..5c241b353a 100644
--- a/src/gcinfo/gcinfo.settings.targets
+++ b/src/gcinfo/gcinfo.settings.targets
@@ -14,7 +14,6 @@
<ItemGroup>
<CppCompile Include="..\ArrayList.cpp" />
<CppCompile Include="..\GCInfoEncoder.cpp" />
- <CppCompile Include="..\DbgGCInfoEncoder.cpp" />
</ItemGroup>
<!-- Import the targets -->
diff --git a/src/gcinfo/gcinfodumper.cpp b/src/gcinfo/gcinfodumper.cpp
index 432e7066ce..4e31871f67 100644
--- a/src/gcinfo/gcinfodumper.cpp
+++ b/src/gcinfo/gcinfodumper.cpp
@@ -21,9 +21,9 @@
#error pick suitable ADDRESS_SPACING for platform
#endif
-GcInfoDumper::GcInfoDumper (PTR_CBYTE pbGCInfo)
+GcInfoDumper::GcInfoDumper (GCInfoToken gcInfoToken)
{
- m_pbGCInfo = pbGCInfo;
+ m_gcTable = gcInfoToken;
m_pRecords = NULL;
m_gcInfoSize = 0;
}
@@ -492,7 +492,7 @@ GcInfoDumper::EnumerateStateChangesResults GcInfoDumper::EnumerateStateChanges (
//
// Decode header information
//
- GcInfoDecoder hdrdecoder(m_pbGCInfo,
+ GcInfoDecoder hdrdecoder(m_gcTable,
(GcInfoDecoderFlags)( DECODE_SECURITY_OBJECT
| DECODE_CODE_LENGTH
| DECODE_GC_LIFETIMES
@@ -617,11 +617,11 @@ PORTABILITY_ASSERT("GcInfoDumper::EnumerateStateChanges is not implemented on th
//
#ifdef PARTIALLY_INTERRUPTIBLE_GC_SUPPORTED
- GcInfoDecoder safePointDecoder(m_pbGCInfo, (GcInfoDecoderFlags)0, 0);
+ GcInfoDecoder safePointDecoder(m_gcTable, (GcInfoDecoderFlags)0, 0);
#endif
{
- GcInfoDecoder untrackedDecoder(m_pbGCInfo, DECODE_GC_LIFETIMES, 0);
+ GcInfoDecoder untrackedDecoder(m_gcTable, DECODE_GC_LIFETIMES, 0);
untrackedDecoder.EnumerateUntrackedSlots(&regdisp,
0,
&LivePointerCallback,
@@ -646,7 +646,7 @@ PORTABILITY_ASSERT("GcInfoDumper::EnumerateStateChanges is not implemented on th
{
BOOL fNewInterruptible = FALSE;
- GcInfoDecoder decoder1(m_pbGCInfo,
+ GcInfoDecoder decoder1(m_gcTable,
(GcInfoDecoderFlags)( DECODE_SECURITY_OBJECT
| DECODE_CODE_LENGTH
| DECODE_VARARG
@@ -680,7 +680,7 @@ PORTABILITY_ASSERT("GcInfoDumper::EnumerateStateChanges is not implemented on th
}
#endif
- GcInfoDecoder decoder2(m_pbGCInfo,
+ GcInfoDecoder decoder2(m_gcTable,
(GcInfoDecoderFlags)( DECODE_SECURITY_OBJECT
| DECODE_CODE_LENGTH
| DECODE_VARARG
diff --git a/src/gcinfo/gcinfoencoder.cpp b/src/gcinfo/gcinfoencoder.cpp
index e6359c86c8..514a3c96be 100644
--- a/src/gcinfo/gcinfoencoder.cpp
+++ b/src/gcinfo/gcinfoencoder.cpp
@@ -12,10 +12,6 @@
#include "gcinfoencoder.h"
-#ifdef VERIFY_GCINFO
-#include "dbggcinfoencoder.h"
-#endif
-
#ifdef _DEBUG
#ifndef LOGGING
#define LOGGING
@@ -446,9 +442,6 @@ GcInfoEncoder::GcInfoEncoder(
m_Info2( pJitAllocator ),
m_InterruptibleRanges( pJitAllocator ),
m_LifetimeTransitions( pJitAllocator )
-#ifdef VERIFY_GCINFO
- , m_DbgEncoder(pCorJitInfo, pMethodInfo, pJitAllocator)
-#endif
{
#ifdef MEASURE_GCINFO
// This causes multiple complus.log files in JIT64. TODO: consider using ICorJitInfo::logMsg instead.
@@ -552,11 +545,6 @@ GcSlotId GcInfoEncoder::GetRegisterSlotId( UINT32 regNum, GcSlotFlags flags )
GcSlotId newSlotId;
newSlotId = m_NumSlots++;
-#ifdef VERIFY_GCINFO
- GcSlotId dbgSlotId = m_DbgEncoder.GetRegisterSlotId(regNum, flags);
- _ASSERTE(dbgSlotId == newSlotId);
-#endif
-
return newSlotId;
}
@@ -590,11 +578,6 @@ GcSlotId GcInfoEncoder::GetStackSlotId( INT32 spOffset, GcSlotFlags flags, GcSta
GcSlotId newSlotId;
newSlotId = m_NumSlots++;
-#ifdef VERIFY_GCINFO
- GcSlotId dbgSlotId = m_DbgEncoder.GetStackSlotId(spOffset, flags, spBase);
- _ASSERTE(dbgSlotId == newSlotId);
-#endif
-
return newSlotId;
}
@@ -624,10 +607,6 @@ void GcInfoEncoder::WriteSlotStateVector(BitStreamWriter &writer, const BitArray
void GcInfoEncoder::DefineInterruptibleRange( UINT32 startInstructionOffset, UINT32 length )
{
-#ifdef VERIFY_GCINFO
- m_DbgEncoder.DefineInterruptibleRange(startInstructionOffset, length);
-#endif
-
UINT32 stopInstructionOffset = startInstructionOffset + length;
UINT32 normStartOffset = NORMALIZE_CODE_OFFSET(startInstructionOffset);
@@ -674,10 +653,6 @@ void GcInfoEncoder::SetSlotState(
{
_ASSERTE( (m_SlotTable[ slotId ].Flags & GC_SLOT_UNTRACKED) == 0 );
-#ifdef VERIFY_GCINFO
- m_DbgEncoder.SetSlotState(instructionOffset, slotId, slotState);
-#endif
-
LifetimeTransition transition;
transition.SlotId = slotId;
@@ -693,19 +668,11 @@ void GcInfoEncoder::SetSlotState(
void GcInfoEncoder::SetIsVarArg()
{
-#ifdef VERIFY_GCINFO
- m_DbgEncoder.SetIsVarArg();
-#endif
-
m_IsVarArg = true;
}
void GcInfoEncoder::SetCodeLength( UINT32 length )
{
-#ifdef VERIFY_GCINFO
- m_DbgEncoder.SetCodeLength(length);
-#endif
-
_ASSERTE( length > 0 );
_ASSERTE( m_CodeLength == 0 || m_CodeLength == length );
m_CodeLength = length;
@@ -714,10 +681,6 @@ void GcInfoEncoder::SetCodeLength( UINT32 length )
void GcInfoEncoder::SetSecurityObjectStackSlot( INT32 spOffset )
{
-#ifdef VERIFY_GCINFO
- m_DbgEncoder.SetSecurityObjectStackSlot(spOffset);
-#endif
-
_ASSERTE( spOffset != NO_SECURITY_OBJECT );
#if defined(_TARGET_AMD64_)
_ASSERTE( spOffset < 0x10 && "The security object cannot reside in an input variable!" );
@@ -751,10 +714,6 @@ void GcInfoEncoder::SetGSCookieStackSlot( INT32 spOffsetGSCookie, UINT32 validRa
void GcInfoEncoder::SetPSPSymStackSlot( INT32 spOffsetPSPSym )
{
-#ifdef VERIFY_GCINFO
- m_DbgEncoder.SetPSPSymStackSlot(spOffsetPSPSym);
-#endif
-
_ASSERTE( spOffsetPSPSym != NO_PSP_SYM );
_ASSERTE( m_PSPSymStackSlot == NO_PSP_SYM || m_PSPSymStackSlot == spOffsetPSPSym );
@@ -763,10 +722,6 @@ void GcInfoEncoder::SetPSPSymStackSlot( INT32 spOffsetPSPSym )
void GcInfoEncoder::SetGenericsInstContextStackSlot( INT32 spOffsetGenericsContext, GENERIC_CONTEXTPARAM_TYPE type)
{
-#ifdef VERIFY_GCINFO
- m_DbgEncoder.SetGenericsInstContextStackSlot(spOffsetGenericsContext);
-#endif
-
_ASSERTE( spOffsetGenericsContext != NO_GENERICS_INST_CONTEXT);
_ASSERTE( m_GenericsInstContextStackSlot == NO_GENERICS_INST_CONTEXT || m_GenericsInstContextStackSlot == spOffsetGenericsContext );
@@ -776,10 +731,6 @@ void GcInfoEncoder::SetGenericsInstContextStackSlot( INT32 spOffsetGenericsConte
void GcInfoEncoder::SetStackBaseRegister( UINT32 regNum )
{
-#ifdef VERIFY_GCINFO
- m_DbgEncoder.SetStackBaseRegister(regNum);
-#endif
-
_ASSERTE( regNum != NO_STACK_BASE_REGISTER );
_ASSERTE(DENORMALIZE_STACK_BASE_REGISTER(NORMALIZE_STACK_BASE_REGISTER(regNum)) == regNum);
_ASSERTE( m_StackBaseRegister == NO_STACK_BASE_REGISTER || m_StackBaseRegister == regNum );
@@ -788,10 +739,6 @@ void GcInfoEncoder::SetStackBaseRegister( UINT32 regNum )
void GcInfoEncoder::SetSizeOfEditAndContinuePreservedArea( UINT32 slots )
{
-#ifdef VERIFY_GCINFO
- m_DbgEncoder.SetSizeOfEditAndContinuePreservedArea(slots);
-#endif
-
_ASSERTE( slots != NO_SIZE_OF_EDIT_AND_CONTINUE_PRESERVED_AREA );
_ASSERTE( m_SizeOfEditAndContinuePreservedArea == NO_SIZE_OF_EDIT_AND_CONTINUE_PRESERVED_AREA );
m_SizeOfEditAndContinuePreservedArea = slots;
@@ -805,10 +752,6 @@ void GcInfoEncoder::SetWantsReportOnlyLeaf()
#ifdef FIXED_STACK_PARAMETER_SCRATCH_AREA
void GcInfoEncoder::SetSizeOfStackOutgoingAndScratchArea( UINT32 size )
{
-#ifdef VERIFY_GCINFO
- m_DbgEncoder.SetSizeOfStackOutgoingAndScratchArea(size);
-#endif
-
_ASSERTE( size != (UINT32)-1 );
_ASSERTE( m_SizeOfStackOutgoingAndScratchArea == (UINT32)-1 || m_SizeOfStackOutgoingAndScratchArea == size );
m_SizeOfStackOutgoingAndScratchArea = size;
@@ -962,10 +905,6 @@ void BitStreamWriter::Write(BitArray& a, UINT32 count)
void GcInfoEncoder::FinalizeSlotIds()
{
-#ifdef VERIFY_GCINFO
- m_DbgEncoder.FinalizeSlotIds();
-#endif
-
#ifdef _DEBUG
m_IsSlotTableFrozen = TRUE;
#endif
@@ -1030,10 +969,6 @@ bool GcInfoEncoder::IsAlwaysScratch(GcSlotDesc &slotDesc)
void GcInfoEncoder::Build()
{
-#ifdef VERIFY_GCINFO
- m_DbgEncoder.Build();
-#endif
-
#ifdef _DEBUG
_ASSERTE(m_IsSlotTableFrozen || m_NumSlots == 0);
#endif
@@ -2641,10 +2576,6 @@ BYTE* GcInfoEncoder::Emit()
size_t cbGcInfoSize = m_Info1.GetByteCount() +
m_Info2.GetByteCount();
-#ifdef VERIFY_GCINFO
- cbGcInfoSize += (sizeof(size_t)) + m_DbgEncoder.GetByteCount();
-#endif
-
LOG((LF_GCINFO, LL_INFO100, "GcInfoEncoder::Emit(): Size of GC info is %u bytes, code size %u bytes.\n", (unsigned)cbGcInfoSize, m_CodeLength ));
BYTE* destBuffer = (BYTE *)eeAllocGCInfo(cbGcInfoSize);
@@ -2654,16 +2585,6 @@ BYTE* GcInfoEncoder::Emit()
BYTE* ptr = destBuffer;
-#ifdef VERIFY_GCINFO
- _ASSERTE(sizeof(size_t) >= sizeof(UINT32));
- size_t __displacement = cbGcInfoSize - m_DbgEncoder.GetByteCount();
- ptr[0] = (BYTE)__displacement;
- ptr[1] = (BYTE) (__displacement >> 8);
- ptr[2] = (BYTE) (__displacement >> 16);
- ptr[3] = (BYTE) (__displacement >> 24);
- ptr += sizeof(size_t);
-#endif
-
m_Info1.CopyTo( ptr );
ptr += m_Info1.GetByteCount();
m_Info1.Dispose();
@@ -2676,11 +2597,6 @@ BYTE* GcInfoEncoder::Emit()
m_pAllocator->Free( m_SlotTable );
#endif
-#ifdef VERIFY_GCINFO
- _ASSERTE(ptr - destBuffer == __displacement);
- m_DbgEncoder.Emit(ptr);
-#endif
-
return destBuffer;
}
diff --git a/src/inc/dbggcinfodecoder.h b/src/inc/dbggcinfodecoder.h
deleted file mode 100644
index 71b62637b7..0000000000
--- a/src/inc/dbggcinfodecoder.h
+++ /dev/null
@@ -1,343 +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.
-/*****************************************************************
- *
- * GC Information Decoding API
- *
- * This is an older well-tested implementation
- * now used to verify the real encoding
- * Define VERIFY_GCINFO to enable the verification
- *
- *****************************************************************/
-
-#ifdef VERIFY_GCINFO
-
-#ifndef _DBG_GC_INFO_DECODER_
-#define _DBG_GC_INFO_DECODER_
-
-#include "daccess.h"
-
-#ifndef GCINFODECODER_NO_EE
-
-#include "eetwain.h"
-
-#else // GCINFODECODER_NO_EE
-
-#if !defined(_NTAMD64_)
-#include "clrnt.h"
-#endif
-
-// Misc. VM types:
-
-class Object;
-typedef Object *OBJECTREF;
-typedef SIZE_T TADDR;
-
-// Stuff from gc.h:
-
-#ifndef __GC_H
-
-#define GC_CALL_INTERIOR 0x1
-#define GC_CALL_PINNED 0x2
-
-#endif // !__GC_H
-
-
-// Stuff from check.h:
-
-#ifndef UNREACHABLE
-#define UNREACHABLE() __assume(0)
-#endif
-
-// Stuff from eetwain.h:
-
-#ifndef _EETWAIN_H
-
-typedef void (*GCEnumCallback)(
- LPVOID hCallback, // callback data
- OBJECTREF* pObject, // address of obect-reference we are reporting
- uint32_t flags // is this a pinned and/or interior pointer
-);
-
-
-#if !defined(_TARGET_X86_)
-#define USE_GC_INFO_DECODER
-#endif
-
-#include "regdisp.h"
-
-#endif // !_EETWAIN_H
-
-#endif // GCINFODECODER_NO_EE
-
-#include "gcinfotypes.h"
-
-
-namespace DbgGcInfo {
-
-struct GcSlotDesc
-{
- union
- {
- UINT32 RegisterNumber;
- GcStackSlot Stack;
- } Slot;
- GcSlotFlags Flags;
-};
-
-class BitStreamReader
-{
-public:
- BitStreamReader( const BYTE* pBuffer )
- {
- _ASSERTE( pBuffer != NULL );
- m_pBuffer = (PTR_BYTE)(TADDR)pBuffer;
- m_BitsRead = 0;
- }
-
- //
- // bit 0 is the least significative bit
- // count can be negative so that bits are written in most-significative to least-significative order
- //
- size_t Read( int numBits )
- {
- size_t result = 0;
- int curBitsRead = 0;
-
- while( curBitsRead < numBits )
- {
- int currByte = m_BitsRead /8;
- int currBitInCurrentByte = m_BitsRead % 8;
- int bitsLeftInCurrentByte = 8 - currBitInCurrentByte;
- _ASSERTE( bitsLeftInCurrentByte > 0 );
-
- int bitsToReadInCurrentByte = min( numBits - curBitsRead, bitsLeftInCurrentByte );
-
- size_t data = m_pBuffer[ currByte ];
- data >>= currBitInCurrentByte;
- data &= (1<<bitsToReadInCurrentByte) -1;
-
- data <<= curBitsRead;
- result |= data;
-
- curBitsRead += bitsToReadInCurrentByte;
- m_BitsRead += bitsToReadInCurrentByte;
- }
-
- return result;
- }
-
- // Returns the number of bits read so far
- size_t GetCurrentPos()
- {
- return m_BitsRead;
- }
-
- void SetCurrentPos( size_t pos )
- {
- m_BitsRead = pos;
- }
-
- // Can use negative values
- void Skip( SSIZE_T numBitsToSkip )
- {
- m_BitsRead += numBitsToSkip;
- _ASSERTE( m_BitsRead >= 0 );
- }
-
- //--------------------------------------------------------------------------
- // Decode variable length numbers
- // See the corresponding methods on BitStreamWriter for more information on the format
- //--------------------------------------------------------------------------
-
- inline size_t DecodeVarLengthUnsigned( int base )
- {
- _ASSERTE((base > 0) && (base < (int)sizeof(size_t)*8));
- size_t numEncodings = 1 << base;
- size_t result = 0;
- for(int shift=0; ; shift+=base)
- {
- _ASSERTE(shift+base <= (int)sizeof(size_t)*8);
-
- size_t currentChunk = Read(base+1);
- result |= (currentChunk & (numEncodings-1)) << shift;
- if(!(currentChunk & numEncodings))
- {
- // Extension bit is not set, we're done.
- return result;
- }
- }
- }
-
- inline SSIZE_T DecodeVarLengthSigned( int base )
- {
- _ASSERTE((base > 0) && (base < (int)sizeof(SSIZE_T)*8));
- size_t numEncodings = 1 << base;
- SSIZE_T result = 0;
- for(int shift=0; ; shift+=base)
- {
- _ASSERTE(shift+base <= (int)sizeof(SSIZE_T)*8);
-
- size_t currentChunk = Read(base+1);
- result |= (currentChunk & (numEncodings-1)) << shift;
- if(!(currentChunk & numEncodings))
- {
- // Extension bit is not set, sign-extend and we're done.
- int sbits = sizeof(SSIZE_T)*8 - (shift+base);
- result <<= sbits;
- result >>= sbits; // This provides the sign extension
- return result;
- }
- }
- }
-
-private:
- PTR_BYTE m_pBuffer;
- size_t m_BitsRead;
-};
-
-
-class GcInfoDecoder
-{
-public:
-
- // If you are not insterested in interruptibility or gc lifetime information, pass 0 as instructionOffset
- GcInfoDecoder(
- const BYTE* gcInfoAddr,
- GcInfoDecoderFlags flags,
- UINT32 instructionOffset = 0
- );
-
-
- //------------------------------------------------------------------------
- // Interruptibility
- //------------------------------------------------------------------------
-
- bool IsInterruptible();
-
- // Returns true to stop enumerating.
- typedef bool EnumerateInterruptibleRangesCallback (UINT32 startOffset, UINT32 stopOffset, LPVOID hCallback);
-
- void EnumerateInterruptibleRanges (
- EnumerateInterruptibleRangesCallback *pCallback,
- LPVOID hCallback);
-
- //------------------------------------------------------------------------
- // GC lifetime information
- //------------------------------------------------------------------------
-
- bool EnumerateLiveSlots(
- PREGDISPLAY pRD,
- bool reportScratchSlots,
- unsigned flags,
- GCEnumCallback pCallBack,
- LPVOID hCallBack
- );
-
- void VerifyLiveRegister(
- UINT32 regNum,
- GcSlotFlags flags
- );
-
-
- void VerifyLiveStackSlot(
- int spOffset,
- GcStackSlotBase spBase,
- GcSlotFlags flags
- );
-
- void DoFinalVerification();
-
- //------------------------------------------------------------------------
- // Miscellaneous method information
- //------------------------------------------------------------------------
-
- INT32 GetSecurityObjectStackSlot();
- INT32 GetPSPSymStackSlot();
- INT32 GetGenericsInstContextStackSlot();
- bool GetIsVarArg();
- UINT32 GetCodeLength();
- UINT32 GetStackBaseRegister();
- UINT32 GetSizeOfEditAndContinuePreservedArea();
-
-#ifdef FIXED_STACK_PARAMETER_SCRATCH_AREA
- UINT32 GetSizeOfStackParameterArea();
-#endif // FIXED_STACK_PARAMETER_SCRATCH_AREA
-
-private:
- BitStreamReader m_Reader;
- UINT32 m_InstructionOffset;
-
- // Pre-decoded information
- bool m_IsInterruptible;
- bool m_IsVarArg;
- INT32 m_SecurityObjectStackSlot;
- INT32 m_PSPSymStackSlot;
- INT32 m_GenericsInstContextStackSlot;
- UINT32 m_CodeLength;
- UINT32 m_StackBaseRegister;
- UINT32 m_SizeOfEditAndContinuePreservedArea;
- UINT32 m_NumInterruptibleRanges;
-
-#ifdef FIXED_STACK_PARAMETER_SCRATCH_AREA
- UINT32 m_SizeOfStackOutgoingAndScratchArea;
-#endif // FIXED_STACK_PARAMETER_SCRATCH_AREA
-
-#ifdef _DEBUG
- GcInfoDecoderFlags m_Flags;
-#endif
-
- GcSlotDesc* m_pLiveRegisters;
- GcSlotDesc* m_pLiveStackSlots;
- int m_NumLiveRegisters;
- int m_NumLiveStackSlots;
-
- CQuickBytes qbSlots1;
- CQuickBytes qbSlots2;
-
- static bool SetIsInterruptibleCB (UINT32 startOffset, UINT32 stopOffset, LPVOID hCallback);
-
- OBJECTREF* GetRegisterSlot(
- int regNum,
- PREGDISPLAY pRD
- );
-
- OBJECTREF* GetStackSlot(
- INT32 spOffset,
- GcStackSlotBase spBase,
- PREGDISPLAY pRD
- );
-
- bool IsScratchRegister(int regNum, PREGDISPLAY pRD);
- bool IsScratchStackSlot(INT32 spOffset, GcStackSlotBase spBase, PREGDISPLAY pRD);
-
- void ReportRegisterToGC(
- int regNum,
- BOOL isInterior,
- BOOL isPinned,
- PREGDISPLAY pRD,
- unsigned flags,
- GCEnumCallback pCallBack,
- LPVOID hCallBack
- );
-
- void ReportStackSlotToGC(
- INT32 spOffset,
- GcStackSlotBase spBase,
- BOOL isInterior,
- BOOL isPinned,
- PREGDISPLAY pRD,
- unsigned flags,
- GCEnumCallback pCallBack,
- LPVOID hCallBack
- );
-
-
-};
-
-}
-
-#endif // _DBG_GC_INFO_DECODER_
-#endif // VERIFY_GCINFO
-
diff --git a/src/inc/dbggcinfoencoder.h b/src/inc/dbggcinfoencoder.h
deleted file mode 100644
index 85b56ad297..0000000000
--- a/src/inc/dbggcinfoencoder.h
+++ /dev/null
@@ -1,469 +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.
-/*****************************************************************************
- *
- * GC Information Encoding API
- *
- * This is an older well-tested implementation
- * now used to verify the real encoding
- * Define VERIFY_GCINFO to enable the verification
- *
- */
-
-#ifdef VERIFY_GCINFO
-
-#ifndef __DBGGCINFOENCODER_H__
-#define __DBGGCINFOENCODER_H__
-
-#include <windows.h>
-
-#include <wchar.h>
-#include <stdio.h>
-
-#include "corjit.h"
-#include "iallocator.h"
-#include "gcinfoarraylist.h"
-
-#include "stdmacros.h"
-#include "gcinfotypes.h"
-
-
-class IJitAllocator;
-
-
-
-namespace DbgGcInfo {
-
-//-----------------------------------------------------------------------------
-// The following macro controls whether the encoder has to call the IJitAllocator::Free method
-// Don't call IJitAllocator::Free for mscorjit64.dll
-//-----------------------------------------------------------------------------
-//#define MUST_CALL_JITALLOCATOR_FREE
-
-
-class BitStreamWriter
-{
-public:
- BitStreamWriter( IJitAllocator* pAllocator );
- void Write( size_t data, int count );
-
- inline size_t GetBitCount()
- {
- return m_BitCount;
- }
-
- inline size_t GetByteCount()
- {
- return ( m_BitCount + 7 ) / 8;
- }
-
-
- void CopyTo( BYTE* buffer );
- void Dispose();
-
- //--------------------------------------------------------
- // Encode variable length numbers
- // Uses base+1 bits at minimum
- // Bits 0..(base-1) represent the encoded quantity
- // If it doesn't fit, set bit #base to 1 and use base+1 more bits
- //--------------------------------------------------------
- int EncodeVarLengthUnsigned( size_t n, int base )
- {
- _ASSERTE((base > 0) && (base < sizeof(size_t)*8));
- size_t numEncodings = 1 << base;
- int bitsUsed = base+1;
- for( ; ; bitsUsed += base+1)
- {
- if( n < numEncodings )
- {
- Write( n, base+1 ); // This sets the extension bit to zero
- return bitsUsed;
- }
- else
- {
- size_t currentChunk = n & (numEncodings-1);
- Write( currentChunk | numEncodings, base+1 );
- n >>= base;
- }
- }
- return bitsUsed;
- }
-
- //--------------------------------------------------------
- // Signed quantities are encoded the same as unsigned
- // The most relevant difference is that a number is considered
- // to fit in base bits if the topmost bit of a base-long chunk
- // matches the sign of the whole number
- //--------------------------------------------------------
- int EncodeVarLengthSigned( SSIZE_T n, int base )
- {
- _ASSERTE((base > 0) && (base < sizeof(SSIZE_T)*8));
- size_t numEncodings = 1 << base;
- for(int bitsUsed = base+1; ; bitsUsed += base+1)
- {
- size_t currentChunk = ((size_t) n) & (numEncodings-1);
- size_t topmostBit = currentChunk & (numEncodings >> 1);
- n >>= base; // signed arithmetic shift
- if( topmostBit && (n == (SSIZE_T)-1) || !topmostBit && (n == 0))
- {
- // The topmost bit correctly represents the sign
- Write( currentChunk, base+1 ); // This sets the extension bit to zero
- return bitsUsed;
- }
- else
- {
- Write( currentChunk | numEncodings, base+1 );
- }
- }
- }
-
-private:
-
- class MemoryBlockList;
- class MemoryBlock
- {
- friend class MemoryBlockList;
- MemoryBlock* m_next;
-
- public:
- size_t Contents[];
-
- inline MemoryBlock* Next()
- {
- return m_next;
- }
- };
-
- class MemoryBlockList
- {
- MemoryBlock* m_head;
- MemoryBlock* m_tail;
-
- public:
- MemoryBlockList();
-
- inline MemoryBlock* Head()
- {
- return m_head;
- }
-
- MemoryBlock* AppendNew(IAllocator* allocator, size_t bytes);
- void Dispose(IAllocator* allocator);
- };
-
- IJitAllocator* m_pAllocator;
- size_t m_BitCount;
- int m_FreeBitsInCurrentSlot;
- MemoryBlockList m_MemoryBlocks;
- const static int m_MemoryBlockSize = 512; // must be a multiple of the pointer size
- size_t* m_pCurrentSlot; // bits are written through this pointer
- size_t* m_OutOfBlockSlot; // sentinel value to determine when the block is full
-#ifdef _DEBUG
- int m_MemoryBlocksCount;
-#endif
-
-private:
- // Writes bits knowing that they will all fit in the current memory slot
- inline void WriteInCurrentSlot( size_t data, int count )
- {
- data &= SAFE_SHIFT_LEFT(1, count) - 1;
-
- data <<= (sizeof( size_t )*8-m_FreeBitsInCurrentSlot);
-
- *m_pCurrentSlot |= data;
- }
-
- void AllocMemoryBlock();
-
- inline void InitCurrentSlot()
- {
- m_FreeBitsInCurrentSlot = sizeof( size_t )*8;
- *m_pCurrentSlot = 0;
- }
-
-};
-
-struct GcSlotDesc
-{
- union
- {
- UINT32 RegisterNumber;
- GcStackSlot Stack;
- } Slot;
- unsigned IsRegister : 1;
- unsigned IsInterior : 1;
- unsigned IsPinned : 1;
-};
-
-
-
-typedef UINT32 GcSlotId;
-
-
-class GcSlotSet
-{
- friend class GcInfoEncoder;
-public:
- GcSlotSet( GcInfoEncoder * pEncoder );
-
- // Copy constructor
- GcSlotSet( GcSlotSet & other );
-
- inline void Add( GcSlotId slotId );
-
- inline void Remove( GcSlotId slotId );
-
-// Not used
-#if 0
- inline void RemoveAll();
-
- void Add( GcSlotSet & other );
- void Subtract( GcSlotSet & other );
- void Intersect( GcSlotSet & other );
-#endif
-
- // Must be called when done with the object
- inline void Dispose();
-
-private:
- // A bit vector representing the set
- BYTE * m_Data;
-
- int m_NumBytes;
-
- GcInfoEncoder* m_pEncoder;
-};
-
-
-class GcInfoEncoder
-{
-public:
- GcInfoEncoder(
- ICorJitInfo* pCorJitInfo,
- CORINFO_METHOD_INFO* pMethodInfo,
- IJitAllocator* pJitAllocator
- );
-
-
- //------------------------------------------------------------------------
- // Interruptibility
- //------------------------------------------------------------------------
-
- // An instruction at offset x will be interruptible
- // if-and-only-if startInstructionOffset <= x < startInstructionOffset+length
- void DefineInterruptibleRange( UINT32 startInstructionOffset, UINT32 length );
-
-
- //------------------------------------------------------------------------
- // Slot information
- //------------------------------------------------------------------------
-
- //
- // spOffset are always relative to the SP of the caller (same as SP at the method entry and exit)
- // Negative offsets describe GC refs in the local and outgoing areas.
- // Positive offsets describe GC refs in the scratch area
- // Note that if the dynamic allocation area is resized, the outgoing area will not be valid anymore
- // Old slots must be declared dead and new ones can be defined.
- // It's up to the JIT to do the right thing. We don't enforce this.
- //
-
- GcSlotId GetRegisterSlotId( UINT32 regNum, GcSlotFlags flags );
- GcSlotId GetStackSlotId( INT32 spOffset, GcSlotFlags flags, GcStackSlotBase spBase = GC_CALLER_SP_REL );
-
- //
- // After a FinalizeSlotIds is called, no more slot definitions can be made.
- // FinalizeSlotIds must be called once and only once before calling DefineGcStateAtCallSite
- // If no call sites are described, calling FinalizeSlotIds can and should (for performance reasons) be avoided
- //
- void FinalizeSlotIds();
-
-
-#if 0
-#ifdef PARTIALLY_INTERRUPTIBLE_GC_SUPPORTED
-
- //------------------------------------------------------------------------
- // Partially-interruptible information
- //------------------------------------------------------------------------
-
-
- void DefineGcStateAtSafePoint(
- UINT32 instructionOffset,
- GcSlotSet &liveSlots
- );
-
-#endif // PARTIALLY_INTERRUPTIBLE_GC_SUPPORTED
-#endif
-
- //------------------------------------------------------------------------
- // Fully-interruptible information
- //------------------------------------------------------------------------
-
- //
- // For inputs, pass zero as offset
- //
-
- // This method defines what the GC state of a slot is when a thread's suspension IP
- // is equal to instructionOffset
-
- void SetSlotState( UINT32 instructionOffset,
- GcSlotId slotId,
- GcSlotState slotState
- );
-
-
-
- //------------------------------------------------------------------------
- // Miscellaneous method information
- //------------------------------------------------------------------------
-
- void SetSecurityObjectStackSlot( INT32 spOffset );
- void SetPSPSymStackSlot( INT32 spOffsetPSPSym );
- void SetGenericsInstContextStackSlot( INT32 spOffsetGenericsContext );
- void SetIsVarArg();
- void SetCodeLength( UINT32 length );
-
- // Optional in the general case. Required if the method uses GC_FRAMEREG_REL stack slots
- void SetStackBaseRegister( UINT32 registerNumber );
- void SetSizeOfEditAndContinuePreservedArea( UINT32 size );
-
-#ifdef FIXED_STACK_PARAMETER_SCRATCH_AREA
- void SetSizeOfStackOutgoingAndScratchArea( UINT32 size );
-#endif // FIXED_STACK_PARAMETER_SCRATCH_AREA
-
-
- //------------------------------------------------------------------------
- // Encoding
- //------------------------------------------------------------------------
-
- //
- // Build() encodes GC information into temporary buffers.
- // The method description cannot change after Build is called
- //
- void Build();
-
- //
- // Write encoded information to its final destination and frees temporary buffers.
- // The encoder shouldn't be used anymore after calling this method.
- // It returns a pointer to the destination buffer, which address is byte-aligned
- //
- size_t GetByteCount();
- BYTE* Emit(BYTE* dest);
-
-private:
-
- friend class LifetimeTransitionsQuickSort;
- friend class LifetimeTransitionsQuickSortByOffset;
-
- struct LifetimeTransition
- {
- UINT32 CodeOffset;
- GcSlotDesc SlotDesc;
- bool BecomesLive;
- };
-
- ICorJitInfo* m_pCorJitInfo;
- CORINFO_METHOD_INFO* m_pMethodInfo;
- IJitAllocator* m_pAllocator;
-
-#ifdef _DEBUG
- char *m_MethodName, *m_ModuleName;
-#endif
-
- BitStreamWriter m_HeaderInfoWriter;
-#if 0
-#ifdef PARTIALLY_INTERRUPTIBLE_GC_SUPPORTED
- BitStreamWriter m_PartiallyInterruptibleInfoWriter;
-#endif
-#endif
- BitStreamWriter m_FullyInterruptibleInfoWriter;
-
- GcInfoArrayList<LifetimeTransition, 64> m_LifetimeTransitions;
- LifetimeTransition *m_rgSortedTransitions;
-
- bool m_IsVarArg;
- INT32 m_SecurityObjectStackSlot;
- INT32 m_PSPSymStackSlot;
- INT32 m_GenericsInstContextStackSlot;
- UINT32 m_CodeLength;
- UINT32 m_StackBaseRegister;
- UINT32 m_SizeOfEditAndContinuePreservedArea;
- UINT32 m_LastInterruptibleRangeStopOffset;
- UINT32 m_NumInterruptibleRanges;
-
-#ifdef FIXED_STACK_PARAMETER_SCRATCH_AREA
- UINT32 m_SizeOfStackOutgoingAndScratchArea;
-#endif // FIXED_STACK_PARAMETER_SCRATCH_AREA
-
- void * eeAllocGCInfo (size_t blockSize);
-
- inline int EncodeFullyInterruptibleSlotFlags(GcSlotDesc slotDesc)
- {
- int flagEnc = 1;
- if( slotDesc.IsInterior )
- flagEnc |= 0x2;
- if( slotDesc.IsPinned )
- flagEnc |= 0x4;
- if(flagEnc == 1)
- {
- m_FullyInterruptibleInfoWriter.Write(0, 1);
- return 1;
- }
- else
- {
- m_FullyInterruptibleInfoWriter.Write(flagEnc, 3);
- return 3;
- }
- }
-
-
-private:
-
- friend class GcSlotSet;
- friend class EncoderCheckState;
-
- static const UINT32 m_MappingTableInitialSize = 32;
- UINT32 m_MappingTableSize;
- UINT32 m_NumSlotMappings;
- GcSlotDesc *m_SlotMappings;
-
-#if 0
-#ifdef PARTIALLY_INTERRUPTIBLE_GC_SUPPORTED
- UINT32 m_NumSafePointsWithGcState;
-#endif
-#endif
-
- void GrowMappingTable();
-
-#ifdef _DEBUG
- bool m_IsMappingTableFrozen;
-#endif
-};
-
-
-
-// Not used
-#if 0
-
-void GcSlotSet::RemoveAll()
-{
- ZeroMemory( m_Data, m_NumBytes );
-}
-
-#endif
-
-
-void GcSlotSet::Dispose()
-{
-#ifdef MUST_CALL_JITALLOCATOR_FREE
- m_pEncoder->m_pAllocator->Free( m_Data );
-#endif
-}
-
-
-}
-
-#endif // !__DBGGCINFOENCODER_H__
-
-#endif // VERIFY_GCINFO
-
diff --git a/src/inc/eetwain.h b/src/inc/eetwain.h
index a7bab8701e..6e183c5546 100644
--- a/src/inc/eetwain.h
+++ b/src/inc/eetwain.h
@@ -30,6 +30,7 @@
#include "corjit.h" // For NativeVarInfo
#include "stackwalktypes.h"
#include "bitvector.h"
+#include "gcinfotypes.h"
#if !defined(_TARGET_X86_)
#define USE_GC_INFO_DECODER
@@ -218,7 +219,7 @@ virtual bool IsGcSafe(EECodeInfo *pCodeInfo,
*/
virtual unsigned FindEndOfLastInterruptibleRegion(unsigned curOffset,
unsigned endOffset,
- PTR_VOID methodInfoPtr) = 0;
+ GCInfoToken gcInfoToken) = 0;
#endif // _TARGET_AMD64_ && _DEBUG
/*
@@ -293,7 +294,7 @@ virtual bool IsInSynchronizedRegion(
not take procedure splitting into account). For the actual size of
the hot region call IJitManager::JitTokenToMethodHotSize.
*/
-virtual size_t GetFunctionSize(PTR_VOID methodInfoPtr) = 0;
+virtual size_t GetFunctionSize(GCInfoToken gcInfoToken) = 0;
/*
Returns the size of the frame (barring localloc)
@@ -447,7 +448,7 @@ bool IsGcSafe( EECodeInfo *pCodeInfo,
virtual
unsigned FindEndOfLastInterruptibleRegion(unsigned curOffset,
unsigned endOffset,
- PTR_VOID methodInfoPtr);
+ GCInfoToken gcInfoToken);
#endif // _TARGET_AMD64_ && _DEBUG
/*
@@ -551,8 +552,7 @@ bool IsInSynchronizedRegion(
Returns the size of a given function.
*/
virtual
-size_t GetFunctionSize(
- PTR_VOID methodInfoPtr);
+size_t GetFunctionSize(GCInfoToken gcInfoToken);
/*
Returns the size of the frame (barring localloc)
diff --git a/src/inc/gcdecoder.cpp b/src/inc/gcdecoder.cpp
index 7472c9aa62..d337faeebc 100644
--- a/src/inc/gcdecoder.cpp
+++ b/src/inc/gcdecoder.cpp
@@ -18,7 +18,7 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
/* This file is shared between the VM and JIT/IL and SOS/Strike directories */
-#include "gcinfo.h"
+#include "gcinfotypes.h"
/*****************************************************************************/
/*
diff --git a/src/inc/gcdump.h b/src/inc/gcdump.h
index aded6bb102..cd73940ded 100644
--- a/src/inc/gcdump.h
+++ b/src/inc/gcdump.h
@@ -17,7 +17,7 @@
#define __GCDUMP_H__
/*****************************************************************************/
-#include "gcinfo.h" // For InfoHdr
+#include "gcinfotypes.h" // For InfoHdr
#ifndef FASTCALL
#ifndef FEATURE_PAL
@@ -32,7 +32,8 @@ class GCDump
{
public:
- GCDump (bool encBytes = true,
+ GCDump (UINT32 gcInfoVersion,
+ bool encBytes = true,
unsigned maxEncBytes = 5,
bool dumpCodeOffs = true);
@@ -44,7 +45,7 @@ public:
* Return value : Size in bytes of the header encoding
*/
- unsigned FASTCALL DumpInfoHdr (PTR_CBYTE table,
+ unsigned FASTCALL DumpInfoHdr (PTR_CBYTE gcInfoBlock,
InfoHdr * header, /* OUT */
unsigned * methodSize, /* OUT */
bool verifyGCTables = false);
@@ -52,13 +53,12 @@ public:
/*-------------------------------------------------------------------------
* Dumps the GC tables to 'stdout'
- * table : Ptr to the start of the table part of the GC info.
- * This immediately follows the GCinfo header
+ * table : The GCInfoToken
* verifyGCTables : If the JIT has been compiled with VERIFY_GC_TABLES
* Return value : Size in bytes of the GC table encodings
*/
- size_t FASTCALL DumpGCTable (PTR_CBYTE table,
+ size_t FASTCALL DumpGCTable (PTR_CBYTE gcInfoBlock,
#ifdef _TARGET_X86_
const InfoHdr& header,
#endif
@@ -79,6 +79,7 @@ public:
public:
typedef void (*printfFtn)(const char* fmt, ...);
printfFtn gcPrintf;
+ UINT32 gcInfoVersion;
//-------------------------------------------------------------------------
protected:
@@ -89,7 +90,7 @@ protected:
/* Helper methods */
- PTR_CBYTE DumpEncoding(PTR_CBYTE table,
+ PTR_CBYTE DumpEncoding(PTR_CBYTE gcInfoBlock,
int cDumpBytes);
void DumpOffset (unsigned o);
void DumpOffsetEx(unsigned o);
diff --git a/src/inc/gcinfo.h b/src/inc/gcinfo.h
index bb80620f31..500e1b7a02 100644
--- a/src/inc/gcinfo.h
+++ b/src/inc/gcinfo.h
@@ -8,11 +8,8 @@
#define _GCINFO_H_
/*****************************************************************************/
-#include <stdlib.h> // For memcmp()
-#include "windef.h" // For BYTE
#include "daccess.h"
-
-#include "bitvector.h" // for ptrArgTP
+#include "windef.h" // For BYTE
// Some declarations in this file are used on non-x86 platforms, but most are x86-specific.
@@ -31,234 +28,32 @@ const unsigned byref_OFFSET_FLAG = 0x1; // the offset is an interior ptr
const unsigned pinned_OFFSET_FLAG = 0x2; // the offset is a pinned ptr
const unsigned this_OFFSET_FLAG = 0x2; // the offset is "this"
-#ifdef _TARGET_X86_
-
-#ifndef FASTCALL
-#define FASTCALL __fastcall
-#endif
+//-----------------------------------------------------------------------------
+// The current GCInfo Version
+//-----------------------------------------------------------------------------
-// we use offsetof to get the offset of a field
-#include <stddef.h> // offsetof
-#ifndef offsetof
-#define offsetof(s,m) ((size_t)&(((s *)0)->m))
-#endif
-
-enum infoHdrAdjustConstants {
- // Constants
- SET_FRAMESIZE_MAX = 7,
- SET_ARGCOUNT_MAX = 8, // Change to 6
- SET_PROLOGSIZE_MAX = 16,
- SET_EPILOGSIZE_MAX = 10, // Change to 6
- SET_EPILOGCNT_MAX = 4,
- SET_UNTRACKED_MAX = 3
-};
+#define GCINFO_VERSION 1
+//-----------------------------------------------------------------------------
+// GCInfoToken: A wrapper that contains the GcInfo data and version number.
//
-// Enum to define the 128 codes that are used to incrementally adjust the InfoHdr structure
+// The version# is not stored in the GcInfo structure -- because it is
+// wasteful to store the version once for every method.
+// Instead, the version# istracked per range-section of generated/loaded methods.
//
-enum infoHdrAdjust {
-
- SET_FRAMESIZE = 0, // 0x00
- SET_ARGCOUNT = SET_FRAMESIZE + SET_FRAMESIZE_MAX + 1, // 0x08
- SET_PROLOGSIZE = SET_ARGCOUNT + SET_ARGCOUNT_MAX + 1, // 0x11
- SET_EPILOGSIZE = SET_PROLOGSIZE + SET_PROLOGSIZE_MAX + 1, // 0x22
- SET_EPILOGCNT = SET_EPILOGSIZE + SET_EPILOGSIZE_MAX + 1, // 0x2d
- SET_UNTRACKED = SET_EPILOGCNT + (SET_EPILOGCNT_MAX + 1) * 2, // 0x37
-
- FIRST_FLIP = SET_UNTRACKED + SET_UNTRACKED_MAX + 1,
-
- FLIP_EDI_SAVED = FIRST_FLIP, // 0x3b
- FLIP_ESI_SAVED, // 0x3c
- FLIP_EBX_SAVED, // 0x3d
- FLIP_EBP_SAVED, // 0x3e
- FLIP_EBP_FRAME, // 0x3f
- FLIP_INTERRUPTIBLE, // 0x40
- FLIP_DOUBLE_ALIGN, // 0x41
- FLIP_SECURITY, // 0x42
- FLIP_HANDLERS, // 0x43
- FLIP_LOCALLOC, // 0x44
- FLIP_EDITnCONTINUE, // 0x45
- FLIP_VAR_PTR_TABLE_SZ, // 0x46 Flip whether a table-size exits after the header encoding
- FFFF_UNTRACKED_CNT, // 0x47 There is a count (>SET_UNTRACKED_MAX) after the header encoding
- FLIP_VARARGS, // 0x48
- FLIP_PROF_CALLBACKS, // 0x49
- FLIP_HAS_GS_COOKIE, // 0x4A - The offset of the GuardStack cookie follows after the header encoding
- FLIP_SYNC, // 0x4B
- FLIP_HAS_GENERICS_CONTEXT,// 0x4C
- FLIP_GENERICS_CONTEXT_IS_METHODDESC,// 0x4D
-
- // 0x4E .. 0x4f unused
-
- NEXT_FOUR_START = 0x50,
- NEXT_FOUR_FRAMESIZE = 0x50,
- NEXT_FOUR_ARGCOUNT = 0x60,
- NEXT_THREE_PROLOGSIZE = 0x70,
- NEXT_THREE_EPILOGSIZE = 0x78
-};
-
-#define HAS_UNTRACKED ((unsigned int) -1)
-#define HAS_VARPTR ((unsigned int) -1)
-// 0 is not a valid offset for EBP-frames as all locals are at a negative offset
-// For ESP frames, the cookie is above (at a higher address than) the buffers,
-// and so cannot be at offset 0.
-#define INVALID_GS_COOKIE_OFFSET 0
-// Temporary value to indicate that the offset needs to be read after the header
-#define HAS_GS_COOKIE_OFFSET ((unsigned int) -1)
-
-// 0 is not a valid sync offset
-#define INVALID_SYNC_OFFSET 0
-// Temporary value to indicate that the offset needs to be read after the header
-#define HAS_SYNC_OFFSET ((unsigned int) -1)
-
-#define INVALID_ARGTAB_OFFSET 0
-
-#include <pshpack1.h>
-
-// Working set optimization: saving 12 * 128 = 1536 bytes in infoHdrShortcut
-struct InfoHdr;
-
-struct InfoHdrSmall {
- unsigned char prologSize; // 0
- unsigned char epilogSize; // 1
- unsigned char epilogCount : 3; // 2 [0:2]
- unsigned char epilogAtEnd : 1; // 2 [3]
- unsigned char ediSaved : 1; // 2 [4] which callee-saved regs are pushed onto stack
- unsigned char esiSaved : 1; // 2 [5]
- unsigned char ebxSaved : 1; // 2 [6]
- unsigned char ebpSaved : 1; // 2 [7]
- unsigned char ebpFrame : 1; // 3 [0] locals accessed relative to ebp
- unsigned char interruptible : 1; // 3 [1] is intr. at all points (except prolog/epilog), not just call-sites
- unsigned char doubleAlign : 1; // 3 [2] uses double-aligned stack (ebpFrame will be false)
- unsigned char security : 1; // 3 [3] has slot for security object
- unsigned char handlers : 1; // 3 [4] has callable handlers
- unsigned char localloc : 1; // 3 [5] uses localloc
- unsigned char editNcontinue : 1; // 3 [6] was JITed in EnC mode
- unsigned char varargs : 1; // 3 [7] function uses varargs calling convention
- unsigned char profCallbacks : 1; // 4 [0]
- unsigned char genericsContext : 1;//4 [1] function reports a generics context parameter is present
- unsigned char genericsContextIsMethodDesc : 1;//4[2]
- unsigned short argCount; // 5,6 in bytes
- unsigned int frameSize; // 7,8,9,10 in bytes
- unsigned int untrackedCnt; // 11,12,13,14
- unsigned int varPtrTableSize; // 15.16,17,18
-
- // Checks whether "this" is compatible with "target".
- // It is not an exact bit match as "this" could have some
- // marker/place-holder values, which will have to be written out
- // after the header.
-
- bool isHeaderMatch(const InfoHdr& target) const;
-};
-
-
-struct InfoHdr : public InfoHdrSmall {
- // 0 (zero) means that there is no GuardStack cookie
- // The cookie is either at ESP+gsCookieOffset or EBP-gsCookieOffset
- unsigned int gsCookieOffset; // 19,20,21,22
- unsigned int syncStartOffset; // 23,24,25,26
- unsigned int syncEndOffset; // 27,28,29,30
-
- // 31 bytes total
-
- // Checks whether "this" is compatible with "target".
- // It is not an exact bit match as "this" could have some
- // marker/place-holder values, which will have to be written out
- // after the header.
-
- bool isHeaderMatch(const InfoHdr& target) const
- {
-#ifdef _ASSERTE
- // target cannot have place-holder values.
- _ASSERTE(target.untrackedCnt != HAS_UNTRACKED &&
- target.varPtrTableSize != HAS_VARPTR &&
- target.gsCookieOffset != HAS_GS_COOKIE_OFFSET &&
- target.syncStartOffset != HAS_SYNC_OFFSET);
-#endif
-
- // compare two InfoHdr's up to but not including the untrackCnt field
- if (memcmp(this, &target, offsetof(InfoHdr, untrackedCnt)) != 0)
- return false;
-
- if (untrackedCnt != target.untrackedCnt) {
- if (target.untrackedCnt <= SET_UNTRACKED_MAX)
- return false;
- else if (untrackedCnt != HAS_UNTRACKED)
- return false;
- }
-
- if (varPtrTableSize != target.varPtrTableSize) {
- if ((varPtrTableSize != 0) != (target.varPtrTableSize != 0))
- return false;
- }
-
- if ((gsCookieOffset == INVALID_GS_COOKIE_OFFSET) !=
- (target.gsCookieOffset == INVALID_GS_COOKIE_OFFSET))
- return false;
-
- if ((syncStartOffset == INVALID_SYNC_OFFSET) !=
- (target.syncStartOffset == INVALID_SYNC_OFFSET))
- return false;
-
- return true;
- }
-};
-
-
-union CallPattern {
- struct {
- unsigned char argCnt;
- unsigned char regMask; // EBP=0x8, EBX=0x4, ESI=0x2, EDI=0x1
- unsigned char argMask;
- unsigned char codeDelta;
- } fld;
- unsigned val;
-};
-
-#include <poppack.h>
-
-#define IH_MAX_PROLOG_SIZE (51)
-
-extern const InfoHdrSmall infoHdrShortcut[];
-extern int infoHdrLookup[];
-
-inline void GetInfoHdr(int index, InfoHdr * header)
+// The GCInfo version is computed as :
+// 1) The current GCINFO_VERSION for JITted and Ngened images
+// 2) A function of the Ready - to - run major version stored in READYTORUN_HEADER
+// for ready - to - run images.ReadyToRunJitManager::JitTokenToGCInfoVersion()
+// provides the GcInfo version for any Method.Currently, there's only one
+// version of GCInfo.
+//-----------------------------------------------------------------------------
+
+struct GCInfoToken
{
- * ((InfoHdrSmall *) header) = infoHdrShortcut[index];
-
- header->gsCookieOffset = 0;
- header->syncStartOffset = 0;
- header->syncEndOffset = 0;
-}
-
-PTR_CBYTE FASTCALL decodeHeader(PTR_CBYTE table, InfoHdr* header);
-
-BYTE FASTCALL encodeHeaderFirst(const InfoHdr& header, InfoHdr* state, int* more, int *pCached);
-BYTE FASTCALL encodeHeaderNext (const InfoHdr& header, InfoHdr* state);
-
-size_t FASTCALL decodeUnsigned (PTR_CBYTE src, unsigned* value);
-size_t FASTCALL decodeUDelta (PTR_CBYTE src, unsigned* value, unsigned lastValue);
-size_t FASTCALL decodeSigned (PTR_CBYTE src, int * value);
-
-#define CP_MAX_CODE_DELTA (0x23)
-#define CP_MAX_ARG_CNT (0x02)
-#define CP_MAX_ARG_MASK (0x00)
-
-extern const unsigned callPatternTable[];
-extern const unsigned callCommonDelta[];
-
-
-int FASTCALL lookupCallPattern(unsigned argCnt,
- unsigned regMask,
- unsigned argMask,
- unsigned codeDelta);
-
-void FASTCALL decodeCallPattern(int pattern,
- unsigned * argCnt,
- unsigned * regMask,
- unsigned * argMask,
- unsigned * codeDelta);
-
-#endif // _TARGET_86_ || _TARGET_ARM_
+ PTR_VOID Info;
+ UINT32 Version;
+};
/*****************************************************************************/
#endif //_GCINFO_H_
diff --git a/src/inc/gcinfodecoder.h b/src/inc/gcinfodecoder.h
index 52e8ed8b62..f703727a76 100644
--- a/src/inc/gcinfodecoder.h
+++ b/src/inc/gcinfodecoder.h
@@ -11,7 +11,7 @@
#ifndef _GC_INFO_DECODER_
#define _GC_INFO_DECODER_
-#include "daccess.h"
+#include "gcinfotypes.h"
#define _max(a, b) (((a) > (b)) ? (a) : (b))
#define _min(a, b) (((a) < (b)) ? (a) : (b))
@@ -176,10 +176,6 @@ enum GcInfoDecoderFlags
DECODE_EDIT_AND_CONTINUE = 0x800,
};
-#ifdef VERIFY_GCINFO
-#include "dbggcinfodecoder.h"
-#endif
-
enum GcInfoHeaderFlags
{
GC_INFO_IS_VARARG = 0x1,
@@ -433,12 +429,11 @@ public:
// If you are not insterested in interruptibility or gc lifetime information, pass 0 as instructionOffset
GcInfoDecoder(
- PTR_CBYTE gcInfoAddr,
+ GCInfoToken gcInfoToken,
GcInfoDecoderFlags flags,
UINT32 instructionOffset = 0
);
-
//------------------------------------------------------------------------
// Interruptibility
//------------------------------------------------------------------------
@@ -538,12 +533,9 @@ private:
#ifdef _DEBUG
GcInfoDecoderFlags m_Flags;
PTR_CBYTE m_GcInfoAddress;
+ UINT32 m_Version;
#endif
-#ifdef VERIFY_GCINFO
- DbgGcInfo::GcInfoDecoder m_DbgDecoder;
-#endif
-
static bool SetIsInterruptibleCB (UINT32 startOffset, UINT32 stopOffset, LPVOID hCallback);
OBJECTREF* GetRegisterSlot(
@@ -617,13 +609,6 @@ private:
UINT32 regNum = pSlot->Slot.RegisterNumber;
if( reportScratchSlots || !IsScratchRegister( regNum, pRD ) )
{
-#ifdef VERIFY_GCINFO
- m_DbgDecoder.VerifyLiveRegister(
- regNum,
- pSlot->Flags
- );
-#endif
-
ReportRegisterToGC(
regNum,
pSlot->Flags,
@@ -644,14 +629,6 @@ private:
GcStackSlotBase spBase = pSlot->Slot.Stack.Base;
if( reportScratchSlots || !IsScratchStackSlot(spOffset, spBase, pRD) )
{
-#ifdef VERIFY_GCINFO
- m_DbgDecoder.VerifyLiveStackSlot(
- spOffset,
- spBase,
- pSlot->Flags
- );
-#endif
-
ReportStackSlotToGC(
spOffset,
spBase,
diff --git a/src/inc/gcinfodumper.h b/src/inc/gcinfodumper.h
index 64801b06c2..296dd29543 100644
--- a/src/inc/gcinfodumper.h
+++ b/src/inc/gcinfodumper.h
@@ -18,7 +18,7 @@ class GcInfoDumper
{
public:
- GcInfoDumper (PTR_CBYTE pbGCInfo);
+ GcInfoDumper (GCInfoToken gcInfoToken);
~GcInfoDumper ();
// Returns TRUE to stop decoding.
@@ -80,7 +80,7 @@ private:
UINT marked;
};
- PTR_CBYTE m_pbGCInfo;
+ GCInfoToken m_gcTable;
UINT32 m_StackBaseRegister;
UINT32 m_SizeOfEditAndContinuePreservedArea;
LivePointerRecord *m_pRecords;
diff --git a/src/inc/gcinfoencoder.h b/src/inc/gcinfoencoder.h
index ff03138032..8875d3b492 100644
--- a/src/inc/gcinfoencoder.h
+++ b/src/inc/gcinfoencoder.h
@@ -87,10 +87,6 @@
#include "gcinfotypes.h"
-#ifdef VERIFY_GCINFO
-#include "dbggcinfoencoder.h"
-#endif //VERIFY_GCINFO
-
#ifdef MEASURE_GCINFO
struct GcInfoSize
{
@@ -526,10 +522,6 @@ private:
bool m_IsSlotTableFrozen;
#endif
-#ifdef VERIFY_GCINFO
- DbgGcInfo::GcInfoEncoder m_DbgEncoder;
-#endif
-
#ifdef MEASURE_GCINFO
GcInfoSize m_CurrentMethodSize;
#endif
diff --git a/src/inc/gcinfotypes.h b/src/inc/gcinfotypes.h
index a54cec30e5..fc624b2c0a 100644
--- a/src/inc/gcinfotypes.h
+++ b/src/inc/gcinfotypes.h
@@ -6,6 +6,8 @@
#ifndef __GCINFOTYPES_H__
#define __GCINFOTYPES_H__
+#include "gcinfo.h"
+
// This file is included when building an "alt jit". In that case, we are doing a cross-compile:
// we may be building the ARM jit on x86, for example. We generally make that work by conditionalizing on
// a _TARGET_XXX_ variable that we explicitly set in the build, rather than the _XXX_ variable implicitly
@@ -62,19 +64,19 @@
__forceinline size_t SAFE_SHIFT_LEFT(size_t x, size_t count)
{
_ASSERTE(count <= BITS_PER_SIZE_T);
- return (x << 1) << (count-1);
+ return (x << 1) << (count - 1);
}
__forceinline size_t SAFE_SHIFT_RIGHT(size_t x, size_t count)
{
_ASSERTE(count <= BITS_PER_SIZE_T);
- return (x >> 1) >> (count-1);
+ return (x >> 1) >> (count - 1);
}
inline UINT32 CeilOfLog2(size_t x)
{
_ASSERTE(x > 0);
- UINT32 result = (x & (x-1)) ? 1 : 0;
- while(x != 1)
+ UINT32 result = (x & (x - 1)) ? 1 : 0;
+ while (x != 1)
{
result++;
x >>= 1;
@@ -84,24 +86,24 @@ inline UINT32 CeilOfLog2(size_t x)
enum GcSlotFlags
{
- GC_SLOT_BASE = 0x0,
- GC_SLOT_INTERIOR = 0x1,
- GC_SLOT_PINNED = 0x2,
- GC_SLOT_UNTRACKED = 0x4,
+ GC_SLOT_BASE = 0x0,
+ GC_SLOT_INTERIOR = 0x1,
+ GC_SLOT_PINNED = 0x2,
+ GC_SLOT_UNTRACKED = 0x4,
// For internal use by the encoder/decoder
- GC_SLOT_IS_REGISTER = 0x8,
- GC_SLOT_IS_DELETED = 0x10,
+ GC_SLOT_IS_REGISTER = 0x8,
+ GC_SLOT_IS_DELETED = 0x10,
};
enum GcStackSlotBase
{
- GC_CALLER_SP_REL = 0x0,
- GC_SP_REL = 0x1,
- GC_FRAMEREG_REL = 0x2,
+ GC_CALLER_SP_REL = 0x0,
+ GC_SP_REL = 0x1,
+ GC_FRAMEREG_REL = 0x2,
- GC_SPBASE_FIRST = GC_CALLER_SP_REL,
- GC_SPBASE_LAST = GC_FRAMEREG_REL,
+ GC_SPBASE_FIRST = GC_CALLER_SP_REL,
+ GC_SPBASE_LAST = GC_FRAMEREG_REL,
};
#ifdef _DEBUG
@@ -113,11 +115,10 @@ const char* const GcStackSlotBaseNames[] =
};
#endif
-
enum GcSlotState
{
- GC_SLOT_DEAD = 0x0,
- GC_SLOT_LIVE = 0x1,
+ GC_SLOT_DEAD = 0x0,
+ GC_SLOT_LIVE = 0x1,
};
struct GcStackSlot
@@ -135,6 +136,238 @@ struct GcStackSlot
}
};
+#ifdef _TARGET_X86_
+
+#include <stdlib.h> // For memcmp()
+#include "bitvector.h" // for ptrArgTP
+
+#ifndef FASTCALL
+#define FASTCALL __fastcall
+#endif
+
+// we use offsetof to get the offset of a field
+#include <stddef.h> // offsetof
+#ifndef offsetof
+#define offsetof(s,m) ((size_t)&(((s *)0)->m))
+#endif
+
+enum infoHdrAdjustConstants {
+ // Constants
+ SET_FRAMESIZE_MAX = 7,
+ SET_ARGCOUNT_MAX = 8, // Change to 6
+ SET_PROLOGSIZE_MAX = 16,
+ SET_EPILOGSIZE_MAX = 10, // Change to 6
+ SET_EPILOGCNT_MAX = 4,
+ SET_UNTRACKED_MAX = 3
+};
+
+//
+// Enum to define the 128 codes that are used to incrementally adjust the InfoHdr structure
+//
+enum infoHdrAdjust {
+
+ SET_FRAMESIZE = 0, // 0x00
+ SET_ARGCOUNT = SET_FRAMESIZE + SET_FRAMESIZE_MAX + 1, // 0x08
+ SET_PROLOGSIZE = SET_ARGCOUNT + SET_ARGCOUNT_MAX + 1, // 0x11
+ SET_EPILOGSIZE = SET_PROLOGSIZE + SET_PROLOGSIZE_MAX + 1, // 0x22
+ SET_EPILOGCNT = SET_EPILOGSIZE + SET_EPILOGSIZE_MAX + 1, // 0x2d
+ SET_UNTRACKED = SET_EPILOGCNT + (SET_EPILOGCNT_MAX + 1) * 2, // 0x37
+
+ FIRST_FLIP = SET_UNTRACKED + SET_UNTRACKED_MAX + 1,
+
+ FLIP_EDI_SAVED = FIRST_FLIP, // 0x3b
+ FLIP_ESI_SAVED, // 0x3c
+ FLIP_EBX_SAVED, // 0x3d
+ FLIP_EBP_SAVED, // 0x3e
+ FLIP_EBP_FRAME, // 0x3f
+ FLIP_INTERRUPTIBLE, // 0x40
+ FLIP_DOUBLE_ALIGN, // 0x41
+ FLIP_SECURITY, // 0x42
+ FLIP_HANDLERS, // 0x43
+ FLIP_LOCALLOC, // 0x44
+ FLIP_EDITnCONTINUE, // 0x45
+ FLIP_VAR_PTR_TABLE_SZ, // 0x46 Flip whether a table-size exits after the header encoding
+ FFFF_UNTRACKED_CNT, // 0x47 There is a count (>SET_UNTRACKED_MAX) after the header encoding
+ FLIP_VARARGS, // 0x48
+ FLIP_PROF_CALLBACKS, // 0x49
+ FLIP_HAS_GS_COOKIE, // 0x4A - The offset of the GuardStack cookie follows after the header encoding
+ FLIP_SYNC, // 0x4B
+ FLIP_HAS_GENERICS_CONTEXT,// 0x4C
+ FLIP_GENERICS_CONTEXT_IS_METHODDESC,// 0x4D
+
+ // 0x4E .. 0x4f unused
+
+ NEXT_FOUR_START = 0x50,
+ NEXT_FOUR_FRAMESIZE = 0x50,
+ NEXT_FOUR_ARGCOUNT = 0x60,
+ NEXT_THREE_PROLOGSIZE = 0x70,
+ NEXT_THREE_EPILOGSIZE = 0x78
+};
+
+#define HAS_UNTRACKED ((unsigned int) -1)
+#define HAS_VARPTR ((unsigned int) -1)
+// 0 is not a valid offset for EBP-frames as all locals are at a negative offset
+// For ESP frames, the cookie is above (at a higher address than) the buffers,
+// and so cannot be at offset 0.
+#define INVALID_GS_COOKIE_OFFSET 0
+// Temporary value to indicate that the offset needs to be read after the header
+#define HAS_GS_COOKIE_OFFSET ((unsigned int) -1)
+
+// 0 is not a valid sync offset
+#define INVALID_SYNC_OFFSET 0
+// Temporary value to indicate that the offset needs to be read after the header
+#define HAS_SYNC_OFFSET ((unsigned int) -1)
+
+#define INVALID_ARGTAB_OFFSET 0
+
+#include <pshpack1.h>
+
+// Working set optimization: saving 12 * 128 = 1536 bytes in infoHdrShortcut
+struct InfoHdr;
+
+struct InfoHdrSmall {
+ unsigned char prologSize; // 0
+ unsigned char epilogSize; // 1
+ unsigned char epilogCount : 3; // 2 [0:2]
+ unsigned char epilogAtEnd : 1; // 2 [3]
+ unsigned char ediSaved : 1; // 2 [4] which callee-saved regs are pushed onto stack
+ unsigned char esiSaved : 1; // 2 [5]
+ unsigned char ebxSaved : 1; // 2 [6]
+ unsigned char ebpSaved : 1; // 2 [7]
+ unsigned char ebpFrame : 1; // 3 [0] locals accessed relative to ebp
+ unsigned char interruptible : 1; // 3 [1] is intr. at all points (except prolog/epilog), not just call-sites
+ unsigned char doubleAlign : 1; // 3 [2] uses double-aligned stack (ebpFrame will be false)
+ unsigned char security : 1; // 3 [3] has slot for security object
+ unsigned char handlers : 1; // 3 [4] has callable handlers
+ unsigned char localloc : 1; // 3 [5] uses localloc
+ unsigned char editNcontinue : 1; // 3 [6] was JITed in EnC mode
+ unsigned char varargs : 1; // 3 [7] function uses varargs calling convention
+ unsigned char profCallbacks : 1; // 4 [0]
+ unsigned char genericsContext : 1;//4 [1] function reports a generics context parameter is present
+ unsigned char genericsContextIsMethodDesc : 1;//4[2]
+ unsigned short argCount; // 5,6 in bytes
+ unsigned int frameSize; // 7,8,9,10 in bytes
+ unsigned int untrackedCnt; // 11,12,13,14
+ unsigned int varPtrTableSize; // 15.16,17,18
+
+ // Checks whether "this" is compatible with "target".
+ // It is not an exact bit match as "this" could have some
+ // marker/place-holder values, which will have to be written out
+ // after the header.
+
+ bool isHeaderMatch(const InfoHdr& target) const;
+};
+
+
+struct InfoHdr : public InfoHdrSmall {
+ // 0 (zero) means that there is no GuardStack cookie
+ // The cookie is either at ESP+gsCookieOffset or EBP-gsCookieOffset
+ unsigned int gsCookieOffset; // 19,20,21,22
+ unsigned int syncStartOffset; // 23,24,25,26
+ unsigned int syncEndOffset; // 27,28,29,30
+
+ // 31 bytes total
+
+ // Checks whether "this" is compatible with "target".
+ // It is not an exact bit match as "this" could have some
+ // marker/place-holder values, which will have to be written out
+ // after the header.
+
+ bool isHeaderMatch(const InfoHdr& target) const
+ {
+#ifdef _ASSERTE
+ // target cannot have place-holder values.
+ _ASSERTE(target.untrackedCnt != HAS_UNTRACKED &&
+ target.varPtrTableSize != HAS_VARPTR &&
+ target.gsCookieOffset != HAS_GS_COOKIE_OFFSET &&
+ target.syncStartOffset != HAS_SYNC_OFFSET);
+#endif
+
+ // compare two InfoHdr's up to but not including the untrackCnt field
+ if (memcmp(this, &target, offsetof(InfoHdr, untrackedCnt)) != 0)
+ return false;
+
+ if (untrackedCnt != target.untrackedCnt) {
+ if (target.untrackedCnt <= SET_UNTRACKED_MAX)
+ return false;
+ else if (untrackedCnt != HAS_UNTRACKED)
+ return false;
+ }
+
+ if (varPtrTableSize != target.varPtrTableSize) {
+ if ((varPtrTableSize != 0) != (target.varPtrTableSize != 0))
+ return false;
+ }
+
+ if ((gsCookieOffset == INVALID_GS_COOKIE_OFFSET) !=
+ (target.gsCookieOffset == INVALID_GS_COOKIE_OFFSET))
+ return false;
+
+ if ((syncStartOffset == INVALID_SYNC_OFFSET) !=
+ (target.syncStartOffset == INVALID_SYNC_OFFSET))
+ return false;
+
+ return true;
+ }
+};
+
+
+union CallPattern {
+ struct {
+ unsigned char argCnt;
+ unsigned char regMask; // EBP=0x8, EBX=0x4, ESI=0x2, EDI=0x1
+ unsigned char argMask;
+ unsigned char codeDelta;
+ } fld;
+ unsigned val;
+};
+
+#include <poppack.h>
+
+#define IH_MAX_PROLOG_SIZE (51)
+
+extern const InfoHdrSmall infoHdrShortcut[];
+extern int infoHdrLookup[];
+
+inline void GetInfoHdr(int index, InfoHdr * header)
+{
+ *((InfoHdrSmall *)header) = infoHdrShortcut[index];
+
+ header->gsCookieOffset = 0;
+ header->syncStartOffset = 0;
+ header->syncEndOffset = 0;
+}
+
+PTR_CBYTE FASTCALL decodeHeader(PTR_CBYTE table, InfoHdr* header);
+
+BYTE FASTCALL encodeHeaderFirst(const InfoHdr& header, InfoHdr* state, int* more, int *pCached);
+BYTE FASTCALL encodeHeaderNext(const InfoHdr& header, InfoHdr* state);
+
+size_t FASTCALL decodeUnsigned(PTR_CBYTE src, unsigned* value);
+size_t FASTCALL decodeUDelta(PTR_CBYTE src, unsigned* value, unsigned lastValue);
+size_t FASTCALL decodeSigned(PTR_CBYTE src, int * value);
+
+#define CP_MAX_CODE_DELTA (0x23)
+#define CP_MAX_ARG_CNT (0x02)
+#define CP_MAX_ARG_MASK (0x00)
+
+extern const unsigned callPatternTable[];
+extern const unsigned callCommonDelta[];
+
+
+int FASTCALL lookupCallPattern(unsigned argCnt,
+ unsigned regMask,
+ unsigned argMask,
+ unsigned codeDelta);
+
+void FASTCALL decodeCallPattern(int pattern,
+ unsigned * argCnt,
+ unsigned * regMask,
+ unsigned * argMask,
+ unsigned * codeDelta);
+
+#endif // _TARGET_86_
+
// Stack offsets must be 8-byte aligned, so we use this unaligned
// offset to represent that the method doesn't have a security object
#define NO_SECURITY_OBJECT (-1)
@@ -144,7 +377,6 @@ struct GcStackSlot
#define NO_GENERICS_INST_CONTEXT (-1)
#define NO_PSP_SYM (-1)
-
#if defined(_TARGET_AMD64_)
#ifndef TARGET_POINTER_SIZE
diff --git a/src/inc/llvm/Dwarf.def b/src/inc/llvm/Dwarf.def
new file mode 100644
index 0000000000..2bc9ef8621
--- /dev/null
+++ b/src/inc/llvm/Dwarf.def
@@ -0,0 +1,393 @@
+// 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.
+
+// ==============================================================================
+// LLVM Release License
+// ==============================================================================
+// University of Illinois/NCSA
+// Open Source License
+//
+// Copyright (c) 2003-2015 University of Illinois at Urbana-Champaign.
+// All rights reserved.
+//
+// Developed by:
+//
+// LLVM Team
+//
+// University of Illinois at Urbana-Champaign
+//
+// http://llvm.org
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy of
+// this software and associated documentation files (the "Software"), to deal with
+// 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:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimers.
+//
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimers in the
+// documentation and/or other materials provided with the distribution.
+//
+// * Neither the names of the LLVM Team, University of Illinois at
+// Urbana-Champaign, nor the names of its contributors may be used to
+// endorse or promote products derived from this Software without specific
+// prior written permission.
+//
+// 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
+// CONTRIBUTORS 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 WITH THE
+// SOFTWARE.
+
+//===----------------------------------------------------------------------===//
+//
+// Macros for running through Dwarf enumerators.
+//
+//===----------------------------------------------------------------------===//
+
+// TODO: Add other DW-based macros.
+#if !(defined HANDLE_DW_TAG || defined HANDLE_DW_OP || \
+ defined HANDLE_DW_LANG || defined HANDLE_DW_ATE || \
+ defined HANDLE_DW_VIRTUALITY)
+#error "Missing macro definition of HANDLE_DW*"
+#endif
+
+#ifndef HANDLE_DW_TAG
+#define HANDLE_DW_TAG(ID, NAME)
+#endif
+
+#ifndef HANDLE_DW_OP
+#define HANDLE_DW_OP(ID, NAME)
+#endif
+
+#ifndef HANDLE_DW_LANG
+#define HANDLE_DW_LANG(ID, NAME)
+#endif
+
+#ifndef HANDLE_DW_ATE
+#define HANDLE_DW_ATE(ID, NAME)
+#endif
+
+#ifndef HANDLE_DW_VIRTUALITY
+#define HANDLE_DW_VIRTUALITY(ID, NAME)
+#endif
+
+HANDLE_DW_TAG(0x0001, array_type)
+HANDLE_DW_TAG(0x0002, class_type)
+HANDLE_DW_TAG(0x0003, entry_point)
+HANDLE_DW_TAG(0x0004, enumeration_type)
+HANDLE_DW_TAG(0x0005, formal_parameter)
+HANDLE_DW_TAG(0x0008, imported_declaration)
+HANDLE_DW_TAG(0x000a, label)
+HANDLE_DW_TAG(0x000b, lexical_block)
+HANDLE_DW_TAG(0x000d, member)
+HANDLE_DW_TAG(0x000f, pointer_type)
+HANDLE_DW_TAG(0x0010, reference_type)
+HANDLE_DW_TAG(0x0011, compile_unit)
+HANDLE_DW_TAG(0x0012, string_type)
+HANDLE_DW_TAG(0x0013, structure_type)
+HANDLE_DW_TAG(0x0015, subroutine_type)
+HANDLE_DW_TAG(0x0016, typedef)
+HANDLE_DW_TAG(0x0017, union_type)
+HANDLE_DW_TAG(0x0018, unspecified_parameters)
+HANDLE_DW_TAG(0x0019, variant)
+HANDLE_DW_TAG(0x001a, common_block)
+HANDLE_DW_TAG(0x001b, common_inclusion)
+HANDLE_DW_TAG(0x001c, inheritance)
+HANDLE_DW_TAG(0x001d, inlined_subroutine)
+HANDLE_DW_TAG(0x001e, module)
+HANDLE_DW_TAG(0x001f, ptr_to_member_type)
+HANDLE_DW_TAG(0x0020, set_type)
+HANDLE_DW_TAG(0x0021, subrange_type)
+HANDLE_DW_TAG(0x0022, with_stmt)
+HANDLE_DW_TAG(0x0023, access_declaration)
+HANDLE_DW_TAG(0x0024, base_type)
+HANDLE_DW_TAG(0x0025, catch_block)
+HANDLE_DW_TAG(0x0026, const_type)
+HANDLE_DW_TAG(0x0027, constant)
+HANDLE_DW_TAG(0x0028, enumerator)
+HANDLE_DW_TAG(0x0029, file_type)
+HANDLE_DW_TAG(0x002a, friend)
+HANDLE_DW_TAG(0x002b, namelist)
+HANDLE_DW_TAG(0x002c, namelist_item)
+HANDLE_DW_TAG(0x002d, packed_type)
+HANDLE_DW_TAG(0x002e, subprogram)
+HANDLE_DW_TAG(0x002f, template_type_parameter)
+HANDLE_DW_TAG(0x0030, template_value_parameter)
+HANDLE_DW_TAG(0x0031, thrown_type)
+HANDLE_DW_TAG(0x0032, try_block)
+HANDLE_DW_TAG(0x0033, variant_part)
+HANDLE_DW_TAG(0x0034, variable)
+HANDLE_DW_TAG(0x0035, volatile_type)
+HANDLE_DW_TAG(0x0036, dwarf_procedure)
+HANDLE_DW_TAG(0x0037, restrict_type)
+HANDLE_DW_TAG(0x0038, interface_type)
+HANDLE_DW_TAG(0x0039, namespace)
+HANDLE_DW_TAG(0x003a, imported_module)
+HANDLE_DW_TAG(0x003b, unspecified_type)
+HANDLE_DW_TAG(0x003c, partial_unit)
+HANDLE_DW_TAG(0x003d, imported_unit)
+HANDLE_DW_TAG(0x003f, condition)
+HANDLE_DW_TAG(0x0040, shared_type)
+HANDLE_DW_TAG(0x0041, type_unit)
+HANDLE_DW_TAG(0x0042, rvalue_reference_type)
+HANDLE_DW_TAG(0x0043, template_alias)
+
+// New in DWARF v5.
+HANDLE_DW_TAG(0x0044, coarray_type)
+HANDLE_DW_TAG(0x0045, generic_subrange)
+HANDLE_DW_TAG(0x0046, dynamic_type)
+
+// User-defined tags.
+HANDLE_DW_TAG(0x4081, MIPS_loop)
+HANDLE_DW_TAG(0x4101, format_label)
+HANDLE_DW_TAG(0x4102, function_template)
+HANDLE_DW_TAG(0x4103, class_template)
+HANDLE_DW_TAG(0x4106, GNU_template_template_param)
+HANDLE_DW_TAG(0x4107, GNU_template_parameter_pack)
+HANDLE_DW_TAG(0x4108, GNU_formal_parameter_pack)
+HANDLE_DW_TAG(0x4200, APPLE_property)
+HANDLE_DW_TAG(0xb000, BORLAND_property)
+HANDLE_DW_TAG(0xb001, BORLAND_Delphi_string)
+HANDLE_DW_TAG(0xb002, BORLAND_Delphi_dynamic_array)
+HANDLE_DW_TAG(0xb003, BORLAND_Delphi_set)
+HANDLE_DW_TAG(0xb004, BORLAND_Delphi_variant)
+
+HANDLE_DW_OP(0x03, addr)
+HANDLE_DW_OP(0x06, deref)
+HANDLE_DW_OP(0x08, const1u)
+HANDLE_DW_OP(0x09, const1s)
+HANDLE_DW_OP(0x0a, const2u)
+HANDLE_DW_OP(0x0b, const2s)
+HANDLE_DW_OP(0x0c, const4u)
+HANDLE_DW_OP(0x0d, const4s)
+HANDLE_DW_OP(0x0e, const8u)
+HANDLE_DW_OP(0x0f, const8s)
+HANDLE_DW_OP(0x10, constu)
+HANDLE_DW_OP(0x11, consts)
+HANDLE_DW_OP(0x12, dup)
+HANDLE_DW_OP(0x13, drop)
+HANDLE_DW_OP(0x14, over)
+HANDLE_DW_OP(0x15, pick)
+HANDLE_DW_OP(0x16, swap)
+HANDLE_DW_OP(0x17, rot)
+HANDLE_DW_OP(0x18, xderef)
+HANDLE_DW_OP(0x19, abs)
+HANDLE_DW_OP(0x1a, and)
+HANDLE_DW_OP(0x1b, div)
+HANDLE_DW_OP(0x1c, minus)
+HANDLE_DW_OP(0x1d, mod)
+HANDLE_DW_OP(0x1e, mul)
+HANDLE_DW_OP(0x1f, neg)
+HANDLE_DW_OP(0x20, not)
+HANDLE_DW_OP(0x21, or )
+HANDLE_DW_OP(0x22, plus)
+HANDLE_DW_OP(0x23, plus_uconst)
+HANDLE_DW_OP(0x24, shl)
+HANDLE_DW_OP(0x25, shr)
+HANDLE_DW_OP(0x26, shra)
+HANDLE_DW_OP(0x27, xor)
+HANDLE_DW_OP(0x2f, skip)
+HANDLE_DW_OP(0x28, bra)
+HANDLE_DW_OP(0x29, eq)
+HANDLE_DW_OP(0x2a, ge)
+HANDLE_DW_OP(0x2b, gt)
+HANDLE_DW_OP(0x2c, le)
+HANDLE_DW_OP(0x2d, lt)
+HANDLE_DW_OP(0x2e, ne)
+HANDLE_DW_OP(0x30, lit0)
+HANDLE_DW_OP(0x31, lit1)
+HANDLE_DW_OP(0x32, lit2)
+HANDLE_DW_OP(0x33, lit3)
+HANDLE_DW_OP(0x34, lit4)
+HANDLE_DW_OP(0x35, lit5)
+HANDLE_DW_OP(0x36, lit6)
+HANDLE_DW_OP(0x37, lit7)
+HANDLE_DW_OP(0x38, lit8)
+HANDLE_DW_OP(0x39, lit9)
+HANDLE_DW_OP(0x3a, lit10)
+HANDLE_DW_OP(0x3b, lit11)
+HANDLE_DW_OP(0x3c, lit12)
+HANDLE_DW_OP(0x3d, lit13)
+HANDLE_DW_OP(0x3e, lit14)
+HANDLE_DW_OP(0x3f, lit15)
+HANDLE_DW_OP(0x40, lit16)
+HANDLE_DW_OP(0x41, lit17)
+HANDLE_DW_OP(0x42, lit18)
+HANDLE_DW_OP(0x43, lit19)
+HANDLE_DW_OP(0x44, lit20)
+HANDLE_DW_OP(0x45, lit21)
+HANDLE_DW_OP(0x46, lit22)
+HANDLE_DW_OP(0x47, lit23)
+HANDLE_DW_OP(0x48, lit24)
+HANDLE_DW_OP(0x49, lit25)
+HANDLE_DW_OP(0x4a, lit26)
+HANDLE_DW_OP(0x4b, lit27)
+HANDLE_DW_OP(0x4c, lit28)
+HANDLE_DW_OP(0x4d, lit29)
+HANDLE_DW_OP(0x4e, lit30)
+HANDLE_DW_OP(0x4f, lit31)
+HANDLE_DW_OP(0x50, reg0)
+HANDLE_DW_OP(0x51, reg1)
+HANDLE_DW_OP(0x52, reg2)
+HANDLE_DW_OP(0x53, reg3)
+HANDLE_DW_OP(0x54, reg4)
+HANDLE_DW_OP(0x55, reg5)
+HANDLE_DW_OP(0x56, reg6)
+HANDLE_DW_OP(0x57, reg7)
+HANDLE_DW_OP(0x58, reg8)
+HANDLE_DW_OP(0x59, reg9)
+HANDLE_DW_OP(0x5a, reg10)
+HANDLE_DW_OP(0x5b, reg11)
+HANDLE_DW_OP(0x5c, reg12)
+HANDLE_DW_OP(0x5d, reg13)
+HANDLE_DW_OP(0x5e, reg14)
+HANDLE_DW_OP(0x5f, reg15)
+HANDLE_DW_OP(0x60, reg16)
+HANDLE_DW_OP(0x61, reg17)
+HANDLE_DW_OP(0x62, reg18)
+HANDLE_DW_OP(0x63, reg19)
+HANDLE_DW_OP(0x64, reg20)
+HANDLE_DW_OP(0x65, reg21)
+HANDLE_DW_OP(0x66, reg22)
+HANDLE_DW_OP(0x67, reg23)
+HANDLE_DW_OP(0x68, reg24)
+HANDLE_DW_OP(0x69, reg25)
+HANDLE_DW_OP(0x6a, reg26)
+HANDLE_DW_OP(0x6b, reg27)
+HANDLE_DW_OP(0x6c, reg28)
+HANDLE_DW_OP(0x6d, reg29)
+HANDLE_DW_OP(0x6e, reg30)
+HANDLE_DW_OP(0x6f, reg31)
+HANDLE_DW_OP(0x70, breg0)
+HANDLE_DW_OP(0x71, breg1)
+HANDLE_DW_OP(0x72, breg2)
+HANDLE_DW_OP(0x73, breg3)
+HANDLE_DW_OP(0x74, breg4)
+HANDLE_DW_OP(0x75, breg5)
+HANDLE_DW_OP(0x76, breg6)
+HANDLE_DW_OP(0x77, breg7)
+HANDLE_DW_OP(0x78, breg8)
+HANDLE_DW_OP(0x79, breg9)
+HANDLE_DW_OP(0x7a, breg10)
+HANDLE_DW_OP(0x7b, breg11)
+HANDLE_DW_OP(0x7c, breg12)
+HANDLE_DW_OP(0x7d, breg13)
+HANDLE_DW_OP(0x7e, breg14)
+HANDLE_DW_OP(0x7f, breg15)
+HANDLE_DW_OP(0x80, breg16)
+HANDLE_DW_OP(0x81, breg17)
+HANDLE_DW_OP(0x82, breg18)
+HANDLE_DW_OP(0x83, breg19)
+HANDLE_DW_OP(0x84, breg20)
+HANDLE_DW_OP(0x85, breg21)
+HANDLE_DW_OP(0x86, breg22)
+HANDLE_DW_OP(0x87, breg23)
+HANDLE_DW_OP(0x88, breg24)
+HANDLE_DW_OP(0x89, breg25)
+HANDLE_DW_OP(0x8a, breg26)
+HANDLE_DW_OP(0x8b, breg27)
+HANDLE_DW_OP(0x8c, breg28)
+HANDLE_DW_OP(0x8d, breg29)
+HANDLE_DW_OP(0x8e, breg30)
+HANDLE_DW_OP(0x8f, breg31)
+HANDLE_DW_OP(0x90, regx)
+HANDLE_DW_OP(0x91, fbreg)
+HANDLE_DW_OP(0x92, bregx)
+HANDLE_DW_OP(0x93, piece)
+HANDLE_DW_OP(0x94, deref_size)
+HANDLE_DW_OP(0x95, xderef_size)
+HANDLE_DW_OP(0x96, nop)
+HANDLE_DW_OP(0x97, push_object_address)
+HANDLE_DW_OP(0x98, call2)
+HANDLE_DW_OP(0x99, call4)
+HANDLE_DW_OP(0x9a, call_ref)
+HANDLE_DW_OP(0x9b, form_tls_address)
+HANDLE_DW_OP(0x9c, call_frame_cfa)
+HANDLE_DW_OP(0x9d, bit_piece)
+HANDLE_DW_OP(0x9e, implicit_value)
+HANDLE_DW_OP(0x9f, stack_value)
+
+// Extensions for GNU-style thread-local storage.
+HANDLE_DW_OP(0xe0, GNU_push_tls_address)
+
+// Extensions for Fission proposal.
+HANDLE_DW_OP(0xfb, GNU_addr_index)
+HANDLE_DW_OP(0xfc, GNU_const_index)
+
+// DWARF languages.
+HANDLE_DW_LANG(0x0001, C89)
+HANDLE_DW_LANG(0x0002, C)
+HANDLE_DW_LANG(0x0003, Ada83)
+HANDLE_DW_LANG(0x0004, C_plus_plus)
+HANDLE_DW_LANG(0x0005, Cobol74)
+HANDLE_DW_LANG(0x0006, Cobol85)
+HANDLE_DW_LANG(0x0007, Fortran77)
+HANDLE_DW_LANG(0x0008, Fortran90)
+HANDLE_DW_LANG(0x0009, Pascal83)
+HANDLE_DW_LANG(0x000a, Modula2)
+HANDLE_DW_LANG(0x000b, Java)
+HANDLE_DW_LANG(0x000c, C99)
+HANDLE_DW_LANG(0x000d, Ada95)
+HANDLE_DW_LANG(0x000e, Fortran95)
+HANDLE_DW_LANG(0x000f, PLI)
+HANDLE_DW_LANG(0x0010, ObjC)
+HANDLE_DW_LANG(0x0011, ObjC_plus_plus)
+HANDLE_DW_LANG(0x0012, UPC)
+HANDLE_DW_LANG(0x0013, D)
+
+// New in DWARF 5:
+HANDLE_DW_LANG(0x0014, Python)
+HANDLE_DW_LANG(0x0015, OpenCL)
+HANDLE_DW_LANG(0x0016, Go)
+HANDLE_DW_LANG(0x0017, Modula3)
+HANDLE_DW_LANG(0x0018, Haskell)
+HANDLE_DW_LANG(0x0019, C_plus_plus_03)
+HANDLE_DW_LANG(0x001a, C_plus_plus_11)
+HANDLE_DW_LANG(0x001b, OCaml)
+HANDLE_DW_LANG(0x001c, Rust)
+HANDLE_DW_LANG(0x001d, C11)
+HANDLE_DW_LANG(0x001e, Swift)
+HANDLE_DW_LANG(0x001f, Julia)
+HANDLE_DW_LANG(0x0020, Dylan)
+HANDLE_DW_LANG(0x0021, C_plus_plus_14)
+HANDLE_DW_LANG(0x0022, Fortran03)
+HANDLE_DW_LANG(0x0023, Fortran08)
+HANDLE_DW_LANG(0x8001, Mips_Assembler)
+HANDLE_DW_LANG(0xb000, BORLAND_Delphi)
+
+// DWARF attribute type encodings.
+HANDLE_DW_ATE(0x01, address)
+HANDLE_DW_ATE(0x02, boolean)
+HANDLE_DW_ATE(0x03, complex_float)
+HANDLE_DW_ATE(0x04, float)
+HANDLE_DW_ATE(0x05, signed)
+HANDLE_DW_ATE(0x06, signed_char)
+HANDLE_DW_ATE(0x07, unsigned)
+HANDLE_DW_ATE(0x08, unsigned_char)
+HANDLE_DW_ATE(0x09, imaginary_float)
+HANDLE_DW_ATE(0x0a, packed_decimal)
+HANDLE_DW_ATE(0x0b, numeric_string)
+HANDLE_DW_ATE(0x0c, edited)
+HANDLE_DW_ATE(0x0d, signed_fixed)
+HANDLE_DW_ATE(0x0e, unsigned_fixed)
+HANDLE_DW_ATE(0x0f, decimal_float)
+HANDLE_DW_ATE(0x10, UTF)
+
+// DWARF virtuality codes.
+HANDLE_DW_VIRTUALITY(0x00, none)
+HANDLE_DW_VIRTUALITY(0x01, virtual)
+HANDLE_DW_VIRTUALITY(0x02, pure_virtual)
+
+#undef HANDLE_DW_TAG
+#undef HANDLE_DW_OP
+#undef HANDLE_DW_LANG
+#undef HANDLE_DW_ATE
+#undef HANDLE_DW_VIRTUALITY
diff --git a/src/inc/llvm/Dwarf.h b/src/inc/llvm/Dwarf.h
new file mode 100644
index 0000000000..5fa73e931c
--- /dev/null
+++ b/src/inc/llvm/Dwarf.h
@@ -0,0 +1,711 @@
+// 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.
+
+// ==============================================================================
+// LLVM Release License
+// ==============================================================================
+// University of Illinois/NCSA
+// Open Source License
+//
+// Copyright (c) 2003-2015 University of Illinois at Urbana-Champaign.
+// All rights reserved.
+//
+// Developed by:
+//
+// LLVM Team
+//
+// University of Illinois at Urbana-Champaign
+//
+// http://llvm.org
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy of
+// this software and associated documentation files (the "Software"), to deal with
+// 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:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimers.
+//
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimers in the
+// documentation and/or other materials provided with the distribution.
+//
+// * Neither the names of the LLVM Team, University of Illinois at
+// Urbana-Champaign, nor the names of its contributors may be used to
+// endorse or promote products derived from this Software without specific
+// prior written permission.
+//
+// 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
+// CONTRIBUTORS 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 WITH THE
+// SOFTWARE.
+
+//===----------------------------------------------------------------------===//
+//
+// \file
+// \brief This file contains constants used for implementing Dwarf
+// debug support.
+//
+// For details on the Dwarf specfication see the latest DWARF Debugging
+// Information Format standard document on http://www.dwarfstd.org. This
+// file often includes support for non-released standard features.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_DWARF_H
+#define LLVM_SUPPORT_DWARF_H
+
+//===----------------------------------------------------------------------===//
+// Dwarf constants as gleaned from the DWARF Debugging Information Format V.4
+// reference manual http://www.dwarfstd.org/.
+//
+
+// Do not mix the following two enumerations sets. DW_TAG_invalid changes the
+// enumeration base type.
+
+enum LLVMConstants : uint32_t {
+ // LLVM mock tags (see also llvm/Support/Dwarf.def).
+ DW_TAG_invalid = ~0U, // Tag for invalid results.
+ DW_VIRTUALITY_invalid = ~0U, // Virtuality for invalid results.
+ DW_MACINFO_invalid = ~0U, // Macinfo type for invalid results.
+
+ // Other constants.
+ DWARF_VERSION = 4, // Default dwarf version we output.
+ DW_PUBTYPES_VERSION = 2, // Section version number for .debug_pubtypes.
+ DW_PUBNAMES_VERSION = 2, // Section version number for .debug_pubnames.
+ DW_ARANGES_VERSION = 2 // Section version number for .debug_aranges.
+};
+
+// Special ID values that distinguish a CIE from a FDE in DWARF CFI.
+// Not inside an enum because a 64-bit value is needed.
+const uint32_t DW_CIE_ID = UINT32_MAX;
+const uint64_t DW64_CIE_ID = UINT64_MAX;
+
+enum Tag : uint16_t {
+#define HANDLE_DW_TAG(ID, NAME) DW_TAG_##NAME = ID,
+#include "Dwarf.def"
+ DW_TAG_lo_user = 0x4080,
+ DW_TAG_hi_user = 0xffff,
+ DW_TAG_user_base = 0x1000 // Recommended base for user tags.
+};
+
+inline bool isType(Tag T) {
+ switch (T) {
+ case DW_TAG_array_type:
+ case DW_TAG_class_type:
+ case DW_TAG_interface_type:
+ case DW_TAG_enumeration_type:
+ case DW_TAG_pointer_type:
+ case DW_TAG_reference_type:
+ case DW_TAG_rvalue_reference_type:
+ case DW_TAG_string_type:
+ case DW_TAG_structure_type:
+ case DW_TAG_subroutine_type:
+ case DW_TAG_union_type:
+ case DW_TAG_ptr_to_member_type:
+ case DW_TAG_set_type:
+ case DW_TAG_subrange_type:
+ case DW_TAG_base_type:
+ case DW_TAG_const_type:
+ case DW_TAG_file_type:
+ case DW_TAG_packed_type:
+ case DW_TAG_volatile_type:
+ case DW_TAG_typedef:
+ return true;
+ default:
+ return false;
+ }
+}
+
+enum Attribute : uint16_t {
+ // Attributes
+ DW_AT_sibling = 0x01,
+ DW_AT_location = 0x02,
+ DW_AT_name = 0x03,
+ DW_AT_ordering = 0x09,
+ DW_AT_byte_size = 0x0b,
+ DW_AT_bit_offset = 0x0c,
+ DW_AT_bit_size = 0x0d,
+ DW_AT_stmt_list = 0x10,
+ DW_AT_low_pc = 0x11,
+ DW_AT_high_pc = 0x12,
+ DW_AT_language = 0x13,
+ DW_AT_discr = 0x15,
+ DW_AT_discr_value = 0x16,
+ DW_AT_visibility = 0x17,
+ DW_AT_import = 0x18,
+ DW_AT_string_length = 0x19,
+ DW_AT_common_reference = 0x1a,
+ DW_AT_comp_dir = 0x1b,
+ DW_AT_const_value = 0x1c,
+ DW_AT_containing_type = 0x1d,
+ DW_AT_default_value = 0x1e,
+ DW_AT_inline = 0x20,
+ DW_AT_is_optional = 0x21,
+ DW_AT_lower_bound = 0x22,
+ DW_AT_producer = 0x25,
+ DW_AT_prototyped = 0x27,
+ DW_AT_return_addr = 0x2a,
+ DW_AT_start_scope = 0x2c,
+ DW_AT_bit_stride = 0x2e,
+ DW_AT_upper_bound = 0x2f,
+ DW_AT_abstract_origin = 0x31,
+ DW_AT_accessibility = 0x32,
+ DW_AT_address_class = 0x33,
+ DW_AT_artificial = 0x34,
+ DW_AT_base_types = 0x35,
+ DW_AT_calling_convention = 0x36,
+ DW_AT_count = 0x37,
+ DW_AT_data_member_location = 0x38,
+ DW_AT_decl_column = 0x39,
+ DW_AT_decl_file = 0x3a,
+ DW_AT_decl_line = 0x3b,
+ DW_AT_declaration = 0x3c,
+ DW_AT_discr_list = 0x3d,
+ DW_AT_encoding = 0x3e,
+ DW_AT_external = 0x3f,
+ DW_AT_frame_base = 0x40,
+ DW_AT_friend = 0x41,
+ DW_AT_identifier_case = 0x42,
+ DW_AT_macro_info = 0x43,
+ DW_AT_namelist_item = 0x44,
+ DW_AT_priority = 0x45,
+ DW_AT_segment = 0x46,
+ DW_AT_specification = 0x47,
+ DW_AT_static_link = 0x48,
+ DW_AT_type = 0x49,
+ DW_AT_use_location = 0x4a,
+ DW_AT_variable_parameter = 0x4b,
+ DW_AT_virtuality = 0x4c,
+ DW_AT_vtable_elem_location = 0x4d,
+ DW_AT_allocated = 0x4e,
+ DW_AT_associated = 0x4f,
+ DW_AT_data_location = 0x50,
+ DW_AT_byte_stride = 0x51,
+ DW_AT_entry_pc = 0x52,
+ DW_AT_use_UTF8 = 0x53,
+ DW_AT_extension = 0x54,
+ DW_AT_ranges = 0x55,
+ DW_AT_trampoline = 0x56,
+ DW_AT_call_column = 0x57,
+ DW_AT_call_file = 0x58,
+ DW_AT_call_line = 0x59,
+ DW_AT_description = 0x5a,
+ DW_AT_binary_scale = 0x5b,
+ DW_AT_decimal_scale = 0x5c,
+ DW_AT_small = 0x5d,
+ DW_AT_decimal_sign = 0x5e,
+ DW_AT_digit_count = 0x5f,
+ DW_AT_picture_string = 0x60,
+ DW_AT_mutable = 0x61,
+ DW_AT_threads_scaled = 0x62,
+ DW_AT_explicit = 0x63,
+ DW_AT_object_pointer = 0x64,
+ DW_AT_endianity = 0x65,
+ DW_AT_elemental = 0x66,
+ DW_AT_pure = 0x67,
+ DW_AT_recursive = 0x68,
+ DW_AT_signature = 0x69,
+ DW_AT_main_subprogram = 0x6a,
+ DW_AT_data_bit_offset = 0x6b,
+ DW_AT_const_expr = 0x6c,
+ DW_AT_enum_class = 0x6d,
+ DW_AT_linkage_name = 0x6e,
+
+ // New in DWARF 5:
+ DW_AT_string_length_bit_size = 0x6f,
+ DW_AT_string_length_byte_size = 0x70,
+ DW_AT_rank = 0x71,
+ DW_AT_str_offsets_base = 0x72,
+ DW_AT_addr_base = 0x73,
+ DW_AT_ranges_base = 0x74,
+ DW_AT_dwo_id = 0x75,
+ DW_AT_dwo_name = 0x76,
+ DW_AT_reference = 0x77,
+ DW_AT_rvalue_reference = 0x78,
+ DW_AT_macros = 0x79,
+
+ DW_AT_lo_user = 0x2000,
+ DW_AT_hi_user = 0x3fff,
+
+ DW_AT_MIPS_loop_begin = 0x2002,
+ DW_AT_MIPS_tail_loop_begin = 0x2003,
+ DW_AT_MIPS_epilog_begin = 0x2004,
+ DW_AT_MIPS_loop_unroll_factor = 0x2005,
+ DW_AT_MIPS_software_pipeline_depth = 0x2006,
+ DW_AT_MIPS_linkage_name = 0x2007,
+ DW_AT_MIPS_stride = 0x2008,
+ DW_AT_MIPS_abstract_name = 0x2009,
+ DW_AT_MIPS_clone_origin = 0x200a,
+ DW_AT_MIPS_has_inlines = 0x200b,
+ DW_AT_MIPS_stride_byte = 0x200c,
+ DW_AT_MIPS_stride_elem = 0x200d,
+ DW_AT_MIPS_ptr_dopetype = 0x200e,
+ DW_AT_MIPS_allocatable_dopetype = 0x200f,
+ DW_AT_MIPS_assumed_shape_dopetype = 0x2010,
+
+ // This one appears to have only been implemented by Open64 for
+ // fortran and may conflict with other extensions.
+ DW_AT_MIPS_assumed_size = 0x2011,
+
+ // GNU extensions
+ DW_AT_sf_names = 0x2101,
+ DW_AT_src_info = 0x2102,
+ DW_AT_mac_info = 0x2103,
+ DW_AT_src_coords = 0x2104,
+ DW_AT_body_begin = 0x2105,
+ DW_AT_body_end = 0x2106,
+ DW_AT_GNU_vector = 0x2107,
+ DW_AT_GNU_template_name = 0x2110,
+
+ DW_AT_GNU_odr_signature = 0x210f,
+ DW_AT_GNU_macros = 0x2119,
+
+ // Extensions for Fission proposal.
+ DW_AT_GNU_dwo_name = 0x2130,
+ DW_AT_GNU_dwo_id = 0x2131,
+ DW_AT_GNU_ranges_base = 0x2132,
+ DW_AT_GNU_addr_base = 0x2133,
+ DW_AT_GNU_pubnames = 0x2134,
+ DW_AT_GNU_pubtypes = 0x2135,
+ DW_AT_GNU_discriminator = 0x2136,
+
+ // Borland extensions.
+ DW_AT_BORLAND_property_read = 0x3b11,
+ DW_AT_BORLAND_property_write = 0x3b12,
+ DW_AT_BORLAND_property_implements = 0x3b13,
+ DW_AT_BORLAND_property_index = 0x3b14,
+ DW_AT_BORLAND_property_default = 0x3b15,
+ DW_AT_BORLAND_Delphi_unit = 0x3b20,
+ DW_AT_BORLAND_Delphi_class = 0x3b21,
+ DW_AT_BORLAND_Delphi_record = 0x3b22,
+ DW_AT_BORLAND_Delphi_metaclass = 0x3b23,
+ DW_AT_BORLAND_Delphi_constructor = 0x3b24,
+ DW_AT_BORLAND_Delphi_destructor = 0x3b25,
+ DW_AT_BORLAND_Delphi_anonymous_method = 0x3b26,
+ DW_AT_BORLAND_Delphi_interface = 0x3b27,
+ DW_AT_BORLAND_Delphi_ABI = 0x3b28,
+ DW_AT_BORLAND_Delphi_return = 0x3b29,
+ DW_AT_BORLAND_Delphi_frameptr = 0x3b30,
+ DW_AT_BORLAND_closure = 0x3b31,
+
+ // LLVM project extensions.
+ DW_AT_LLVM_include_path = 0x3e00,
+ DW_AT_LLVM_config_macros = 0x3e01,
+ DW_AT_LLVM_isysroot = 0x3e02,
+
+ // Apple extensions.
+ DW_AT_APPLE_optimized = 0x3fe1,
+ DW_AT_APPLE_flags = 0x3fe2,
+ DW_AT_APPLE_isa = 0x3fe3,
+ DW_AT_APPLE_block = 0x3fe4,
+ DW_AT_APPLE_major_runtime_vers = 0x3fe5,
+ DW_AT_APPLE_runtime_class = 0x3fe6,
+ DW_AT_APPLE_omit_frame_ptr = 0x3fe7,
+ DW_AT_APPLE_property_name = 0x3fe8,
+ DW_AT_APPLE_property_getter = 0x3fe9,
+ DW_AT_APPLE_property_setter = 0x3fea,
+ DW_AT_APPLE_property_attribute = 0x3feb,
+ DW_AT_APPLE_objc_complete_type = 0x3fec,
+ DW_AT_APPLE_property = 0x3fed
+};
+
+enum Form : uint16_t {
+ // Attribute form encodings
+ DW_FORM_addr = 0x01,
+ DW_FORM_block2 = 0x03,
+ DW_FORM_block4 = 0x04,
+ DW_FORM_data2 = 0x05,
+ DW_FORM_data4 = 0x06,
+ DW_FORM_data8 = 0x07,
+ DW_FORM_string = 0x08,
+ DW_FORM_block = 0x09,
+ DW_FORM_block1 = 0x0a,
+ DW_FORM_data1 = 0x0b,
+ DW_FORM_flag = 0x0c,
+ DW_FORM_sdata = 0x0d,
+ DW_FORM_strp = 0x0e,
+ DW_FORM_udata = 0x0f,
+ DW_FORM_ref_addr = 0x10,
+ DW_FORM_ref1 = 0x11,
+ DW_FORM_ref2 = 0x12,
+ DW_FORM_ref4 = 0x13,
+ DW_FORM_ref8 = 0x14,
+ DW_FORM_ref_udata = 0x15,
+ DW_FORM_indirect = 0x16,
+ DW_FORM_sec_offset = 0x17,
+ DW_FORM_exprloc = 0x18,
+ DW_FORM_flag_present = 0x19,
+ DW_FORM_ref_sig8 = 0x20,
+
+ // Extensions for Fission proposal
+ DW_FORM_GNU_addr_index = 0x1f01,
+ DW_FORM_GNU_str_index = 0x1f02,
+
+ // Alternate debug sections proposal (output of "dwz" tool).
+ DW_FORM_GNU_ref_alt = 0x1f20,
+ DW_FORM_GNU_strp_alt = 0x1f21
+};
+
+enum LocationAtom {
+#define HANDLE_DW_OP(ID, NAME) DW_OP_##NAME = ID,
+#include "Dwarf.def"
+ DW_OP_lo_user = 0xe0,
+ DW_OP_hi_user = 0xff
+};
+
+enum TypeKind {
+#define HANDLE_DW_ATE(ID, NAME) DW_ATE_##NAME = ID,
+#include "Dwarf.def"
+ DW_ATE_lo_user = 0x80,
+ DW_ATE_hi_user = 0xff
+};
+
+enum DecimalSignEncoding {
+ // Decimal sign attribute values
+ DW_DS_unsigned = 0x01,
+ DW_DS_leading_overpunch = 0x02,
+ DW_DS_trailing_overpunch = 0x03,
+ DW_DS_leading_separate = 0x04,
+ DW_DS_trailing_separate = 0x05
+};
+
+enum EndianityEncoding {
+ // Endianity attribute values
+ DW_END_default = 0x00,
+ DW_END_big = 0x01,
+ DW_END_little = 0x02,
+ DW_END_lo_user = 0x40,
+ DW_END_hi_user = 0xff
+};
+
+enum AccessAttribute {
+ // Accessibility codes
+ DW_ACCESS_public = 0x01,
+ DW_ACCESS_protected = 0x02,
+ DW_ACCESS_private = 0x03
+};
+
+enum VisibilityAttribute {
+ // Visibility codes
+ DW_VIS_local = 0x01,
+ DW_VIS_exported = 0x02,
+ DW_VIS_qualified = 0x03
+};
+
+enum VirtualityAttribute {
+#define HANDLE_DW_VIRTUALITY(ID, NAME) DW_VIRTUALITY_##NAME = ID,
+#include "Dwarf.def"
+ DW_VIRTUALITY_max = 0x02
+};
+
+enum SourceLanguage {
+#define HANDLE_DW_LANG(ID, NAME) DW_LANG_##NAME = ID,
+#include "Dwarf.def"
+ DW_LANG_lo_user = 0x8000,
+ DW_LANG_hi_user = 0xffff
+};
+
+enum CaseSensitivity {
+ // Identifier case codes
+ DW_ID_case_sensitive = 0x00,
+ DW_ID_up_case = 0x01,
+ DW_ID_down_case = 0x02,
+ DW_ID_case_insensitive = 0x03
+};
+
+enum CallingConvention {
+ // Calling convention codes
+ DW_CC_normal = 0x01,
+ DW_CC_program = 0x02,
+ DW_CC_nocall = 0x03,
+ DW_CC_lo_user = 0x40,
+ DW_CC_GNU_borland_fastcall_i386 = 0x41,
+ DW_CC_BORLAND_safecall = 0xb0,
+ DW_CC_BORLAND_stdcall = 0xb1,
+ DW_CC_BORLAND_pascal = 0xb2,
+ DW_CC_BORLAND_msfastcall = 0xb3,
+ DW_CC_BORLAND_msreturn = 0xb4,
+ DW_CC_BORLAND_thiscall = 0xb5,
+ DW_CC_BORLAND_fastcall = 0xb6,
+ DW_CC_hi_user = 0xff
+};
+
+enum InlineAttribute {
+ // Inline codes
+ DW_INL_not_inlined = 0x00,
+ DW_INL_inlined = 0x01,
+ DW_INL_declared_not_inlined = 0x02,
+ DW_INL_declared_inlined = 0x03
+};
+
+enum ArrayDimensionOrdering {
+ // Array ordering
+ DW_ORD_row_major = 0x00,
+ DW_ORD_col_major = 0x01
+};
+
+enum DiscriminantList {
+ // Discriminant descriptor values
+ DW_DSC_label = 0x00,
+ DW_DSC_range = 0x01
+};
+
+enum LineNumberOps {
+ // Line Number Standard Opcode Encodings
+ DW_LNS_extended_op = 0x00,
+ DW_LNS_copy = 0x01,
+ DW_LNS_advance_pc = 0x02,
+ DW_LNS_advance_line = 0x03,
+ DW_LNS_set_file = 0x04,
+ DW_LNS_set_column = 0x05,
+ DW_LNS_negate_stmt = 0x06,
+ DW_LNS_set_basic_block = 0x07,
+ DW_LNS_const_add_pc = 0x08,
+ DW_LNS_fixed_advance_pc = 0x09,
+ DW_LNS_set_prologue_end = 0x0a,
+ DW_LNS_set_epilogue_begin = 0x0b,
+ DW_LNS_set_isa = 0x0c
+};
+
+enum LineNumberExtendedOps {
+ // Line Number Extended Opcode Encodings
+ DW_LNE_end_sequence = 0x01,
+ DW_LNE_set_address = 0x02,
+ DW_LNE_define_file = 0x03,
+ DW_LNE_set_discriminator = 0x04,
+ DW_LNE_lo_user = 0x80,
+ DW_LNE_hi_user = 0xff
+};
+
+enum MacinfoRecordType {
+ // Macinfo Type Encodings
+ DW_MACINFO_define = 0x01,
+ DW_MACINFO_undef = 0x02,
+ DW_MACINFO_start_file = 0x03,
+ DW_MACINFO_end_file = 0x04,
+ DW_MACINFO_vendor_ext = 0xff
+};
+
+enum MacroEntryType {
+ // Macro Information Entry Type Encodings
+ DW_MACRO_define = 0x01,
+ DW_MACRO_undef = 0x02,
+ DW_MACRO_start_file = 0x03,
+ DW_MACRO_end_file = 0x04,
+ DW_MACRO_define_indirect = 0x05,
+ DW_MACRO_undef_indirect = 0x06,
+ DW_MACRO_transparent_include = 0x07,
+ DW_MACRO_define_indirect_sup = 0x08,
+ DW_MACRO_undef_indirect_sup = 0x09,
+ DW_MACRO_transparent_include_sup = 0x0a,
+ DW_MACRO_define_indirectx = 0x0b,
+ DW_MACRO_undef_indirectx = 0x0c,
+ DW_MACRO_lo_user = 0xe0,
+ DW_MACRO_hi_user = 0xff
+};
+
+enum CallFrameInfo {
+ // Call frame instruction encodings
+ DW_CFA_extended = 0x00,
+ DW_CFA_nop = 0x00,
+ DW_CFA_advance_loc = 0x40,
+ DW_CFA_offset = 0x80,
+ DW_CFA_restore = 0xc0,
+ DW_CFA_set_loc = 0x01,
+ DW_CFA_advance_loc1 = 0x02,
+ DW_CFA_advance_loc2 = 0x03,
+ DW_CFA_advance_loc4 = 0x04,
+ DW_CFA_offset_extended = 0x05,
+ DW_CFA_restore_extended = 0x06,
+ DW_CFA_undefined = 0x07,
+ DW_CFA_same_value = 0x08,
+ DW_CFA_register = 0x09,
+ DW_CFA_remember_state = 0x0a,
+ DW_CFA_restore_state = 0x0b,
+ DW_CFA_def_cfa = 0x0c,
+ DW_CFA_def_cfa_register = 0x0d,
+ DW_CFA_def_cfa_offset = 0x0e,
+ DW_CFA_def_cfa_expression = 0x0f,
+ DW_CFA_expression = 0x10,
+ DW_CFA_offset_extended_sf = 0x11,
+ DW_CFA_def_cfa_sf = 0x12,
+ DW_CFA_def_cfa_offset_sf = 0x13,
+ DW_CFA_val_offset = 0x14,
+ DW_CFA_val_offset_sf = 0x15,
+ DW_CFA_val_expression = 0x16,
+ DW_CFA_MIPS_advance_loc8 = 0x1d,
+ DW_CFA_GNU_window_save = 0x2d,
+ DW_CFA_GNU_args_size = 0x2e,
+ DW_CFA_lo_user = 0x1c,
+ DW_CFA_hi_user = 0x3f
+};
+
+enum Constants {
+ // Children flag
+ DW_CHILDREN_no = 0x00,
+ DW_CHILDREN_yes = 0x01,
+
+ DW_EH_PE_absptr = 0x00,
+ DW_EH_PE_omit = 0xff,
+ DW_EH_PE_uleb128 = 0x01,
+ DW_EH_PE_udata2 = 0x02,
+ DW_EH_PE_udata4 = 0x03,
+ DW_EH_PE_udata8 = 0x04,
+ DW_EH_PE_sleb128 = 0x09,
+ DW_EH_PE_sdata2 = 0x0A,
+ DW_EH_PE_sdata4 = 0x0B,
+ DW_EH_PE_sdata8 = 0x0C,
+ DW_EH_PE_signed = 0x08,
+ DW_EH_PE_pcrel = 0x10,
+ DW_EH_PE_textrel = 0x20,
+ DW_EH_PE_datarel = 0x30,
+ DW_EH_PE_funcrel = 0x40,
+ DW_EH_PE_aligned = 0x50,
+ DW_EH_PE_indirect = 0x80
+};
+
+// Constants for debug_loc.dwo in the DWARF5 Split Debug Info Proposal
+enum LocationListEntry : unsigned char {
+ DW_LLE_end_of_list_entry,
+ DW_LLE_base_address_selection_entry,
+ DW_LLE_start_end_entry,
+ DW_LLE_start_length_entry,
+ DW_LLE_offset_pair_entry
+};
+
+/// Contstants for the DW_APPLE_PROPERTY_attributes attribute.
+/// Keep this list in sync with clang's DeclSpec.h ObjCPropertyAttributeKind.
+enum ApplePropertyAttributes {
+ // Apple Objective-C Property Attributes
+ DW_APPLE_PROPERTY_readonly = 0x01,
+ DW_APPLE_PROPERTY_getter = 0x02,
+ DW_APPLE_PROPERTY_assign = 0x04,
+ DW_APPLE_PROPERTY_readwrite = 0x08,
+ DW_APPLE_PROPERTY_retain = 0x10,
+ DW_APPLE_PROPERTY_copy = 0x20,
+ DW_APPLE_PROPERTY_nonatomic = 0x40,
+ DW_APPLE_PROPERTY_setter = 0x80,
+ DW_APPLE_PROPERTY_atomic = 0x100,
+ DW_APPLE_PROPERTY_weak = 0x200,
+ DW_APPLE_PROPERTY_strong = 0x400,
+ DW_APPLE_PROPERTY_unsafe_unretained = 0x800
+};
+
+// Constants for the DWARF5 Accelerator Table Proposal
+enum AcceleratorTable {
+ // Data layout descriptors.
+ DW_ATOM_null = 0u, // Marker as the end of a list of atoms.
+ DW_ATOM_die_offset = 1u, // DIE offset in the debug_info section.
+ DW_ATOM_cu_offset = 2u, // Offset of the compile unit header that contains the
+ // item in question.
+ DW_ATOM_die_tag = 3u, // A tag entry.
+ DW_ATOM_type_flags = 4u, // Set of flags for a type.
+
+ // DW_ATOM_type_flags values.
+
+ // Always set for C++, only set for ObjC if this is the @implementation for a
+ // class.
+ DW_FLAG_type_implementation = 2u,
+
+ // Hash functions.
+
+ // Daniel J. Bernstein hash.
+ DW_hash_function_djb = 0u
+};
+
+// Constants for the GNU pubnames/pubtypes extensions supporting gdb index.
+enum GDBIndexEntryKind {
+ GIEK_NONE,
+ GIEK_TYPE,
+ GIEK_VARIABLE,
+ GIEK_FUNCTION,
+ GIEK_OTHER,
+ GIEK_UNUSED5,
+ GIEK_UNUSED6,
+ GIEK_UNUSED7
+};
+
+enum GDBIndexEntryLinkage {
+ GIEL_EXTERNAL,
+ GIEL_STATIC
+};
+
+/// \defgroup DwarfConstantsDumping Dwarf constants dumping functions
+///
+/// All these functions map their argument's value back to the
+/// corresponding enumerator name or return nullptr if the value isn't
+/// known.
+///
+/// @{
+const char *TagString(unsigned Tag);
+const char *ChildrenString(unsigned Children);
+const char *AttributeString(unsigned Attribute);
+const char *FormEncodingString(unsigned Encoding);
+const char *OperationEncodingString(unsigned Encoding);
+const char *AttributeEncodingString(unsigned Encoding);
+const char *DecimalSignString(unsigned Sign);
+const char *EndianityString(unsigned Endian);
+const char *AccessibilityString(unsigned Access);
+const char *VisibilityString(unsigned Visibility);
+const char *VirtualityString(unsigned Virtuality);
+const char *LanguageString(unsigned Language);
+const char *CaseString(unsigned Case);
+const char *ConventionString(unsigned Convention);
+const char *InlineCodeString(unsigned Code);
+const char *ArrayOrderString(unsigned Order);
+const char *DiscriminantString(unsigned Discriminant);
+const char *LNStandardString(unsigned Standard);
+const char *LNExtendedString(unsigned Encoding);
+const char *MacinfoString(unsigned Encoding);
+const char *CallFrameString(unsigned Encoding);
+const char *ApplePropertyString(unsigned);
+const char *AtomTypeString(unsigned Atom);
+const char *GDBIndexEntryKindString(GDBIndexEntryKind Kind);
+const char *GDBIndexEntryLinkageString(GDBIndexEntryLinkage Linkage);
+/// @}
+
+/// \brief Returns the symbolic string representing Val when used as a value
+/// for attribute Attr.
+const char *AttributeValueString(uint16_t Attr, unsigned Val);
+
+/// \brief Decsribes an entry of the various gnu_pub* debug sections.
+///
+/// The gnu_pub* kind looks like:
+///
+/// 0-3 reserved
+/// 4-6 symbol kind
+/// 7 0 == global, 1 == static
+///
+/// A gdb_index descriptor includes the above kind, shifted 24 bits up with the
+/// offset of the cu within the debug_info section stored in those 24 bits.
+struct PubIndexEntryDescriptor {
+ GDBIndexEntryKind Kind;
+ GDBIndexEntryLinkage Linkage;
+ PubIndexEntryDescriptor(GDBIndexEntryKind Kind, GDBIndexEntryLinkage Linkage)
+ : Kind(Kind), Linkage(Linkage) {}
+ /* implicit */ PubIndexEntryDescriptor(GDBIndexEntryKind Kind)
+ : Kind(Kind), Linkage(GIEL_EXTERNAL) {}
+ explicit PubIndexEntryDescriptor(uint8_t Value)
+ : Kind(static_cast<GDBIndexEntryKind>((Value & KIND_MASK) >>
+ KIND_OFFSET)),
+ Linkage(static_cast<GDBIndexEntryLinkage>((Value & LINKAGE_MASK) >>
+ LINKAGE_OFFSET)) {}
+ uint8_t toBits() { return Kind << KIND_OFFSET | Linkage << LINKAGE_OFFSET; }
+
+private:
+ enum {
+ KIND_OFFSET = 4,
+ KIND_MASK = 7 << KIND_OFFSET,
+ LINKAGE_OFFSET = 7,
+ LINKAGE_MASK = 1 << LINKAGE_OFFSET
+ };
+};
+
+#endif
diff --git a/src/inc/llvm/ELF.h b/src/inc/llvm/ELF.h
new file mode 100644
index 0000000000..76c7824208
--- /dev/null
+++ b/src/inc/llvm/ELF.h
@@ -0,0 +1,1273 @@
+// 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.
+
+// ==============================================================================
+// LLVM Release License
+// ==============================================================================
+// University of Illinois/NCSA
+// Open Source License
+//
+// Copyright (c) 2003-2015 University of Illinois at Urbana-Champaign.
+// All rights reserved.
+//
+// Developed by:
+//
+// LLVM Team
+//
+// University of Illinois at Urbana-Champaign
+//
+// http://llvm.org
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy of
+// this software and associated documentation files (the "Software"), to deal with
+// 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:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimers.
+//
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimers in the
+// documentation and/or other materials provided with the distribution.
+//
+// * Neither the names of the LLVM Team, University of Illinois at
+// Urbana-Champaign, nor the names of its contributors may be used to
+// endorse or promote products derived from this Software without specific
+// prior written permission.
+//
+// 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
+// CONTRIBUTORS 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 WITH THE
+// SOFTWARE.
+
+//===----------------------------------------------------------------------===//
+// This header contains common, non-processor-specific data structures and
+// constants for the ELF file format.
+//
+// The details of the ELF32 bits in this file are largely based on the Tool
+// Interface Standard (TIS) Executable and Linking Format (ELF) Specification
+// Version 1.2, May 1995. The ELF64 stuff is based on ELF-64 Object File Format
+// Version 1.5, Draft 2, May 1998 as well as OpenBSD header files.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_ELF_H
+#define LLVM_SUPPORT_ELF_H
+
+typedef uint32_t Elf32_Addr; // Program address
+typedef uint32_t Elf32_Off; // File offset
+typedef uint16_t Elf32_Half;
+typedef uint32_t Elf32_Word;
+typedef int32_t Elf32_Sword;
+
+typedef uint64_t Elf64_Addr;
+typedef uint64_t Elf64_Off;
+typedef uint16_t Elf64_Half;
+typedef uint32_t Elf64_Word;
+typedef int32_t Elf64_Sword;
+typedef uint64_t Elf64_Xword;
+typedef int64_t Elf64_Sxword;
+
+// Object file magic string.
+static const char ElfMagic[] = { 0x7f, 'E', 'L', 'F', '\0' };
+
+// e_ident size and indices.
+enum {
+ EI_MAG0 = 0, // File identification index.
+ EI_MAG1 = 1, // File identification index.
+ EI_MAG2 = 2, // File identification index.
+ EI_MAG3 = 3, // File identification index.
+ EI_CLASS = 4, // File class.
+ EI_DATA = 5, // Data encoding.
+ EI_VERSION = 6, // File version.
+ EI_OSABI = 7, // OS/ABI identification.
+ EI_ABIVERSION = 8, // ABI version.
+ EI_PAD = 9, // Start of padding bytes.
+ EI_NIDENT = 16 // Number of bytes in e_ident.
+};
+
+struct Elf32_Ehdr {
+ unsigned char e_ident[EI_NIDENT]; // ELF Identification bytes
+ Elf32_Half e_type; // Type of file (see ET_* below)
+ Elf32_Half e_machine; // Required architecture for this file (see EM_*)
+ Elf32_Word e_version; // Must be equal to 1
+ Elf32_Addr e_entry; // Address to jump to in order to start program
+ Elf32_Off e_phoff; // Program header table's file offset, in bytes
+ Elf32_Off e_shoff; // Section header table's file offset, in bytes
+ Elf32_Word e_flags; // Processor-specific flags
+ Elf32_Half e_ehsize; // Size of ELF header, in bytes
+ Elf32_Half e_phentsize; // Size of an entry in the program header table
+ Elf32_Half e_phnum; // Number of entries in the program header table
+ Elf32_Half e_shentsize; // Size of an entry in the section header table
+ Elf32_Half e_shnum; // Number of entries in the section header table
+ Elf32_Half e_shstrndx; // Sect hdr table index of sect name string table
+ bool checkMagic() const {
+ return (memcmp(e_ident, ElfMagic, strlen(ElfMagic))) == 0;
+ }
+ unsigned char getFileClass() const { return e_ident[EI_CLASS]; }
+ unsigned char getDataEncoding() const { return e_ident[EI_DATA]; }
+ Elf32_Ehdr();
+};
+
+// 64-bit ELF header. Fields are the same as for ELF32, but with different
+// types (see above).
+struct Elf64_Ehdr {
+ unsigned char e_ident[EI_NIDENT];
+ Elf64_Half e_type;
+ Elf64_Half e_machine;
+ Elf64_Word e_version;
+ Elf64_Addr e_entry;
+ Elf64_Off e_phoff;
+ Elf64_Off e_shoff;
+ Elf64_Word e_flags;
+ Elf64_Half e_ehsize;
+ Elf64_Half e_phentsize;
+ Elf64_Half e_phnum;
+ Elf64_Half e_shentsize;
+ Elf64_Half e_shnum;
+ Elf64_Half e_shstrndx;
+ bool checkMagic() const {
+ return (memcmp(e_ident, ElfMagic, strlen(ElfMagic))) == 0;
+ }
+ unsigned char getFileClass() const { return e_ident[EI_CLASS]; }
+ unsigned char getDataEncoding() const { return e_ident[EI_DATA]; }
+ Elf64_Ehdr();
+};
+
+// File types
+enum {
+ ET_NONE = 0, // No file type
+ ET_REL = 1, // Relocatable file
+ ET_EXEC = 2, // Executable file
+ ET_DYN = 3, // Shared object file
+ ET_CORE = 4, // Core file
+ ET_LOPROC = 0xff00, // Beginning of processor-specific codes
+ ET_HIPROC = 0xffff // Processor-specific
+};
+
+// Versioning
+enum {
+ EV_NONE = 0,
+ EV_CURRENT = 1
+};
+
+// Machine architectures
+// See current registered ELF machine architectures at:
+// http://www.uxsglobal.com/developers/gabi/latest/ch4.eheader.html
+enum {
+ EM_NONE = 0, // No machine
+ EM_M32 = 1, // AT&T WE 32100
+ EM_SPARC = 2, // SPARC
+ EM_386 = 3, // Intel 386
+ EM_68K = 4, // Motorola 68000
+ EM_88K = 5, // Motorola 88000
+ EM_IAMCU = 6, // Intel MCU
+ EM_860 = 7, // Intel 80860
+ EM_MIPS = 8, // MIPS R3000
+ EM_S370 = 9, // IBM System/370
+ EM_MIPS_RS3_LE = 10, // MIPS RS3000 Little-endian
+ EM_PARISC = 15, // Hewlett-Packard PA-RISC
+ EM_VPP500 = 17, // Fujitsu VPP500
+ EM_SPARC32PLUS = 18, // Enhanced instruction set SPARC
+ EM_960 = 19, // Intel 80960
+ EM_PPC = 20, // PowerPC
+ EM_PPC64 = 21, // PowerPC64
+ EM_S390 = 22, // IBM System/390
+ EM_SPU = 23, // IBM SPU/SPC
+ EM_V800 = 36, // NEC V800
+ EM_FR20 = 37, // Fujitsu FR20
+ EM_RH32 = 38, // TRW RH-32
+ EM_RCE = 39, // Motorola RCE
+ EM_ARM = 40, // ARM
+ EM_ALPHA = 41, // DEC Alpha
+ EM_SH = 42, // Hitachi SH
+ EM_SPARCV9 = 43, // SPARC V9
+ EM_TRICORE = 44, // Siemens TriCore
+ EM_ARC = 45, // Argonaut RISC Core
+ EM_H8_300 = 46, // Hitachi H8/300
+ EM_H8_300H = 47, // Hitachi H8/300H
+ EM_H8S = 48, // Hitachi H8S
+ EM_H8_500 = 49, // Hitachi H8/500
+ EM_IA_64 = 50, // Intel IA-64 processor architecture
+ EM_MIPS_X = 51, // Stanford MIPS-X
+ EM_COLDFIRE = 52, // Motorola ColdFire
+ EM_68HC12 = 53, // Motorola M68HC12
+ EM_MMA = 54, // Fujitsu MMA Multimedia Accelerator
+ EM_PCP = 55, // Siemens PCP
+ EM_NCPU = 56, // Sony nCPU embedded RISC processor
+ EM_NDR1 = 57, // Denso NDR1 microprocessor
+ EM_STARCORE = 58, // Motorola Star*Core processor
+ EM_ME16 = 59, // Toyota ME16 processor
+ EM_ST100 = 60, // STMicroelectronics ST100 processor
+ EM_TINYJ = 61, // Advanced Logic Corp. TinyJ embedded processor family
+ EM_X86_64 = 62, // AMD x86-64 architecture
+ EM_PDSP = 63, // Sony DSP Processor
+ EM_PDP10 = 64, // Digital Equipment Corp. PDP-10
+ EM_PDP11 = 65, // Digital Equipment Corp. PDP-11
+ EM_FX66 = 66, // Siemens FX66 microcontroller
+ EM_ST9PLUS = 67, // STMicroelectronics ST9+ 8/16 bit microcontroller
+ EM_ST7 = 68, // STMicroelectronics ST7 8-bit microcontroller
+ EM_68HC16 = 69, // Motorola MC68HC16 Microcontroller
+ EM_68HC11 = 70, // Motorola MC68HC11 Microcontroller
+ EM_68HC08 = 71, // Motorola MC68HC08 Microcontroller
+ EM_68HC05 = 72, // Motorola MC68HC05 Microcontroller
+ EM_SVX = 73, // Silicon Graphics SVx
+ EM_ST19 = 74, // STMicroelectronics ST19 8-bit microcontroller
+ EM_VAX = 75, // Digital VAX
+ EM_CRIS = 76, // Axis Communications 32-bit embedded processor
+ EM_JAVELIN = 77, // Infineon Technologies 32-bit embedded processor
+ EM_FIREPATH = 78, // Element 14 64-bit DSP Processor
+ EM_ZSP = 79, // LSI Logic 16-bit DSP Processor
+ EM_MMIX = 80, // Donald Knuth's educational 64-bit processor
+ EM_HUANY = 81, // Harvard University machine-independent object files
+ EM_PRISM = 82, // SiTera Prism
+ EM_AVR = 83, // Atmel AVR 8-bit microcontroller
+ EM_FR30 = 84, // Fujitsu FR30
+ EM_D10V = 85, // Mitsubishi D10V
+ EM_D30V = 86, // Mitsubishi D30V
+ EM_V850 = 87, // NEC v850
+ EM_M32R = 88, // Mitsubishi M32R
+ EM_MN10300 = 89, // Matsushita MN10300
+ EM_MN10200 = 90, // Matsushita MN10200
+ EM_PJ = 91, // picoJava
+ EM_OPENRISC = 92, // OpenRISC 32-bit embedded processor
+ EM_ARC_COMPACT = 93, // ARC International ARCompact processor (old
+ // spelling/synonym: EM_ARC_A5)
+ EM_XTENSA = 94, // Tensilica Xtensa Architecture
+ EM_VIDEOCORE = 95, // Alphamosaic VideoCore processor
+ EM_TMM_GPP = 96, // Thompson Multimedia General Purpose Processor
+ EM_NS32K = 97, // National Semiconductor 32000 series
+ EM_TPC = 98, // Tenor Network TPC processor
+ EM_SNP1K = 99, // Trebia SNP 1000 processor
+ EM_ST200 = 100, // STMicroelectronics (www.st.com) ST200
+ EM_IP2K = 101, // Ubicom IP2xxx microcontroller family
+ EM_MAX = 102, // MAX Processor
+ EM_CR = 103, // National Semiconductor CompactRISC microprocessor
+ EM_F2MC16 = 104, // Fujitsu F2MC16
+ EM_MSP430 = 105, // Texas Instruments embedded microcontroller msp430
+ EM_BLACKFIN = 106, // Analog Devices Blackfin (DSP) processor
+ EM_SE_C33 = 107, // S1C33 Family of Seiko Epson processors
+ EM_SEP = 108, // Sharp embedded microprocessor
+ EM_ARCA = 109, // Arca RISC Microprocessor
+ EM_UNICORE = 110, // Microprocessor series from PKU-Unity Ltd. and MPRC
+ // of Peking University
+ EM_EXCESS = 111, // eXcess: 16/32/64-bit configurable embedded CPU
+ EM_DXP = 112, // Icera Semiconductor Inc. Deep Execution Processor
+ EM_ALTERA_NIOS2 = 113, // Altera Nios II soft-core processor
+ EM_CRX = 114, // National Semiconductor CompactRISC CRX
+ EM_XGATE = 115, // Motorola XGATE embedded processor
+ EM_C166 = 116, // Infineon C16x/XC16x processor
+ EM_M16C = 117, // Renesas M16C series microprocessors
+ EM_DSPIC30F = 118, // Microchip Technology dsPIC30F Digital Signal
+ // Controller
+ EM_CE = 119, // Freescale Communication Engine RISC core
+ EM_M32C = 120, // Renesas M32C series microprocessors
+ EM_TSK3000 = 131, // Altium TSK3000 core
+ EM_RS08 = 132, // Freescale RS08 embedded processor
+ EM_SHARC = 133, // Analog Devices SHARC family of 32-bit DSP
+ // processors
+ EM_ECOG2 = 134, // Cyan Technology eCOG2 microprocessor
+ EM_SCORE7 = 135, // Sunplus S+core7 RISC processor
+ EM_DSP24 = 136, // New Japan Radio (NJR) 24-bit DSP Processor
+ EM_VIDEOCORE3 = 137, // Broadcom VideoCore III processor
+ EM_LATTICEMICO32 = 138, // RISC processor for Lattice FPGA architecture
+ EM_SE_C17 = 139, // Seiko Epson C17 family
+ EM_TI_C6000 = 140, // The Texas Instruments TMS320C6000 DSP family
+ EM_TI_C2000 = 141, // The Texas Instruments TMS320C2000 DSP family
+ EM_TI_C5500 = 142, // The Texas Instruments TMS320C55x DSP family
+ EM_MMDSP_PLUS = 160, // STMicroelectronics 64bit VLIW Data Signal Processor
+ EM_CYPRESS_M8C = 161, // Cypress M8C microprocessor
+ EM_R32C = 162, // Renesas R32C series microprocessors
+ EM_TRIMEDIA = 163, // NXP Semiconductors TriMedia architecture family
+ EM_HEXAGON = 164, // Qualcomm Hexagon processor
+ EM_8051 = 165, // Intel 8051 and variants
+ EM_STXP7X = 166, // STMicroelectronics STxP7x family of configurable
+ // and extensible RISC processors
+ EM_NDS32 = 167, // Andes Technology compact code size embedded RISC
+ // processor family
+ EM_ECOG1 = 168, // Cyan Technology eCOG1X family
+ EM_ECOG1X = 168, // Cyan Technology eCOG1X family
+ EM_MAXQ30 = 169, // Dallas Semiconductor MAXQ30 Core Micro-controllers
+ EM_XIMO16 = 170, // New Japan Radio (NJR) 16-bit DSP Processor
+ EM_MANIK = 171, // M2000 Reconfigurable RISC Microprocessor
+ EM_CRAYNV2 = 172, // Cray Inc. NV2 vector architecture
+ EM_RX = 173, // Renesas RX family
+ EM_METAG = 174, // Imagination Technologies META processor
+ // architecture
+ EM_MCST_ELBRUS = 175, // MCST Elbrus general purpose hardware architecture
+ EM_ECOG16 = 176, // Cyan Technology eCOG16 family
+ EM_CR16 = 177, // National Semiconductor CompactRISC CR16 16-bit
+ // microprocessor
+ EM_ETPU = 178, // Freescale Extended Time Processing Unit
+ EM_SLE9X = 179, // Infineon Technologies SLE9X core
+ EM_L10M = 180, // Intel L10M
+ EM_K10M = 181, // Intel K10M
+ EM_AARCH64 = 183, // ARM AArch64
+ EM_AVR32 = 185, // Atmel Corporation 32-bit microprocessor family
+ EM_STM8 = 186, // STMicroeletronics STM8 8-bit microcontroller
+ EM_TILE64 = 187, // Tilera TILE64 multicore architecture family
+ EM_TILEPRO = 188, // Tilera TILEPro multicore architecture family
+ EM_CUDA = 190, // NVIDIA CUDA architecture
+ EM_TILEGX = 191, // Tilera TILE-Gx multicore architecture family
+ EM_CLOUDSHIELD = 192, // CloudShield architecture family
+ EM_COREA_1ST = 193, // KIPO-KAIST Core-A 1st generation processor family
+ EM_COREA_2ND = 194, // KIPO-KAIST Core-A 2nd generation processor family
+ EM_ARC_COMPACT2 = 195, // Synopsys ARCompact V2
+ EM_OPEN8 = 196, // Open8 8-bit RISC soft processor core
+ EM_RL78 = 197, // Renesas RL78 family
+ EM_VIDEOCORE5 = 198, // Broadcom VideoCore V processor
+ EM_78KOR = 199, // Renesas 78KOR family
+ EM_56800EX = 200, // Freescale 56800EX Digital Signal Controller (DSC)
+ EM_BA1 = 201, // Beyond BA1 CPU architecture
+ EM_BA2 = 202, // Beyond BA2 CPU architecture
+ EM_XCORE = 203, // XMOS xCORE processor family
+ EM_MCHP_PIC = 204, // Microchip 8-bit PIC(r) family
+ EM_INTEL205 = 205, // Reserved by Intel
+ EM_INTEL206 = 206, // Reserved by Intel
+ EM_INTEL207 = 207, // Reserved by Intel
+ EM_INTEL208 = 208, // Reserved by Intel
+ EM_INTEL209 = 209, // Reserved by Intel
+ EM_KM32 = 210, // KM211 KM32 32-bit processor
+ EM_KMX32 = 211, // KM211 KMX32 32-bit processor
+ EM_KMX16 = 212, // KM211 KMX16 16-bit processor
+ EM_KMX8 = 213, // KM211 KMX8 8-bit processor
+ EM_KVARC = 214, // KM211 KVARC processor
+ EM_CDP = 215, // Paneve CDP architecture family
+ EM_COGE = 216, // Cognitive Smart Memory Processor
+ EM_COOL = 217, // iCelero CoolEngine
+ EM_NORC = 218, // Nanoradio Optimized RISC
+ EM_CSR_KALIMBA = 219, // CSR Kalimba architecture family
+ EM_AMDGPU = 224, // AMD GPU architecture
+
+ // A request has been made to the maintainer of the official registry for
+ // such numbers for an official value for WebAssembly. As soon as one is
+ // allocated, this enum will be updated to use it.
+ EM_WEBASSEMBLY = 0x4157, // WebAssembly architecture
+};
+
+// Object file classes.
+enum {
+ ELFCLASSNONE = 0,
+ ELFCLASS32 = 1, // 32-bit object file
+ ELFCLASS64 = 2 // 64-bit object file
+};
+
+// Object file byte orderings.
+enum {
+ ELFDATANONE = 0, // Invalid data encoding.
+ ELFDATA2LSB = 1, // Little-endian object file
+ ELFDATA2MSB = 2 // Big-endian object file
+};
+
+// OS ABI identification.
+enum {
+ ELFOSABI_NONE = 0, // UNIX System V ABI
+ ELFOSABI_HPUX = 1, // HP-UX operating system
+ ELFOSABI_NETBSD = 2, // NetBSD
+ ELFOSABI_GNU = 3, // GNU/Linux
+ ELFOSABI_LINUX = 3, // Historical alias for ELFOSABI_GNU.
+ ELFOSABI_HURD = 4, // GNU/Hurd
+ ELFOSABI_SOLARIS = 6, // Solaris
+ ELFOSABI_AIX = 7, // AIX
+ ELFOSABI_IRIX = 8, // IRIX
+ ELFOSABI_FREEBSD = 9, // FreeBSD
+ ELFOSABI_TRU64 = 10, // TRU64 UNIX
+ ELFOSABI_MODESTO = 11, // Novell Modesto
+ ELFOSABI_OPENBSD = 12, // OpenBSD
+ ELFOSABI_OPENVMS = 13, // OpenVMS
+ ELFOSABI_NSK = 14, // Hewlett-Packard Non-Stop Kernel
+ ELFOSABI_AROS = 15, // AROS
+ ELFOSABI_FENIXOS = 16, // FenixOS
+ ELFOSABI_CLOUDABI = 17, // Nuxi CloudABI
+ ELFOSABI_C6000_ELFABI = 64, // Bare-metal TMS320C6000
+ ELFOSABI_AMDGPU_HSA = 64, // AMD HSA runtime
+ ELFOSABI_C6000_LINUX = 65, // Linux TMS320C6000
+ ELFOSABI_ARM = 97, // ARM
+ ELFOSABI_STANDALONE = 255 // Standalone (embedded) application
+};
+
+#define ELF_RELOC(name, value) name = value,
+
+// Specific e_flags for PPC64
+enum {
+ // e_flags bits specifying ABI:
+ // 1 for original ABI using function descriptors,
+ // 2 for revised ABI without function descriptors,
+ // 0 for unspecified or not using any features affected by the differences.
+ EF_PPC64_ABI = 3
+};
+
+// Special values for the st_other field in the symbol table entry for PPC64.
+enum {
+ STO_PPC64_LOCAL_BIT = 5,
+ STO_PPC64_LOCAL_MASK = (7 << STO_PPC64_LOCAL_BIT)
+};
+static inline int64_t
+decodePPC64LocalEntryOffset(unsigned Other) {
+ unsigned Val = (Other & STO_PPC64_LOCAL_MASK) >> STO_PPC64_LOCAL_BIT;
+ return ((1 << Val) >> 2) << 2;
+}
+static inline unsigned
+encodePPC64LocalEntryOffset(int64_t Offset) {
+ unsigned Val = (Offset >= 4 * 4
+ ? (Offset >= 8 * 4
+ ? (Offset >= 16 * 4 ? 6 : 5)
+ : 4)
+ : (Offset >= 2 * 4
+ ? 3
+ : (Offset >= 1 * 4 ? 2 : 0)));
+ return Val << STO_PPC64_LOCAL_BIT;
+}
+
+// ARM Specific e_flags
+enum : unsigned {
+ EF_ARM_SOFT_FLOAT = 0x00000200U,
+ EF_ARM_VFP_FLOAT = 0x00000400U,
+ EF_ARM_EABI_UNKNOWN = 0x00000000U,
+ EF_ARM_EABI_VER1 = 0x01000000U,
+ EF_ARM_EABI_VER2 = 0x02000000U,
+ EF_ARM_EABI_VER3 = 0x03000000U,
+ EF_ARM_EABI_VER4 = 0x04000000U,
+ EF_ARM_EABI_VER5 = 0x05000000U,
+ EF_ARM_EABIMASK = 0xFF000000U
+};
+
+// AVR specific e_flags
+enum : unsigned {
+ EF_AVR_ARCH_AVR1 = 1,
+ EF_AVR_ARCH_AVR2 = 2,
+ EF_AVR_ARCH_AVR25 = 25,
+ EF_AVR_ARCH_AVR3 = 3,
+ EF_AVR_ARCH_AVR31 = 31,
+ EF_AVR_ARCH_AVR35 = 35,
+ EF_AVR_ARCH_AVR4 = 4,
+ EF_AVR_ARCH_AVR5 = 5,
+ EF_AVR_ARCH_AVR51 = 51,
+ EF_AVR_ARCH_AVR6 = 6,
+ EF_AVR_ARCH_AVRTINY = 100,
+ EF_AVR_ARCH_XMEGA1 = 101,
+ EF_AVR_ARCH_XMEGA2 = 102,
+ EF_AVR_ARCH_XMEGA3 = 103,
+ EF_AVR_ARCH_XMEGA4 = 104,
+ EF_AVR_ARCH_XMEGA5 = 105,
+ EF_AVR_ARCH_XMEGA6 = 106,
+ EF_AVR_ARCH_XMEGA7 = 107
+};
+
+// Mips Specific e_flags
+enum : unsigned {
+ EF_MIPS_NOREORDER = 0x00000001, // Don't reorder instructions
+ EF_MIPS_PIC = 0x00000002, // Position independent code
+ EF_MIPS_CPIC = 0x00000004, // Call object with Position independent code
+ EF_MIPS_ABI2 = 0x00000020, // File uses N32 ABI
+ EF_MIPS_32BITMODE = 0x00000100, // Code compiled for a 64-bit machine
+ // in 32-bit mode
+ EF_MIPS_FP64 = 0x00000200, // Code compiled for a 32-bit machine
+ // but uses 64-bit FP registers
+ EF_MIPS_NAN2008 = 0x00000400, // Uses IEE 754-2008 NaN encoding
+
+ // ABI flags
+ EF_MIPS_ABI_O32 = 0x00001000, // This file follows the first MIPS 32 bit ABI
+ EF_MIPS_ABI_O64 = 0x00002000, // O32 ABI extended for 64-bit architecture.
+ EF_MIPS_ABI_EABI32 = 0x00003000, // EABI in 32 bit mode.
+ EF_MIPS_ABI_EABI64 = 0x00004000, // EABI in 64 bit mode.
+ EF_MIPS_ABI = 0x0000f000, // Mask for selecting EF_MIPS_ABI_ variant.
+
+ // MIPS machine variant
+ EF_MIPS_MACH_3900 = 0x00810000, // Toshiba R3900
+ EF_MIPS_MACH_4010 = 0x00820000, // LSI R4010
+ EF_MIPS_MACH_4100 = 0x00830000, // NEC VR4100
+ EF_MIPS_MACH_4650 = 0x00850000, // MIPS R4650
+ EF_MIPS_MACH_4120 = 0x00870000, // NEC VR4120
+ EF_MIPS_MACH_4111 = 0x00880000, // NEC VR4111/VR4181
+ EF_MIPS_MACH_SB1 = 0x008a0000, // Broadcom SB-1
+ EF_MIPS_MACH_OCTEON = 0x008b0000, // Cavium Networks Octeon
+ EF_MIPS_MACH_XLR = 0x008c0000, // RMI Xlr
+ EF_MIPS_MACH_OCTEON2 = 0x008d0000, // Cavium Networks Octeon2
+ EF_MIPS_MACH_OCTEON3 = 0x008e0000, // Cavium Networks Octeon3
+ EF_MIPS_MACH_5400 = 0x00910000, // NEC VR5400
+ EF_MIPS_MACH_5900 = 0x00920000, // MIPS R5900
+ EF_MIPS_MACH_5500 = 0x00980000, // NEC VR5500
+ EF_MIPS_MACH_9000 = 0x00990000, // Unknown
+ EF_MIPS_MACH_LS2E = 0x00a00000, // ST Microelectronics Loongson 2E
+ EF_MIPS_MACH_LS2F = 0x00a10000, // ST Microelectronics Loongson 2F
+ EF_MIPS_MACH_LS3A = 0x00a20000, // Loongson 3A
+ EF_MIPS_MACH = 0x00ff0000, // EF_MIPS_MACH_xxx selection mask
+
+ // ARCH_ASE
+ EF_MIPS_MICROMIPS = 0x02000000, // microMIPS
+ EF_MIPS_ARCH_ASE_M16 =
+ 0x04000000, // Has Mips-16 ISA extensions
+ EF_MIPS_ARCH_ASE_MDMX =
+ 0x08000000, // Has MDMX multimedia extensions
+ EF_MIPS_ARCH_ASE = 0x0f000000, // Mask for EF_MIPS_ARCH_ASE_xxx flags
+
+ // ARCH
+ EF_MIPS_ARCH_1 = 0x00000000, // MIPS1 instruction set
+ EF_MIPS_ARCH_2 = 0x10000000, // MIPS2 instruction set
+ EF_MIPS_ARCH_3 = 0x20000000, // MIPS3 instruction set
+ EF_MIPS_ARCH_4 = 0x30000000, // MIPS4 instruction set
+ EF_MIPS_ARCH_5 = 0x40000000, // MIPS5 instruction set
+ EF_MIPS_ARCH_32 = 0x50000000, // MIPS32 instruction set per linux not elf.h
+ EF_MIPS_ARCH_64 = 0x60000000, // MIPS64 instruction set per linux not elf.h
+ EF_MIPS_ARCH_32R2 = 0x70000000, // mips32r2, mips32r3, mips32r5
+ EF_MIPS_ARCH_64R2 = 0x80000000, // mips64r2, mips64r3, mips64r5
+ EF_MIPS_ARCH_32R6 = 0x90000000, // mips32r6
+ EF_MIPS_ARCH_64R6 = 0xa0000000, // mips64r6
+ EF_MIPS_ARCH = 0xf0000000 // Mask for applying EF_MIPS_ARCH_ variant
+};
+
+// Special values for the st_other field in the symbol table entry for MIPS.
+enum {
+ STO_MIPS_OPTIONAL = 0x04, // Symbol whose definition is optional
+ STO_MIPS_PLT = 0x08, // PLT entry related dynamic table record
+ STO_MIPS_PIC = 0x20, // PIC func in an object mixes PIC/non-PIC
+ STO_MIPS_MICROMIPS = 0x80, // MIPS Specific ISA for MicroMips
+ STO_MIPS_MIPS16 = 0xf0 // MIPS Specific ISA for Mips16
+};
+
+// .MIPS.options section descriptor kinds
+enum {
+ ODK_NULL = 0, // Undefined
+ ODK_REGINFO = 1, // Register usage information
+ ODK_EXCEPTIONS = 2, // Exception processing options
+ ODK_PAD = 3, // Section padding options
+ ODK_HWPATCH = 4, // Hardware patches applied
+ ODK_FILL = 5, // Linker fill value
+ ODK_TAGS = 6, // Space for tool identification
+ ODK_HWAND = 7, // Hardware AND patches applied
+ ODK_HWOR = 8, // Hardware OR patches applied
+ ODK_GP_GROUP = 9, // GP group to use for text/data sections
+ ODK_IDENT = 10, // ID information
+ ODK_PAGESIZE = 11 // Page size information
+};
+
+// Hexagon-specific e_flags
+enum {
+ // Object processor version flags, bits[11:0]
+ EF_HEXAGON_MACH_V2 = 0x00000001, // Hexagon V2
+ EF_HEXAGON_MACH_V3 = 0x00000002, // Hexagon V3
+ EF_HEXAGON_MACH_V4 = 0x00000003, // Hexagon V4
+ EF_HEXAGON_MACH_V5 = 0x00000004, // Hexagon V5
+ EF_HEXAGON_MACH_V55 = 0x00000005, // Hexagon V55
+ EF_HEXAGON_MACH_V60 = 0x00000060, // Hexagon V60
+
+ // Highest ISA version flags
+ EF_HEXAGON_ISA_MACH = 0x00000000, // Same as specified in bits[11:0]
+ // of e_flags
+ EF_HEXAGON_ISA_V2 = 0x00000010, // Hexagon V2 ISA
+ EF_HEXAGON_ISA_V3 = 0x00000020, // Hexagon V3 ISA
+ EF_HEXAGON_ISA_V4 = 0x00000030, // Hexagon V4 ISA
+ EF_HEXAGON_ISA_V5 = 0x00000040, // Hexagon V5 ISA
+ EF_HEXAGON_ISA_V55 = 0x00000050, // Hexagon V55 ISA
+ EF_HEXAGON_ISA_V60 = 0x00000060, // Hexagon V60 ISA
+};
+
+// Hexagon-specific section indexes for common small data
+enum {
+ SHN_HEXAGON_SCOMMON = 0xff00, // Other access sizes
+ SHN_HEXAGON_SCOMMON_1 = 0xff01, // Byte-sized access
+ SHN_HEXAGON_SCOMMON_2 = 0xff02, // Half-word-sized access
+ SHN_HEXAGON_SCOMMON_4 = 0xff03, // Word-sized access
+ SHN_HEXAGON_SCOMMON_8 = 0xff04 // Double-word-size access
+};
+
+
+#undef ELF_RELOC
+
+// Section header.
+struct Elf32_Shdr {
+ Elf32_Word sh_name; // Section name (index into string table)
+ Elf32_Word sh_type; // Section type (SHT_*)
+ Elf32_Word sh_flags; // Section flags (SHF_*)
+ Elf32_Addr sh_addr; // Address where section is to be loaded
+ Elf32_Off sh_offset; // File offset of section data, in bytes
+ Elf32_Word sh_size; // Size of section, in bytes
+ Elf32_Word sh_link; // Section type-specific header table index link
+ Elf32_Word sh_info; // Section type-specific extra information
+ Elf32_Word sh_addralign; // Section address alignment
+ Elf32_Word sh_entsize; // Size of records contained within the section
+};
+
+// Section header for ELF64 - same fields as ELF32, different types.
+struct Elf64_Shdr {
+ Elf64_Word sh_name;
+ Elf64_Word sh_type;
+ Elf64_Xword sh_flags;
+ Elf64_Addr sh_addr;
+ Elf64_Off sh_offset;
+ Elf64_Xword sh_size;
+ Elf64_Word sh_link;
+ Elf64_Word sh_info;
+ Elf64_Xword sh_addralign;
+ Elf64_Xword sh_entsize;
+};
+
+// Special section indices.
+enum {
+ SHN_UNDEF = 0, // Undefined, missing, irrelevant, or meaningless
+ SHN_LORESERVE = 0xff00, // Lowest reserved index
+ SHN_LOPROC = 0xff00, // Lowest processor-specific index
+ SHN_HIPROC = 0xff1f, // Highest processor-specific index
+ SHN_LOOS = 0xff20, // Lowest operating system-specific index
+ SHN_HIOS = 0xff3f, // Highest operating system-specific index
+ SHN_ABS = 0xfff1, // Symbol has absolute value; does not need relocation
+ SHN_COMMON = 0xfff2, // FORTRAN COMMON or C external global variables
+ SHN_XINDEX = 0xffff, // Mark that the index is >= SHN_LORESERVE
+ SHN_HIRESERVE = 0xffff // Highest reserved index
+};
+
+// Section types.
+enum : unsigned {
+ SHT_NULL = 0, // No associated section (inactive entry).
+ SHT_PROGBITS = 1, // Program-defined contents.
+ SHT_SYMTAB = 2, // Symbol table.
+ SHT_STRTAB = 3, // String table.
+ SHT_RELA = 4, // Relocation entries; explicit addends.
+ SHT_HASH = 5, // Symbol hash table.
+ SHT_DYNAMIC = 6, // Information for dynamic linking.
+ SHT_NOTE = 7, // Information about the file.
+ SHT_NOBITS = 8, // Data occupies no space in the file.
+ SHT_REL = 9, // Relocation entries; no explicit addends.
+ SHT_SHLIB = 10, // Reserved.
+ SHT_DYNSYM = 11, // Symbol table.
+ SHT_INIT_ARRAY = 14, // Pointers to initialization functions.
+ SHT_FINI_ARRAY = 15, // Pointers to termination functions.
+ SHT_PREINIT_ARRAY = 16, // Pointers to pre-init functions.
+ SHT_GROUP = 17, // Section group.
+ SHT_SYMTAB_SHNDX = 18, // Indices for SHN_XINDEX entries.
+ SHT_LOOS = 0x60000000, // Lowest operating system-specific type.
+ SHT_GNU_ATTRIBUTES= 0x6ffffff5, // Object attributes.
+ SHT_GNU_HASH = 0x6ffffff6, // GNU-style hash table.
+ SHT_GNU_verdef = 0x6ffffffd, // GNU version definitions.
+ SHT_GNU_verneed = 0x6ffffffe, // GNU version references.
+ SHT_GNU_versym = 0x6fffffff, // GNU symbol versions table.
+ SHT_HIOS = 0x6fffffff, // Highest operating system-specific type.
+ SHT_LOPROC = 0x70000000, // Lowest processor arch-specific type.
+ // Fixme: All this is duplicated in MCSectionELF. Why??
+ // Exception Index table
+ SHT_ARM_EXIDX = 0x70000001U,
+ // BPABI DLL dynamic linking pre-emption map
+ SHT_ARM_PREEMPTMAP = 0x70000002U,
+ // Object file compatibility attributes
+ SHT_ARM_ATTRIBUTES = 0x70000003U,
+ SHT_ARM_DEBUGOVERLAY = 0x70000004U,
+ SHT_ARM_OVERLAYSECTION = 0x70000005U,
+ SHT_HEX_ORDERED = 0x70000000, // Link editor is to sort the entries in
+ // this section based on their sizes
+ SHT_X86_64_UNWIND = 0x70000001, // Unwind information
+
+ SHT_MIPS_REGINFO = 0x70000006, // Register usage information
+ SHT_MIPS_OPTIONS = 0x7000000d, // General options
+ SHT_MIPS_ABIFLAGS = 0x7000002a, // ABI information.
+
+ SHT_HIPROC = 0x7fffffff, // Highest processor arch-specific type.
+ SHT_LOUSER = 0x80000000, // Lowest type reserved for applications.
+ SHT_HIUSER = 0xffffffff // Highest type reserved for applications.
+};
+
+// Section flags.
+enum : unsigned {
+ // Section data should be writable during execution.
+ SHF_WRITE = 0x1,
+
+ // Section occupies memory during program execution.
+ SHF_ALLOC = 0x2,
+
+ // Section contains executable machine instructions.
+ SHF_EXECINSTR = 0x4,
+
+ // The data in this section may be merged.
+ SHF_MERGE = 0x10,
+
+ // The data in this section is null-terminated strings.
+ SHF_STRINGS = 0x20,
+
+ // A field in this section holds a section header table index.
+ SHF_INFO_LINK = 0x40U,
+
+ // Adds special ordering requirements for link editors.
+ SHF_LINK_ORDER = 0x80U,
+
+ // This section requires special OS-specific processing to avoid incorrect
+ // behavior.
+ SHF_OS_NONCONFORMING = 0x100U,
+
+ // This section is a member of a section group.
+ SHF_GROUP = 0x200U,
+
+ // This section holds Thread-Local Storage.
+ SHF_TLS = 0x400U,
+
+ // This section is excluded from the final executable or shared library.
+ SHF_EXCLUDE = 0x80000000U,
+
+ // Start of target-specific flags.
+
+ /// XCORE_SHF_CP_SECTION - All sections with the "c" flag are grouped
+ /// together by the linker to form the constant pool and the cp register is
+ /// set to the start of the constant pool by the boot code.
+ XCORE_SHF_CP_SECTION = 0x800U,
+
+ /// XCORE_SHF_DP_SECTION - All sections with the "d" flag are grouped
+ /// together by the linker to form the data section and the dp register is
+ /// set to the start of the section by the boot code.
+ XCORE_SHF_DP_SECTION = 0x1000U,
+
+ SHF_MASKOS = 0x0ff00000,
+
+ // Bits indicating processor-specific flags.
+ SHF_MASKPROC = 0xf0000000,
+
+ // If an object file section does not have this flag set, then it may not hold
+ // more than 2GB and can be freely referred to in objects using smaller code
+ // models. Otherwise, only objects using larger code models can refer to them.
+ // For example, a medium code model object can refer to data in a section that
+ // sets this flag besides being able to refer to data in a section that does
+ // not set it; likewise, a small code model object can refer only to code in a
+ // section that does not set this flag.
+ SHF_X86_64_LARGE = 0x10000000,
+
+ // All sections with the GPREL flag are grouped into a global data area
+ // for faster accesses
+ SHF_HEX_GPREL = 0x10000000,
+
+ // Section contains text/data which may be replicated in other sections.
+ // Linker must retain only one copy.
+ SHF_MIPS_NODUPES = 0x01000000,
+
+ // Linker must generate implicit hidden weak names.
+ SHF_MIPS_NAMES = 0x02000000,
+
+ // Section data local to process.
+ SHF_MIPS_LOCAL = 0x04000000,
+
+ // Do not strip this section.
+ SHF_MIPS_NOSTRIP = 0x08000000,
+
+ // Section must be part of global data area.
+ SHF_MIPS_GPREL = 0x10000000,
+
+ // This section should be merged.
+ SHF_MIPS_MERGE = 0x20000000,
+
+ // Address size to be inferred from section entry size.
+ SHF_MIPS_ADDR = 0x40000000,
+
+ // Section data is string data by default.
+ SHF_MIPS_STRING = 0x80000000,
+
+ SHF_AMDGPU_HSA_GLOBAL = 0x00100000,
+ SHF_AMDGPU_HSA_READONLY = 0x00200000,
+ SHF_AMDGPU_HSA_CODE = 0x00400000,
+ SHF_AMDGPU_HSA_AGENT = 0x00800000
+};
+
+// Section Group Flags
+enum : unsigned {
+ GRP_COMDAT = 0x1,
+ GRP_MASKOS = 0x0ff00000,
+ GRP_MASKPROC = 0xf0000000
+};
+
+// Symbol table entries for ELF32.
+struct Elf32_Sym {
+ Elf32_Word st_name; // Symbol name (index into string table)
+ Elf32_Addr st_value; // Value or address associated with the symbol
+ Elf32_Word st_size; // Size of the symbol
+ unsigned char st_info; // Symbol's type and binding attributes
+ unsigned char st_other; // Must be zero; reserved
+ Elf32_Half st_shndx; // Which section (header table index) it's defined in
+
+ // These accessors and mutators correspond to the ELF32_ST_BIND,
+ // ELF32_ST_TYPE, and ELF32_ST_INFO macros defined in the ELF specification:
+ unsigned char getBinding() const { return st_info >> 4; }
+ unsigned char getType() const { return st_info & 0x0f; }
+ void setBinding(unsigned char b) { setBindingAndType(b, getType()); }
+ void setType(unsigned char t) { setBindingAndType(getBinding(), t); }
+ void setBindingAndType(unsigned char b, unsigned char t) {
+ st_info = (b << 4) + (t & 0x0f);
+ }
+};
+
+// Symbol table entries for ELF64.
+struct Elf64_Sym {
+ Elf64_Word st_name; // Symbol name (index into string table)
+ unsigned char st_info; // Symbol's type and binding attributes
+ unsigned char st_other; // Must be zero; reserved
+ Elf64_Half st_shndx; // Which section (header tbl index) it's defined in
+ Elf64_Addr st_value; // Value or address associated with the symbol
+ Elf64_Xword st_size; // Size of the symbol
+
+ // These accessors and mutators are identical to those defined for ELF32
+ // symbol table entries.
+ unsigned char getBinding() const { return st_info >> 4; }
+ unsigned char getType() const { return st_info & 0x0f; }
+ void setBinding(unsigned char b) { setBindingAndType(b, getType()); }
+ void setType(unsigned char t) { setBindingAndType(getBinding(), t); }
+ void setBindingAndType(unsigned char b, unsigned char t) {
+ st_info = (b << 4) + (t & 0x0f);
+ }
+};
+
+// The size (in bytes) of symbol table entries.
+enum {
+ SYMENTRY_SIZE32 = 16, // 32-bit symbol entry size
+ SYMENTRY_SIZE64 = 24 // 64-bit symbol entry size.
+};
+
+// Symbol bindings.
+enum {
+ STB_LOCAL = 0, // Local symbol, not visible outside obj file containing def
+ STB_GLOBAL = 1, // Global symbol, visible to all object files being combined
+ STB_WEAK = 2, // Weak symbol, like global but lower-precedence
+ STB_GNU_UNIQUE = 10,
+ STB_LOOS = 10, // Lowest operating system-specific binding type
+ STB_HIOS = 12, // Highest operating system-specific binding type
+ STB_LOPROC = 13, // Lowest processor-specific binding type
+ STB_HIPROC = 15 // Highest processor-specific binding type
+};
+
+// Symbol types.
+enum {
+ STT_NOTYPE = 0, // Symbol's type is not specified
+ STT_OBJECT = 1, // Symbol is a data object (variable, array, etc.)
+ STT_FUNC = 2, // Symbol is executable code (function, etc.)
+ STT_SECTION = 3, // Symbol refers to a section
+ STT_FILE = 4, // Local, absolute symbol that refers to a file
+ STT_COMMON = 5, // An uninitialized common block
+ STT_TLS = 6, // Thread local data object
+ STT_GNU_IFUNC = 10, // GNU indirect function
+ STT_LOOS = 10, // Lowest operating system-specific symbol type
+ STT_HIOS = 12, // Highest operating system-specific symbol type
+ STT_LOPROC = 13, // Lowest processor-specific symbol type
+ STT_HIPROC = 15, // Highest processor-specific symbol type
+
+ // AMDGPU symbol types
+ STT_AMDGPU_HSA_KERNEL = 10,
+ STT_AMDGPU_HSA_INDIRECT_FUNCTION = 11,
+ STT_AMDGPU_HSA_METADATA = 12
+};
+
+enum {
+ STV_DEFAULT = 0, // Visibility is specified by binding type
+ STV_INTERNAL = 1, // Defined by processor supplements
+ STV_HIDDEN = 2, // Not visible to other components
+ STV_PROTECTED = 3 // Visible in other components but not preemptable
+};
+
+// Symbol number.
+enum {
+ STN_UNDEF = 0
+};
+
+// Special relocation symbols used in the MIPS64 ELF relocation entries
+enum {
+ RSS_UNDEF = 0, // None
+ RSS_GP = 1, // Value of gp
+ RSS_GP0 = 2, // Value of gp used to create object being relocated
+ RSS_LOC = 3 // Address of location being relocated
+};
+
+// Relocation entry, without explicit addend.
+struct Elf32_Rel {
+ Elf32_Addr r_offset; // Location (file byte offset, or program virtual addr)
+ Elf32_Word r_info; // Symbol table index and type of relocation to apply
+
+ // These accessors and mutators correspond to the ELF32_R_SYM, ELF32_R_TYPE,
+ // and ELF32_R_INFO macros defined in the ELF specification:
+ Elf32_Word getSymbol() const { return (r_info >> 8); }
+ unsigned char getType() const { return (unsigned char) (r_info & 0x0ff); }
+ void setSymbol(Elf32_Word s) { setSymbolAndType(s, getType()); }
+ void setType(unsigned char t) { setSymbolAndType(getSymbol(), t); }
+ void setSymbolAndType(Elf32_Word s, unsigned char t) {
+ r_info = (s << 8) + t;
+ }
+};
+
+// Relocation entry with explicit addend.
+struct Elf32_Rela {
+ Elf32_Addr r_offset; // Location (file byte offset, or program virtual addr)
+ Elf32_Word r_info; // Symbol table index and type of relocation to apply
+ Elf32_Sword r_addend; // Compute value for relocatable field by adding this
+
+ // These accessors and mutators correspond to the ELF32_R_SYM, ELF32_R_TYPE,
+ // and ELF32_R_INFO macros defined in the ELF specification:
+ Elf32_Word getSymbol() const { return (r_info >> 8); }
+ unsigned char getType() const { return (unsigned char) (r_info & 0x0ff); }
+ void setSymbol(Elf32_Word s) { setSymbolAndType(s, getType()); }
+ void setType(unsigned char t) { setSymbolAndType(getSymbol(), t); }
+ void setSymbolAndType(Elf32_Word s, unsigned char t) {
+ r_info = (s << 8) + t;
+ }
+};
+
+// Relocation entry, without explicit addend.
+struct Elf64_Rel {
+ Elf64_Addr r_offset; // Location (file byte offset, or program virtual addr).
+ Elf64_Xword r_info; // Symbol table index and type of relocation to apply.
+
+ // These accessors and mutators correspond to the ELF64_R_SYM, ELF64_R_TYPE,
+ // and ELF64_R_INFO macros defined in the ELF specification:
+ Elf64_Word getSymbol() const { return (r_info >> 32); }
+ Elf64_Word getType() const {
+ return (Elf64_Word) (r_info & 0xffffffffL);
+ }
+ void setSymbol(Elf64_Word s) { setSymbolAndType(s, getType()); }
+ void setType(Elf64_Word t) { setSymbolAndType(getSymbol(), t); }
+ void setSymbolAndType(Elf64_Word s, Elf64_Word t) {
+ r_info = ((Elf64_Xword)s << 32) + (t&0xffffffffL);
+ }
+};
+
+// Relocation entry with explicit addend.
+struct Elf64_Rela {
+ Elf64_Addr r_offset; // Location (file byte offset, or program virtual addr).
+ Elf64_Xword r_info; // Symbol table index and type of relocation to apply.
+ Elf64_Sxword r_addend; // Compute value for relocatable field by adding this.
+
+ // These accessors and mutators correspond to the ELF64_R_SYM, ELF64_R_TYPE,
+ // and ELF64_R_INFO macros defined in the ELF specification:
+ Elf64_Word getSymbol() const { return (r_info >> 32); }
+ Elf64_Word getType() const {
+ return (Elf64_Word) (r_info & 0xffffffffL);
+ }
+ void setSymbol(Elf64_Word s) { setSymbolAndType(s, getType()); }
+ void setType(Elf64_Word t) { setSymbolAndType(getSymbol(), t); }
+ void setSymbolAndType(Elf64_Word s, Elf64_Word t) {
+ r_info = ((Elf64_Xword)s << 32) + (t&0xffffffffL);
+ }
+};
+
+// Program header for ELF32.
+struct Elf32_Phdr {
+ Elf32_Word p_type; // Type of segment
+ Elf32_Off p_offset; // File offset where segment is located, in bytes
+ Elf32_Addr p_vaddr; // Virtual address of beginning of segment
+ Elf32_Addr p_paddr; // Physical address of beginning of segment (OS-specific)
+ Elf32_Word p_filesz; // Num. of bytes in file image of segment (may be zero)
+ Elf32_Word p_memsz; // Num. of bytes in mem image of segment (may be zero)
+ Elf32_Word p_flags; // Segment flags
+ Elf32_Word p_align; // Segment alignment constraint
+};
+
+// Program header for ELF64.
+struct Elf64_Phdr {
+ Elf64_Word p_type; // Type of segment
+ Elf64_Word p_flags; // Segment flags
+ Elf64_Off p_offset; // File offset where segment is located, in bytes
+ Elf64_Addr p_vaddr; // Virtual address of beginning of segment
+ Elf64_Addr p_paddr; // Physical addr of beginning of segment (OS-specific)
+ Elf64_Xword p_filesz; // Num. of bytes in file image of segment (may be zero)
+ Elf64_Xword p_memsz; // Num. of bytes in mem image of segment (may be zero)
+ Elf64_Xword p_align; // Segment alignment constraint
+};
+
+// Segment types.
+enum {
+ PT_NULL = 0, // Unused segment.
+ PT_LOAD = 1, // Loadable segment.
+ PT_DYNAMIC = 2, // Dynamic linking information.
+ PT_INTERP = 3, // Interpreter pathname.
+ PT_NOTE = 4, // Auxiliary information.
+ PT_SHLIB = 5, // Reserved.
+ PT_PHDR = 6, // The program header table itself.
+ PT_TLS = 7, // The thread-local storage template.
+ PT_LOOS = 0x60000000, // Lowest operating system-specific pt entry type.
+ PT_HIOS = 0x6fffffff, // Highest operating system-specific pt entry type.
+ PT_LOPROC = 0x70000000, // Lowest processor-specific program hdr entry type.
+ PT_HIPROC = 0x7fffffff, // Highest processor-specific program hdr entry type.
+
+ // x86-64 program header types.
+ // These all contain stack unwind tables.
+ PT_GNU_EH_FRAME = 0x6474e550,
+ PT_SUNW_EH_FRAME = 0x6474e550,
+ PT_SUNW_UNWIND = 0x6464e550,
+
+ PT_GNU_STACK = 0x6474e551, // Indicates stack executability.
+ PT_GNU_RELRO = 0x6474e552, // Read-only after relocation.
+
+ // ARM program header types.
+ PT_ARM_ARCHEXT = 0x70000000, // Platform architecture compatibility info
+ // These all contain stack unwind tables.
+ PT_ARM_EXIDX = 0x70000001,
+ PT_ARM_UNWIND = 0x70000001,
+
+ // MIPS program header types.
+ PT_MIPS_REGINFO = 0x70000000, // Register usage information.
+ PT_MIPS_RTPROC = 0x70000001, // Runtime procedure table.
+ PT_MIPS_OPTIONS = 0x70000002, // Options segment.
+ PT_MIPS_ABIFLAGS = 0x70000003, // Abiflags segment.
+
+ // AMDGPU program header types.
+ PT_AMDGPU_HSA_LOAD_GLOBAL_PROGRAM = 0x60000000,
+ PT_AMDGPU_HSA_LOAD_GLOBAL_AGENT = 0x60000001,
+ PT_AMDGPU_HSA_LOAD_READONLY_AGENT = 0x60000002,
+ PT_AMDGPU_HSA_LOAD_CODE_AGENT = 0x60000003,
+
+ // WebAssembly program header types.
+ PT_WEBASSEMBLY_FUNCTIONS = PT_LOPROC + 0, // Function definitions.
+};
+
+// Segment flag bits.
+enum : unsigned {
+ PF_X = 1, // Execute
+ PF_W = 2, // Write
+ PF_R = 4, // Read
+ PF_MASKOS = 0x0ff00000,// Bits for operating system-specific semantics.
+ PF_MASKPROC = 0xf0000000 // Bits for processor-specific semantics.
+};
+
+// Dynamic table entry for ELF32.
+struct Elf32_Dyn
+{
+ Elf32_Sword d_tag; // Type of dynamic table entry.
+ union
+ {
+ Elf32_Word d_val; // Integer value of entry.
+ Elf32_Addr d_ptr; // Pointer value of entry.
+ } d_un;
+};
+
+// Dynamic table entry for ELF64.
+struct Elf64_Dyn
+{
+ Elf64_Sxword d_tag; // Type of dynamic table entry.
+ union
+ {
+ Elf64_Xword d_val; // Integer value of entry.
+ Elf64_Addr d_ptr; // Pointer value of entry.
+ } d_un;
+};
+
+// Dynamic table entry tags.
+enum {
+ DT_NULL = 0, // Marks end of dynamic array.
+ DT_NEEDED = 1, // String table offset of needed library.
+ DT_PLTRELSZ = 2, // Size of relocation entries in PLT.
+ DT_PLTGOT = 3, // Address associated with linkage table.
+ DT_HASH = 4, // Address of symbolic hash table.
+ DT_STRTAB = 5, // Address of dynamic string table.
+ DT_SYMTAB = 6, // Address of dynamic symbol table.
+ DT_RELA = 7, // Address of relocation table (Rela entries).
+ DT_RELASZ = 8, // Size of Rela relocation table.
+ DT_RELAENT = 9, // Size of a Rela relocation entry.
+ DT_STRSZ = 10, // Total size of the string table.
+ DT_SYMENT = 11, // Size of a symbol table entry.
+ DT_INIT = 12, // Address of initialization function.
+ DT_FINI = 13, // Address of termination function.
+ DT_SONAME = 14, // String table offset of a shared objects name.
+ DT_RPATH = 15, // String table offset of library search path.
+ DT_SYMBOLIC = 16, // Changes symbol resolution algorithm.
+ DT_REL = 17, // Address of relocation table (Rel entries).
+ DT_RELSZ = 18, // Size of Rel relocation table.
+ DT_RELENT = 19, // Size of a Rel relocation entry.
+ DT_PLTREL = 20, // Type of relocation entry used for linking.
+ DT_DEBUG = 21, // Reserved for debugger.
+ DT_TEXTREL = 22, // Relocations exist for non-writable segments.
+ DT_JMPREL = 23, // Address of relocations associated with PLT.
+ DT_BIND_NOW = 24, // Process all relocations before execution.
+ DT_INIT_ARRAY = 25, // Pointer to array of initialization functions.
+ DT_FINI_ARRAY = 26, // Pointer to array of termination functions.
+ DT_INIT_ARRAYSZ = 27, // Size of DT_INIT_ARRAY.
+ DT_FINI_ARRAYSZ = 28, // Size of DT_FINI_ARRAY.
+ DT_RUNPATH = 29, // String table offset of lib search path.
+ DT_FLAGS = 30, // Flags.
+ DT_ENCODING = 32, // Values from here to DT_LOOS follow the rules
+ // for the interpretation of the d_un union.
+
+ DT_PREINIT_ARRAY = 32, // Pointer to array of preinit functions.
+ DT_PREINIT_ARRAYSZ = 33, // Size of the DT_PREINIT_ARRAY array.
+
+ DT_LOOS = 0x60000000, // Start of environment specific tags.
+ DT_HIOS = 0x6FFFFFFF, // End of environment specific tags.
+ DT_LOPROC = 0x70000000, // Start of processor specific tags.
+ DT_HIPROC = 0x7FFFFFFF, // End of processor specific tags.
+
+ DT_GNU_HASH = 0x6FFFFEF5, // Reference to the GNU hash table.
+ DT_RELACOUNT = 0x6FFFFFF9, // ELF32_Rela count.
+ DT_RELCOUNT = 0x6FFFFFFA, // ELF32_Rel count.
+
+ DT_FLAGS_1 = 0X6FFFFFFB, // Flags_1.
+ DT_VERSYM = 0x6FFFFFF0, // The address of .gnu.version section.
+ DT_VERDEF = 0X6FFFFFFC, // The address of the version definition table.
+ DT_VERDEFNUM = 0X6FFFFFFD, // The number of entries in DT_VERDEF.
+ DT_VERNEED = 0X6FFFFFFE, // The address of the version Dependency table.
+ DT_VERNEEDNUM = 0X6FFFFFFF, // The number of entries in DT_VERNEED.
+
+ // Mips specific dynamic table entry tags.
+ DT_MIPS_RLD_VERSION = 0x70000001, // 32 bit version number for runtime
+ // linker interface.
+ DT_MIPS_TIME_STAMP = 0x70000002, // Time stamp.
+ DT_MIPS_ICHECKSUM = 0x70000003, // Checksum of external strings
+ // and common sizes.
+ DT_MIPS_IVERSION = 0x70000004, // Index of version string
+ // in string table.
+ DT_MIPS_FLAGS = 0x70000005, // 32 bits of flags.
+ DT_MIPS_BASE_ADDRESS = 0x70000006, // Base address of the segment.
+ DT_MIPS_MSYM = 0x70000007, // Address of .msym section.
+ DT_MIPS_CONFLICT = 0x70000008, // Address of .conflict section.
+ DT_MIPS_LIBLIST = 0x70000009, // Address of .liblist section.
+ DT_MIPS_LOCAL_GOTNO = 0x7000000a, // Number of local global offset
+ // table entries.
+ DT_MIPS_CONFLICTNO = 0x7000000b, // Number of entries
+ // in the .conflict section.
+ DT_MIPS_LIBLISTNO = 0x70000010, // Number of entries
+ // in the .liblist section.
+ DT_MIPS_SYMTABNO = 0x70000011, // Number of entries
+ // in the .dynsym section.
+ DT_MIPS_UNREFEXTNO = 0x70000012, // Index of first external dynamic symbol
+ // not referenced locally.
+ DT_MIPS_GOTSYM = 0x70000013, // Index of first dynamic symbol
+ // in global offset table.
+ DT_MIPS_HIPAGENO = 0x70000014, // Number of page table entries
+ // in global offset table.
+ DT_MIPS_RLD_MAP = 0x70000016, // Address of run time loader map,
+ // used for debugging.
+ DT_MIPS_DELTA_CLASS = 0x70000017, // Delta C++ class definition.
+ DT_MIPS_DELTA_CLASS_NO = 0x70000018, // Number of entries
+ // in DT_MIPS_DELTA_CLASS.
+ DT_MIPS_DELTA_INSTANCE = 0x70000019, // Delta C++ class instances.
+ DT_MIPS_DELTA_INSTANCE_NO = 0x7000001A, // Number of entries
+ // in DT_MIPS_DELTA_INSTANCE.
+ DT_MIPS_DELTA_RELOC = 0x7000001B, // Delta relocations.
+ DT_MIPS_DELTA_RELOC_NO = 0x7000001C, // Number of entries
+ // in DT_MIPS_DELTA_RELOC.
+ DT_MIPS_DELTA_SYM = 0x7000001D, // Delta symbols that Delta
+ // relocations refer to.
+ DT_MIPS_DELTA_SYM_NO = 0x7000001E, // Number of entries
+ // in DT_MIPS_DELTA_SYM.
+ DT_MIPS_DELTA_CLASSSYM = 0x70000020, // Delta symbols that hold
+ // class declarations.
+ DT_MIPS_DELTA_CLASSSYM_NO = 0x70000021, // Number of entries
+ // in DT_MIPS_DELTA_CLASSSYM.
+ DT_MIPS_CXX_FLAGS = 0x70000022, // Flags indicating information
+ // about C++ flavor.
+ DT_MIPS_PIXIE_INIT = 0x70000023, // Pixie information.
+ DT_MIPS_SYMBOL_LIB = 0x70000024, // Address of .MIPS.symlib
+ DT_MIPS_LOCALPAGE_GOTIDX = 0x70000025, // The GOT index of the first PTE
+ // for a segment
+ DT_MIPS_LOCAL_GOTIDX = 0x70000026, // The GOT index of the first PTE
+ // for a local symbol
+ DT_MIPS_HIDDEN_GOTIDX = 0x70000027, // The GOT index of the first PTE
+ // for a hidden symbol
+ DT_MIPS_PROTECTED_GOTIDX = 0x70000028, // The GOT index of the first PTE
+ // for a protected symbol
+ DT_MIPS_OPTIONS = 0x70000029, // Address of `.MIPS.options'.
+ DT_MIPS_INTERFACE = 0x7000002A, // Address of `.interface'.
+ DT_MIPS_DYNSTR_ALIGN = 0x7000002B, // Unknown.
+ DT_MIPS_INTERFACE_SIZE = 0x7000002C, // Size of the .interface section.
+ DT_MIPS_RLD_TEXT_RESOLVE_ADDR = 0x7000002D, // Size of rld_text_resolve
+ // function stored in the GOT.
+ DT_MIPS_PERF_SUFFIX = 0x7000002E, // Default suffix of DSO to be added
+ // by rld on dlopen() calls.
+ DT_MIPS_COMPACT_SIZE = 0x7000002F, // Size of compact relocation
+ // section (O32).
+ DT_MIPS_GP_VALUE = 0x70000030, // GP value for auxiliary GOTs.
+ DT_MIPS_AUX_DYNAMIC = 0x70000031, // Address of auxiliary .dynamic.
+ DT_MIPS_PLTGOT = 0x70000032, // Address of the base of the PLTGOT.
+ DT_MIPS_RWPLT = 0x70000034, // Points to the base
+ // of a writable PLT.
+ DT_MIPS_RLD_MAP_REL = 0x70000035 // Relative offset of run time loader
+ // map, used for debugging.
+};
+
+// DT_FLAGS values.
+enum {
+ DF_ORIGIN = 0x01, // The object may reference $ORIGIN.
+ DF_SYMBOLIC = 0x02, // Search the shared lib before searching the exe.
+ DF_TEXTREL = 0x04, // Relocations may modify a non-writable segment.
+ DF_BIND_NOW = 0x08, // Process all relocations on load.
+ DF_STATIC_TLS = 0x10 // Reject attempts to load dynamically.
+};
+
+// State flags selectable in the `d_un.d_val' element of the DT_FLAGS_1 entry.
+enum {
+ DF_1_NOW = 0x00000001, // Set RTLD_NOW for this object.
+ DF_1_GLOBAL = 0x00000002, // Set RTLD_GLOBAL for this object.
+ DF_1_GROUP = 0x00000004, // Set RTLD_GROUP for this object.
+ DF_1_NODELETE = 0x00000008, // Set RTLD_NODELETE for this object.
+ DF_1_LOADFLTR = 0x00000010, // Trigger filtee loading at runtime.
+ DF_1_INITFIRST = 0x00000020, // Set RTLD_INITFIRST for this object.
+ DF_1_NOOPEN = 0x00000040, // Set RTLD_NOOPEN for this object.
+ DF_1_ORIGIN = 0x00000080, // $ORIGIN must be handled.
+ DF_1_DIRECT = 0x00000100, // Direct binding enabled.
+ DF_1_TRANS = 0x00000200,
+ DF_1_INTERPOSE = 0x00000400, // Object is used to interpose.
+ DF_1_NODEFLIB = 0x00000800, // Ignore default lib search path.
+ DF_1_NODUMP = 0x00001000, // Object can't be dldump'ed.
+ DF_1_CONFALT = 0x00002000, // Configuration alternative created.
+ DF_1_ENDFILTEE = 0x00004000, // Filtee terminates filters search.
+ DF_1_DISPRELDNE = 0x00008000, // Disp reloc applied at build time.
+ DF_1_DISPRELPND = 0x00010000, // Disp reloc applied at run-time.
+ DF_1_NODIRECT = 0x00020000, // Object has no-direct binding.
+ DF_1_IGNMULDEF = 0x00040000,
+ DF_1_NOKSYMS = 0x00080000,
+ DF_1_NOHDR = 0x00100000,
+ DF_1_EDITED = 0x00200000, // Object is modified after built.
+ DF_1_NORELOC = 0x00400000,
+ DF_1_SYMINTPOSE = 0x00800000, // Object has individual interposers.
+ DF_1_GLOBAUDIT = 0x01000000, // Global auditing required.
+ DF_1_SINGLETON = 0x02000000 // Singleton symbols are used.
+};
+
+// DT_MIPS_FLAGS values.
+enum {
+ RHF_NONE = 0x00000000, // No flags.
+ RHF_QUICKSTART = 0x00000001, // Uses shortcut pointers.
+ RHF_NOTPOT = 0x00000002, // Hash size is not a power of two.
+ RHS_NO_LIBRARY_REPLACEMENT = 0x00000004, // Ignore LD_LIBRARY_PATH.
+ RHF_NO_MOVE = 0x00000008, // DSO address may not be relocated.
+ RHF_SGI_ONLY = 0x00000010, // SGI specific features.
+ RHF_GUARANTEE_INIT = 0x00000020, // Guarantee that .init will finish
+ // executing before any non-init
+ // code in DSO is called.
+ RHF_DELTA_C_PLUS_PLUS = 0x00000040, // Contains Delta C++ code.
+ RHF_GUARANTEE_START_INIT = 0x00000080, // Guarantee that .init will start
+ // executing before any non-init
+ // code in DSO is called.
+ RHF_PIXIE = 0x00000100, // Generated by pixie.
+ RHF_DEFAULT_DELAY_LOAD = 0x00000200, // Delay-load DSO by default.
+ RHF_REQUICKSTART = 0x00000400, // Object may be requickstarted
+ RHF_REQUICKSTARTED = 0x00000800, // Object has been requickstarted
+ RHF_CORD = 0x00001000, // Generated by cord.
+ RHF_NO_UNRES_UNDEF = 0x00002000, // Object contains no unresolved
+ // undef symbols.
+ RHF_RLD_ORDER_SAFE = 0x00004000 // Symbol table is in a safe order.
+};
+
+// ElfXX_VerDef structure version (GNU versioning)
+enum {
+ VER_DEF_NONE = 0,
+ VER_DEF_CURRENT = 1
+};
+
+// VerDef Flags (ElfXX_VerDef::vd_flags)
+enum {
+ VER_FLG_BASE = 0x1,
+ VER_FLG_WEAK = 0x2,
+ VER_FLG_INFO = 0x4
+};
+
+// Special constants for the version table. (SHT_GNU_versym/.gnu.version)
+enum {
+ VER_NDX_LOCAL = 0, // Unversioned local symbol
+ VER_NDX_GLOBAL = 1, // Unversioned global symbol
+ VERSYM_VERSION = 0x7fff, // Version Index mask
+ VERSYM_HIDDEN = 0x8000 // Hidden bit (non-default version)
+};
+
+// ElfXX_VerNeed structure version (GNU versioning)
+enum {
+ VER_NEED_NONE = 0,
+ VER_NEED_CURRENT = 1
+};
+
+
+#endif
diff --git a/src/inc/volatile.h b/src/inc/volatile.h
index 8de299590e..c295f98696 100644
--- a/src/inc/volatile.h
+++ b/src/inc/volatile.h
@@ -90,9 +90,9 @@
// notice.
//
#define VOLATILE_MEMORY_BARRIER() asm volatile ("" : : : "memory")
-#endif // !_ARM_
-#elif defined(_ARM_) && _ISO_VOLATILE
-// ARM has a very weak memory model and very few tools to control that model. We're forced to perform a full
+#endif // _ARM_ || _ARM64_
+#elif (defined(_ARM_) || defined(_ARM64_)) && _ISO_VOLATILE
+// ARM & ARM64 have a very weak memory model and very few tools to control that model. We're forced to perform a full
// memory barrier to preserve the volatile semantics. Technically this is only necessary on MP systems but we
// currently don't have a cheap way to determine the number of CPUs from this header file. Revisit this if it
// turns out to be a performance issue for the uni-proc case.
@@ -104,7 +104,7 @@
// targeted by VC++ with /iso_volatile-.
//
#define VOLATILE_MEMORY_BARRIER()
-#endif
+#endif // __GNUC__
//
// VolatileLoad loads a T from a pointer to T. It is guaranteed that this load will not be optimized
diff --git a/src/jit/CMakeLists.txt b/src/jit/CMakeLists.txt
index 7ebf3f7d52..b9f0c840a5 100644
--- a/src/jit/CMakeLists.txt
+++ b/src/jit/CMakeLists.txt
@@ -84,6 +84,7 @@ if(CLR_CMAKE_TARGET_ARCH_AMD64)
elseif(CLR_CMAKE_TARGET_ARCH_ARM)
set( ARCH_SOURCES
codegenarm.cpp
+ decomposelongs.cpp
emitarm.cpp
lowerarm.cpp
targetarm.cpp
@@ -92,6 +93,7 @@ elseif(CLR_CMAKE_TARGET_ARCH_ARM)
elseif(CLR_CMAKE_TARGET_ARCH_I386)
set( ARCH_SOURCES
codegenxarch.cpp
+ decomposelongs.cpp
emitxarch.cpp
lowerxarch.cpp
simd.cpp
diff --git a/src/jit/assertionprop.cpp b/src/jit/assertionprop.cpp
index 9b30f949af..1ac1cd285f 100644
--- a/src/jit/assertionprop.cpp
+++ b/src/jit/assertionprop.cpp
@@ -1911,7 +1911,7 @@ void Compiler::optAssertionGen(GenTreePtr tree)
{
// Retrieve the 'this' arg
GenTreePtr thisArg = gtGetThisArg(tree);
-#if defined(_TARGET_AMD64_) || defined(_TARGET_ARM_)
+#if defined(_TARGET_X86_) || defined(_TARGET_AMD64_) || defined(_TARGET_ARM_)
if (thisArg == nullptr)
{
// For tail calls we lose the this pointer in the argument list but that's OK because a null check
@@ -1919,7 +1919,7 @@ void Compiler::optAssertionGen(GenTreePtr tree)
noway_assert(tree->gtCall.IsTailCall());
break;
}
-#endif // _TARGET_AMD64_ || _TARGET_ARM_
+#endif // _TARGET_X86_ || _TARGET_AMD64_ || _TARGET_ARM_
noway_assert(thisArg != nullptr);
assertionIndex = optCreateAssertion(thisArg, nullptr, OAK_NOT_EQUAL);
}
diff --git a/src/jit/block.cpp b/src/jit/block.cpp
index 29c81aa91e..50d352c594 100644
--- a/src/jit/block.cpp
+++ b/src/jit/block.cpp
@@ -548,7 +548,7 @@ GenTreeStmt* BasicBlock::lastStmt()
//
// Notes:
// The last statement may be an embedded statement, when in linear order,
-// so this method is provided to obtain the last top-level statment, which
+// so this method is provided to obtain the last top-level statement, which
// will also contain the last tree nodes in execution order.
GenTreeStmt* BasicBlock::lastTopLevelStmt()
diff --git a/src/jit/block.h b/src/jit/block.h
index 08d6d3d2de..92f9f0103d 100644
--- a/src/jit/block.h
+++ b/src/jit/block.h
@@ -372,10 +372,10 @@ struct BasicBlock
// TODO: Should BBF_RUN_RARELY be added to BBF_SPLIT_GAINED ?
-#define BBF_SPLIT_GAINED (BBF_DONT_REMOVE | BBF_HAS_LABEL | \
+#define BBF_SPLIT_GAINED (BBF_DONT_REMOVE | BBF_HAS_LABEL | \
BBF_HAS_JMP | BBF_BACKWARD_JUMP | \
- BBF_HAS_INDX | BBF_HAS_NEWARRAY | \
- BBF_PROF_WEIGHT | \
+ BBF_HAS_INDX | BBF_HAS_NEWARRAY | \
+ BBF_PROF_WEIGHT | BBF_HAS_NEWOBJ | \
BBF_KEEP_BBJ_ALWAYS)
#ifndef __GNUC__ // GCC doesn't like C_ASSERT at global scope
diff --git a/src/jit/codegen.h b/src/jit/codegen.h
index ce08d9fa65..70f21c6010 100755
--- a/src/jit/codegen.h
+++ b/src/jit/codegen.h
@@ -103,8 +103,7 @@ private:
static void genJumpKindsForTree(GenTreePtr cmpTree, emitJumpKind jmpKind[2], bool jmpToTrueLabel[2]);
#if !defined(_TARGET_64BIT_)
- static void genJumpKindsForTreeLongHi(GenTreePtr cmpTree, emitJumpKind jmpKind[2], bool jmpToTrueLabel[2]);
- static void genJumpKindsForTreeLongLo(GenTreePtr cmpTree, emitJumpKind jmpKind[2], bool jmpToTrueLabel[2]);
+ static void genJumpKindsForTreeLongHi(GenTreePtr cmpTree, emitJumpKind jmpKind[2]);
#endif //!defined(_TARGET_64BIT_)
static bool genShouldRoundFP();
diff --git a/src/jit/codegenarm.cpp b/src/jit/codegenarm.cpp
index 419c7a21ec..dea03189f4 100644
--- a/src/jit/codegenarm.cpp
+++ b/src/jit/codegenarm.cpp
@@ -2161,6 +2161,6 @@ void CodeGen::genSetScopeInfo (unsigned which,
}
#endif // DEBUGGING_SUPPORT
-#endif // _TARGET_AMD64_
+#endif // _TARGET_ARM_
#endif // !LEGACY_BACKEND
diff --git a/src/jit/codegencommon.cpp b/src/jit/codegencommon.cpp
index 1196e610ac..35360394fb 100755
--- a/src/jit/codegencommon.cpp
+++ b/src/jit/codegencommon.cpp
@@ -1391,13 +1391,32 @@ void CodeGenInterface::reloadFloatReg(var_types type, TempDsc* tm
regNumber CodeGenInterface::genGetThisArgReg(GenTreePtr call)
{
noway_assert(call->IsCall());
-#if RETBUFARG_PRECEDES_THIS
- if (call->AsCall()->HasRetBufArg())
- return REG_ARG_1;
-#endif // RETBUFARG_PRECEEDS_THIS
return REG_ARG_0;
}
+//----------------------------------------------------------------------
+// getSpillTempDsc: get the TempDsc corresponding to a spilled tree.
+//
+// Arguments:
+// tree - spilled GenTree node
+//
+// Return Value:
+// TempDsc corresponding to tree
+TempDsc* CodeGenInterface::getSpillTempDsc(GenTree* tree)
+{
+ // tree must be in spilled state.
+ assert((tree->gtFlags & GTF_SPILLED) != 0);
+
+ // Get the tree's SpillDsc.
+ RegSet::SpillDsc* prevDsc;
+ RegSet::SpillDsc* spillDsc = regSet.rsGetSpillInfo(tree, tree->gtRegNum, &prevDsc);
+ assert(spillDsc != nullptr);
+
+ // Get the temp desc.
+ TempDsc* temp = regSet.rsGetSpillTempWord(tree->gtRegNum, spillDsc, prevDsc);
+ return temp;
+}
+
#ifdef _TARGET_XARCH_
#ifdef _TARGET_AMD64_
@@ -7790,6 +7809,18 @@ void CodeGen::genFinalizeFrame()
// Set various registers as "modified" for special code generation scenarios: Edit & Continue, P/Invoke calls, etc.
+#if defined(_TARGET_X86_)
+ if (compiler->compTailCallUsed)
+ {
+ // If we are generating a helper-based tailcall, we've set the tailcall helper "flags"
+ // argument to "1", indicating to the tailcall helper that we've saved the callee-saved
+ // registers (ebx, esi, edi). So, we need to make sure all the callee-saved registers
+ // actually get saved.
+
+ regSet.rsSetRegsModified(RBM_INT_CALLEE_SAVED);
+ }
+#endif // _TARGET_X86_
+
#if defined(_TARGET_ARMARCH_)
// We need to determine if we will change SP larger than a specific amount to determine if we want to use a loop
// to touch stack pages, that will require multiple registers. See genAllocLclFrame() for details.
diff --git a/src/jit/codegeninterface.h b/src/jit/codegeninterface.h
index cb4774d240..d321b5719a 100644
--- a/src/jit/codegeninterface.h
+++ b/src/jit/codegeninterface.h
@@ -313,6 +313,9 @@ public:
void SpillFloat (regNumber reg, bool bIsCall = false);
#endif // LEGACY_BACKEND
+ // The following method is used by xarch emitter for handling contained tree temps.
+ TempDsc* getSpillTempDsc(GenTree* tree);
+
public:
emitter* getEmitter() { return m_cgEmitter; }
protected:
diff --git a/src/jit/codegenlegacy.cpp b/src/jit/codegenlegacy.cpp
index aeb170825b..0b93c6d243 100644
--- a/src/jit/codegenlegacy.cpp
+++ b/src/jit/codegenlegacy.cpp
@@ -1029,11 +1029,10 @@ void CodeGen::genMoveRegPair(GenTreePtr tree,
if (newHi == oldLo)
{
#ifdef _TARGET_ARM_
- regNumber regTmp = regSet.rsPickFreeReg(RBM_ALLINT & ~genRegPairMask(oldPair) & ~genRegPairMask(newPair));
- inst_RV_RV(INS_mov, regTmp, oldLo);
- inst_RV_RV(INS_mov, oldLo, oldHi);
- inst_RV_RV(INS_mov, oldHi, regTmp);
- regTracker.rsTrackRegTrash(regTmp);
+ /* Let's use XOR swap to reduce register pressure. */
+ inst_RV_RV(INS_eor, oldLo, oldHi);
+ inst_RV_RV(INS_eor, oldHi, oldLo);
+ inst_RV_RV(INS_eor, oldLo, oldHi);
#else
inst_RV_RV(INS_xchg, oldHi, oldLo);
#endif
diff --git a/src/jit/codegenlinear.h b/src/jit/codegenlinear.h
index 6ffccbf593..2fbb8d004c 100644
--- a/src/jit/codegenlinear.h
+++ b/src/jit/codegenlinear.h
@@ -49,6 +49,7 @@
#if !defined(_TARGET_64BIT_)
void genCompareLong(GenTreePtr treeNode);
+ void genJTrueLong(GenTreePtr treeNode);
#endif
#ifdef FEATURE_SIMD
diff --git a/src/jit/codegenxarch.cpp b/src/jit/codegenxarch.cpp
index 33af83ba1d..5fea9fc583 100755
--- a/src/jit/codegenxarch.cpp
+++ b/src/jit/codegenxarch.cpp
@@ -1341,7 +1341,7 @@ void CodeGen::genCodeForDivMod(GenTreeOp* treeNode)
{
emit->emitInsBinary(genGetInsForOper(treeNode->gtOper, targetType), size, treeNode, divisor);
}
- else if (divisor->gtRegNum == targetReg)
+ else if (!divisor->isContained() && divisor->gtRegNum == targetReg)
{
// It is not possible to generate 2-operand divss or divsd where reg2 = reg1 / reg2
// because divss/divsd reg1, reg2 will over-write reg1. Therefore, in case of AMD64
@@ -1434,7 +1434,9 @@ void CodeGen::genCodeForBinary(GenTree* treeNode)
assert (oper == GT_OR ||
oper == GT_XOR ||
oper == GT_AND ||
+ oper == GT_ADD_LO ||
oper == GT_ADD_HI ||
+ oper == GT_SUB_LO ||
oper == GT_SUB_HI ||
oper == GT_MUL_HI ||
oper == GT_DIV_HI ||
@@ -1464,8 +1466,8 @@ void CodeGen::genCodeForBinary(GenTree* treeNode)
// The arithmetic node must be sitting in a register (since it's not contained)
noway_assert(targetReg != REG_NA);
- regNumber op1reg = op1->gtRegNum;
- regNumber op2reg = op2->gtRegNum;
+ regNumber op1reg = op1->isContained() ? REG_NA: op1->gtRegNum;
+ regNumber op2reg = op2->isContained() ? REG_NA: op2->gtRegNum;
GenTreePtr dst;
GenTreePtr src;
@@ -2032,7 +2034,9 @@ CodeGen::genCodeForTreeNode(GenTreePtr treeNode)
__fallthrough;
#if !defined(_TARGET_64BIT_)
+ case GT_ADD_LO:
case GT_ADD_HI:
+ case GT_SUB_LO:
case GT_SUB_HI:
#endif // !defined(_TARGET_64BIT_)
case GT_ADD:
@@ -2453,7 +2457,18 @@ CodeGen::genCodeForTreeNode(GenTreePtr treeNode)
// X86 Long comparison
else if (varTypeIsLong(op1Type))
{
- genCompareLong(treeNode);
+ // When not materializing the result in a register, the compare logic is generated
+ // when we generate the GT_JTRUE.
+ if (treeNode->gtRegNum != REG_NA)
+ {
+ genCompareLong(treeNode);
+ }
+ else
+ {
+ // We generate the compare when we generate the GT_JTRUE, but we need to consume
+ // the operands now.
+ genConsumeOperands(treeNode->AsOp());
+ }
}
#endif // !defined(_TARGET_64BIT_)
else
@@ -2466,44 +2481,55 @@ CodeGen::genCodeForTreeNode(GenTreePtr treeNode)
case GT_JTRUE:
{
GenTree *cmp = treeNode->gtOp.gtOp1;
+
assert(cmp->OperIsCompare());
assert(compiler->compCurBB->bbJumpKind == BBJ_COND);
- // Get the "kind" and type of the comparison. Note that whether it is an unsigned cmp
- // is governed by a flag NOT by the inherent type of the node
- // TODO-XArch-CQ: Check if we can use the currently set flags.
- emitJumpKind jumpKind[2];
- bool branchToTrueLabel[2];
- genJumpKindsForTree(cmp, jumpKind, branchToTrueLabel);
-
- BasicBlock* skipLabel = nullptr;
- if (jumpKind[0] != EJ_NONE)
+#if !defined(_TARGET_64BIT_)
+ // For long compares, we emit special logic
+ if (varTypeIsLong(cmp->gtGetOp1()))
{
- BasicBlock *jmpTarget;
- if (branchToTrueLabel[0])
+ genJTrueLong(cmp);
+ }
+ else
+#endif
+ {
+ // Get the "kind" and type of the comparison. Note that whether it is an unsigned cmp
+ // is governed by a flag NOT by the inherent type of the node
+ // TODO-XArch-CQ: Check if we can use the currently set flags.
+ emitJumpKind jumpKind[2];
+ bool branchToTrueLabel[2];
+ genJumpKindsForTree(cmp, jumpKind, branchToTrueLabel);
+
+ BasicBlock* skipLabel = nullptr;
+ if (jumpKind[0] != EJ_NONE)
{
- jmpTarget = compiler->compCurBB->bbJumpDest;
+ BasicBlock *jmpTarget;
+ if (branchToTrueLabel[0])
+ {
+ jmpTarget = compiler->compCurBB->bbJumpDest;
+ }
+ else
+ {
+ // This case arises only for ordered GT_EQ right now
+ assert((cmp->gtOper == GT_EQ) && ((cmp->gtFlags & GTF_RELOP_NAN_UN) == 0));
+ skipLabel = genCreateTempLabel();
+ jmpTarget = skipLabel;
+ }
+
+ inst_JMP(jumpKind[0], jmpTarget);
}
- else
+
+ if (jumpKind[1] != EJ_NONE)
{
- // This case arises only for ordered GT_EQ right now
- assert((cmp->gtOper == GT_EQ) && ((cmp->gtFlags & GTF_RELOP_NAN_UN) == 0));
- skipLabel = genCreateTempLabel();
- jmpTarget = skipLabel;
+ // the second conditional branch always has to be to the true label
+ assert(branchToTrueLabel[1]);
+ inst_JMP(jumpKind[1], compiler->compCurBB->bbJumpDest);
}
- inst_JMP(jumpKind[0], jmpTarget);
+ if (skipLabel != nullptr)
+ genDefineTempLabel(skipLabel);
}
-
- if (jumpKind[1] != EJ_NONE)
- {
- // the second conditional branch always has to be to the true label
- assert(branchToTrueLabel[1]);
- inst_JMP(jumpKind[1], compiler->compCurBB->bbJumpDest);
- }
-
- if (skipLabel != nullptr)
- genDefineTempLabel(skipLabel);
}
break;
@@ -3042,13 +3068,25 @@ CodeGen::genMultiRegCallStoreToLocal(GenTreePtr treeNode)
}
-/***********************************************************************************************
- * Generate code for localloc
- */
+//------------------------------------------------------------------------
+// genLclHeap: Generate code for localloc.
+//
+// Arguments:
+// tree - the localloc tree to generate.
+//
+// Notes:
+// Note that for x86, we don't track ESP movements while generating the localloc code.
+// The ESP tracking is used to report stack pointer-relative GC info, which is not
+// interesting while doing the localloc construction. Also, for functions with localloc,
+// we have EBP frames, and EBP-relative locals, and ESP-relative accesses only for function
+// call arguments. We store the ESP after the localloc is complete in the LocAllocSP
+// variable. This variable is implicitly reported to the VM in the GC info (its position
+// is defined by convention relative to other items), and is used by the GC to find the
+// "base" stack pointer in functions with localloc.
+//
void
CodeGen::genLclHeap(GenTreePtr tree)
{
- NYI_X86("Localloc");
assert(tree->OperGet() == GT_LCLHEAP);
assert(compiler->compLocallocUsed);
@@ -3103,7 +3141,9 @@ CodeGen::genLclHeap(GenTreePtr tree)
}
else
{
- // If 0 bail out by returning null in targetReg
+ // The localloc requested memory size is non-constant.
+
+ // Put the size value in targetReg. If it is zero, bail out by returning null in targetReg.
genConsumeRegAndCopy(size, targetReg);
endLabel = genCreateTempLabel();
getEmitter()->emitIns_R_R(INS_test, easz, targetReg, targetReg);
@@ -3124,13 +3164,40 @@ CodeGen::genLclHeap(GenTreePtr tree)
tmpRegsMask &= ~regCntMask;
regCnt = genRegNumFromMask(regCntMask);
if (regCnt != targetReg)
+ {
+ // Above, we put the size in targetReg. Now, copy it to our new temp register if necessary.
inst_RV_RV(INS_mov, regCnt, targetReg, size->TypeGet());
+ }
}
- // Align to STACK_ALIGN
- // regCnt will be the total number of bytes to localloc
- inst_RV_IV(INS_add, regCnt, (STACK_ALIGN - 1), emitActualTypeSize(type));
- inst_RV_IV(INS_AND, regCnt, ~(STACK_ALIGN - 1), emitActualTypeSize(type));
+ // Round up the number of bytes to allocate to a STACK_ALIGN boundary. This is done
+ // by code like:
+ // add reg, 15
+ // and reg, -16
+ // However, in the initialized memory case, we need the count of STACK_ALIGN-sized
+ // elements, not a byte count, after the alignment. So instead of the "and", which
+ // becomes unnecessary, generate a shift, e.g.:
+ // add reg, 15
+ // shr reg, 4
+
+ inst_RV_IV(INS_add, regCnt, STACK_ALIGN - 1, emitActualTypeSize(type));
+
+ if (compiler->info.compInitMem)
+ {
+ // Convert the count from a count of bytes to a loop count. We will loop once per
+ // stack alignment size, so each loop will zero 4 bytes on x86 and 16 bytes on x64.
+ // Note that we zero a single reg-size word per iteration on x86, and 2 reg-size
+ // words per iteration on x64. We will shift off all the stack alignment bits
+ // added above, so there is no need for an 'and' instruction.
+
+ // --- shr regCnt, 2 (or 4) ---
+ inst_RV_SH(INS_SHIFT_RIGHT_LOGICAL, EA_PTRSIZE, regCnt, STACK_ALIGN_SHIFT_ALL);
+ }
+ else
+ {
+ // Otherwise, mask off the low bits to align the byte count.
+ inst_RV_IV(INS_AND, regCnt, ~(STACK_ALIGN - 1), emitActualTypeSize(type));
+ }
}
#if FEATURE_FIXED_OUT_ARGS
@@ -3156,75 +3223,108 @@ CodeGen::genLclHeap(GenTreePtr tree)
{
// We should reach here only for non-zero, constant size allocations.
assert(amount > 0);
+ assert((amount % STACK_ALIGN) == 0);
+ assert((amount % REGSIZE_BYTES) == 0);
// For small allocations we will generate up to six push 0 inline
- size_t cntPtrSizedWords = (amount >> STACK_ALIGN_SHIFT);
- if (cntPtrSizedWords <= 6)
+ size_t cntRegSizedWords = amount / REGSIZE_BYTES;
+ if (cntRegSizedWords <= 6)
{
- while (cntPtrSizedWords != 0)
+ for (; cntRegSizedWords != 0; cntRegSizedWords--)
{
- // push_hide means don't track the stack
- inst_IV(INS_push_hide, 0);
- cntPtrSizedWords--;
+ inst_IV(INS_push_hide, 0); // push_hide means don't track the stack
}
-
goto ALLOC_DONE;
}
- else if (!compiler->info.compInitMem && (amount < compiler->eeGetPageSize())) // must be < not <=
+
+ bool doNoInitLessThanOnePageAlloc = !compiler->info.compInitMem && (amount < compiler->eeGetPageSize()); // must be < not <=
+
+#ifdef _TARGET_X86_
+ bool needRegCntRegister = true;
+#else // !_TARGET_X86_
+ bool needRegCntRegister = !doNoInitLessThanOnePageAlloc;
+#endif // !_TARGET_X86_
+
+ if (needRegCntRegister)
+ {
+ // If compInitMem=true, we can reuse targetReg as regcnt.
+ // Since size is a constant, regCnt is not yet initialized.
+ assert(regCnt == REG_NA);
+ if (compiler->info.compInitMem)
+ {
+ assert(genCountBits(tmpRegsMask) == 0);
+ regCnt = targetReg;
+ }
+ else
+ {
+ assert(genCountBits(tmpRegsMask) >= 1);
+ regMaskTP regCntMask = genFindLowestBit(tmpRegsMask);
+ tmpRegsMask &= ~regCntMask;
+ regCnt = genRegNumFromMask(regCntMask);
+ }
+ }
+
+ if (doNoInitLessThanOnePageAlloc)
{
// Since the size is less than a page, simply adjust ESP.
// ESP might already be in the guard page, so we must touch it BEFORE
// the alloc, not after.
+
+#ifdef _TARGET_X86_
+ // For x86, we don't want to use "sub ESP" because we don't want the emitter to track the adjustment
+ // to ESP. So do the work in the count register.
+ // TODO-CQ: manipulate ESP directly, to share code, reduce #ifdefs, and improve CQ. This would require
+ // creating a way to temporarily turn off the emitter's tracking of ESP, maybe marking instrDescs as "don't track".
+ inst_RV_RV(INS_mov, regCnt, REG_SPBASE, TYP_I_IMPL);
+ getEmitter()->emitIns_AR_R(INS_TEST, EA_4BYTE, REG_SPBASE, REG_SPBASE, 0);
+ inst_RV_IV(INS_sub, regCnt, amount, EA_PTRSIZE);
+ inst_RV_RV(INS_mov, REG_SPBASE, regCnt, TYP_I_IMPL);
+#else // !_TARGET_X86_
getEmitter()->emitIns_AR_R(INS_TEST, EA_4BYTE, REG_SPBASE, REG_SPBASE, 0);
inst_RV_IV(INS_sub, REG_SPBASE, amount, EA_PTRSIZE);
+#endif // !_TARGET_X86_
+
goto ALLOC_DONE;
}
// else, "mov regCnt, amount"
- // If compInitMem=true, we can reuse targetReg as regcnt.
- // Since size is a constant, regCnt is not yet initialized.
- assert(regCnt == REG_NA);
+
if (compiler->info.compInitMem)
- {
- assert(genCountBits(tmpRegsMask) == 0);
- regCnt = targetReg;
- }
- else
{
- assert(genCountBits(tmpRegsMask) >= 1);
- regMaskTP regCntMask = genFindLowestBit(tmpRegsMask);
- tmpRegsMask &= ~regCntMask;
- regCnt = genRegNumFromMask(regCntMask);
+ // When initializing memory, we want 'amount' to be the loop count.
+ assert((amount % STACK_ALIGN) == 0);
+ amount /= STACK_ALIGN;
}
+
genSetRegToIcon(regCnt, amount, ((int)amount == amount)? TYP_INT : TYP_LONG);
}
loop = genCreateTempLabel();
if (compiler->info.compInitMem)
{
- // At this point 'regCnt' is set to the total number of bytes to locAlloc.
+ // At this point 'regCnt' is set to the number of loop iterations for this loop, if each
+ // iteration zeros (and subtracts from the stack pointer) STACK_ALIGN bytes.
// Since we have to zero out the allocated memory AND ensure that RSP is always valid
// by tickling the pages, we will just push 0's on the stack.
- //
- // Note: regCnt is guaranteed to be even on Amd64 since STACK_ALIGN/TARGET_POINTER_SIZE = 2
- // and localloc size is a multiple of STACK_ALIGN.
+
+ assert(genIsValidIntReg(regCnt));
// Loop:
genDefineTempLabel(loop);
- // dec is a 2 byte instruction, but sub is 4 (could be 3 if
- // we know size is TYP_INT instead of TYP_I_IMPL)
- // Also we know that we can only push 8 bytes at a time, but
- // alignment is 16 bytes, so we can push twice and do a sub
- // for just a little bit of loop unrolling
- inst_IV(INS_push_hide, 0); // --- push 0
- inst_IV(INS_push_hide, 0); // --- push 0
-
- // If not done, loop
- // Note that regCnt is the number of bytes to stack allocate.
- // Therefore we need to subtract 16 from regcnt here.
- assert(genIsValidIntReg(regCnt));
- inst_RV_IV(INS_sub, regCnt, 16, emitActualTypeSize(type));
+#if defined(_TARGET_AMD64_)
+ // Push two 8-byte zeros. This matches the 16-byte STACK_ALIGN value.
+ static_assert_no_msg(STACK_ALIGN == (REGSIZE_BYTES * 2));
+ inst_IV(INS_push_hide, 0); // --- push 8-byte 0
+ inst_IV(INS_push_hide, 0); // --- push 8-byte 0
+#elif defined(_TARGET_X86_)
+ // Push a single 4-byte zero. This matches the 4-byte STACK_ALIGN value.
+ static_assert_no_msg(STACK_ALIGN == REGSIZE_BYTES);
+ inst_IV(INS_push_hide, 0); // --- push 4-byte 0
+#endif // _TARGET_X86_
+
+ // Decrement the loop counter and loop if not done.
+ inst_RV(INS_dec, regCnt, TYP_I_IMPL);
inst_JMP(EJ_jne, loop);
}
else
@@ -4512,7 +4612,9 @@ instruction CodeGen::genGetInsForOper(genTreeOps oper, var_types type)
case GT_SUB: ins = INS_sub; break;
case GT_XOR: ins = INS_xor; break;
#if !defined(_TARGET_64BIT_)
+ case GT_ADD_LO: ins = INS_add; break;
case GT_ADD_HI: ins = INS_adc; break;
+ case GT_SUB_LO: ins = INS_sub; break;
case GT_SUB_HI: ins = INS_sbb; break;
#endif // !defined(_TARGET_64BIT_)
default: unreached();
@@ -5068,7 +5170,11 @@ void CodeGen::genConsumeRegs(GenTree* tree)
if (tree->isContained())
{
- if (tree->isIndir())
+ if (tree->isContainedSpillTemp())
+ {
+ // spill temps are un-tracked and hence no need to update life
+ }
+ else if (tree->isIndir())
{
genConsumeAddress(tree->AsIndir()->Addr());
}
@@ -6468,8 +6574,10 @@ void CodeGen::genJmpMethod(GenTreePtr jmp)
}
}
-#if FEATURE_VARARG
+#if FEATURE_VARARG && defined(_TARGET_AMD64_)
// In case of a jmp call to a vararg method also pass the float/double arg in the corresponding int arg register.
+ // This is due to the AMD64 ABI which requires floating point values passed to varargs functions to be passed in
+ // both integer and floating point registers. It doesn't apply to x86, which passes floating point values on the stack.
if (compiler->info.compIsVarArgs)
{
regNumber intArgReg;
@@ -6498,13 +6606,16 @@ void CodeGen::genJmpMethod(GenTreePtr jmp)
#endif // FEATURE_VARARG
}
-#if FEATURE_VARARG
+#if FEATURE_VARARG && defined(_TARGET_AMD64_)
// Jmp call to a vararg method - if the method has fewer than 4 fixed arguments,
// load the remaining arg registers (both int and float) from the corresponding
// shadow stack slots. This is for the reason that we don't know the number and type
// of non-fixed params passed by the caller, therefore we have to assume the worst case
// of caller passing float/double args both in int and float arg regs.
//
+ // This doesn't apply to x86, which doesn't pass floating point values in floating
+ // point registers.
+ //
// The caller could have passed gc-ref/byref type var args. Since these are var args
// the callee no way of knowing their gc-ness. Therefore, mark the region that loads
// remaining arg registers from shadow stack slots as non-gc interruptible.
@@ -6682,7 +6793,8 @@ void CodeGen::genJumpKindsForTree(GenTreePtr cmpTree,
//------------------------------------------------------------------------
// genJumpKindsForTreeLongHi: Generate the jump types for compare
// operators of the high parts of a compare with long type operands
-// on x86
+// on x86 for the case where rel-op result needs to be materialized into a
+// register.
//
// Arguments:
// cmpTree - The GT_CMP node
@@ -6692,38 +6804,50 @@ void CodeGen::genJumpKindsForTree(GenTreePtr cmpTree,
// Return Value:
// None.
//
-void CodeGen::genJumpKindsForTreeLongHi(GenTreePtr cmpTree,
- emitJumpKind jmpKind[2],
- bool jmpToTrueLabel[2])
+void CodeGen::genJumpKindsForTreeLongHi(GenTreePtr cmpTree,
+ emitJumpKind jmpKind[2])
{
- jmpToTrueLabel[0] = true;
- jmpToTrueLabel[1] = true;
-
assert(cmpTree->OperIsCompare());
+ CompareKind compareKind = ((cmpTree->gtFlags & GTF_UNSIGNED) != 0) ? CK_UNSIGNED : CK_SIGNED;
- bool isUnsigned = (cmpTree->gtFlags & GTF_UNSIGNED) != 0;
-
- // For comparison of longs on x86, GT_LT, GT_LE, GT_GT, and GT_GE need two jump cases, since
- // only if the hi operators are equal will we fall through.
switch (cmpTree->gtOper)
{
case GT_LT:
case GT_LE:
+ if (compareKind == CK_SIGNED)
+ {
+ jmpKind[0] = EJ_jl;
+ jmpKind[1] = EJ_jg;
+ }
+ else
+ {
+ jmpKind[0] = EJ_jb;
+ jmpKind[1] = EJ_ja;
+ }
+ break;
+
case GT_GT:
case GT_GE:
- if (isUnsigned)
+ if (compareKind == CK_SIGNED)
{
- jmpKind[0] = EJ_ja;
+ jmpKind[0] = EJ_jg;
+ jmpKind[1] = EJ_jl;
}
else
{
- jmpKind[0] = EJ_jg;
+ jmpKind[0] = EJ_ja;
+ jmpKind[1] = EJ_jb;
}
+ break;
+
+ case GT_EQ:
+ // GT_EQ will not jump to the true label if the hi parts are equal
+ jmpKind[0] = EJ_NONE;
jmpKind[1] = EJ_jne;
break;
-
+
case GT_NE:
- case GT_EQ:
+ // GT_NE will always jump to the true label if the high parts are not equal
jmpKind[0] = EJ_jne;
jmpKind[1] = EJ_NONE;
break;
@@ -6734,32 +6858,8 @@ void CodeGen::genJumpKindsForTreeLongHi(GenTreePtr cmpTree,
}
//------------------------------------------------------------------------
-// genJumpKindsForTreeLongLo: Generate the jump types for compare
-// operators of the low parts of a compare with long type operands
-// on x86
-//
-// Arguments:
-// cmpTree - The GT_CMP node
-// jmpKind - Return array of jump kinds
-// jmpToTrueLabel - Return array of if the jump is going to true label
-//
-// Return Value:
-// None.
-//
-void CodeGen::genJumpKindsForTreeLongLo(GenTreePtr cmpTree,
- emitJumpKind jmpKind[2],
- bool jmpToTrueLabel[2])
-{
- jmpToTrueLabel[0] = true;
- jmpToTrueLabel[1] = true;
-
- assert(cmpTree->OperIsCompare());
- jmpKind[0] = genJumpKindForOper(cmpTree->gtOper, CK_UNSIGNED);
- jmpKind[1] = EJ_NONE;
-}
-
-//------------------------------------------------------------------------
-// genCompareLong: Generate code for comparing two longs on x86
+// genCompareLong: Generate code for comparing two longs on x86 when the result of the compare
+// is manifested in a register.
//
// Arguments:
// treeNode - the compare tree
@@ -6769,7 +6869,8 @@ void CodeGen::genJumpKindsForTreeLongLo(GenTreePtr cmpTree,
// Comments:
// For long compares, we need to compare the high parts of operands first, then the low parts.
// If the high compare is false, we do not need to compare the low parts. For less than and
-// greater than, if the high compare is true, we can assume the entire compare is true.
+// greater than, if the high compare is true, we can assume the entire compare is true. For
+// compares that are realized in a register, we will generate:
//
// Opcode x86 equivalent Comment
// ------ -------------- -------
@@ -6783,43 +6884,78 @@ void CodeGen::genJumpKindsForTreeLongLo(GenTreePtr cmpTree,
// cmp loOp1,loOp2
// label: setne
//
-// GT_LT cmp hiOp1,hiOp2 If hiOp1 is greater than hiOp2, the entire compare
-// ja label is false. If hiOp1 is less than hiOp2, the entire
-// jne label compare is true.
-// cmp loOp1,loOp2
+// GT_LT; unsigned cmp hiOp1,hiOp2 If hiOp1 is not equal to hiOp2, the flags are set
+// jne label correctly and we do not need to check lo. Otherwise,
+// cmp loOp1,loOp2 we need to compare the lo halves
// label: setb
//
-// GT_LE cmp hiOp1,hiOp2 If hiOp1 is greater than hiOp2, the entire compare
-// ja label is false. If hiOp1 is less than hiOp2, the entire
-// jne label compare is true.
-// cmp loOp1,loOp2
+// GT_LE; unsigned cmp hiOp1,hiOp2 If hiOp1 is not equal to hiOp2, the flags are set
+// jne label correctly and we do not need to check lo. Otherwise,
+// cmp loOp1,loOp2 we need to compare the lo halves
// label: setbe
//
-// GT_GT cmp hiOp1,hiOp2 If hiOp1 is greater than hiOp2, the entire compare
-// ja label is true. If hiOp1 is less than hiOp2, the entire
-// jne label compare is false.
-// cmp loOp1,loOp2
+// GT_GT; unsigned cmp hiOp1,hiOp2 If hiOp1 is not equal to hiOp2, the flags are set
+// jne label correctly and we do not need to check lo. Otherwise,
+// cmp loOp1,loOp2 we need to compare the lo halves
// label: seta
//
-// GT_GE cmp hiOp1,hiOp2 If hiOp1 is greater than hiOp2, the entire compare
-// ja label is true. If hiOp1 is less than hiOp2, the entire
-// jne label compare is false.
-// cmp loOp1,loOp2
+// GT_GE; unsigned cmp hiOp1,hiOp2 If hiOp1 is not equal to hiOp2, the flags are set
+// jne label correctly and we do not need to check lo. Otherwise,
+// cmp loOp1,loOp2 we need to compare the lo halves
// label: setae
//
+// For signed long comparisons, we need additional labels, as we need to use signed conditions on the
+// "set" instruction:
+//
+// GT_LT; signed cmp hiOp1,hiOp2 If hiOp1 is not equal to hiOp2, the flags are set
+// jne labelHi correctly and we do not need to check lo. Otherwise,
+// cmp loOp1,loOp2 we need to compare the lo halves
+// setb Unsigned set for lo compare
+// jmp labelFinal
+// labelHi: setl Signed set for high compare
+// labelFinal:
+//
+// GT_LE; signed cmp hiOp1,hiOp2 If hiOp1 is not equal to hiOp2, the flags are set
+// jne labelHi correctly and we do not need to check lo. Otherwise,
+// cmp loOp1,loOp2 we need to compare the lo halves
+// setbe Unsigend set for lo compare
+// jmp labelFinal
+// labelHi: setle Signed set for hi compare
+// labelFinal:
+//
+// GT_GT; signed cmp hiOp1,hiOp2 If hiOp1 is not equal to hiOp2, the flags are set
+// jne labelHi correctly and we do not need to check lo. Otherwise,
+// cmp loOp1,loOp2 we need to compare the lo halves
+// seta Unsigned set for lo compare
+// jmp labelFinal
+// labelHi: setg Signed set for high compare
+// labelFinal
+//
+// GT_GE; signed cmp hiOp1,hiOp2 If hiOp1 is not equal to hiOp2, the flags are set
+// jne labelHi correctly and we do not need to check lo. Otherwise,
+// cmp loOp1,loOp2 we need to compare the lo halves
+// setae Unsigned set for lo compare
+// jmp labelFinal
+// labelHi: setge Signed set for hi compare
+// labelFinal:
+//
// TODO-X86-CQ: Check if hi or lo parts of op2 are 0 and change the compare to a test.
void CodeGen::genCompareLong(GenTreePtr treeNode)
{
assert(treeNode->OperIsCompare());
- GenTreeOp *tree = treeNode->AsOp();
+ GenTreeOp* tree = treeNode->AsOp();
GenTreePtr op1 = tree->gtOp1;
GenTreePtr op2 = tree->gtOp2;
+ assert(varTypeIsLong(op1->TypeGet()));
+ assert(varTypeIsLong(op2->TypeGet()));
+
+ regNumber targetReg = treeNode->gtRegNum;
+
genConsumeOperands(tree);
- assert(varTypeIsLong(op1->TypeGet()) && varTypeIsLong(op2->TypeGet()));
- regNumber targetReg = treeNode->gtRegNum;
+ assert(targetReg != REG_NA);
GenTreePtr loOp1 = op1->gtGetOp1();
GenTreePtr hiOp1 = op1->gtGetOp2();
@@ -6835,48 +6971,221 @@ void CodeGen::genCompareLong(GenTreePtr treeNode)
getEmitter()->emitInsBinary(ins, cmpAttr, hiOp1, hiOp2);
// Generate the first jump for the high compare
- emitJumpKind jumpKind[2];
- bool branchToTrueLabel[2];
- genJumpKindsForTreeLongHi(tree, jumpKind, branchToTrueLabel);
-
- BasicBlock* label = genCreateTempLabel();
- inst_JMP(jumpKind[0], label);
+ CompareKind compareKind = ((tree->gtFlags & GTF_UNSIGNED) != 0) ? CK_UNSIGNED : CK_SIGNED;
+
+ BasicBlock* labelHi = genCreateTempLabel();
+ BasicBlock* labelFinal = genCreateTempLabel();
- // Generate the second jump for LE, LT, GT, and GE. We only do the lower compare if
- // the hi parts are equal
- if (jumpKind[1] != EJ_NONE)
+ if (compareKind == CK_SIGNED && (tree->gtOper != GT_NE && tree->gtOper != GT_EQ))
{
- assert(branchToTrueLabel[1]);
- inst_JMP(jumpKind[1], label);
- }
+ // If we are doing a signed comparison, we need to do a signed set if the high compare is true,
+ // but an unsigned set if we fall through to the low compare. If we have a GT_NE or GT_EQ, we do not
+ // need to worry about the sign of the comparison, so we can use the simplified case.
- // Now create compare for low parts
- ins = INS_cmp;
- cmpType = TYP_INT;
- cmpAttr = emitTypeSize(cmpType);
+ // We only have to check for equality for the hi comparison. If they are not equal, then the set will
+ // do the right thing. If they are equal, we have to check the lo halves.
+ inst_JMP(EJ_jne, labelHi);
- // Emit the comparison
- getEmitter()->emitInsBinary(ins, cmpAttr, loOp1, loOp2);
+ // Emit the comparison. Perform the set for the lo. Jump to labelFinal
+ getEmitter()->emitInsBinary(ins, cmpAttr, loOp1, loOp2);
- // Define the label for hi jump target here. If we have jumped here, we want to set
- // the target register based on the jump kind of the lower half (the actual compare
- // type). If we have fallen through, then we are doing a normal int compare for the
- // lower parts
+ // The low set must be unsigned
+ emitJumpKind jumpKindLo = genJumpKindForOper(tree->gtOper, CK_UNSIGNED);
- genDefineTempLabel(label);
- if (targetReg != REG_NA)
+ inst_SET(jumpKindLo, targetReg);
+ // Set the higher bytes to 0
+ inst_RV_RV(ins_Move_Extend(TYP_UBYTE, true), targetReg, targetReg, TYP_UBYTE, emitTypeSize(TYP_UBYTE));
+ genProduceReg(tree);
+
+ inst_JMP(EJ_jmp, labelFinal);
+
+ // Define the label for hi jump target here. If we have jumped here, we want to set
+ // the target register based on the jump kind of the actual compare type.
+
+ genDefineTempLabel(labelHi);
+ inst_SET(genJumpKindForOper(tree->gtOper, compareKind), targetReg);
+
+ // Set the higher bytes to 0
+ inst_RV_RV(ins_Move_Extend(TYP_UBYTE, true), targetReg, targetReg, TYP_UBYTE, emitTypeSize(TYP_UBYTE));
+ genProduceReg(tree);
+
+ genDefineTempLabel(labelFinal);
+ }
+ else
{
- emitJumpKind jumpKindLo[2];
- bool branchToTrueLabelLo[2];
+ // If the compare is unsigned, or if the sign doesn't change the set instruction, we can use
+ // the same set logic for both the hi and lo compare, so we don't need to jump to a high label,
+ // we can just jump to the set that the lo compare will use.
+
+ // We only have to check for equality for the hi comparison. If they are not equal, then the set will
+ // do the right thing. If they are equal, we have to check the lo halves.
+ inst_JMP(EJ_jne, labelFinal);
+
+ // Emit the comparison
+ getEmitter()->emitInsBinary(ins, cmpAttr, loOp1, loOp2);
+
+ // Define the label for hi jump target here. If we have jumped here, we want to set
+ // the target register based on the jump kind of the lower half (the actual compare
+ // type). If we have fallen through, then we are doing a normal int compare for the
+ // lower parts
+
+ genDefineTempLabel(labelFinal);
// The low set must be unsigned
- genJumpKindsForTreeLongLo(tree, jumpKindLo, branchToTrueLabelLo);
- inst_SET(jumpKindLo[0], targetReg);
+ emitJumpKind jumpKindLo = genJumpKindForOper(tree->gtOper, CK_UNSIGNED);
+ inst_SET(jumpKindLo, targetReg);
// Set the higher bytes to 0
inst_RV_RV(ins_Move_Extend(TYP_UBYTE, true), targetReg, targetReg, TYP_UBYTE, emitTypeSize(TYP_UBYTE));
genProduceReg(tree);
}
+
+}
+
+//------------------------------------------------------------------------
+// genJTrueLong: Generate code for comparing two longs on x86 for the case where the result
+// is not manifested in a register.
+//
+// Arguments:
+// treeNode - the compare tree
+//
+// Return Value:
+// None.
+// Comments:
+// For long compares, we need to compare the high parts of operands first, then the low parts.
+// We only have to do the low compare if the high parts of the operands are equal.
+//
+// In the case where the result of a rel-op is not realized in a register, we generate:
+//
+// Opcode x86 equivalent Comment
+// ------ -------------- -------
+//
+// GT_LT; unsigned cmp hiOp1,hiOp2
+// jb trueLabel
+// ja falseLabel
+// cmp loOp1,loOp2
+// jb trueLabel
+// falseLabel:
+//
+// GT_LE; unsigned cmp hiOp1,hiOp2
+// jb trueLabel
+// ja falseLabel
+// cmp loOp1,loOp2
+// jbe trueLabel
+// falseLabel:
+//
+// GT_GT; unsigned cmp hiOp1,hiOp2
+// ja trueLabel
+// jb falseLabel
+// cmp loOp1,loOp2
+// ja trueLabel
+// falseLabel:
+//
+// GT_GE; unsigned cmp hiOp1,hiOp2
+// ja trueLabel
+// jb falseLabel
+// cmp loOp1,loOp2
+// jae trueLabel
+// falseLabel:
+//
+// GT_LT; signed cmp hiOp1,hiOp2
+// jl trueLabel
+// jg falseLabel
+// cmp loOp1,loOp2
+// jb trueLabel
+// falseLabel:
+//
+// GT_LE; signed cmp hiOp1,hiOp2
+// jl trueLabel
+// jg falseLabel
+// cmp loOp1,loOp2
+// jbe trueLabel
+// falseLabel:
+//
+// GT_GT; signed cmp hiOp1,hiOp2
+// jg trueLabel
+// jl falseLabel
+// cmp loOp1,loOp2
+// ja trueLabel
+// falseLabel:
+//
+// GT_GE; signed cmp hiOp1,hiOp2
+// jg trueLabel
+// jl falseLabel
+// cmp loOp1,loOp2
+// jae trueLabel
+// falseLabel:
+//
+// GT_EQ; cmp hiOp1,hiOp2
+// jne falseLabel
+// cmp loOp1,loOp2
+// je trueLabel
+// falseLabel:
+//
+// GT_NE; cmp hiOp1,hiOp2
+// jne labelTrue
+// cmp loOp1,loOp2
+// jne trueLabel
+// falseLabel:
+//
+// TODO-X86-CQ: Check if hi or lo parts of op2 are 0 and change the compare to a test.
+void CodeGen::genJTrueLong(GenTreePtr treeNode)
+{
+ assert(treeNode->OperIsCompare());
+
+ GenTreeOp* tree = treeNode->AsOp();
+ GenTreePtr op1 = tree->gtOp1;
+ GenTreePtr op2 = tree->gtOp2;
+
+ assert(varTypeIsLong(op1->TypeGet()));
+ assert(varTypeIsLong(op2->TypeGet()));
+
+ regNumber targetReg = treeNode->gtRegNum;
+
+ assert(targetReg == REG_NA);
+
+ GenTreePtr loOp1 = op1->gtGetOp1();
+ GenTreePtr hiOp1 = op1->gtGetOp2();
+ GenTreePtr loOp2 = op2->gtGetOp1();
+ GenTreePtr hiOp2 = op2->gtGetOp2();
+
+ // Emit the compare instruction
+ getEmitter()->emitInsBinary(INS_cmp, EA_4BYTE, hiOp1, hiOp2);
+
+ // Generate the first jump for the high compare
+ CompareKind compareKind = ((tree->gtFlags & GTF_UNSIGNED) != 0) ? CK_UNSIGNED : CK_SIGNED;
+
+ // TODO-X86-CQ: If the next block is a BBJ_ALWAYS, we can set falseLabel = compiler->compCurBB->bbNext->bbJumpDest.
+ BasicBlock* falseLabel = genCreateTempLabel();
+
+ emitJumpKind jumpKindHi[2];
+
+ // Generate the jumps for the high compare
+ genJumpKindsForTreeLongHi(tree, jumpKindHi);
+
+ BasicBlock* trueLabel = compiler->compCurBB->bbJumpDest;
+
+ if (jumpKindHi[0] != EJ_NONE)
+ {
+ inst_JMP(jumpKindHi[0], trueLabel);
+ }
+
+ if (jumpKindHi[1] != EJ_NONE)
+ {
+ inst_JMP(jumpKindHi[1], falseLabel);
+ }
+
+ // The low jump must be unsigned
+ emitJumpKind jumpKindLo = genJumpKindForOper(tree->gtOper, CK_UNSIGNED);
+
+ // Emit the comparison and the jump to the trueLabel
+ getEmitter()->emitInsBinary(INS_cmp, EA_4BYTE, loOp1, loOp2);
+
+ inst_JMP(jumpKindLo, trueLabel);
+
+ // Generate falseLabel, which is the false path. We will jump here if the high compare is false
+ // or fall through if the low compare is false.
+ genDefineTempLabel(falseLabel);
}
#endif //!defined(_TARGET_64BIT_)
diff --git a/src/jit/compiler.cpp b/src/jit/compiler.cpp
index ea14d35820..04c90d78af 100644
--- a/src/jit/compiler.cpp
+++ b/src/jit/compiler.cpp
@@ -447,62 +447,84 @@ void Compiler::getStructGcPtrsFromOp(GenTreePtr op, BYTE *gcPtrsOut)
}
#endif // FEATURE_MULTIREG_ARGS
-//------------------------------------------------------------------------
-// argOrReturnTypeForStruct: Get the "primitive" type, if any, that is used to pass or return
-// values of the given struct type.
+#ifdef ARM_SOFTFP
+//---------------------------------------------------------------------------
+// IsSingleFloat32Struct:
+// Check if the given struct type contains only one float32 value type
//
// Arguments:
-// clsHnd - the handle for the struct type
-// forReturn - true if we asking for this in a GT_RETURN context
-// false if we are asking for this in a parameter passing context
+// clsHnd - the handle for the struct type
//
// Return Value:
-// The primitive type used to pass or return the struct, if applicable, or
-// TYP_UNKNOWN otherwise.
+// true if the given struct type contains only one float32 value type,
+// false otherwise.
//
-// Assumptions:
-// The given class handle must be for a value type (struct).
-//
-// Notes:
-// Most of the work is done by the method of the same name that takes the
-// size of the struct.
-
-var_types Compiler::argOrReturnTypeForStruct(CORINFO_CLASS_HANDLE clsHnd, bool forReturn)
+bool Compiler::isSingleFloat32Struct(CORINFO_CLASS_HANDLE clsHnd)
{
- unsigned size = info.compCompHnd->getClassSize(clsHnd);
- return argOrReturnTypeForStruct(size, clsHnd, forReturn);
+ for (;;)
+ {
+ // all of class chain must be of value type and must have only one field
+ if (!info.compCompHnd->isValueClass(clsHnd) &&
+ info.compCompHnd->getClassNumInstanceFields(clsHnd) != 1)
+ {
+ return false;
+ }
+
+ CORINFO_CLASS_HANDLE* pClsHnd = &clsHnd;
+ CORINFO_FIELD_HANDLE fldHnd = info.compCompHnd->getFieldInClass(clsHnd, 0);
+ CorInfoType fieldType = info.compCompHnd->getFieldType(fldHnd, pClsHnd);
+
+ switch (fieldType)
+ {
+ case CORINFO_TYPE_VALUECLASS:
+ clsHnd = *pClsHnd;
+ break;
+
+ case CORINFO_TYPE_FLOAT:
+ return true;
+
+ default:
+ return false;
+ }
+ }
}
+#endif // ARM_SOFTFP
-//------------------------------------------------------------------------
-// argOrReturnTypeForStruct: Get the "primitive" type, if any, that is used to pass or return
-// values of the given struct type.
+//-----------------------------------------------------------------------------
+// getPrimitiveTypeForStruct:
+// Get the "primitive" type that is is used for a struct
+// of size 'structSize'.
+// We examine 'clsHnd' to check the GC layout of the struct and
+// return TYP_REF for structs that simply wrap an object.
+// If the struct is a one element HFA, we will return the
+// proper floating point type.
//
// Arguments:
-// size - the size of the struct type
-// clsHnd - the handle for the struct type
-// forReturn - true if we asking for this in a GT_RETURN context
-// false if we are asking for this in a parameter passing context
+// structSize - the size of the struct type, cannot be zero
+// clsHnd - the handle for the struct type, used when may have
+// an HFA or if we need the GC layout for an object ref.
//
// Return Value:
-// The primitive type used to pass or return the struct, if applicable, or
-// TYP_UNKNOWN otherwise.
-//
-// Assumptions:
-// The size must be the size of the given type.
-// The given class handle must be for a value type (struct).
-//
+// The primitive type (i.e. byte, short, int, long, ref, float, double)
+// used to pass or return structs of this size.
+// If we shouldn't use a "primitive" type then TYP_UNKNOWN is returned.
// Notes:
-// Some callers call into this method directly, instead of the above method,
-// when they have already determined the size.
-// This is to avoid a redundant call across the JIT/EE interface.
-
-var_types Compiler::argOrReturnTypeForStruct(unsigned size, CORINFO_CLASS_HANDLE clsHnd, bool forReturn)
+// For 32-bit targets (X86/ARM32) the 64-bit TYP_LONG type is not
+// considered a primitive type by this method.
+// So a struct that wraps a 'long' is passed and returned in the
+// same way as any other 8-byte struct
+// For ARM32 if we have an HFA struct that wraps a 64-bit double
+// we will return TYP_DOUBLE.
+//
+var_types Compiler::getPrimitiveTypeForStruct( unsigned structSize,
+ CORINFO_CLASS_HANDLE clsHnd)
{
- BYTE gcPtr = 0;
- var_types useType = TYP_UNKNOWN;
+ assert(structSize != 0);
- switch (size)
+ var_types useType;
+
+ switch (structSize)
{
case 1:
useType = TYP_BYTE;
@@ -516,63 +538,515 @@ var_types Compiler::argOrReturnTypeForStruct(unsigned size, CORINFO_CLASS_HAN
case 3:
useType = TYP_INT;
break;
+
#endif // _TARGET_XARCH_
#ifdef _TARGET_64BIT_
case 4:
- useType = TYP_INT;
+ if (IsHfa(clsHnd))
+ {
+ // A structSize of 4 with IsHfa, it must be an HFA of one float
+ useType = TYP_FLOAT;
+ }
+ else
+ {
+ useType = TYP_INT;
+ }
break;
-#endif // _TARGET_64BIT_
- // Pointer size
-#ifdef _TARGET_64BIT_
-#ifndef _TARGET_AMD64_
+#ifndef _TARGET_XARCH_
case 5:
case 6:
case 7:
-#endif // _TARGET_AMD64_
+ useType = TYP_I_IMPL;
+ break;
+
+#endif // _TARGET_XARCH_
+#endif // _TARGET_64BIT_
+
+
+ case TARGET_POINTER_SIZE:
+#ifdef ARM_SOFTFP
+ // For ARM_SOFTFP, HFA is unsupported so we need to check in another way
+ // This matters only for size-4 struct cause bigger structs would be processed with RetBuf
+ if (isSingleFloat32Struct(clsHnd))
+#else // !ARM_SOFTFP
+ if (IsHfa(clsHnd))
+#endif // ARM_SOFTFP
+ {
+#ifdef _TARGET_64BIT_
+ var_types hfaType = GetHfaType(clsHnd);
+
+ // A structSize of 8 with IsHfa, we have two possiblities:
+ // An HFA of one double or an HFA of two floats
+ //
+ // Check and exclude the case of an HFA of two floats
+ if (hfaType == TYP_DOUBLE)
+ {
+ // We have an HFA of one double
+ useType = TYP_DOUBLE;
+ }
+ else
+ {
+ assert(hfaType == TYP_FLOAT);
+
+ // We have an HFA of two floats
+ // This should be passed or returned in two FP registers
+ useType = TYP_UNKNOWN;
+ }
+#else // a 32BIT target
+ // A structSize of 4 with IsHfa, it must be an HFA of one float
+ useType = TYP_FLOAT;
+#endif // _TARGET_64BIT_
+ }
+ else
+ {
+ BYTE gcPtr = 0;
+ // Check if this pointer-sized struct is wrapping a GC object
+ info.compCompHnd->getClassGClayout(clsHnd, &gcPtr);
+ useType = getJitGCType(gcPtr);
+ }
+ break;
+
+#ifdef _TARGET_ARM_
case 8:
-#else // !_TARGET_64BIT_
- case 4:
-#endif // !_TARGET_64BIT_
- info.compCompHnd->getClassGClayout(clsHnd, &gcPtr);
- useType = getJitGCType(gcPtr);
+ if (IsHfa(clsHnd))
+ {
+ var_types hfaType = GetHfaType(clsHnd);
+
+ // A structSize of 8 with IsHfa, we have two possiblities:
+ // An HFA of one double or an HFA of two floats
+ //
+ // Check and exclude the case of an HFA of two floats
+ if (hfaType == TYP_DOUBLE)
+ {
+ // We have an HFA of one double
+ useType = TYP_DOUBLE;
+ }
+ else
+ {
+ assert(hfaType == TYP_FLOAT);
+
+ // We have an HFA of two floats
+ // This should be passed or returned in two FP registers
+ useType = TYP_UNKNOWN;
+ }
+ }
+ else
+ {
+ // We don't have an HFA
+ useType = TYP_UNKNOWN;
+ }
break;
+#endif // _TARGET_ARM_
default:
-#if FEATURE_MULTIREG_RET
- if (forReturn)
+ useType = TYP_UNKNOWN;
+ break;
+ }
+
+ return useType;
+}
+
+//-----------------------------------------------------------------------------
+// getArgTypeForStruct:
+// Get the type that is used to pass values of the given struct type.
+// If you have already retrieved the struct size then it should be
+// passed as the optional third argument, as this allows us to avoid
+// an extra call to getClassSize(clsHnd)
+//
+// Arguments:
+// clsHnd - the handle for the struct type
+// wbPassStruct - An "out" argument with information about how
+// the struct is to be passed
+// structSize - the size of the struct type,
+// or zero if we should call getClassSize(clsHnd)
+//
+// Return Value:
+// For wbPassStruct you can pass a 'nullptr' and nothing will be written
+// or returned for that out parameter.
+// When *wbPassStruct is SPK_PrimitiveType this method's return value
+// is the primitive type used to pass the struct.
+// When *wbPassStruct is SPK_ByReference this method's return value
+// is always TYP_UNKNOWN and the struct type is passed by reference to a copy
+// When *wbPassStruct is SPK_ByValue or SPK_ByValueAsHfa this method's return value
+// can be TYP_STRUCT and the struct type is passed using multiple registers.
+// or can be TYP_UNKNOWN and the struct type is passed by value (for x86 and ARM32)
+//
+// Assumptions:
+// The size must be the size of the given type.
+// The given class handle must be for a value type (struct).
+//
+// Notes:
+// About HFA types:
+// When the clsHnd is a one element HFA type we return the appropriate
+// floating point primitive type and *wbPassStruct is SPK_PrimitiveType
+// If there are two or more elements in the HFA type then the this method's
+// return value is TYP_STRUCT and *wbPassStruct is SPK_ByValueAsHfa
+// About returning TYP_STRUCT:
+// Whenever this method's return value is TYP_STRUCT it usually means that multiple
+// registers will be used to pass this struct.
+// The only exception occurs if all of the parameters registers are used up
+// then we must use stack slots instead. In such a case the amount of stack needed
+// is always equal to the structSize (rounded up to the next pointer size)
+//
+var_types Compiler::getArgTypeForStruct(CORINFO_CLASS_HANDLE clsHnd,
+ structPassingKind* wbPassStruct,
+ unsigned structSize /* = 0 */)
+{
+ var_types useType = TYP_UNKNOWN;
+ structPassingKind howToPassStruct = SPK_Unknown; // We must change this before we return
+
+ if (structSize == 0)
+ {
+ structSize = info.compCompHnd->getClassSize(clsHnd);
+ }
+ assert(structSize > 0);
+
+#ifdef FEATURE_UNIX_AMD64_STRUCT_PASSING
+
+ // An 8-byte struct may need to be passed in a floating point register
+ // So we always consult the struct "Classifier" routine
+ //
+ SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR structDesc;
+ eeGetSystemVAmd64PassStructInRegisterDescriptor(clsHnd, &structDesc);
+
+ // If we have one eightByteCount then we can set 'useType' based on that
+ if (structDesc.eightByteCount == 1)
+ {
+ // Set 'useType' to the type of the first eightbyte item
+ useType = GetEightByteType(structDesc, 0);
+ }
+
+#else // not UNIX_AMD64
+
+ // We set the "primitive" useType based upon the structSize
+ // and also examine the clsHnd to see if it is an HFA of count one
+ useType = getPrimitiveTypeForStruct(structSize, clsHnd);
+
+#endif // FEATURE_UNIX_AMD64_STRUCT_PASSING
+
+ // Did we change this struct type into a simple "primitive" type?
+ //
+ if (useType != TYP_UNKNOWN)
+ {
+ // Yes, we should use the "primitive" type in 'useType'
+ howToPassStruct = SPK_PrimitiveType;
+ }
+ else // We can't replace the struct with a "primitive" type
+ {
+ // See if we can pass this struct by value, possibly in multiple registers
+ // or if we should pass it by reference to a copy
+ //
+ if (structSize <= MAX_PASS_MULTIREG_BYTES)
{
- if (size <= MAX_RET_MULTIREG_BYTES)
+ // Structs that are HFA's are passed by value in multiple registers
+ if (IsHfa(clsHnd))
{
-#ifdef _TARGET_ARM64_
- // TODO-ARM64-HFA - Implement x0,x1 returns
- // TODO-ARM64 - Implement HFA returns
-#endif // _TARGET_XXX_
+ // HFA's of count one should have been handled by getPrimitiveTypeForStruct
+ assert(GetHfaCount(clsHnd) >= 2);
+
+ // setup wbPassType and useType indicate that this is passed by value as an HFA
+ // using multiple registers
+ // (when all of the parameters registers are used, then the stack will be used)
+ howToPassStruct = SPK_ByValueAsHfa;
+ useType = TYP_STRUCT;
+ }
+ else // Not an HFA struct type
+ {
+
+#ifdef FEATURE_UNIX_AMD64_STRUCT_PASSING
+
+ // The case of (structDesc.eightByteCount == 1) should have already been handled
+ if (structDesc.eightByteCount > 1)
+ {
+ // setup wbPassType and useType indicate that this is passed by value in multiple registers
+ // (when all of the parameters registers are used, then the stack will be used)
+ howToPassStruct = SPK_ByValue;
+ useType = TYP_STRUCT;
+ }
+ else
+ {
+ assert(structDesc.eightByteCount == 0);
+ // Otherwise we pass this struct by reference to a copy
+ // setup wbPassType and useType indicate that this is passed using one register
+ // (by reference to a copy)
+ howToPassStruct = SPK_ByReference;
+ useType = TYP_UNKNOWN;
+ }
+
+#elif defined(_TARGET_ARM64_)
+
+ // Structs that are pointer sized or smaller should have been handled by getPrimitiveTypeForStruct
+ assert(structSize > TARGET_POINTER_SIZE);
+
+ // On ARM64 structs that are 9-16 bytes are passed by value in multiple registers
+ //
+ if (structSize <= (TARGET_POINTER_SIZE * 2))
+ {
+ // setup wbPassType and useType indicate that this is passed by value in multiple registers
+ // (when all of the parameters registers are used, then the stack will be used)
+ howToPassStruct = SPK_ByValue;
+ useType = TYP_STRUCT;
+ }
+ else // a structSize that is 17-32 bytes in size
+ {
+ // Otherwise we pass this struct by reference to a copy
+ // setup wbPassType and useType indicate that this is passed using one register
+ // (by reference to a copy)
+ howToPassStruct = SPK_ByReference;
+ useType = TYP_UNKNOWN;
+ }
+
+#elif defined(_TARGET_X86_) || defined(_TARGET_ARM_)
+
+ // Otherwise we pass this struct by value
+ // setup wbPassType and useType indicate that this is passed by value according to the X86/ARM32 ABI
+ howToPassStruct = SPK_ByValue;
+ useType = TYP_UNKNOWN;
+
+#else // _TARGET_XXX_
+
+ noway_assert(!"Unhandled TARGET in getArgTypeForStruct (with FEATURE_MULTIREG_ARGS=1)");
+
+#endif // _TARGET_XXX_
+
}
}
-#endif // FEATURE_MULTIREG_RET
+ else // (structSize > MAX_PASS_MULTIREG_BYTES)
+ {
+ // We have a (large) struct that can't be replaced with a "primitive" type
+ // and can't be passed in multiple registers
-#if FEATURE_MULTIREG_ARGS
- if (!forReturn)
+#if defined(_TARGET_X86_) || defined(_TARGET_ARM_)
+
+ // Otherwise we pass this struct by value on the stack
+ // setup wbPassType and useType indicate that this is passed by value according to the X86/ARM32 ABI
+ howToPassStruct = SPK_ByValue;
+ useType = TYP_UNKNOWN;
+
+#elif defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_)
+
+ // Otherwise we pass this struct by reference to a copy
+ // setup wbPassType and useType indicate that this is passed using one register (by reference to a copy)
+ howToPassStruct = SPK_ByReference;
+ useType = TYP_UNKNOWN;
+
+#else // _TARGET_XXX_
+
+ noway_assert(!"Unhandled TARGET in getArgTypeForStruct");
+
+#endif // _TARGET_XXX_
+
+ }
+ }
+
+ // 'howToPassStruct' must be set to one of the valid values before we return
+ assert(howToPassStruct != SPK_Unknown);
+ if (wbPassStruct != nullptr)
+ {
+ *wbPassStruct = howToPassStruct;
+ }
+ return useType;
+}
+
+//-----------------------------------------------------------------------------
+// getReturnTypeForStruct:
+// Get the type that is used to return values of the given struct type.
+// If you have already retrieved the struct size then it should be
+// passed as the optional third argument, as this allows us to avoid
+// an extra call to getClassSize(clsHnd)
+//
+// Arguments:
+// clsHnd - the handle for the struct type
+// wbReturnStruct - An "out" argument with information about how
+// the struct is to be returned
+// structSize - the size of the struct type,
+// or zero if we should call getClassSize(clsHnd)
+//
+// Return Value:
+// For wbReturnStruct you can pass a 'nullptr' and nothing will be written
+// or returned for that out parameter.
+// When *wbReturnStruct is SPK_PrimitiveType this method's return value
+// is the primitive type used to return the struct.
+// When *wbReturnStruct is SPK_ByReference this method's return value
+// is always TYP_UNKNOWN and the struct type is returned using a return buffer
+// When *wbReturnStruct is SPK_ByValue or SPK_ByValueAsHfa this method's return value
+// is always TYP_STRUCT and the struct type is returned using multiple registers.
+//
+// Assumptions:
+// The size must be the size of the given type.
+// The given class handle must be for a value type (struct).
+//
+// Notes:
+// About HFA types:
+// When the clsHnd is a one element HFA type then this method's return
+// value is the appropriate floating point primitive type and
+// *wbReturnStruct is SPK_PrimitiveType.
+// If there are two or more elements in the HFA type and the target supports
+// multireg return types then the return value is TYP_STRUCT and
+// *wbReturnStruct is SPK_ByValueAsHfa.
+// Additionally if there are two or more elements in the HFA type and
+// the target doesn't support multreg return types then it is treated
+// as if it wasn't an HFA type.
+// About returning TYP_STRUCT:
+// Whenever this method's return value is TYP_STRUCT it always means
+// that multiple registers are used to return this struct.
+//
+var_types Compiler::getReturnTypeForStruct(CORINFO_CLASS_HANDLE clsHnd,
+ structPassingKind* wbReturnStruct,
+ unsigned structSize /* = 0 */)
+{
+ var_types useType = TYP_UNKNOWN;
+ structPassingKind howToReturnStruct = SPK_Unknown; // We must change this before we return
+
+ if (structSize == 0)
+ {
+ structSize = info.compCompHnd->getClassSize(clsHnd);
+ }
+ assert(structSize > 0);
+
+#ifdef FEATURE_UNIX_AMD64_STRUCT_PASSING
+
+ // An 8-byte struct may need to be returned in a floating point register
+ // So we always consult the struct "Classifier" routine
+ //
+ SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR structDesc;
+ eeGetSystemVAmd64PassStructInRegisterDescriptor(clsHnd, &structDesc);
+
+ // If we have one eightByteCount then we can set 'useType' based on that
+ if (structDesc.eightByteCount == 1)
+ {
+ // Set 'useType' to the type of the first eightbyte item
+ useType = GetEightByteType(structDesc, 0);
+ }
+
+#else // not UNIX_AMD64
+
+ // We set the "primitive" useType based upon the structSize
+ // and also examine the clsHnd to see if it is an HFA of count one
+ useType = getPrimitiveTypeForStruct(structSize, clsHnd);
+
+#endif // FEATURE_UNIX_AMD64_STRUCT_PASSING
+
+ // Note this handles an odd case when FEATURE_MULTIREG_RET is disabled and HFAs are enabled
+ //
+ // getPrimitiveTypeForStruct will return TYP_UNKNOWN for a struct that is an HFA of two floats
+ // because when HFA are enabled, normally we would use two FP registers to pass or return it
+ //
+ // But if we don't have support for multiple register return types, we have to change this.
+ // Since we what we have an 8-byte struct (float + float) we change useType to TYP_I_IMPL
+ // so that the struct is returned instead using an 8-byte integer register.
+ //
+ if ((MAX_RET_MULTIREG_BYTES == 0) && (useType == TYP_UNKNOWN) &&
+ (structSize == 8) && IsHfa(clsHnd))
+ {
+ useType = TYP_I_IMPL;
+ }
+
+ // Did we change this struct type into a simple "primitive" type?
+ //
+ if (useType != TYP_UNKNOWN)
+ {
+ // Yes, we should use the "primitive" type in 'useType'
+ howToReturnStruct = SPK_PrimitiveType;
+ }
+ else // We can't replace the struct with a "primitive" type
+ {
+ // See if we can return this struct by value, possibly in multiple registers
+ // or if we should return it using a return buffer register
+ //
+ if (structSize <= MAX_RET_MULTIREG_BYTES)
{
- if (size <= MAX_PASS_MULTIREG_BYTES)
+ // Structs that are HFA's are returned in multiple registers
+ if (IsHfa(clsHnd))
{
-#ifdef _TARGET_ARM64_
- assert(size > TARGET_POINTER_SIZE);
+ // HFA's of count one should have been handled by getPrimitiveTypeForStruct
+ assert(GetHfaCount(clsHnd) >= 2);
+
+ // setup wbPassType and useType indicate that this is returned by value as an HFA
+ // using multiple registers
+ howToReturnStruct = SPK_ByValueAsHfa;
+ useType = TYP_STRUCT;
+ }
+ else // Not an HFA struct type
+ {
+
+#ifdef FEATURE_UNIX_AMD64_STRUCT_PASSING
- // On ARM64 structs that are 9-16 bytes are passed by value
- // or if the struct is an HFA it is passed by value
- if ((size <= (TARGET_POINTER_SIZE * 2)) || IsHfa(clsHnd))
+ // The case of (structDesc.eightByteCount == 1) should have already been handled
+ if (structDesc.eightByteCount > 1)
{
- // set useType to TYP_STRUCT to indicate that this is passed by value in registers
+ // setup wbPassType and useType indicate that this is returned by value in multiple registers
+ howToReturnStruct = SPK_ByValue;
useType = TYP_STRUCT;
}
-#endif // _TARGET_ARM64_
+ else
+ {
+ assert(structDesc.eightByteCount == 0);
+ // Otherwise we return this struct using a return buffer
+ // setup wbPassType and useType indicate that this is return using a return buffer register
+ // (reference to a return buffer)
+ howToReturnStruct = SPK_ByReference;
+ useType = TYP_UNKNOWN;
+ }
+
+#elif defined(_TARGET_ARM64_)
+
+ // Structs that are pointer sized or smaller should have been handled by getPrimitiveTypeForStruct
+ assert(structSize > TARGET_POINTER_SIZE);
+
+ // On ARM64 structs that are 9-16 bytes are returned by value in multiple registers
+ //
+ if (structSize <= (TARGET_POINTER_SIZE * 2))
+ {
+ // setup wbPassType and useType indicate that this is return by value in multiple registers
+ howToReturnStruct = SPK_ByValue;
+ useType = TYP_STRUCT;
+ }
+ else // a structSize that is 17-32 bytes in size
+ {
+ // Otherwise we return this struct using a return buffer
+ // setup wbPassType and useType indicate that this is returned using a return buffer register
+ // (reference to a return buffer)
+ howToReturnStruct = SPK_ByReference;
+ useType = TYP_UNKNOWN;
+ }
+
+#elif defined(_TARGET_ARM_) || defined(_TARGET_X86_)
+
+ // Otherwise we return this struct using a return buffer
+ // setup wbPassType and useType indicate that this is returned using a return buffer register
+ // (reference to a return buffer)
+ howToReturnStruct = SPK_ByReference;
+ useType = TYP_UNKNOWN;
+
+#else // _TARGET_XXX_
+
+ noway_assert(!"Unhandled TARGET in getReturnTypeForStruct (with FEATURE_MULTIREG_ARGS=1)");
+
+#endif // _TARGET_XXX_
+
}
}
-#endif // FEATURE_MULTIREG_ARGS
- break;
+ else // (structSize > MAX_RET_MULTIREG_BYTES)
+ {
+ // We have a (large) struct that can't be replaced with a "primitive" type
+ // and can't be returned in multiple registers
+
+ // We return this struct using a return buffer register
+ // setup wbPassType and useType indicate that this is returned using a return buffer register
+ // (reference to a return buffer)
+ howToReturnStruct = SPK_ByReference;
+ useType = TYP_UNKNOWN;
+ }
+ }
+
+ // 'howToReturnStruct' must be set to one of the valid values before we return
+ assert(howToReturnStruct != SPK_Unknown);
+ if (wbReturnStruct != nullptr)
+ {
+ *wbReturnStruct = howToReturnStruct;
}
return useType;
}
diff --git a/src/jit/compiler.h b/src/jit/compiler.h
index 1d0ad5eea8..664206ffd7 100644
--- a/src/jit/compiler.h
+++ b/src/jit/compiler.h
@@ -1140,7 +1140,7 @@ struct fgArgTabEntry
bool processed :1; // True when we have decided the evaluation order for this argument in the gtCallLateArgs
bool isHfaRegArg :1; // True when the argument is passed as a HFA in FP registers.
bool isBackFilled :1; // True when the argument fills a register slot skipped due to alignment requirements of previous arguments.
- bool isNonStandard:1; // True if it is an arg that is passed in a reg other than a standard arg reg
+ bool isNonStandard:1; // True if it is an arg that is passed in a reg other than a standard arg reg, or is forced to be on the stack despite its arg list position.
#if defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
bool isStruct :1; // True if this is a struct arg
@@ -1279,7 +1279,6 @@ public:
unsigned GetNextSlotNum() { return nextSlotNum; }
bool HasRegArgs() { return hasRegArgs; }
bool HasStackArgs() { return hasStackArgs; }
-
};
@@ -1385,6 +1384,10 @@ class Compiler
friend class LclVarDsc;
friend class TempDsc;
+#ifndef _TARGET_64BIT_
+ friend class DecomposeLongs;
+#endif // !_TARGET_64BIT_
+
/*
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
@@ -1439,6 +1442,10 @@ public:
GenTreePtr impAssignMultiRegTypeToVar(GenTreePtr op, CORINFO_CLASS_HANDLE hClass);
#endif // FEATURE_MULTIREG_RET
+#ifdef ARM_SOFTFP
+ bool isSingleFloat32Struct(CORINFO_CLASS_HANDLE hClass);
+#endif // ARM_SOFTFP
+
//-------------------------------------------------------------------------
// Functions to handle homogeneous floating-point aggregates (HFAs) in ARM.
// HFAs are one to four element structs where each element is the same
@@ -1998,12 +2005,16 @@ public:
GenTreePtr gtWalkOpEffectiveVal(GenTreePtr op);
#endif
- void gtPrepareCost (GenTree * tree);
- bool gtIsLikelyRegVar(GenTree * tree);
+ void gtPrepareCost (GenTree* tree);
+ bool gtIsLikelyRegVar(GenTree* tree);
unsigned gtSetEvalOrderAndRestoreFPstkLevel(GenTree * tree);
- unsigned gtSetEvalOrder (GenTree * tree);
+ // Returns true iff the secondNode can be swapped with firstNode.
+ bool gtCanSwapOrder (GenTree* firstNode,
+ GenTree* secondNode);
+
+ unsigned gtSetEvalOrder (GenTree* tree);
#if FEATURE_STACK_FP_X87
bool gtFPstLvlRedo;
@@ -3861,13 +3872,37 @@ public :
// Convert a BYTE which represents the VM's CorInfoGCtype to the JIT's var_types
var_types getJitGCType(BYTE gcType);
- // Get the "primitive" type, if any, that is used to pass or return
- // values of the given struct type.
- var_types argOrReturnTypeForStruct(CORINFO_CLASS_HANDLE clsHnd, bool forReturn);
+ enum structPassingKind { SPK_Unknown, // Invalid value, never returned
+ SPK_PrimitiveType, // The struct is passed/returned using a primitive type.
+ SPK_ByValue, // The struct is passed/returned by value (using the ABI rules)
+ // for ARM64 and UNIX_X64 in multiple registers. (when all of the
+ // parameters registers are used, then the stack will be used)
+ // for X86 passed on the stack, for ARM32 passed in registers
+ // or the stack or split between registers and the stack.
+ SPK_ByValueAsHfa, // The struct is passed/returned as an HFA in multiple registers.
+ SPK_ByReference }; // The struct is passed/returned by reference to a copy/buffer.
+
+ // Get the "primitive" type that is is used when we are given a struct of size 'structSize'.
+ // For pointer sized structs the 'clsHnd' is used to determine if the struct contains GC ref.
+ // A "primitive" type is one of the scalar types: byte, short, int, long, ref, float, double
+ // If we can't or shouldn't use a "primitive" type then TYP_UNKNOWN is returned.
+ //
+ var_types getPrimitiveTypeForStruct(unsigned structSize, CORINFO_CLASS_HANDLE clsHnd);
+
+ // Get the type that is used to pass values of the given struct type.
+ // If you have already retrieved the struct size then pass it as the optional third argument
+ //
+ var_types getArgTypeForStruct(CORINFO_CLASS_HANDLE clsHnd,
+ structPassingKind* wbPassStruct,
+ unsigned structSize = 0);
+
+ // Get the type that is used to return values of the given struct type.
+ // If you have already retrieved the struct size then pass it as the optional third argument
+ //
+ var_types getReturnTypeForStruct(CORINFO_CLASS_HANDLE clsHnd,
+ structPassingKind* wbPassStruct,
+ unsigned structSize = 0);
- // Slightly optimized version of the above where we've already computed the size,
- // so as to avoid a repeated JIT/EE interface call.
- var_types argOrReturnTypeForStruct(unsigned size, CORINFO_CLASS_HANDLE clsHnd, bool forReturn);
#ifdef DEBUG
// Print a representation of "vnp" or "vn" on standard output.
@@ -4468,9 +4503,6 @@ private:
GenTree *stmt,
BasicBlock *blk);
- // insert the given subtree 'tree' as a top level statement before 'insertionPoint'. Give it the specified source code IL offset.
- GenTreeStmt* fgSpliceTreeBefore(BasicBlock* block, GenTreeStmt* insertionPoint, GenTree* tree, IL_OFFSETX ilOffset);
-
// insert the given subtree as an embedded statement of parentStmt
GenTreeStmt* fgMakeEmbeddedStmt(BasicBlock *block, GenTreePtr tree, GenTreePtr parentStmt);
@@ -4743,7 +4775,7 @@ private:
fgWalkResult fgMorphStructField(GenTreePtr tree, fgWalkData *fgWalkPre);
fgWalkResult fgMorphLocalField(GenTreePtr tree, fgWalkData *fgWalkPre);
void fgMarkImplicitByRefArgs();
- bool fgMorphImplicitByRefArgs(GenTreePtr tree, fgWalkData *fgWalkPre);
+ bool fgMorphImplicitByRefArgs(GenTree** pTree, fgWalkData *fgWalkPre);
static fgWalkPreFn fgMarkAddrTakenLocalsPreCB;
static fgWalkPostFn fgMarkAddrTakenLocalsPostCB;
void fgMarkAddressExposedLocals();
@@ -5376,8 +5408,9 @@ protected :
//
void optCSE_GetMaskData (GenTreePtr tree, optCSE_MaskData* pMaskData);
- // Given a binary tree node return true if it is safe to swap the order of evaluation for op1 and op2
- bool optCSE_canSwap (GenTreePtr tree);
+ // Given a binary tree node return true if it is safe to swap the order of evaluation for op1 and op2.
+ bool optCSE_canSwap(GenTree* firstNode, GenTree* secondNode);
+ bool optCSE_canSwap(GenTree* tree);
static fgWalkPostFn optPropagateNonCSE;
static fgWalkPreFn optHasNonCSEChild;
diff --git a/src/jit/compiler.hpp b/src/jit/compiler.hpp
index 1a338905bb..6bf7c48f8e 100644
--- a/src/jit/compiler.hpp
+++ b/src/jit/compiler.hpp
@@ -661,7 +661,16 @@ bool Compiler::VarTypeIsMultiByteAndCanEnreg(var_types type,
// Account for the classification of the struct.
result = IsRegisterPassable(typeClass);
#else // !FEATURE_UNIX_AMD64_STRUCT_PASSING
- type = argOrReturnTypeForStruct(size, typeClass, forReturn);
+ if (forReturn)
+ {
+ structPassingKind howToReturnStruct;
+ type = getReturnTypeForStruct(typeClass, &howToReturnStruct, size);
+ }
+ else
+ {
+ structPassingKind howToPassStruct;
+ type = getArgTypeForStruct(typeClass, &howToPassStruct, size);
+ }
if (type != TYP_UNKNOWN)
{
result = true;
@@ -1532,6 +1541,7 @@ bool GenTree::gtOverflow() const
assert(gtOper == GT_MUL || gtOper == GT_CAST ||
gtOper == GT_ADD || gtOper == GT_SUB ||
gtOper == GT_ASG_ADD || gtOper == GT_ASG_SUB ||
+ gtOper == GT_ADD_LO || gtOper == GT_SUB_LO ||
gtOper == GT_ADD_HI || gtOper == GT_SUB_HI);
#else
assert(gtOper == GT_MUL || gtOper == GT_CAST ||
diff --git a/src/jit/decomposelongs.cpp b/src/jit/decomposelongs.cpp
new file mode 100644
index 0000000000..365a0ff529
--- /dev/null
+++ b/src/jit/decomposelongs.cpp
@@ -0,0 +1,1289 @@
+// 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.
+
+/*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XX XX
+XX DecomposeLongs XX
+XX XX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX*/
+
+//
+// This file contains code to decompose 64-bit LONG operations on 32-bit platforms
+// into multiple single-register operations so individual register usage and requirements
+// are explicit for LSRA. The rationale behind this is to avoid adding code complexity
+// downstream caused by the introduction of handling longs as special cases,
+// especially in LSRA.
+//
+// Long decomposition happens on a statement immediately prior to more general
+// purpose lowering.
+//
+
+#include "jitpch.h"
+#ifdef _MSC_VER
+#pragma hdrstop
+#endif
+
+#ifndef LEGACY_BACKEND // This file is ONLY used for the RyuJIT backend that uses the linear scan register allocator
+#ifndef _TARGET_64BIT_ // DecomposeLongs is only used on 32-bit platforms
+
+#include "decomposelongs.h"
+
+//------------------------------------------------------------------------
+
+//------------------------------------------------------------------------
+// PrepareForDecomposition: Do one-time preparation required for LONG decomposition.
+// Namely, promote long variables to multi-register structs.
+//
+// Arguments:
+// None
+//
+// Return Value:
+// None.
+//
+void DecomposeLongs::PrepareForDecomposition()
+{
+ m_compiler->lvaPromoteLongVars();
+}
+
+
+//------------------------------------------------------------------------
+// DecomposeBlock: Do LONG decomposition to all the statements in the given block.
+// This must be done before lowering the block, as decomposition can insert
+// additional statements.
+//
+// Decomposition is done as a post-order tree walk. Lower levels of the tree can
+// create new nodes that need to be further decomposed at higher levels. That is,
+// the decomposition "bubbles up" the tree.
+//
+// Arguments:
+// block - the block to process
+//
+// Return Value:
+// None.
+//
+void DecomposeLongs::DecomposeBlock(BasicBlock* block)
+{
+ assert(block == m_compiler->compCurBB); // compCurBB must already be set.
+
+ for (GenTree* stmt = block->bbTreeList; stmt != nullptr; stmt = stmt->gtNext)
+ {
+#ifdef DEBUG
+ if (m_compiler->verbose)
+ {
+ printf("Decomposing BB%02u, stmt id %u\n", block->bbNum, stmt->gtTreeID);
+ }
+#endif // DEBUG
+
+ DecomposeStmt(stmt->AsStmt());
+ }
+}
+
+
+//------------------------------------------------------------------------
+// DecomposeStmt: Do LONG decomposition to a statement tree.
+//
+// Arguments:
+// stmt - the statement to process
+//
+// Return Value:
+// None.
+//
+void DecomposeLongs::DecomposeStmt(GenTreeStmt* stmt)
+{
+ GenTree* savedStmt = m_compiler->compCurStmt; // We'll need to restore this later, in case this call was recursive.
+ m_compiler->compCurStmt = stmt; // Publish the current statement globally. One reason: fgInsertEmbeddedFormTemp requires it.
+ m_compiler->fgWalkTreePost(&stmt->gtStmt.gtStmtExpr, &DecomposeLongs::DecompNodeHelper, this, true);
+ m_compiler->compCurStmt = savedStmt;
+}
+
+
+//------------------------------------------------------------------------
+// DecompNodeHelper: fgWalkTreePost callback helper for LONG decomposition
+//
+// Arguments:
+// ppTree - tree node we are working on.
+// data - tree walk context, with data->pCallbackData as a DecomposeLongs*
+//
+// Return Value:
+// Standard tree walk result.
+//
+// static
+Compiler::fgWalkResult DecomposeLongs::DecompNodeHelper(GenTree** ppTree, Compiler::fgWalkData* data)
+{
+ DecomposeLongs* decomp = (DecomposeLongs*)data->pCallbackData;
+ decomp->DecomposeNode(ppTree, data);
+ return Compiler::WALK_CONTINUE;
+}
+
+
+//------------------------------------------------------------------------
+// DecomposeNode: Decompose long-type trees into lower and upper halves.
+//
+// Arguments:
+// *ppTree - A node that may or may not require decomposition.
+// data - The tree-walk data that provides the context.
+//
+// Return Value:
+// None. It the tree at *ppTree is of TYP_LONG, it will generally be replaced.
+//
+void DecomposeLongs::DecomposeNode(GenTree** ppTree, Compiler::fgWalkData* data)
+{
+ GenTree* tree = *ppTree;
+
+ // Handle the case where we are implicitly using the lower half of a long lclVar.
+ if ((tree->TypeGet() == TYP_INT) && tree->OperIsLocal())
+ {
+ LclVarDsc* varDsc = m_compiler->lvaTable + tree->AsLclVarCommon()->gtLclNum;
+ if (varTypeIsLong(varDsc) && varDsc->lvPromoted)
+ {
+#ifdef DEBUG
+ if (m_compiler->verbose)
+ {
+ printf("Changing implicit reference to lo half of long lclVar to an explicit reference of its promoted half:\n");
+ m_compiler->gtDispTree(tree);
+ }
+#endif // DEBUG
+ m_compiler->lvaDecRefCnts(tree);
+ unsigned loVarNum = varDsc->lvFieldLclStart;
+ tree->AsLclVarCommon()->SetLclNum(loVarNum);
+ m_compiler->lvaIncRefCnts(tree);
+ return;
+ }
+ }
+
+ if (tree->TypeGet() != TYP_LONG)
+ {
+ return;
+ }
+
+#ifdef DEBUG
+ if (m_compiler->verbose)
+ {
+ printf("Decomposing TYP_LONG tree. BEFORE:\n");
+ m_compiler->gtDispTree(tree);
+ }
+#endif // DEBUG
+
+ switch (tree->OperGet())
+ {
+ case GT_PHI:
+ case GT_PHI_ARG:
+ break;
+
+ case GT_LCL_VAR:
+ DecomposeLclVar(ppTree, data);
+ break;
+
+ case GT_LCL_FLD:
+ DecomposeLclFld(ppTree, data);
+ break;
+
+ case GT_STORE_LCL_VAR:
+ DecomposeStoreLclVar(ppTree, data);
+ break;
+
+ case GT_CAST:
+ DecomposeCast(ppTree, data);
+ break;
+
+ case GT_CNS_LNG:
+ DecomposeCnsLng(ppTree, data);
+ break;
+
+ case GT_CALL:
+ DecomposeCall(ppTree, data);
+ break;
+
+ case GT_RETURN:
+ assert(tree->gtOp.gtOp1->OperGet() == GT_LONG);
+ break;
+
+ case GT_STOREIND:
+ DecomposeStoreInd(ppTree, data);
+ break;
+
+ case GT_STORE_LCL_FLD:
+ assert(tree->gtOp.gtOp1->OperGet() == GT_LONG);
+ NYI("st.lclFld of of TYP_LONG");
+ break;
+
+ case GT_IND:
+ DecomposeInd(ppTree, data);
+ break;
+
+ case GT_NOT:
+ DecomposeNot(ppTree, data);
+ break;
+
+ case GT_NEG:
+ DecomposeNeg(ppTree, data);
+ break;
+
+ // Binary operators. Those that require different computation for upper and lower half are
+ // handled by the use of GetHiOper().
+ case GT_ADD:
+ case GT_SUB:
+ case GT_OR:
+ case GT_XOR:
+ case GT_AND:
+ DecomposeArith(ppTree, data);
+ break;
+
+ case GT_MUL:
+ NYI("Arithmetic binary operators on TYP_LONG - GT_MUL");
+ break;
+
+ case GT_DIV:
+ NYI("Arithmetic binary operators on TYP_LONG - GT_DIV");
+ break;
+
+ case GT_MOD:
+ NYI("Arithmetic binary operators on TYP_LONG - GT_MOD");
+ break;
+
+ case GT_UDIV:
+ NYI("Arithmetic binary operators on TYP_LONG - GT_UDIV");
+ break;
+
+ case GT_UMOD:
+ NYI("Arithmetic binary operators on TYP_LONG - GT_UMOD");
+ break;
+
+ case GT_LSH:
+ case GT_RSH:
+ case GT_RSZ:
+ NYI("Arithmetic binary operators on TYP_LONG - SHIFT");
+ break;
+
+ case GT_ROL:
+ case GT_ROR:
+ NYI("Arithmetic binary operators on TYP_LONG - ROTATE");
+ break;
+
+ case GT_MULHI:
+ NYI("Arithmetic binary operators on TYP_LONG - MULHI");
+ break;
+
+ case GT_LOCKADD:
+ case GT_XADD:
+ case GT_XCHG:
+ case GT_CMPXCHG:
+ NYI("Interlocked operations on TYP_LONG");
+ break;
+
+ default:
+ {
+ JITDUMP("Illegal TYP_LONG node %s in Decomposition.", GenTree::NodeName(tree->OperGet()));
+ noway_assert(!"Illegal TYP_LONG node in Decomposition.");
+ break;
+ }
+ }
+
+#ifdef DEBUG
+ if (m_compiler->verbose)
+ {
+ printf(" AFTER:\n");
+ m_compiler->gtDispTree(*ppTree);
+ }
+#endif
+}
+
+
+//------------------------------------------------------------------------
+// FinalizeDecomposition: A helper function to finalize LONG decomposition by
+// taking the resulting two halves of the decomposition, and tie them together
+// with a new GT_LONG node that will replace the original node.
+//
+// Arguments:
+// ppTree - the original tree node
+// data - tree walk context
+// loResult - the decomposed low part
+// hiResult - the decomposed high part
+//
+// Return Value:
+// None.
+//
+void DecomposeLongs::FinalizeDecomposition(GenTree** ppTree, Compiler::fgWalkData* data, GenTree* loResult, GenTree* hiResult)
+{
+ assert(ppTree != nullptr);
+ assert(*ppTree != nullptr);
+ assert(data != nullptr);
+ assert(loResult != nullptr);
+ assert(hiResult != nullptr);
+ assert(m_compiler->compCurStmt != nullptr);
+
+ GenTree* tree = *ppTree;
+
+ m_compiler->fgInsertTreeInListAfter(hiResult, loResult, m_compiler->compCurStmt->AsStmt());
+ hiResult->CopyCosts(tree);
+
+ GenTree* newTree = new (m_compiler, GT_LONG) GenTreeOp(GT_LONG, TYP_LONG, loResult, hiResult);
+ SimpleLinkNodeAfter(hiResult, newTree);
+ m_compiler->fgFixupIfCallArg(data->parentStack, tree, newTree);
+ newTree->CopyCosts(tree);
+ *ppTree = newTree;
+}
+
+
+//------------------------------------------------------------------------
+// DecomposeLclVar: Decompose GT_LCL_VAR.
+//
+// Arguments:
+// ppTree - the tree to decompose
+// data - tree walk context
+//
+// Return Value:
+// None.
+//
+void DecomposeLongs::DecomposeLclVar(GenTree** ppTree, Compiler::fgWalkData* data)
+{
+ assert(ppTree != nullptr);
+ assert(*ppTree != nullptr);
+ assert(data != nullptr);
+ assert((*ppTree)->OperGet() == GT_LCL_VAR);
+
+ GenTree* tree = *ppTree;
+ unsigned varNum = tree->AsLclVarCommon()->gtLclNum;
+ LclVarDsc* varDsc = m_compiler->lvaTable + varNum;
+ m_compiler->lvaDecRefCnts(tree);
+
+ GenTree* loResult = tree;
+ loResult->gtType = TYP_INT;
+ GenTree* hiResult = m_compiler->gtNewLclLNode(varNum, TYP_INT);
+
+ if (varDsc->lvPromoted)
+ {
+ assert(varDsc->lvFieldCnt == 2);
+ unsigned loVarNum = varDsc->lvFieldLclStart;
+ unsigned hiVarNum = loVarNum + 1;
+ loResult->AsLclVarCommon()->SetLclNum(loVarNum);
+ hiResult->AsLclVarCommon()->SetLclNum(hiVarNum);
+ }
+ else
+ {
+ noway_assert(varDsc->lvLRACandidate == false);
+
+ loResult->SetOper(GT_LCL_FLD);
+ loResult->AsLclFld()->gtLclOffs = 0;
+ loResult->AsLclFld()->gtFieldSeq = FieldSeqStore::NotAField();
+
+ hiResult->SetOper(GT_LCL_FLD);
+ hiResult->AsLclFld()->gtLclOffs = 4;
+ hiResult->AsLclFld()->gtFieldSeq = FieldSeqStore::NotAField();
+ }
+
+ m_compiler->lvaIncRefCnts(loResult);
+ m_compiler->lvaIncRefCnts(hiResult);
+
+ FinalizeDecomposition(ppTree, data, loResult, hiResult);
+}
+
+
+//------------------------------------------------------------------------
+// DecomposeLclFld: Decompose GT_LCL_FLD.
+//
+// Arguments:
+// ppTree - the tree to decompose
+// data - tree walk context
+//
+// Return Value:
+// None.
+//
+void DecomposeLongs::DecomposeLclFld(GenTree** ppTree, Compiler::fgWalkData* data)
+{
+ assert(ppTree != nullptr);
+ assert(*ppTree != nullptr);
+ assert(data != nullptr);
+ assert((*ppTree)->OperGet() == GT_LCL_FLD);
+
+ GenTree* tree = *ppTree;
+ GenTreeLclFld* loResult = tree->AsLclFld();
+ loResult->gtType = TYP_INT;
+
+ GenTree* hiResult = m_compiler->gtNewLclFldNode(loResult->gtLclNum,
+ TYP_INT,
+ loResult->gtLclOffs + 4);
+
+ FinalizeDecomposition(ppTree, data, loResult, hiResult);
+}
+
+
+//------------------------------------------------------------------------
+// DecomposeStoreLclVar: Decompose GT_STORE_LCL_VAR.
+//
+// Arguments:
+// ppTree - the tree to decompose
+// data - tree walk context
+//
+// Return Value:
+// None.
+//
+void DecomposeLongs::DecomposeStoreLclVar(GenTree** ppTree, Compiler::fgWalkData* data)
+{
+ assert(ppTree != nullptr);
+ assert(*ppTree != nullptr);
+ assert(data != nullptr);
+ assert((*ppTree)->OperGet() == GT_STORE_LCL_VAR);
+ assert(m_compiler->compCurStmt != nullptr);
+
+ GenTreeStmt* curStmt = m_compiler->compCurStmt->AsStmt();
+
+ GenTree* tree = *ppTree;
+ GenTree* nextTree = tree->gtNext;
+ GenTree* rhs = tree->gtGetOp1();
+ if ((rhs->OperGet() == GT_PHI) || (rhs->OperGet() == GT_CALL))
+ {
+ // GT_CALLs are not decomposed, so will not be converted to GT_LONG
+ // GT_STORE_LCL_VAR = GT_CALL are handled in genMultiRegCallStoreToLocal
+ return;
+ }
+
+ noway_assert(rhs->OperGet() == GT_LONG);
+ unsigned varNum = tree->AsLclVarCommon()->gtLclNum;
+ LclVarDsc* varDsc = m_compiler->lvaTable + varNum;
+ m_compiler->lvaDecRefCnts(tree);
+
+ GenTree* loRhs = rhs->gtGetOp1();
+ GenTree* hiRhs = rhs->gtGetOp2();
+ GenTree* hiStore = m_compiler->gtNewLclLNode(varNum, TYP_INT);
+
+ if (varDsc->lvPromoted)
+ {
+ assert(varDsc->lvFieldCnt == 2);
+
+ unsigned loVarNum = varDsc->lvFieldLclStart;
+ unsigned hiVarNum = loVarNum + 1;
+ tree->AsLclVarCommon()->SetLclNum(loVarNum);
+ hiStore->SetOper(GT_STORE_LCL_VAR);
+ hiStore->AsLclVarCommon()->SetLclNum(hiVarNum);
+ }
+ else
+ {
+ noway_assert(varDsc->lvLRACandidate == false);
+
+ tree->SetOper(GT_STORE_LCL_FLD);
+ tree->AsLclFld()->gtLclOffs = 0;
+ tree->AsLclFld()->gtFieldSeq = FieldSeqStore::NotAField();
+
+ hiStore->SetOper(GT_STORE_LCL_FLD);
+ hiStore->AsLclFld()->gtLclOffs = 4;
+ hiStore->AsLclFld()->gtFieldSeq = FieldSeqStore::NotAField();
+ }
+
+ tree->gtOp.gtOp1 = loRhs;
+ tree->gtType = TYP_INT;
+
+ loRhs->gtNext = tree;
+ tree->gtPrev = loRhs;
+
+ hiStore->gtOp.gtOp1 = hiRhs;
+ hiStore->CopyCosts(tree);
+ hiStore->gtFlags |= GTF_VAR_DEF;
+
+ m_compiler->lvaIncRefCnts(tree);
+ m_compiler->lvaIncRefCnts(hiStore);
+
+ tree->gtNext = hiRhs;
+ hiRhs->gtPrev = tree;
+ hiRhs->gtNext = hiStore;
+ hiStore->gtPrev = hiRhs;
+ hiStore->gtNext = nextTree;
+ if (nextTree != nullptr)
+ {
+ nextTree->gtPrev = hiStore;
+ }
+ nextTree = hiRhs;
+
+ bool isEmbeddedStmt = !curStmt->gtStmtIsTopLevel();
+ if (!isEmbeddedStmt)
+ {
+ tree->gtNext = nullptr;
+ hiRhs->gtPrev = nullptr;
+ }
+
+ InsertNodeAsStmt(hiStore);
+}
+
+
+//------------------------------------------------------------------------
+// DecomposeCast: Decompose GT_CAST.
+//
+// Arguments:
+// ppTree - the tree to decompose
+// data - tree walk context
+//
+// Return Value:
+// None.
+//
+void DecomposeLongs::DecomposeCast(GenTree** ppTree, Compiler::fgWalkData* data)
+{
+ assert(ppTree != nullptr);
+ assert(*ppTree != nullptr);
+ assert(data != nullptr);
+ assert((*ppTree)->OperGet() == GT_CAST);
+ assert(m_compiler->compCurStmt != nullptr);
+
+ GenTree* tree = *ppTree;
+ GenTree* loResult = nullptr;
+ GenTree* hiResult = nullptr;
+ GenTreeStmt* curStmt = m_compiler->compCurStmt->AsStmt();
+
+ assert(tree->gtPrev == tree->gtGetOp1());
+ NYI_IF(tree->gtOverflow(), "TYP_LONG cast with overflow");
+ switch (tree->AsCast()->CastFromType())
+ {
+ case TYP_INT:
+ if (tree->gtFlags & GTF_UNSIGNED)
+ {
+ loResult = tree->gtGetOp1();
+ hiResult = new (m_compiler, GT_CNS_INT) GenTreeIntCon(TYP_INT, 0);
+ m_compiler->fgSnipNode(curStmt, tree);
+ }
+ else
+ {
+ NYI("Lowering of signed cast TYP_INT->TYP_LONG");
+ }
+ break;
+
+ default:
+ NYI("Unimplemented type for Lowering of cast to TYP_LONG");
+ break;
+ }
+
+ FinalizeDecomposition(ppTree, data, loResult, hiResult);
+}
+
+
+//------------------------------------------------------------------------
+// DecomposeCnsLng: Decompose GT_CNS_LNG.
+//
+// Arguments:
+// ppTree - the tree to decompose
+// data - tree walk context
+//
+// Return Value:
+// None.
+//
+void DecomposeLongs::DecomposeCnsLng(GenTree** ppTree, Compiler::fgWalkData* data)
+{
+ assert(ppTree != nullptr);
+ assert(*ppTree != nullptr);
+ assert(data != nullptr);
+ assert((*ppTree)->OperGet() == GT_CNS_LNG);
+
+ GenTree* tree = *ppTree;
+ INT32 hiVal = tree->AsLngCon()->HiVal();
+
+ GenTree* loResult = tree;
+ loResult->ChangeOperConst(GT_CNS_INT);
+ loResult->gtType = TYP_INT;
+
+ GenTree* hiResult = new (m_compiler, GT_CNS_INT) GenTreeIntCon(TYP_INT, hiVal);
+
+ FinalizeDecomposition(ppTree, data, loResult, hiResult);
+}
+
+
+//------------------------------------------------------------------------
+// DecomposeCall: Decompose GT_CALL.
+//
+// Arguments:
+// ppTree - the tree to decompose
+// data - tree walk context
+//
+// Return Value:
+// None.
+//
+void DecomposeLongs::DecomposeCall(GenTree** ppTree, Compiler::fgWalkData* data)
+{
+ assert(ppTree != nullptr);
+ assert(*ppTree != nullptr);
+ assert(data != nullptr);
+ assert((*ppTree)->OperGet() == GT_CALL);
+
+ GenTree* parent = data->parent;
+
+ // We only need to force var = call() if the call is not a top-level node.
+ if (parent == nullptr)
+ return;
+
+ if (parent->gtOper == GT_STORE_LCL_VAR)
+ {
+ // If parent is already a STORE_LCL_VAR, we can skip it if
+ // it is already marked as lvIsMultiRegRet.
+ unsigned varNum = parent->AsLclVarCommon()->gtLclNum;
+ if (m_compiler->lvaTable[varNum].lvIsMultiRegRet)
+ {
+ return;
+ }
+ else if (!m_compiler->lvaTable[varNum].lvPromoted)
+ {
+ // If var wasn't promoted, we can just set lvIsMultiRegRet.
+ m_compiler->lvaTable[varNum].lvIsMultiRegRet = true;
+ return;
+ }
+ }
+
+ // Otherwise, we need to force var = call()
+ GenTree* tree = *ppTree;
+ GenTree** treePtr = nullptr;
+ parent = tree->gtGetParent(&treePtr);
+
+ assert(treePtr != nullptr);
+
+ GenTreeStmt* asgStmt = m_compiler->fgInsertEmbeddedFormTemp(treePtr);
+ GenTree* stLclVar = asgStmt->gtStmtExpr;
+ assert(stLclVar->OperIsLocalStore());
+
+ unsigned varNum = stLclVar->AsLclVarCommon()->gtLclNum;
+ m_compiler->lvaTable[varNum].lvIsMultiRegRet = true;
+ m_compiler->fgFixupIfCallArg(data->parentStack, tree, *treePtr);
+
+ // Decompose new node
+ DecomposeNode(treePtr, data);
+}
+
+
+//------------------------------------------------------------------------
+// DecomposeStoreInd: Decompose GT_STOREIND.
+//
+// Arguments:
+// tree - the tree to decompose
+//
+// Return Value:
+// None.
+//
+void DecomposeLongs::DecomposeStoreInd(GenTree** ppTree, Compiler::fgWalkData* data)
+{
+ assert(ppTree != nullptr);
+ assert(*ppTree != nullptr);
+ assert(data != nullptr);
+ assert((*ppTree)->OperGet() == GT_STOREIND);
+ assert(m_compiler->compCurStmt != nullptr);
+
+ GenTree* tree = *ppTree;
+
+ assert(tree->gtOp.gtOp2->OperGet() == GT_LONG);
+
+ GenTreeStmt* curStmt = m_compiler->compCurStmt->AsStmt();
+ bool isEmbeddedStmt = !curStmt->gtStmtIsTopLevel();
+
+ // Example input trees (a nested embedded statement case)
+ //
+ // <linkBegin Node>
+ // * stmtExpr void (top level) (IL ???... ???)
+ // | /--* argPlace ref $280
+ // | +--* argPlace int $4a
+ // | | { * stmtExpr void (embedded) (IL ???... ???)
+ // | | { | /--* lclVar ref V11 tmp9 u:3 $21c
+ // | | { | +--* const int 4 $44
+ // | | { | /--* + byref $2c8
+ // | | { | | { * stmtExpr void (embedded) (IL ???... ???)
+ // | | { | | { | /--* lclFld long V01 arg1 u:2[+8] Fseq[i] $380
+ // | | { | | { \--* st.lclVar long (P) V21 cse8
+ // | | { | | { \--* int V21.hi (offs=0x00) -> V22 rat0
+ // | | { | | { \--* int V21.hi (offs=0x04) -> V23 rat1
+ // | | { | | /--* lclVar int V22 rat0 $380
+ // | | { | | +--* lclVar int V23 rat1
+ // | | { | +--* gt_long long
+ // | | { \--* storeIndir long
+ // | +--* lclVar ref V11 tmp9 u:3 (last use) $21c
+ // | +--* lclVar ref V02 tmp0 u:3 $280
+ // | +--* const int 8 $4a
+ // \--* call help void HELPER.CORINFO_HELP_ARRADDR_ST $205
+ // <linkEndNode>
+ //
+ // (editor brace matching compensation: }}}}}}}}}}}}}}}}}})
+
+ GenTree* linkBegin = m_compiler->fgGetFirstNode(tree)->gtPrev;
+ GenTree* linkEnd = tree->gtNext;
+ GenTree* gtLong = tree->gtOp.gtOp2;
+
+ // Save address to a temp. It is used in storeIndLow and storeIndHigh trees.
+ GenTreeStmt* addrStmt = CreateTemporary(&tree->gtOp.gtOp1);
+ JITDUMP("[DecomposeStoreInd]: Saving address tree to a temp var:\n");
+ DISPTREE(addrStmt);
+
+ if (!gtLong->gtOp.gtOp1->OperIsLeaf())
+ {
+ GenTreeStmt* dataLowStmt = CreateTemporary(&gtLong->gtOp.gtOp1);
+ JITDUMP("[DecomposeStoreInd]: Saving low data tree to a temp var:\n");
+ DISPTREE(dataLowStmt);
+ }
+
+ if (!gtLong->gtOp.gtOp2->OperIsLeaf())
+ {
+ GenTreeStmt* dataHighStmt = CreateTemporary(&gtLong->gtOp.gtOp2);
+ JITDUMP("[DecomposeStoreInd]: Saving high data tree to a temp var:\n");
+ DISPTREE(dataHighStmt);
+ }
+
+ // Example trees after embedded statements for address and data are added.
+ // This example saves all address and data trees into temp variables
+ // to show how those embedded statements are created.
+ //
+ // * stmtExpr void (top level) (IL ???... ???)
+ // | /--* argPlace ref $280
+ // | +--* argPlace int $4a
+ // | | { * stmtExpr void (embedded) (IL ???... ???)
+ // | | { | /--* lclVar ref V11 tmp9 u:3 $21c
+ // | | { | +--* const int 4 $44
+ // | | { | /--* + byref $2c8
+ // | | { \--* st.lclVar byref V24 rat2
+ // | | { * stmtExpr void (embedded) (IL ???... ???)
+ // | | { | /--* lclVar byref V24 rat2
+ // | | { | | { * stmtExpr void (embedded) (IL ???... ???)
+ // | | { | | { | /--* lclFld long V01 arg1 u:2[+8] Fseq[i] $380380
+ // | | { | | { \--* st.lclVar long (P) V21 cse8
+ // | | { | | { \--* int V21.hi (offs=0x00) -> V22 rat0
+ // | | { | | { \--* int V21.hi (offs=0x04) -> V23 rat1
+ // | | { | | { * stmtExpr void (embedded) (IL ???... ???)
+ // | | { | | { | /--* lclVar int V22 rat0 $380
+ // | | { | | { \--* st.lclVar int V25 rat3
+ // | | { | | /--* lclVar int V25 rat3
+ // | | { | | | { * stmtExpr void (embedded) (IL ???... ???)
+ // | | { | | | { | /--* lclVar int V23 rat1
+ // | | { | | | { \--* st.lclVar int V26 rat4
+ // | | { | | +--* lclVar int V26 rat4
+ // | | { | +--* gt_long long
+ // | | { \--* storeIndir long
+ // | +--* lclVar ref V11 tmp9 u:3 (last use) $21c
+ // | +--* lclVar ref V02 tmp0 u:3 $280
+ // | +--* const int 8 $4a
+ // \--* call help void HELPER.CORINFO_HELP_ARRADDR_ST $205
+ //
+ // (editor brace matching compensation: }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}})
+
+ GenTree* addrBase = tree->gtOp.gtOp1;
+ GenTree* dataHigh = gtLong->gtOp.gtOp2;
+ GenTree* dataLow = gtLong->gtOp.gtOp1;
+ GenTree* storeIndLow = tree;
+
+ // Rewrite storeIndLow tree to save only lower 32-bit data.
+ //
+ // | | { | /--* lclVar byref V24 rat2 (address)
+ // ...
+ // | | { | +--* lclVar int V25 rat3 (lower 32-bit data)
+ // | | { | { * stmtExpr void (embedded) (IL ???... ???)
+ // | | { | { | /--* lclVar int V23 rat1
+ // | | { | { \--* st.lclVar int V26 rat4
+ // | | { \--* storeIndir int
+ //
+ // (editor brace matching compensation: }}}}}}}}})
+
+ m_compiler->fgSnipNode(curStmt, gtLong);
+ m_compiler->fgSnipNode(curStmt, dataHigh);
+ storeIndLow->gtOp.gtOp2 = dataLow;
+ storeIndLow->gtType = TYP_INT;
+
+ // Construct storeIndHigh tree
+ //
+ // | | { *stmtExpr void (embedded)(IL ? ? ? ... ? ? ? )
+ // | | { | / --* lclVar int V26 rat4
+ // | | { | | / --* lclVar byref V24 rat2
+ // | | { | +--* lea(b + 4) ref
+ // | | { \--* storeIndir int
+ //
+ // (editor brace matching compensation: }}}}})
+
+ GenTree* addrBaseHigh = new(m_compiler, GT_LCL_VAR) GenTreeLclVar(GT_LCL_VAR,
+ addrBase->TypeGet(), addrBase->AsLclVarCommon()->GetLclNum(), BAD_IL_OFFSET);
+ GenTree* addrHigh = new(m_compiler, GT_LEA) GenTreeAddrMode(TYP_REF, addrBaseHigh, nullptr, 0, genTypeSize(TYP_INT));
+ GenTree* storeIndHigh = new(m_compiler, GT_STOREIND) GenTreeStoreInd(TYP_INT, addrHigh, dataHigh);
+ storeIndHigh->gtFlags = (storeIndLow->gtFlags & (GTF_ALL_EFFECT | GTF_LIVENESS_MASK));
+ storeIndHigh->gtFlags |= GTF_REVERSE_OPS;
+ storeIndHigh->CopyCosts(storeIndLow);
+
+ // Internal links of storeIndHigh tree
+ dataHigh->gtPrev = nullptr;
+ dataHigh->gtNext = nullptr;
+ SimpleLinkNodeAfter(dataHigh, addrBaseHigh);
+ SimpleLinkNodeAfter(addrBaseHigh, addrHigh);
+ SimpleLinkNodeAfter(addrHigh, storeIndHigh);
+
+ // External links of storeIndHigh tree
+ //dataHigh->gtPrev = nullptr;
+ if (isEmbeddedStmt)
+ {
+ // If storeIndTree is an embedded statement, connect storeIndLow
+ // and dataHigh
+ storeIndLow->gtNext = dataHigh;
+ dataHigh->gtPrev = storeIndLow;
+ }
+ storeIndHigh->gtNext = linkEnd;
+ if (linkEnd != nullptr)
+ {
+ linkEnd->gtPrev = storeIndHigh;
+ }
+
+ InsertNodeAsStmt(storeIndHigh);
+
+ // Example final output
+ //
+ // * stmtExpr void (top level) (IL ???... ???)
+ // | /--* argPlace ref $280
+ // | +--* argPlace int $4a
+ // | | { * stmtExpr void (embedded) (IL ???... ???)
+ // | | { | /--* lclVar ref V11 tmp9 u:3 $21c
+ // | | { | +--* const int 4 $44
+ // | | { | /--* + byref $2c8
+ // | | { \--* st.lclVar byref V24 rat2
+ // | | { * stmtExpr void (embedded) (IL ???... ???)
+ // | | { | /--* lclVar byref V24 rat2
+ // | | { | | { * stmtExpr void (embedded) (IL ???... ???)
+ // | | { | | { | /--* lclFld int V01 arg1 u:2[+8] Fseq[i] $380
+ // | | { | | { | +--* lclFld int V01 arg1 [+12]
+ // | | { | | { | /--* gt_long long
+ // | | { | | { \--* st.lclVar long (P) V21 cse8
+ // | | { | | { \--* int V21.hi (offs=0x00) -> V22 rat0
+ // | | { | | { \--* int V21.hi (offs=0x04) -> V23 rat1
+ // | | { | | { * stmtExpr void (embedded) (IL ???... ???)
+ // | | { | | { | /--* lclVar int V22 rat0 $380
+ // | | { | | { \--* st.lclVar int V25 rat3
+ // | | { | +--* lclVar int V25 rat3
+ // | | { | { * stmtExpr void (embedded) (IL ???... ???)
+ // | | { | { | /--* lclVar int V23 rat1
+ // | | { | { \--* st.lclVar int V26 rat4
+ // | | { \--* storeIndir int
+ // | | { * stmtExpr void (embedded) (IL ???... ???)
+ // | | { | /--* lclVar int V26 rat4
+ // | | { | | /--* lclVar byref V24 rat2
+ // | | { | +--* lea(b+4) ref
+ // | | { \--* storeIndir int
+ // | | /--* lclVar ref V11 tmp9 u:3 (last use) $21c
+ // | +--* putarg_stk [+0x00] ref
+ // | | /--* lclVar ref V02 tmp0 u:3 $280
+ // | +--* putarg_reg ref
+ // | | /--* const int 8 $4a
+ // | +--* putarg_reg int
+ // \--* call help void HELPER.CORINFO_HELP_ARRADDR_ST $205
+ //
+ // (editor brace matching compensation: }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}})
+}
+
+
+//------------------------------------------------------------------------
+// DecomposeInd: Decompose GT_IND.
+//
+// Arguments:
+// tree - the tree to decompose
+//
+// Return Value:
+// None.
+//
+void DecomposeLongs::DecomposeInd(GenTree** ppTree, Compiler::fgWalkData* data)
+{
+ GenTreePtr indLow = *ppTree;
+ GenTreeStmt* addrStmt = CreateTemporary(&indLow->gtOp.gtOp1);
+ JITDUMP("[DecomposeInd]: Saving addr tree to a temp var:\n");
+ DISPTREE(addrStmt);
+
+ // Change the type of lower ind.
+ indLow->gtType = TYP_INT;
+
+ // Create tree of ind(addr+4)
+ GenTreePtr addrBase = indLow->gtGetOp1();
+ GenTreePtr addrBaseHigh = new(m_compiler, GT_LCL_VAR) GenTreeLclVar(GT_LCL_VAR,
+ addrBase->TypeGet(), addrBase->AsLclVarCommon()->GetLclNum(), BAD_IL_OFFSET);
+ GenTreePtr addrHigh = new(m_compiler, GT_LEA) GenTreeAddrMode(TYP_REF, addrBaseHigh, nullptr, 0, genTypeSize(TYP_INT));
+ GenTreePtr indHigh = new (m_compiler, GT_IND) GenTreeIndir(GT_IND, TYP_INT, addrHigh, nullptr);
+
+ // Connect linear links
+ SimpleLinkNodeAfter(addrBaseHigh, addrHigh);
+ SimpleLinkNodeAfter(addrHigh, indHigh);
+
+ FinalizeDecomposition(ppTree, data, indLow, indHigh);
+}
+
+//------------------------------------------------------------------------
+// DecomposeNot: Decompose GT_NOT.
+//
+// Arguments:
+// ppTree - the tree to decompose
+// data - tree walk context
+//
+// Return Value:
+// None.
+//
+void DecomposeLongs::DecomposeNot(GenTree** ppTree, Compiler::fgWalkData* data)
+{
+ assert(ppTree != nullptr);
+ assert(*ppTree != nullptr);
+ assert(data != nullptr);
+ assert((*ppTree)->OperGet() == GT_NOT);
+ assert(m_compiler->compCurStmt != nullptr);
+
+ GenTreeStmt* curStmt = m_compiler->compCurStmt->AsStmt();
+
+ GenTree* tree = *ppTree;
+ GenTree* op1 = tree->gtGetOp1();
+ noway_assert(op1->OperGet() == GT_LONG);
+ GenTree* loOp1 = op1->gtGetOp1();
+ GenTree* hiOp1 = op1->gtGetOp2();
+ m_compiler->fgSnipNode(curStmt, op1);
+
+ GenTree* loResult = tree;
+ loResult->gtType = TYP_INT;
+ loResult->gtOp.gtOp1 = loOp1;
+ loOp1->gtNext = loResult;
+ loResult->gtPrev = loOp1;
+
+ GenTree* hiResult = new (m_compiler, GT_NOT) GenTreeOp(GT_NOT, TYP_INT, hiOp1, nullptr);
+ hiOp1->gtNext = hiResult;
+ hiResult->gtPrev = hiOp1;
+
+ FinalizeDecomposition(ppTree, data, loResult, hiResult);
+}
+
+//------------------------------------------------------------------------
+// DecomposeNeg: Decompose GT_NEG.
+//
+// Arguments:
+// ppTree - the tree to decompose
+// data - tree walk context
+//
+// Return Value:
+// None.
+//
+void DecomposeLongs::DecomposeNeg(GenTree** ppTree, Compiler::fgWalkData* data)
+{
+ assert(ppTree != nullptr);
+ assert(*ppTree != nullptr);
+ assert(data != nullptr);
+ assert((*ppTree)->OperGet() == GT_NEG);
+ assert(m_compiler->compCurStmt != nullptr);
+
+ GenTreeStmt* curStmt = m_compiler->compCurStmt->AsStmt();
+ GenTree* tree = *ppTree;
+ GenTree* op1 = tree->gtGetOp1();
+ noway_assert(op1->OperGet() == GT_LONG);
+
+ CreateTemporary(&(op1->gtOp.gtOp1));
+ CreateTemporary(&(op1->gtOp.gtOp2));
+ // Neither GT_NEG nor the introduced temporaries have side effects.
+ tree->gtFlags &= ~GTF_ALL_EFFECT;
+ GenTree* loOp1 = op1->gtGetOp1();
+ GenTree* hiOp1 = op1->gtGetOp2();
+ Compiler::fgSnipNode(curStmt, op1);
+
+ GenTree* loResult = tree;
+ loResult->gtType = TYP_INT;
+ loResult->gtOp.gtOp1 = loOp1;
+
+ GenTree* zero = m_compiler->gtNewZeroConNode(TYP_INT);
+ GenTree* hiAdjust = m_compiler->gtNewOperNode(GT_ADD_HI, TYP_INT, hiOp1, zero);
+ GenTree* hiResult = m_compiler->gtNewOperNode(GT_NEG, TYP_INT, hiAdjust);
+ hiResult->gtFlags = tree->gtFlags;
+
+ Compiler::fgSnipNode(curStmt, hiOp1);
+ // fgSnipNode doesn't clear gtNext/gtPrev...
+ hiOp1->gtNext = nullptr;
+ hiOp1->gtPrev = nullptr;
+ SimpleLinkNodeAfter(hiOp1, zero);
+ SimpleLinkNodeAfter(zero, hiAdjust);
+ SimpleLinkNodeAfter(hiAdjust, hiResult);
+
+ FinalizeDecomposition(ppTree, data, loResult, hiResult);
+}
+
+//------------------------------------------------------------------------
+// DecomposeArith: Decompose GT_ADD, GT_SUB, GT_OR, GT_XOR, GT_AND.
+//
+// Arguments:
+// ppTree - the tree to decompose
+// data - tree walk context
+//
+// Return Value:
+// None.
+//
+void DecomposeLongs::DecomposeArith(GenTree** ppTree, Compiler::fgWalkData* data)
+{
+ assert(ppTree != nullptr);
+ assert(*ppTree != nullptr);
+ assert(data != nullptr);
+ assert(m_compiler->compCurStmt != nullptr);
+
+ GenTreeStmt* curStmt = m_compiler->compCurStmt->AsStmt();
+ GenTree* tree = *ppTree;
+ genTreeOps oper = tree->OperGet();
+
+ assert((oper == GT_ADD) ||
+ (oper == GT_SUB) ||
+ (oper == GT_OR) ||
+ (oper == GT_XOR) ||
+ (oper == GT_AND));
+
+ NYI_IF((tree->gtFlags & GTF_REVERSE_OPS) != 0, "Binary operator with GTF_REVERSE_OPS");
+
+ GenTree* op1 = tree->gtGetOp1();
+ GenTree* op2 = tree->gtGetOp2();
+
+ // Both operands must have already been decomposed into GT_LONG operators.
+ noway_assert((op1->OperGet() == GT_LONG) && (op2->OperGet() == GT_LONG));
+
+ // Capture the lo and hi halves of op1 and op2.
+ GenTree* loOp1 = op1->gtGetOp1();
+ GenTree* hiOp1 = op1->gtGetOp2();
+ GenTree* loOp2 = op2->gtGetOp1();
+ GenTree* hiOp2 = op2->gtGetOp2();
+
+ // We don't have support to decompose a TYP_LONG node that already has a child that has
+ // been decomposed into parts, where the high part depends on the value generated by the
+ // low part (via the flags register). For example, if we have:
+ // +(gt_long(+(lo3, lo4), +Hi(hi3, hi4)), gt_long(lo2, hi2))
+ // We would decompose it here to:
+ // gt_long(+(+(lo3, lo4), lo2), +Hi(+Hi(hi3, hi4), hi2))
+ // But this would generate incorrect code, because the "+Hi(hi3, hi4)" code generation
+ // needs to immediately follow the "+(lo3, lo4)" part. Also, if this node is one that
+ // requires a unique high operator, and the child nodes are not simple locals (e.g.,
+ // they are decomposed nodes), then we also can't decompose the node, as we aren't
+ // guaranteed the high and low parts will be executed immediately after each other.
+
+ NYI_IF(hiOp1->OperIsHigh() ||
+ hiOp2->OperIsHigh() ||
+ (GenTree::OperIsHigh(GetHiOper(oper)) &&
+ (!loOp1->OperIsLeaf() ||
+ !hiOp1->OperIsLeaf() ||
+ !loOp1->OperIsLeaf() ||
+ !hiOp2->OperIsLeaf())),
+ "Can't decompose expression tree TYP_LONG node");
+
+ // Now, remove op1 and op2 from the node list.
+ m_compiler->fgSnipNode(curStmt, op1);
+ m_compiler->fgSnipNode(curStmt, op2);
+
+ // We will reuse "tree" for the loResult, which will now be of TYP_INT, and its operands
+ // will be the lo halves of op1 from above.
+ GenTree* loResult = tree;
+ loResult->SetOper(GetLoOper(loResult->OperGet()));
+ loResult->gtType = TYP_INT;
+ loResult->gtOp.gtOp1 = loOp1;
+ loResult->gtOp.gtOp2 = loOp2;
+
+ // The various halves will be correctly threaded internally. We simply need to
+ // relink them into the proper order, i.e. loOp1 is followed by loOp2, and then
+ // the loResult node.
+ // (This rethreading, and that below, are where we need to address the reverse ops case).
+ // The current order is (after snipping op1 and op2):
+ // ... loOp1-> ... hiOp1->loOp2First ... loOp2->hiOp2First ... hiOp2
+ // The order we want is:
+ // ... loOp1->loOp2First ... loOp2->loResult
+ // ... hiOp1->hiOp2First ... hiOp2->hiResult
+ // i.e. we swap hiOp1 and loOp2, and create (for now) separate loResult and hiResult trees
+ GenTree* loOp2First = hiOp1->gtNext;
+ GenTree* hiOp2First = loOp2->gtNext;
+
+ // First, we will NYI if both hiOp1 and loOp2 have side effects.
+ NYI_IF(((loOp2->gtFlags & GTF_ALL_EFFECT) != 0) && ((hiOp1->gtFlags & GTF_ALL_EFFECT) != 0),
+ "Binary long operator with non-reorderable sub expressions");
+
+ // Now, we reorder the loOps and the loResult.
+ loOp1->gtNext = loOp2First;
+ loOp2First->gtPrev = loOp1;
+ loOp2->gtNext = loResult;
+ loResult->gtPrev = loOp2;
+
+ // Next, reorder the hiOps and the hiResult.
+ GenTree* hiResult = new (m_compiler, oper) GenTreeOp(GetHiOper(oper), TYP_INT, hiOp1, hiOp2);
+ hiOp1->gtNext = hiOp2First;
+ hiOp2First->gtPrev = hiOp1;
+ hiOp2->gtNext = hiResult;
+ hiResult->gtPrev = hiOp2;
+
+ if ((oper == GT_ADD) || (oper == GT_SUB))
+ {
+ if (loResult->gtOverflow())
+ {
+ hiResult->gtFlags |= GTF_OVERFLOW;
+ loResult->gtFlags &= ~GTF_OVERFLOW;
+ }
+ if (loResult->gtFlags & GTF_UNSIGNED)
+ {
+ hiResult->gtFlags |= GTF_UNSIGNED;
+ }
+ }
+
+ FinalizeDecomposition(ppTree, data, loResult, hiResult);
+}
+
+
+//------------------------------------------------------------------------
+// CreateTemporary: call fgInsertEmbeddedFormTemp to replace *ppTree with
+// a new temp that is assigned to the value previously at *ppTree by inserting
+// an embedded statement. In addition, if the resulting statement actually ends
+// up being top-level, it might pull along some embedded statements that have
+// not yet been decomposed. So recursively decompose those before returning.
+//
+// Arguments:
+// *ppTree - tree to replace with a temp.
+//
+// Return Value:
+// The new statement that was created to create the temp.
+//
+GenTreeStmt* DecomposeLongs::CreateTemporary(GenTree** ppTree)
+{
+ GenTreeStmt* newStmt = m_compiler->fgInsertEmbeddedFormTemp(ppTree);
+ if (newStmt->gtStmtIsTopLevel())
+ {
+ for (GenTreeStmt* nextEmbeddedStmt = newStmt->gtStmtNextIfEmbedded();
+ nextEmbeddedStmt != nullptr;
+ nextEmbeddedStmt = nextEmbeddedStmt->gtStmt.gtStmtNextIfEmbedded())
+ {
+ DecomposeStmt(nextEmbeddedStmt);
+ }
+ }
+
+ return newStmt;
+}
+
+
+//------------------------------------------------------------------------
+// InsertNodeAsStmt: Insert a node as the root node of a new statement.
+// If the current statement is embedded, the new statement will also be
+// embedded. Otherwise, the new statement will be top level.
+//
+// Arguments:
+// node - node to insert
+//
+// Return Value:
+// None
+//
+// Notes:
+// compCurStmt and compCurBB must be correctly set.
+//
+void DecomposeLongs::InsertNodeAsStmt(GenTree* node)
+{
+ assert(node != nullptr);
+ assert(m_compiler->compCurBB != nullptr);
+ assert(m_compiler->compCurStmt != nullptr);
+
+ GenTreeStmt* curStmt = m_compiler->compCurStmt->AsStmt();
+ GenTreeStmt* newStmt;
+
+ if (curStmt->gtStmtIsTopLevel())
+ {
+ newStmt = m_compiler->fgNewStmtFromTree(node);
+
+ // Find an insert point. Skip all embedded statements.
+ GenTree* insertPt = curStmt;
+ while ((insertPt->gtNext != nullptr) && (!insertPt->gtNext->AsStmt()->gtStmtIsTopLevel()))
+ {
+ insertPt = insertPt->gtNext;
+ }
+
+ m_compiler->fgInsertStmtAfter(m_compiler->compCurBB, insertPt, newStmt);
+ }
+ else
+ {
+ // The current statement is an embedded statement. Create a new embedded statement to
+ // contain the node. First, find the parent non-embedded statement containing the
+ // current statement.
+ GenTree* parentStmt = curStmt;
+ while ((parentStmt != nullptr) && (!parentStmt->AsStmt()->gtStmtIsTopLevel()))
+ {
+ parentStmt = parentStmt->gtPrev;
+ }
+ assert(parentStmt != nullptr);
+
+ newStmt = m_compiler->fgMakeEmbeddedStmt(m_compiler->compCurBB, node, parentStmt);
+ }
+
+ newStmt->gtStmtILoffsx = curStmt->gtStmtILoffsx;
+#ifdef DEBUG
+ newStmt->gtStmtLastILoffs = curStmt->gtStmtLastILoffs;
+#endif // DEBUG
+}
+
+
+//------------------------------------------------------------------------
+// GetHiOper: Convert arithmetic operator to "high half" operator of decomposed node.
+//
+// Arguments:
+// oper - operator to map
+//
+// Return Value:
+// mapped operator
+//
+// static
+genTreeOps DecomposeLongs::GetHiOper(genTreeOps oper)
+{
+ switch (oper)
+ {
+ case GT_ADD: return GT_ADD_HI; break;
+ case GT_SUB: return GT_SUB_HI; break;
+ case GT_MUL: return GT_MUL_HI; break;
+ case GT_DIV: return GT_DIV_HI; break;
+ case GT_MOD: return GT_MOD_HI; break;
+ case GT_OR: return GT_OR; break;
+ case GT_AND: return GT_AND; break;
+ case GT_XOR: return GT_XOR; break;
+ default:
+ assert(!"GetHiOper called for invalid oper");
+ return GT_NONE;
+ }
+}
+
+
+//------------------------------------------------------------------------
+// GetLoOper: Convert arithmetic operator to "low half" operator of decomposed node.
+//
+// Arguments:
+// oper - operator to map
+//
+// Return Value:
+// mapped operator
+//
+// static
+genTreeOps DecomposeLongs::GetLoOper(genTreeOps oper)
+{
+ switch (oper)
+ {
+ case GT_ADD: return GT_ADD_LO; break;
+ case GT_SUB: return GT_SUB_LO; break;
+ case GT_OR: return GT_OR; break;
+ case GT_AND: return GT_AND; break;
+ case GT_XOR: return GT_XOR; break;
+ default:
+ assert(!"GetLoOper called for invalid oper");
+ return GT_NONE;
+ }
+}
+
+
+//------------------------------------------------------------------------
+// SimpleLinkNodeAfter: insert a node after a given node in the execution order.
+// NOTE: Does not support inserting after the last node of a statement, which
+// would require updating the statement links.
+//
+// Arguments:
+// insertionPoint - Insert after this tree node.
+// node - The node to insert.
+//
+// Return Value:
+// None
+//
+// Notes:
+// Seems like this should be moved to someplace that houses all the flowgraph
+// manipulation functions.
+//
+void DecomposeLongs::SimpleLinkNodeAfter(GenTree* insertionPoint, GenTree* node)
+{
+ assert(insertionPoint != nullptr);
+ assert(node != nullptr);
+
+ GenTree* nextTree = insertionPoint->gtNext;
+ node->gtPrev = insertionPoint;
+ node->gtNext = nextTree;
+ insertionPoint->gtNext = node;
+ if (nextTree != nullptr)
+ {
+ nextTree->gtPrev = node;
+ }
+}
+
+
+#endif // !_TARGET_64BIT_
+#endif // !LEGACY_BACKEND \ No newline at end of file
diff --git a/src/jit/decomposelongs.h b/src/jit/decomposelongs.h
new file mode 100644
index 0000000000..778e6de244
--- /dev/null
+++ b/src/jit/decomposelongs.h
@@ -0,0 +1,63 @@
+// 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.
+
+/*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XX XX
+XX DecomposeLongs XX
+XX XX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+*/
+
+#ifndef _DECOMPOSELONGS_H_
+#define _DECOMPOSELONGS_H_
+
+#include "compiler.h"
+
+class DecomposeLongs
+{
+public:
+
+ DecomposeLongs(Compiler* compiler)
+ : m_compiler(compiler)
+ {
+ }
+
+ void PrepareForDecomposition();
+ void DecomposeBlock(BasicBlock* block);
+
+private:
+
+ // Driver functions
+ static Compiler::fgWalkResult DecompNodeHelper(GenTree** ppTree, Compiler::fgWalkData* data);
+ void DecomposeStmt(GenTreeStmt* stmt);
+ void DecomposeNode(GenTree** ppTree, Compiler::fgWalkData* data);
+
+ // Per-node type decompose cases
+ void DecomposeLclVar(GenTree** ppTree, Compiler::fgWalkData* data);
+ void DecomposeLclFld(GenTree** ppTree, Compiler::fgWalkData* data);
+ void DecomposeStoreLclVar(GenTree** ppTree, Compiler::fgWalkData* data);
+ void DecomposeCast(GenTree** ppTree, Compiler::fgWalkData* data);
+ void DecomposeCnsLng(GenTree** ppTree, Compiler::fgWalkData* data);
+ void DecomposeCall(GenTree** ppTree, Compiler::fgWalkData* data);
+ void DecomposeInd(GenTree** ppTree, Compiler::fgWalkData* data);
+ void DecomposeStoreInd(GenTree** ppTree, Compiler::fgWalkData* data);
+ void DecomposeNot(GenTree** ppTree, Compiler::fgWalkData* data);
+ void DecomposeNeg(GenTree** ppTree, Compiler::fgWalkData* data);
+ void DecomposeArith(GenTree** ppTree, Compiler::fgWalkData* data);
+
+ // Helper functions
+ void FinalizeDecomposition(GenTree** ppTree, Compiler::fgWalkData* data, GenTree* loResult, GenTree* hiResult);
+ void InsertNodeAsStmt(GenTree* node);
+ GenTreeStmt* CreateTemporary(GenTree** ppTree);
+ static genTreeOps GetHiOper(genTreeOps oper);
+ static genTreeOps GetLoOper(genTreeOps oper);
+ void SimpleLinkNodeAfter(GenTree* insertionPoint, GenTree* node);
+
+ // Data
+ Compiler* m_compiler;
+};
+
+#endif // _DECOMPOSELONGS_H_
diff --git a/src/jit/emitxarch.cpp b/src/jit/emitxarch.cpp
index 388a51d82d..632cc023e5 100644
--- a/src/jit/emitxarch.cpp
+++ b/src/jit/emitxarch.cpp
@@ -2893,7 +2893,7 @@ regNumber emitter::emitInsBinary(instruction ins, emitAttr attr, GenTree* dst, G
{
dblConst = src->AsDblCon();
}
-
+
// find local field if any
GenTreeLclFld* lclField = nullptr;
if (src->isContainedLclField())
@@ -2918,9 +2918,25 @@ regNumber emitter::emitInsBinary(instruction ins, emitAttr attr, GenTree* dst, G
lclVar = dst->AsLclVar();
}
+ // find contained spill tmp if any
+ TempDsc* tmpDsc = nullptr;
+ if (src->isContainedSpillTemp())
+ {
+ assert(src->IsRegOptional());
+ tmpDsc = codeGen->getSpillTempDsc(src);
+ }
+ else if (dst->isContainedSpillTemp())
+ {
+ assert(dst->IsRegOptional());
+ tmpDsc = codeGen->getSpillTempDsc(dst);
+ }
+
// First handle the simple non-memory cases
//
- if ((mem == nullptr) && (lclField == nullptr) && (lclVar == nullptr))
+ if ((mem == nullptr) &&
+ (lclField == nullptr) &&
+ (lclVar == nullptr) &&
+ (tmpDsc == nullptr))
{
if (intConst != nullptr)
{
@@ -2959,7 +2975,7 @@ regNumber emitter::emitInsBinary(instruction ins, emitAttr attr, GenTree* dst, G
// Next handle the cases where we have a stack based local memory operand.
//
unsigned varNum = BAD_VAR_NUM;
- unsigned offset = (unsigned) -1;
+ unsigned offset = (unsigned)-1;
if (lclField != nullptr)
{
@@ -2971,12 +2987,22 @@ regNumber emitter::emitInsBinary(instruction ins, emitAttr attr, GenTree* dst, G
varNum = lclVar->AsLclVarCommon()->GetLclNum();
offset = 0;
}
+ else if (tmpDsc != nullptr)
+ {
+ varNum = tmpDsc->tdTempNum();
+ offset = 0;
+ }
- if (varNum != BAD_VAR_NUM)
+ // Spill temp numbers are negative and start with -1
+ // which also happens to be BAD_VAR_NUM. For this reason
+ // we also need to check 'tmpDsc != nullptr' here.
+ if (varNum != BAD_VAR_NUM ||
+ tmpDsc != nullptr)
{
// Is the memory op in the source position?
if (src->isContainedLclField() ||
- src->isContainedLclVar())
+ src->isContainedLclVar() ||
+ src->isContainedSpillTemp())
{
if (instrHasImplicitRegPairDest(ins))
{
@@ -2993,7 +3019,7 @@ regNumber emitter::emitInsBinary(instruction ins, emitAttr attr, GenTree* dst, G
}
else // The memory op is in the dest position.
{
- assert(dst->gtRegNum == REG_NA);
+ assert(dst->gtRegNum == REG_NA || dst->IsRegOptional());
// src could be int or reg
if (src->isContainedIntOrIImmed())
@@ -3011,6 +3037,11 @@ regNumber emitter::emitInsBinary(instruction ins, emitAttr attr, GenTree* dst, G
}
}
+ if (tmpDsc != nullptr)
+ {
+ emitComp->tmpRlsTemp(tmpDsc);
+ }
+
return dst->gtRegNum;
}
diff --git a/src/jit/flowgraph.cpp b/src/jit/flowgraph.cpp
index c2ceaa70ac..32e069f524 100644
--- a/src/jit/flowgraph.cpp
+++ b/src/jit/flowgraph.cpp
@@ -702,7 +702,7 @@ GenTreeStmt* Compiler::fgInsertStmtNearEnd(BasicBlock* block, GenTreePtr node)
*
* Insert the given statement "stmt" after GT_STMT node "insertionPoint".
* Returns the newly inserted GT_STMT node.
- * Note that the gtPrev list of statment nodes is circular, but the gtNext list is not.
+ * Note that the gtPrev list of statement nodes is circular, but the gtNext list is not.
*/
GenTreePtr Compiler::fgInsertStmtAfter(BasicBlock* block,
@@ -4954,39 +4954,54 @@ void Compiler::fgAdjustForAddressExposedOrWrittenThis()
//
// If we're inlining we also look at the argument values supplied by
// the caller at this call site.
+//
+// The crude stack model may overestimate stack depth.
void Compiler::fgObserveInlineConstants(OPCODE opcode, const FgStack& stack, bool isInlining)
{
// We should be able to record inline observations.
assert(compInlineResult != nullptr);
- if (!stack.IsStackTwoDeep())
+ // The stack only has to be 1 deep for BRTRUE/FALSE
+ bool lookForBranchCases = stack.IsStackAtLeastOneDeep();
+
+ if (compInlineResult->UsesLegacyPolicy())
{
- // The stack only has to be 1 deep for BRTRUE/FALSE
- if (stack.IsStackOneDeep())
+ // LegacyPolicy misses cases where the stack is really one
+ // deep but the model says it's two deep. We need to do
+ // likewise to preseve old behavior.
+ lookForBranchCases &= !stack.IsStackTwoDeep();
+ }
+
+ if (lookForBranchCases)
+ {
+ if (opcode == CEE_BRFALSE || opcode == CEE_BRFALSE_S ||
+ opcode == CEE_BRTRUE || opcode == CEE_BRTRUE_S)
{
- if (opcode == CEE_BRFALSE || opcode == CEE_BRFALSE_S ||
- opcode == CEE_BRTRUE || opcode == CEE_BRTRUE_S)
+ unsigned slot0 = stack.GetSlot0();
+ if (FgStack::IsArgument(slot0))
{
- unsigned slot0 = stack.GetSlot0();
- if (FgStack::IsArgument(slot0))
- {
- compInlineResult->Note(InlineObservation::CALLEE_ARG_FEEDS_CONSTANT_TEST);
+ compInlineResult->Note(InlineObservation::CALLEE_ARG_FEEDS_CONSTANT_TEST);
- if (isInlining)
+ if (isInlining)
+ {
+ // Check for the double whammy of an incoming constant argument
+ // feeding a constant test.
+ unsigned varNum = FgStack::SlotTypeToArgNum(slot0);
+ if (impInlineInfo->inlArgInfo[varNum].argNode->OperIsConst())
{
- // Check for the double whammy of an incoming constant argument
- // feeding a constant test.
- unsigned varNum = FgStack::SlotTypeToArgNum(slot0);
- if (impInlineInfo->inlArgInfo[varNum].argNode->OperIsConst())
- {
- compInlineResult->Note(InlineObservation::CALLSITE_CONSTANT_ARG_FEEDS_TEST);
- }
+ compInlineResult->Note(InlineObservation::CALLSITE_CONSTANT_ARG_FEEDS_TEST);
}
}
}
+
+ return;
}
+ }
+ // Remaining cases require at least two things on the stack.
+ if (!stack.IsStackTwoDeep())
+ {
return;
}
@@ -6756,13 +6771,23 @@ bool Compiler::fgIsCommaThrow(GenTreePtr tree,
return false;
}
-
+//------------------------------------------------------------------------
+// fgIsIndirOfAddrOfLocal: Determine whether "tree" is an indirection of a local.
+//
+// Arguments:
+// tree - The tree node under consideration
+//
+// Return Value:
+// If "tree" is a indirection (GT_IND, GT_BLK, or GT_OBJ) whose arg is an ADDR,
+// whose arg in turn is a LCL_VAR, return that LCL_VAR node, else nullptr.
+//
+// static
GenTreePtr Compiler::fgIsIndirOfAddrOfLocal(GenTreePtr tree)
{
GenTreePtr res = nullptr;
- if (tree->OperGet() == GT_OBJ || tree->OperIsIndir())
+ if (tree->OperIsIndir())
{
- GenTreePtr addr = tree->gtOp.gtOp1;
+ GenTreePtr addr = tree->AsIndir()->Addr();
// Post rationalization, we can have Indir(Lea(..) trees. Therefore to recognize
// Indir of addr of a local, skip over Lea in Indir(Lea(base, index, scale, offset))
@@ -18240,7 +18265,7 @@ void Compiler::fgOrderBlockOps(GenTreePtr tree,
// The nearest one might be 'stmt' itself.
//
// Arguments:
-// stmt - The statment to start the search with.
+// stmt - The statement to start the search with.
//
// Return Value:
// The nearest top-level statement, walking backwards.
@@ -18426,7 +18451,7 @@ void Compiler::fgDeleteTreeFromList(GenTreeStmt* stmt, GenTreePtr tree)
//------------------------------------------------------------------------
-// fgTreeIsInStmt: return 'true' if 'tree' is in the execution order list of statment 'stmt'.
+// fgTreeIsInStmt: return 'true' if 'tree' is in the execution order list of statement 'stmt'.
// This works for a single node or an entire tree, assuming a well-formed tree, where the entire
// tree's set of nodes are in the statement execution order list.
//
@@ -18540,7 +18565,7 @@ GenTreeStmt* Compiler::fgInsertTreeBeforeAsEmbedded(GenTree* tree, GenTree* inse
fgInsertTreeInListBefore(tree, insertionPoint, stmt);
// While inserting a statement as embedded, the parent specified has to be a top-level statement
- // since we could be inserting it ahead of an already existing embedded statment
+ // since we could be inserting it ahead of an already existing embedded statement
// in execution order.
GenTreeStmt* topStmt = fgFindTopLevelStmtBackwards(stmt);
GenTreeStmt* result = fgMakeEmbeddedStmt(block, tree, topStmt);
@@ -21997,6 +22022,12 @@ void Compiler::fgInsertInlineeBlocks(InlineInfo* pInlineInfo)
stmtAfter = fgInsertStmtListAfter(iciBlock,
stmtAfter,
InlineeCompiler->fgFirstBB->bbTreeList);
+
+ // Copy inlinee bbFlags to caller bbFlags.
+ const unsigned int inlineeBlockFlags = InlineeCompiler->fgFirstBB->bbFlags;
+ noway_assert((inlineeBlockFlags & BBF_HAS_JMP) == 0);
+ noway_assert((inlineeBlockFlags & BBF_KEEP_BBJ_ALWAYS) == 0);
+ iciBlock->bbFlags |= inlineeBlockFlags;
}
#ifdef DEBUG
if (verbose)
@@ -22237,7 +22268,7 @@ _Done:
//
// Detach the GT_CALL node from the original statement by hanging a "nothing" node under it,
- // so that fgMorphStmts can remove the statment once we return from here.
+ // so that fgMorphStmts can remove the statement once we return from here.
//
iciStmt->gtStmt.gtStmtExpr = gtNewNothingNode();
}
diff --git a/src/jit/gcencode.cpp b/src/jit/gcencode.cpp
index c3ae12bcf4..fb033ddfae 100644
--- a/src/jit/gcencode.cpp
+++ b/src/jit/gcencode.cpp
@@ -21,7 +21,7 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
#endif
-#include "gcinfo.h"
+#include "gcinfotypes.h"
#ifdef JIT32_GCENCODER
@@ -3236,7 +3236,7 @@ unsigned GCInfo::gcInfoBlockHdrDump(const BYTE* table,
InfoHdr* header,
unsigned* methodSize)
{
- GCDump gcDump;
+ GCDump gcDump(GCINFO_VERSION);
gcDump.gcPrintf = gcDump_logf; // use my printf (which logs to VM)
printf("Method info block:\n");
@@ -3252,7 +3252,7 @@ unsigned GCInfo::gcDumpPtrTable(const BYTE* table,
{
printf("Pointer table:\n");
- GCDump gcDump;
+ GCDump gcDump(GCINFO_VERSION);
gcDump.gcPrintf = gcDump_logf; // use my printf (which logs to VM)
return gcDump.DumpGCTable(table, header, methodSize, verifyGCTables);
@@ -3268,7 +3268,7 @@ void GCInfo::gcFindPtrsInFrame(const void* infoBlock,
const void* codeBlock,
unsigned offs)
{
- GCDump gcDump;
+ GCDump gcDump(GCINFO_VERSION);
gcDump.gcPrintf = gcDump_logf; // use my printf (which logs to VM)
gcDump.DumpPtrsInFrame((const BYTE*)infoBlock, (const BYTE*)codeBlock, offs, verifyGCTables);
diff --git a/src/jit/gentree.cpp b/src/jit/gentree.cpp
index 30f25b2c57..f9addbb490 100644
--- a/src/jit/gentree.cpp
+++ b/src/jit/gentree.cpp
@@ -2978,6 +2978,71 @@ bool Compiler::gtIsLikelyRegVar(GenTree * tree)
return true;
}
+//------------------------------------------------------------------------
+// gtCanSwapOrder: Returns true iff the secondNode can be swapped with firstNode.
+//
+// Arguments:
+// firstNode - An operand of a tree that can have GTF_REVERSE_OPS set.
+// secondNode - The other operand of the tree.
+//
+// Return Value:
+// Returns a boolean indicating whether it is safe to reverse the execution
+// order of the two trees, considering any exception, global effects, or
+// ordering constraints.
+//
+bool
+Compiler::gtCanSwapOrder(GenTree* firstNode, GenTree* secondNode)
+{
+ // Relative of order of global / side effects can't be swapped.
+
+ bool canSwap = true;
+
+ if (optValnumCSE_phase)
+ {
+ canSwap = optCSE_canSwap(firstNode, secondNode);
+ }
+
+ // We cannot swap in the presence of special side effects such as GT_CATCH_ARG.
+
+ if (canSwap &&
+ (firstNode->gtFlags & GTF_ORDER_SIDEEFF))
+ {
+ canSwap = false;
+ }
+
+ // When strict side effect order is disabled we allow GTF_REVERSE_OPS to be set
+ // when one or both sides contains a GTF_CALL or GTF_EXCEPT.
+ // Currently only the C and C++ languages allow non strict side effect order.
+
+ unsigned strictEffects = GTF_GLOB_EFFECT;
+
+ if (canSwap &&
+ (firstNode->gtFlags & strictEffects))
+ {
+ // op1 has side efects that can't be reordered.
+ // Check for some special cases where we still may be able to swap.
+
+ if (secondNode->gtFlags & strictEffects)
+ {
+ // op2 has also has non reorderable side effects - can't swap.
+ canSwap = false;
+ }
+ else
+ {
+ // No side effects in op2 - we can swap iff op1 has no way of modifying op2,
+ // i.e. through byref assignments or calls or op2 is a constant.
+
+ if (firstNode->gtFlags & strictEffects & GTF_PERSISTENT_SIDE_EFFECTS)
+ {
+ // We have to be conservative - can swap iff op2 is constant.
+ if (!secondNode->OperIsConst())
+ canSwap = false;
+ }
+ }
+ }
+ return canSwap;
+}
+
/*****************************************************************************
*
* Given a tree, figure out the order in which its sub-operands should be
@@ -3543,17 +3608,18 @@ COMMON_CNS:
unsigned mul;
#endif
unsigned cns;
- GenTreePtr adr;
+ GenTreePtr base;
GenTreePtr idx;
/* See if we can form a complex addressing mode? */
- if (codeGen->genCreateAddrMode(op1, // address
+ GenTreePtr addr = op1;
+ if (codeGen->genCreateAddrMode(addr, // address
0, // mode
false, // fold
RBM_NONE, // reg mask
&rev, // reverse ops
- &adr, // base addr
+ &base, // base addr
&idx, // index val
#if SCALED_ADDR_MODES
&mul, // scaling
@@ -3564,17 +3630,17 @@ COMMON_CNS:
// We can form a complex addressing mode, so mark each of the interior
// nodes with GTF_ADDRMODE_NO_CSE and calculate a more accurate cost.
- op1->gtFlags |= GTF_ADDRMODE_NO_CSE;
+ addr->gtFlags |= GTF_ADDRMODE_NO_CSE;
#ifdef _TARGET_XARCH_
// addrmodeCount is the count of items that we used to form
// an addressing mode. The maximum value is 4 when we have
- // all of these: { adr, idx, cns, mul }
+ // all of these: { base, idx, cns, mul }
//
unsigned addrmodeCount = 0;
- if (adr)
+ if (base)
{
- costEx += adr->gtCostEx;
- costSz += adr->gtCostSz;
+ costEx += base->gtCostEx;
+ costSz += base->gtCostSz;
addrmodeCount++;
}
@@ -3604,7 +3670,7 @@ COMMON_CNS:
// / \ --
// GT_ADD 'cns' -- reduce this interior GT_ADD by (-2,-2)
// / \ --
- // 'adr' GT_LSL -- reduce this interior GT_LSL by (-1,-1)
+ // 'base' GT_LSL -- reduce this interior GT_LSL by (-1,-1)
// / \ --
// 'idx' 'mul'
//
@@ -3614,7 +3680,7 @@ COMMON_CNS:
//
addrmodeCount--;
- GenTreePtr tmp = op1;
+ GenTreePtr tmp = addr;
while (addrmodeCount > 0)
{
// decrement the gtCosts for the interior GT_ADD or GT_LSH node by the remaining addrmodeCount
@@ -3627,7 +3693,7 @@ COMMON_CNS:
GenTreePtr tmpOp2 = tmp->gtGetOp2();
assert(tmpOp2 != nullptr);
- if ((tmpOp1 != adr) && (tmpOp1->OperGet() == GT_ADD))
+ if ((tmpOp1 != base) && (tmpOp1->OperGet() == GT_ADD))
{
tmp = tmpOp1;
}
@@ -3653,11 +3719,11 @@ COMMON_CNS:
}
}
#elif defined _TARGET_ARM_
- if (adr)
+ if (base)
{
- costEx += adr->gtCostEx;
- costSz += adr->gtCostSz;
- if ((adr->gtOper == GT_LCL_VAR) &&
+ costEx += base->gtCostEx;
+ costSz += base->gtCostSz;
+ if ((base->gtOper == GT_LCL_VAR) &&
((idx==NULL) || (cns==0)))
{
costSz -= 1;
@@ -3691,10 +3757,10 @@ COMMON_CNS:
}
}
#elif defined _TARGET_ARM64_
- if (adr)
+ if (base)
{
- costEx += adr->gtCostEx;
- costSz += adr->gtCostSz;
+ costEx += base->gtCostEx;
+ costSz += base->gtCostSz;
}
if (idx)
@@ -3715,62 +3781,62 @@ COMMON_CNS:
#error "Unknown _TARGET_"
#endif
- assert(op1->gtOper == GT_ADD);
- assert(!op1->gtOverflow());
+ assert(addr->gtOper == GT_ADD);
+ assert(!addr->gtOverflow());
assert(op2 == NULL);
assert(mul != 1);
// If we have an addressing mode, we have one of:
- // [adr + cns]
- // [ idx * mul ] // mul >= 2, else we would use adr instead of idx
- // [ idx * mul + cns] // mul >= 2, else we would use adr instead of idx
- // [adr + idx * mul ] // mul can be 0, 2, 4, or 8
- // [adr + idx * mul + cns] // mul can be 0, 2, 4, or 8
+ // [base + cns]
+ // [ idx * mul ] // mul >= 2, else we would use base instead of idx
+ // [ idx * mul + cns] // mul >= 2, else we would use base instead of idx
+ // [base + idx * mul ] // mul can be 0, 2, 4, or 8
+ // [base + idx * mul + cns] // mul can be 0, 2, 4, or 8
// Note that mul == 0 is semantically equivalent to mul == 1.
// Note that cns can be zero.
#if SCALED_ADDR_MODES
- assert((adr != NULL) || (idx != NULL && mul >= 2));
+ assert((base != NULL) || (idx != NULL && mul >= 2));
#else
- assert(adr != NULL);
+ assert(base != NULL);
#endif
- INDEBUG(GenTreePtr op1Save = op1);
+ INDEBUG(GenTreePtr op1Save = addr);
- /* Walk op1 looking for non-overflow GT_ADDs */
- gtWalkOp(&op1, &op2, adr, false);
+ /* Walk addr looking for non-overflow GT_ADDs */
+ gtWalkOp(&addr, &op2, base, false);
- // op1 and op2 are now children of the root GT_ADD of the addressing mode
- assert(op1 != op1Save);
+ // addr and op2 are now children of the root GT_ADD of the addressing mode
+ assert(addr != op1Save);
assert(op2 != NULL);
- /* Walk op1 looking for non-overflow GT_ADDs of constants */
- gtWalkOp(&op1, &op2, NULL, true);
+ /* Walk addr looking for non-overflow GT_ADDs of constants */
+ gtWalkOp(&addr, &op2, NULL, true);
// TODO-Cleanup: It seems very strange that we might walk down op2 now, even though the prior
// call to gtWalkOp() may have altered op2.
/* Walk op2 looking for non-overflow GT_ADDs of constants */
- gtWalkOp(&op2, &op1, NULL, true);
+ gtWalkOp(&op2, &addr, NULL, true);
// OK we are done walking the tree
- // Now assert that op1 and op2 correspond with adr and idx
+ // Now assert that addr and op2 correspond with base and idx
// in one of the several acceptable ways.
- // Note that sometimes op1/op2 is equal to idx/adr
- // and other times op1/op2 is a GT_COMMA node with
- // an effective value that is idx/adr
+ // Note that sometimes addr/op2 is equal to idx/base
+ // and other times addr/op2 is a GT_COMMA node with
+ // an effective value that is idx/base
if (mul > 1)
{
- if ((op1 != adr) && (op1->gtOper == GT_LSH))
+ if ((addr != base) && (addr->gtOper == GT_LSH))
{
- op1->gtFlags |= GTF_ADDRMODE_NO_CSE;
- if (op1->gtOp.gtOp1->gtOper == GT_MUL)
+ addr->gtFlags |= GTF_ADDRMODE_NO_CSE;
+ if (addr->gtOp.gtOp1->gtOper == GT_MUL)
{
- op1->gtOp.gtOp1->gtFlags |= GTF_ADDRMODE_NO_CSE;
+ addr->gtOp.gtOp1->gtFlags |= GTF_ADDRMODE_NO_CSE;
}
- assert((adr == NULL) || (op2 == adr) || (op2->gtEffectiveVal() == adr->gtEffectiveVal()) ||
- (gtWalkOpEffectiveVal(op2) == gtWalkOpEffectiveVal(adr)));
+ assert((base == NULL) || (op2 == base) || (op2->gtEffectiveVal() == base->gtEffectiveVal()) ||
+ (gtWalkOpEffectiveVal(op2) == gtWalkOpEffectiveVal(base)));
}
else
{
@@ -3785,7 +3851,7 @@ COMMON_CNS:
op2op1->gtFlags |= GTF_ADDRMODE_NO_CSE;
op2op1 = op2op1->gtOp.gtOp1;
}
- assert(op1->gtEffectiveVal() == adr);
+ assert(addr->gtEffectiveVal() == base);
assert(op2op1 == idx);
}
}
@@ -3793,24 +3859,24 @@ COMMON_CNS:
{
assert(mul == 0);
- if ((op1 == idx) || (op1->gtEffectiveVal() == idx))
+ if ((addr == idx) || (addr->gtEffectiveVal() == idx))
{
if (idx != NULL)
{
- if ((op1->gtOper == GT_MUL) || (op1->gtOper == GT_LSH))
+ if ((addr->gtOper == GT_MUL) || (addr->gtOper == GT_LSH))
{
- if ((op1->gtOp.gtOp1->gtOper == GT_NOP) ||
- (op1->gtOp.gtOp1->gtOper == GT_MUL && op1->gtOp.gtOp1->gtOp.gtOp1->gtOper == GT_NOP))
+ if ((addr->gtOp.gtOp1->gtOper == GT_NOP) ||
+ (addr->gtOp.gtOp1->gtOper == GT_MUL && addr->gtOp.gtOp1->gtOp.gtOp1->gtOper == GT_NOP))
{
- op1->gtFlags |= GTF_ADDRMODE_NO_CSE;
- if (op1->gtOp.gtOp1->gtOper == GT_MUL)
- op1->gtOp.gtOp1->gtFlags |= GTF_ADDRMODE_NO_CSE;
+ addr->gtFlags |= GTF_ADDRMODE_NO_CSE;
+ if (addr->gtOp.gtOp1->gtOper == GT_MUL)
+ addr->gtOp.gtOp1->gtFlags |= GTF_ADDRMODE_NO_CSE;
}
}
}
- assert((op2 == adr) || (op2->gtEffectiveVal() == adr));
+ assert((op2 == base) || (op2->gtEffectiveVal() == base));
}
- else if ((op1 == adr) || (op1->gtEffectiveVal() == adr))
+ else if ((addr == base) || (addr->gtEffectiveVal() == base))
{
if (idx != NULL)
{
@@ -3831,7 +3897,7 @@ COMMON_CNS:
}
else
{
- // op1 isn't adr or idx. Is this possible? Or should there be an assert?
+ // addr isn't base or idx. Is this possible? Or should there be an assert?
}
}
goto DONE;
@@ -4302,60 +4368,7 @@ COMMON_CNS:
if (tryToSwap)
{
- /* Relative of order of global / side effects can't be swapped */
-
- bool canSwap = true;
-
- if (optValnumCSE_phase)
- {
- canSwap = optCSE_canSwap(tree);
- }
-
- /* We cannot swap in the presence of special side effects such as GT_CATCH_ARG */
-
- if (canSwap &&
- (opA->gtFlags & GTF_ORDER_SIDEEFF))
- {
- canSwap = false;
- }
-
- /* When strict side effect order is disabled we allow
- * GTF_REVERSE_OPS to be set when one or both sides contains
- * a GTF_CALL or GTF_EXCEPT.
- * Currently only the C and C++ languages
- * allow non strict side effect order
- */
- unsigned strictEffects = GTF_GLOB_EFFECT;
-
- if (canSwap &&
- (opA->gtFlags & strictEffects))
- {
- /* op1 has side efects, that can't be reordered.
- * Check for some special cases where we still
- * may be able to swap
- */
-
- if (opB->gtFlags & strictEffects)
- {
- /* op2 has also has non reorderable side effects - can't swap */
- canSwap = false;
- }
- else
- {
- /* No side effects in op2 - we can swap iff
- * op1 has no way of modifying op2,
- * i.e. through byref assignments or calls
- * unless op2 is a constant
- */
-
- if (opA->gtFlags & strictEffects & GTF_PERSISTENT_SIDE_EFFECTS)
- {
- /* We have to be conservative - can swap iff op2 is constant */
- if (!opB->OperIsConst())
- canSwap = false;
- }
- }
- }
+ bool canSwap = gtCanSwapOrder(opA, opB);
if (canSwap)
{
@@ -8074,10 +8087,15 @@ void Compiler::gtDispNode(GenTreePtr tree,
// If we have an indent stack, don't add additional characters,
// as it will mess up the alignment.
- if (tree->gtOper != GT_STMT && hasSeqNum && (indentStack == nullptr))
+ bool displayDotNum = tree->gtOper != GT_STMT && hasSeqNum && (indentStack == nullptr);
+ if (displayDotNum)
+ {
printf("N%03u.%02u ", prev->gtSeqNum, dotNum);
+ }
else
+ {
printf(" ");
+ }
if (tree->gtCostsInitialized)
{
@@ -8085,7 +8103,7 @@ void Compiler::gtDispNode(GenTreePtr tree,
}
else
{
- if (tree->gtOper != GT_STMT && hasSeqNum)
+ if (displayDotNum)
{
// Do better alignment in this case
printf(" ");
@@ -12191,7 +12209,7 @@ void Compiler::gtExtractSideEffList(GenTreePtr expr, GenTreePtr *
// Special case - GT_ADDR of GT_IND nodes of TYP_STRUCT
// have to be kept together
- if (oper == GT_ADDR && op1->gtOper == GT_IND && op1->gtType == TYP_STRUCT)
+ if (oper == GT_ADDR && op1->OperIsIndir() && op1->gtType == TYP_STRUCT)
{
*pList = gtBuildCommaList(*pList, expr);
@@ -13306,13 +13324,22 @@ GenTree::IsLclVarUpdateTree(GenTree** pOtherTree, genTreeOps *pOper)
// until after the LSRA phase has allocated physical registers to the treenodes.
bool GenTree::isContained() const
{
+ if (isContainedSpillTemp())
+ {
+ return true;
+ }
+
if (gtHasReg())
+ {
return false;
+ }
// these actually produce a register (the flags reg, we just don't model it)
// and are a separate instruction from the branch that consumes the result
if (OperKind() & GTK_RELOP)
+ {
return false;
+ }
// TODO-Cleanup : this is not clean, would be nice to have some way of marking this.
switch (OperGet())
@@ -13388,7 +13415,7 @@ bool GenTree::isContainedIndir() const
bool GenTree::isIndirAddrMode()
{
- return isIndir() && gtOp.gtOp1->OperIsAddrMode() && gtOp.gtOp1->isContained();
+ return isIndir() && AsIndir()->Addr()->OperIsAddrMode() && AsIndir()->Addr()->isContained();
}
bool GenTree::isIndir() const
@@ -14041,7 +14068,7 @@ void GenTree::ParseArrayAddressWork(Compiler* comp, ssize_t inputMul, GenTreePtr
bool GenTree::ParseArrayElemForm(Compiler* comp, ArrayInfo* arrayInfo, FieldSeqNode** pFldSeq)
{
- if (OperGet() == GT_IND)
+ if (OperIsIndir())
{
if (gtFlags & GTF_IND_ARR_INDEX)
{
@@ -14051,7 +14078,7 @@ bool GenTree::ParseArrayElemForm(Compiler* comp, ArrayInfo* arrayInfo, FieldSeqN
}
// Otherwise...
- GenTreePtr addr = gtOp.gtOp1;
+ GenTreePtr addr = AsIndir()->Addr();
return addr->ParseArrayElemAddrForm(comp, arrayInfo, pFldSeq);
}
else
diff --git a/src/jit/gentree.h b/src/jit/gentree.h
index 716d38553e..48a04b6d9e 100644
--- a/src/jit/gentree.h
+++ b/src/jit/gentree.h
@@ -495,7 +495,9 @@ public:
bool isContainedLclField() const { return isContained() && isLclField(); }
- bool isContainedLclVar() const { return isContained() && (OperGet() == GT_LCL_VAR); }
+ bool isContainedLclVar() const { return isContained() && (OperGet() == GT_LCL_VAR); }
+
+ bool isContainedSpillTemp() const;
// Indicates whether it is a memory op.
// Right now it includes Indir and LclField ops.
@@ -503,7 +505,7 @@ public:
bool isContainedMemoryOp() const
{
- return (isContained() && isMemoryOp()) || isContainedLclVar();
+ return (isContained() && isMemoryOp()) || isContainedLclVar() || isContainedSpillTemp();
}
regNumber GetRegNum() const
@@ -665,11 +667,13 @@ public:
#define GTF_REVERSE_OPS 0x00000020 // operand op2 should be evaluated before op1 (normally, op1 is evaluated first and op2 is evaluated second)
#define GTF_REG_VAL 0x00000040 // operand is sitting in a register (or part of a TYP_LONG operand is sitting in a register)
- #define GTF_SPILLED 0x00000080 // the value has been spilled
- #define GTF_SPILLED_OPER 0x00000100 // op1 has been spilled
+ #define GTF_SPILLED 0x00000080 // the value has been spilled
#ifdef LEGACY_BACKEND
- #define GTF_SPILLED_OP2 0x00000200 // op2 has been spilled
+ #define GTF_SPILLED_OPER 0x00000100 // op1 has been spilled
+ #define GTF_SPILLED_OP2 0x00000200 // op2 has been spilled
+#else
+ #define GTF_NOREG_AT_USE 0x00000100 // tree node is in memory at the point of use
#endif // LEGACY_BACKEND
#define GTF_REDINDEX_CHECK 0x00000100 // Used for redundant range checks. Disjoint from GTF_SPILLED_OPER
@@ -1200,7 +1204,7 @@ public:
static
bool OperIsIndir(genTreeOps gtOper)
{
- return gtOper == GT_IND || gtOper == GT_STOREIND || gtOper == GT_NULLCHECK;
+ return gtOper == GT_IND || gtOper == GT_STOREIND || gtOper == GT_NULLCHECK || gtOper == GT_OBJ;
}
bool OperIsIndir() const
@@ -3316,27 +3320,6 @@ protected:
#endif // DEBUGGABLE_GENTREE
};
-// gtObj -- 'object' (GT_OBJ). */
-
-struct GenTreeObj: public GenTreeUnOp
-{
- // The address of the block.
- GenTreePtr& Addr() { return gtOp1; }
-
- CORINFO_CLASS_HANDLE gtClass; // the class of the object
-
- GenTreeObj(var_types type, GenTreePtr addr, CORINFO_CLASS_HANDLE cls) :
- GenTreeUnOp(GT_OBJ, type, addr),
- gtClass(cls)
- {
- gtFlags |= GTF_GLOB_REF; // An Obj is always a global reference.
- }
-
-#if DEBUGGABLE_GENTREE
- GenTreeObj() : GenTreeUnOp() {}
-#endif
-};
-
// Represents a CpObj MSIL Node.
struct GenTreeCpObj : public GenTreeBlkOp
{
@@ -3545,6 +3528,25 @@ protected:
#endif
};
+// gtObj -- 'object' (GT_OBJ). */
+
+struct GenTreeObj: public GenTreeIndir
+{
+ CORINFO_CLASS_HANDLE gtClass; // the class of the object
+
+ GenTreeObj(var_types type, GenTreePtr addr, CORINFO_CLASS_HANDLE cls) :
+ GenTreeIndir(GT_OBJ, type, addr, nullptr),
+ gtClass(cls)
+ {
+ // By default, an OBJ is assumed to be a global reference.
+ gtFlags |= GTF_GLOB_REF;
+ }
+
+#if DEBUGGABLE_GENTREE
+ GenTreeObj() : GenTreeIndir() {}
+#endif
+};
+
// Read-modify-write status of a RMW memory op rooted at a storeInd
enum RMWStatus {
STOREIND_RMW_STATUS_UNKNOWN, // RMW status of storeInd unknown
@@ -4497,6 +4499,19 @@ GenTreeBlkOp::HasGCPtr()
return false;
}
+inline bool GenTree::isContainedSpillTemp() const
+{
+#if !defined(LEGACY_BACKEND)
+ // If spilled and no reg at use, then it is treated as contained.
+ if (((gtFlags & GTF_SPILLED) != 0) &&
+ ((gtFlags & GTF_NOREG_AT_USE) != 0))
+ {
+ return true;
+ }
+#endif //!LEGACY_BACKEND
+
+ return false;
+}
/*****************************************************************************/
diff --git a/src/jit/gtlist.h b/src/jit/gtlist.h
index 8248b532b9..ee33797234 100644
--- a/src/jit/gtlist.h
+++ b/src/jit/gtlist.h
@@ -153,7 +153,9 @@ GTNODE(LONG , "gt_long" ,0,GTK_BINOP)
// The following are nodes representing the upper half of a 64-bit operation
// that requires a carry/borrow. However, they are all named GT_XXX_HI for
// consistency.
+GTNODE(ADD_LO , "+Lo" ,1,GTK_BINOP)
GTNODE(ADD_HI , "+Hi" ,1,GTK_BINOP)
+GTNODE(SUB_LO , "-Lo" ,0,GTK_BINOP)
GTNODE(SUB_HI , "-Hi" ,0,GTK_BINOP)
GTNODE(MUL_HI , "*Hi" ,1,GTK_BINOP)
GTNODE(DIV_HI , "/Hi" ,0,GTK_BINOP)
diff --git a/src/jit/gtstructs.h b/src/jit/gtstructs.h
index 2f0b3a3936..06c5b9816f 100644
--- a/src/jit/gtstructs.h
+++ b/src/jit/gtstructs.h
@@ -90,7 +90,7 @@ GTSTRUCT_1(AddrMode , GT_LEA)
GTSTRUCT_1(Qmark , GT_QMARK)
GTSTRUCT_1(PhiArg , GT_PHI_ARG)
GTSTRUCT_1(StoreInd , GT_STOREIND)
-GTSTRUCT_2(Indir , GT_STOREIND, GT_IND)
+GTSTRUCT_N(Indir , GT_STOREIND, GT_IND, GT_NULLCHECK, GT_OBJ)
GTSTRUCT_1(PutArgStk , GT_PUTARG_STK)
GTSTRUCT_1(PhysReg , GT_PHYSREG)
GTSTRUCT_3(BlkOp , GT_COPYBLK, GT_INITBLK, GT_COPYOBJ)
diff --git a/src/jit/importer.cpp b/src/jit/importer.cpp
index 7c5a5093b5..8a07d9214c 100644
--- a/src/jit/importer.cpp
+++ b/src/jit/importer.cpp
@@ -3381,13 +3381,6 @@ InterlockedBinOpCommon:
{
NO_WAY("JIT must expand the intrinsic!");
}
- else if ((retNode->gtFlags & GTF_CALL) != 0)
- {
- // If we must expand the intrinsic,
- // retNode (the tree that corresponds to the intrinsic expansion) must be non-null,
- // and the returned tree must not contain a call.
- NO_WAY("JIT must not implement the intrinsic by a user call!");
- }
}
return retNode;
@@ -7458,16 +7451,28 @@ GenTreePtr Compiler::impFixupCallStructReturn(GenTreePtr call
return call;
#endif // FEATURE_UNIX_AMD64_STRUCT_PASSING
- // Check for TYP_STRUCT argument that can fit into a single register
- // change the type on those trees.
- var_types regType = argOrReturnTypeForStruct(retClsHnd, true);
- if (regType != TYP_UNKNOWN)
+ // Check for TYP_STRUCT type that wraps a primitive type
+ // Such structs are returned using a single register
+ // and we change the return type on those calls here.
+ //
+ structPassingKind howToReturnStruct;
+ var_types returnType = getReturnTypeForStruct(retClsHnd, &howToReturnStruct);
+
+ if (howToReturnStruct == SPK_ByReference)
{
- call->gtCall.gtReturnType = regType;
+ assert(returnType == TYP_UNKNOWN);
+ call->gtCall.gtCallMoreFlags |= GTF_CALL_M_RETBUFFARG;
}
else
{
- call->gtCall.gtCallMoreFlags |= GTF_CALL_M_RETBUFFARG;
+ assert(returnType != TYP_UNKNOWN);
+ call->gtCall.gtReturnType = returnType;
+
+ // ToDo: Refactor this common code sequence into its own method as it is used 4+ times
+ if ((returnType == TYP_LONG) && (compLongUsed == false))
+ compLongUsed = true;
+ else if (((returnType == TYP_FLOAT) || (returnType == TYP_DOUBLE)) && (compFloatingPointUsed == false))
+ compFloatingPointUsed = true;
}
return call;
diff --git a/src/jit/inline.cpp b/src/jit/inline.cpp
index 146ef0585f..cca67570b1 100644
--- a/src/jit/inline.cpp
+++ b/src/jit/inline.cpp
@@ -955,8 +955,23 @@ void InlineStrategy::NoteOutcome(InlineContext* context)
#if defined(DEBUG) || defined(INLINE_DATA)
- m_LastContext = context;
- m_LastSuccessfulPolicy = context->m_Policy;
+ // Keep track of the inline targeted for data collection or,
+ // if we don't have one (yet), the last successful inline.
+ bool updateLast =
+ (m_LastSuccessfulPolicy == nullptr) ||
+ !m_LastSuccessfulPolicy->IsDataCollectionTarget();
+
+ if (updateLast)
+ {
+ m_LastContext = context;
+ m_LastSuccessfulPolicy = context->m_Policy;
+ }
+ else
+ {
+ // We only expect one inline to be a data collection
+ // target.
+ assert(!context->m_Policy->IsDataCollectionTarget());
+ }
#endif // defined(DEBUG) || defined(INLINE_DATA)
diff --git a/src/jit/inline.h b/src/jit/inline.h
index effe421903..aa0573ccf0 100644
--- a/src/jit/inline.h
+++ b/src/jit/inline.h
@@ -244,6 +244,7 @@ public:
// Policy policies
virtual bool PropagateNeverToRuntime() const = 0;
+ virtual bool IsLegacyPolicy() const = 0;
// Policy estimates
virtual int CodeSizeEstimate() = 0;
@@ -256,6 +257,8 @@ public:
virtual void DumpData(FILE* file) const { }
// Detailed data name dump
virtual void DumpSchema(FILE* file) const { }
+ // True if this is the inline targeted by data collection
+ bool IsDataCollectionTarget() { return m_IsDataCollectionTarget; }
#endif // defined(DEBUG) || defined(INLINE_DATA)
@@ -265,6 +268,10 @@ protected:
: m_Decision(InlineDecision::UNDECIDED)
, m_Observation(InlineObservation::CALLEE_UNUSED_INITIAL)
, m_IsPrejitRoot(isPrejitRoot)
+#if defined(DEBUG) || defined(INLINE_DATA)
+ , m_IsDataCollectionTarget(false)
+#endif // defined(DEBUG) || defined(INLINE_DATA)
+
{
// empty
}
@@ -280,6 +287,12 @@ protected:
InlineDecision m_Decision;
InlineObservation m_Observation;
bool m_IsPrejitRoot;
+
+#if defined(DEBUG) || defined(INLINE_DATA)
+
+ bool m_IsDataCollectionTarget;
+
+#endif // defined(DEBUG) || defined(INLINE_DATA)
};
// InlineResult summarizes what is known about the viability of a
@@ -439,6 +452,13 @@ public:
return m_Policy;
}
+ // True if the policy used for this result is (exactly) the legacy
+ // policy.
+ bool UsesLegacyPolicy() const
+ {
+ return m_Policy->IsLegacyPolicy();
+ }
+
// SetReported indicates that this particular result doesn't need
// to be reported back to the runtime, either because the runtime
// already knows, or we aren't actually inlining yet.
diff --git a/src/jit/inlinepolicy.cpp b/src/jit/inlinepolicy.cpp
index 30ec8f593d..36e1f1b578 100644
--- a/src/jit/inlinepolicy.cpp
+++ b/src/jit/inlinepolicy.cpp
@@ -284,7 +284,7 @@ void LegacyPolicy::NoteBool(InlineObservation obs, bool value)
// LegacyPolicy ignores this for prejit roots.
if (!m_IsPrejitRoot)
{
- m_ArgFeedsConstantTest = value;
+ m_ArgFeedsConstantTest++;
}
break;
@@ -292,7 +292,7 @@ void LegacyPolicy::NoteBool(InlineObservation obs, bool value)
// LegacyPolicy ignores this for prejit roots.
if (!m_IsPrejitRoot)
{
- m_ArgFeedsRangeCheck = value;
+ m_ArgFeedsRangeCheck++;
}
break;
@@ -311,7 +311,7 @@ void LegacyPolicy::NoteBool(InlineObservation obs, bool value)
// We shouldn't see this for a prejit root since
// we don't know anything about callers.
assert(!m_IsPrejitRoot);
- m_ConstantFeedsConstantTest = value;
+ m_ConstantArgFeedsConstantTest++;
break;
case InlineObservation::CALLEE_BEGIN_OPCODE_SCAN:
@@ -575,7 +575,7 @@ double LegacyPolicy::DetermineMultiplier()
JITDUMP("\nInline candidate looks like a wrapper method. Multiplier increased to %g.", multiplier);
}
- if (m_ArgFeedsConstantTest)
+ if (m_ArgFeedsConstantTest > 0)
{
multiplier += 1.0;
JITDUMP("\nInline candidate has an arg that feeds a constant test. Multiplier increased to %g.", multiplier);
@@ -587,13 +587,13 @@ double LegacyPolicy::DetermineMultiplier()
JITDUMP("\nInline candidate is mostly loads and stores. Multiplier increased to %g.", multiplier);
}
- if (m_ArgFeedsRangeCheck)
+ if (m_ArgFeedsRangeCheck > 0)
{
multiplier += 0.5;
JITDUMP("\nInline candidate has arg that feeds range check. Multiplier increased to %g.", multiplier);
}
- if (m_ConstantFeedsConstantTest)
+ if (m_ConstantArgFeedsConstantTest > 0)
{
multiplier += 3.0;
JITDUMP("\nInline candidate has const arg that feeds a conditional. Multiplier increased to %g.", multiplier);
@@ -1164,11 +1164,18 @@ void DiscretionaryPolicy::NoteBool(InlineObservation obs, bool value)
break;
case InlineObservation::CALLEE_ARG_FEEDS_CONSTANT_TEST:
- m_ArgFeedsConstantTest = value;
+ assert(value);
+ m_ArgFeedsConstantTest++;
break;
case InlineObservation::CALLEE_ARG_FEEDS_RANGE_CHECK:
- m_ArgFeedsRangeCheck = value;
+ assert(value);
+ m_ArgFeedsRangeCheck++;
+ break;
+
+ case InlineObservation::CALLSITE_CONSTANT_ARG_FEEDS_TEST:
+ assert(value);
+ m_ConstantArgFeedsConstantTest++;
break;
default:
@@ -1701,7 +1708,7 @@ void DiscretionaryPolicy::EstimateCodeSize()
6.021 * m_CallCount +
-0.238 * m_IsInstanceCtor +
-5.357 * m_IsFromPromotableValueClass +
- -7.901 * m_ConstantFeedsConstantTest +
+ -7.901 * (m_ConstantArgFeedsConstantTest > 0 ? 1 : 0) +
0.065 * m_CalleeNativeSizeEstimate;
// Scaled up and reported as an integer value.
@@ -1816,7 +1823,7 @@ void DiscretionaryPolicy::DumpSchema(FILE* file) const
fprintf(file, ",ArgFeedsConstantTest");
fprintf(file, ",IsMostlyLoadStore");
fprintf(file, ",ArgFeedsRangeCheck");
- fprintf(file, ",ConstantFeedsConstantTest");
+ fprintf(file, ",ConstantArgFeedsConstantTest");
fprintf(file, ",CalleeNativeSizeEstimate");
fprintf(file, ",CallsiteNativeSizeEstimate");
fprintf(file, ",ModelCodeSizeEstimate");
@@ -1888,10 +1895,10 @@ void DiscretionaryPolicy::DumpData(FILE* file) const
fprintf(file, ",%u", m_IsFromPromotableValueClass ? 1 : 0);
fprintf(file, ",%u", m_HasSimd ? 1 : 0);
fprintf(file, ",%u", m_LooksLikeWrapperMethod ? 1 : 0);
- fprintf(file, ",%u", m_ArgFeedsConstantTest ? 1 : 0);
+ fprintf(file, ",%u", m_ArgFeedsConstantTest);
fprintf(file, ",%u", m_MethodIsMostlyLoadStore ? 1 : 0);
- fprintf(file, ",%u", m_ArgFeedsRangeCheck ? 1 : 0);
- fprintf(file, ",%u", m_ConstantFeedsConstantTest ? 1 : 0);
+ fprintf(file, ",%u", m_ArgFeedsRangeCheck);
+ fprintf(file, ",%u", m_ConstantArgFeedsConstantTest);
fprintf(file, ",%d", m_CalleeNativeSizeEstimate);
fprintf(file, ",%d", m_CallsiteNativeSizeEstimate);
fprintf(file, ",%d", m_ModelCodeSizeEstimate);
@@ -1914,6 +1921,73 @@ ModelPolicy::ModelPolicy(Compiler* compiler, bool isPrejitRoot)
}
//------------------------------------------------------------------------
+// NoteInt: handle an observed integer value
+//
+// Arguments:
+// obs - the current obsevation
+// value - the value being observed
+//
+// Notes:
+// The ILSize threshold used here should be large enough that
+// it does not generally influence inlining decisions -- it only
+// helps to make them faster.
+//
+// The value is determined as follows. We figure out the maximum
+// possible code size estimate that will lead to an inline. This is
+// found by determining the maximum possible inline benefit and
+// working backwards.
+//
+// In the current ModelPolicy, the maximum benefit is -28.1, which
+// comes from a CallSiteWeight of 3 and a per call benefit of
+// -9.37. This implies that any candidate with code size larger
+// than (28.1/0.2) will not pass the threshold. So maximum code
+// size estimate (in bytes) for any inlinee is 140.55, and hence
+// maximum estimate is 1405.
+//
+// Since we are trying to short circuit early in the evaluation
+// process we don't have the code size estimate in hand. We need to
+// estimate the possible code size estimate based on something we
+// know cheaply and early -- the ILSize. So we use quantile
+// regression to project how ILSize predicts the model code size
+// estimate. Note that ILSize does not currently directly enter
+// into the model.
+//
+// The median value for the model code size estimate based on
+// ILSize is given by -107 + 12.6 * ILSize for the V9 data. This
+// means an ILSize of 120 is likely to lead to a size estimate of
+// at least 1405 at least 50% of the time. So we choose this as the
+// early rejection threshold.
+
+void ModelPolicy::NoteInt(InlineObservation obs, int value)
+{
+ // Let underlying policy do its thing.
+ DiscretionaryPolicy::NoteInt(obs, value);
+
+ // Fail fast for inlinees that are too large to ever inline.
+ // The value of 120 is model-dependent; see notes above.
+ if (!m_IsForceInline &&
+ (obs == InlineObservation::CALLEE_IL_CODE_SIZE) &&
+ (value >= 120))
+ {
+ // Callee too big, not a candidate
+ SetNever(InlineObservation::CALLEE_TOO_MUCH_IL);
+ return;
+ }
+
+ // Safeguard against overly deep inlines
+ if (obs == InlineObservation::CALLSITE_DEPTH)
+ {
+ unsigned depthLimit = m_RootCompiler->m_inlineStrategy->GetMaxInlineDepth();
+
+ if (m_Depth > depthLimit)
+ {
+ SetFailure(InlineObservation::CALLSITE_IS_TOO_DEEP);
+ return;
+ }
+ }
+}
+
+//------------------------------------------------------------------------
// DetermineProfitability: determine if this inline is profitable
//
// Arguments:
@@ -1971,7 +2045,7 @@ void ModelPolicy::DetermineProfitability(CORINFO_METHOD_INFO* methodInfo)
// positive be better and negative worse.
double perCallBenefit = -((double) m_PerCallInstructionEstimate / (double) m_ModelCodeSizeEstimate);
- // Now estimate the local call frequency.
+ // Now estimate the local call frequency.
//
// Todo: use IBC data, or a better local profile estimate, or
// try and incorporate this into the model. For instance if we
@@ -1980,10 +2054,24 @@ void ModelPolicy::DetermineProfitability(CORINFO_METHOD_INFO* methodInfo)
// frequency, somehow.
double callSiteWeight = 1.0;
- if ((m_CallsiteFrequency == InlineCallsiteFrequency::LOOP) ||
- (m_CallsiteFrequency == InlineCallsiteFrequency::HOT))
+ switch (m_CallsiteFrequency)
{
- callSiteWeight = 8.0;
+ case InlineCallsiteFrequency::RARE:
+ callSiteWeight = 0.1;
+ break;
+ case InlineCallsiteFrequency::BORING:
+ callSiteWeight = 1.0;
+ break;
+ case InlineCallsiteFrequency::WARM:
+ callSiteWeight = 1.5;
+ break;
+ case InlineCallsiteFrequency::LOOP:
+ case InlineCallsiteFrequency::HOT:
+ callSiteWeight = 3.0;
+ break;
+ default:
+ assert(false);
+ break;
}
// Determine the estimated number of instructions saved per
@@ -1991,8 +2079,8 @@ void ModelPolicy::DetermineProfitability(CORINFO_METHOD_INFO* methodInfo)
// is our benefit figure of merit.
double benefit = callSiteWeight * perCallBenefit;
- // Compare this to the threshold, and inline if greater.
- //
+ // Compare this to the threshold, and inline if greater.
+ //
// The threshold is interpretable as a size/speed tradeoff:
// the value of 0.2 below indicates we'll allow inlines that
// grow code by as many as 5 bytes to save 1 instruction
@@ -2502,6 +2590,22 @@ bool ReplayPolicy::FindInline(unsigned token, unsigned hash, unsigned offset)
// We're good!
foundInline = true;
+
+ // Check for a data collection marker. This does not affect
+ // matching...
+
+ // Get next line
+ if (fgets(buffer, sizeof(buffer), s_ReplayFile) != nullptr)
+ {
+ unsigned collectData = 0;
+ count = sscanf(buffer, " <CollectData>%u</CollectData> ", &collectData);
+
+ if (count == 1)
+ {
+ m_IsDataCollectionTarget = (collectData == 1);
+ }
+ }
+
break;
}
@@ -2588,12 +2692,13 @@ void ReplayPolicy::DetermineProfitability(CORINFO_METHOD_INFO* methodInfo)
}
// If we're also dumping inline data, make additional observations
- // based on the method info, and estimate code size, so that the
- // reports have the necessary data.
+ // based on the method info, and estimate code size and perf
+ // impact, so that the reports have the necessary data.
if (JitConfig.JitInlineDumpData() != 0)
{
MethodInfoObservations(methodInfo);
EstimateCodeSize();
+ EstimatePerformanceImpact();
m_IsForceInline = m_WasForceInline;
}
diff --git a/src/jit/inlinepolicy.h b/src/jit/inlinepolicy.h
index f834577a43..f5773d1ede 100644
--- a/src/jit/inlinepolicy.h
+++ b/src/jit/inlinepolicy.h
@@ -82,23 +82,23 @@ public:
: LegalPolicy(isPrejitRoot)
, m_RootCompiler(compiler)
, m_StateMachine(nullptr)
+ , m_Multiplier(0.0)
, m_CodeSize(0)
, m_CallsiteFrequency(InlineCallsiteFrequency::UNUSED)
, m_InstructionCount(0)
, m_LoadStoreCount(0)
+ , m_ArgFeedsConstantTest(0)
+ , m_ArgFeedsRangeCheck(0)
+ , m_ConstantArgFeedsConstantTest(0)
, m_CalleeNativeSizeEstimate(0)
, m_CallsiteNativeSizeEstimate(0)
- , m_Multiplier(0.0)
, m_IsForceInline(false)
, m_IsForceInlineKnown(false)
, m_IsInstanceCtor(false)
, m_IsFromPromotableValueClass(false)
, m_HasSimd(false)
, m_LooksLikeWrapperMethod(false)
- , m_ArgFeedsConstantTest(false)
, m_MethodIsMostlyLoadStore(false)
- , m_ArgFeedsRangeCheck(false)
- , m_ConstantFeedsConstantTest(false)
{
// empty
}
@@ -113,6 +113,7 @@ public:
// Policy policies
bool PropagateNeverToRuntime() const override { return true; }
+ bool IsLegacyPolicy() const override { return true; }
// Policy estimates
int CodeSizeEstimate() override;
@@ -136,23 +137,23 @@ protected:
// Data members
Compiler* m_RootCompiler; // root compiler instance
CodeSeqSM* m_StateMachine;
+ double m_Multiplier;
unsigned m_CodeSize;
InlineCallsiteFrequency m_CallsiteFrequency;
unsigned m_InstructionCount;
unsigned m_LoadStoreCount;
+ unsigned m_ArgFeedsConstantTest;
+ unsigned m_ArgFeedsRangeCheck;
+ unsigned m_ConstantArgFeedsConstantTest;
int m_CalleeNativeSizeEstimate;
int m_CallsiteNativeSizeEstimate;
- double m_Multiplier;
bool m_IsForceInline :1;
bool m_IsForceInlineKnown :1;
bool m_IsInstanceCtor :1;
bool m_IsFromPromotableValueClass :1;
bool m_HasSimd :1;
bool m_LooksLikeWrapperMethod :1;
- bool m_ArgFeedsConstantTest :1;
bool m_MethodIsMostlyLoadStore :1;
- bool m_ArgFeedsRangeCheck :1;
- bool m_ConstantFeedsConstantTest :1;
};
#ifdef DEBUG
@@ -177,6 +178,7 @@ public:
// Policy policies
bool PropagateNeverToRuntime() const override { return true; }
+ bool IsLegacyPolicy() const override { return false; }
// Policy estimates
int CodeSizeEstimate() override
@@ -200,8 +202,8 @@ private:
// DiscretionaryPolicy is a variant of the legacy policy. It differs
// in that there is no ALWAYS_INLINE class, there is no IL size limit,
-// and in prejit mode, discretionary failures do not set the "NEVER"
-// inline bit.
+// it does not try and maintain legacy compatabilty, and in prejit mode,
+// discretionary failures do not set the "NEVER" inline bit.
//
// It is useful for gathering data about inline costs.
@@ -218,6 +220,7 @@ public:
// Policy policies
bool PropagateNeverToRuntime() const override;
+ bool IsLegacyPolicy() const override { return false; }
// Policy determinations
void DetermineProfitability(CORINFO_METHOD_INFO* methodInfo) override;
@@ -297,6 +300,9 @@ public:
// Construct a ModelPolicy
ModelPolicy(Compiler* compiler, bool isPrejitRoot);
+ // Policy observations
+ void NoteInt(InlineObservation obs, int value) override;
+
// Policy determinations
void DetermineProfitability(CORINFO_METHOD_INFO* methodInfo) override;
diff --git a/src/jit/jit.settings.targets b/src/jit/jit.settings.targets
index 26b5af903d..2ffcfcb69c 100644
--- a/src/jit/jit.settings.targets
+++ b/src/jit/jit.settings.targets
@@ -92,6 +92,7 @@
<CppCompile Include="..\emitXArch.cpp" />
<CppCompile Include="..\TargetX86.cpp" />
<CppCompile Condition="'$(ClDefines.Contains(`LEGACY_BACKEND`))'=='True'" Include="..\stackfp.cpp" />
+ <CppCompile Condition="'$(ClDefines.Contains(`LEGACY_BACKEND`))'=='False'" Include="..\DecomposeLongs.cpp" />
<CppCompile Condition="'$(ClDefines.Contains(`LEGACY_BACKEND`))'=='False'" Include="..\LowerXArch.cpp" />
<CppCompile Condition="'$(ClDefines.Contains(`LEGACY_BACKEND`))'=='False'" Include="..\CodeGenXArch.cpp" />
<CppCompile Condition="'$(ClDefines.Contains(`LEGACY_BACKEND`))'=='False'" Include="..\SIMD.cpp" />
@@ -111,6 +112,7 @@
<CppCompile Include="..\emitarm.cpp" />
<CppCompile Include="..\TargetArm.cpp" />
<CppCompile Condition="'$(ClDefines.Contains(`LEGACY_BACKEND`))'=='True'" Include="..\registerfp.cpp" />
+ <CppCompile Condition="'$(ClDefines.Contains(`LEGACY_BACKEND`))'=='False'" Include="..\DecomposeLongs.cpp" />
<CppCompile Condition="'$(ClDefines.Contains(`LEGACY_BACKEND`))'=='False'" Include="..\LowerArm.cpp" />
<CppCompile Condition="'$(ClDefines.Contains(`LEGACY_BACKEND`))'=='False'" Include="..\CodeGenArm.cpp" />
<CppCompile Include="..\unwindArm.cpp" />
diff --git a/src/jit/jitgcinfo.h b/src/jit/jitgcinfo.h
index 480f88491a..e5092cfaa1 100644
--- a/src/jit/jitgcinfo.h
+++ b/src/jit/jitgcinfo.h
@@ -8,11 +8,11 @@
#ifndef _JITGCINFO_H_
#define _JITGCINFO_H_
-#include "gcinfo.h"
+
+#include "gcinfotypes.h"
#ifndef JIT32_GCENCODER
#include "gcinfoencoder.h"
-#include "gcinfotypes.h"
#endif
/*****************************************************************************/
diff --git a/src/jit/lclvars.cpp b/src/jit/lclvars.cpp
index cf6e2b0d7b..e0c4f75599 100644
--- a/src/jit/lclvars.cpp
+++ b/src/jit/lclvars.cpp
@@ -156,12 +156,20 @@ void Compiler::lvaInitTypeRef()
}
#else // !FEATURE_UNIX_AMD64_STRUCT_PASSING
// Check for TYP_STRUCT argument that can fit into a single register
- var_types argRetType = argOrReturnTypeForStruct(info.compMethodInfo->args.retTypeClass, true /* forReturn */);
- info.compRetNativeType = argRetType;
- if (argRetType == TYP_UNKNOWN)
+ structPassingKind howToReturnStruct;
+ var_types returnType = getReturnTypeForStruct(info.compMethodInfo->args.retTypeClass, &howToReturnStruct);
+ assert(howToReturnStruct != SPK_ByReference); // hasRetBuffArg is false, so we can't have this answer here
+ info.compRetNativeType = returnType;
+ if (returnType == TYP_UNKNOWN)
{
assert(!"Unexpected size when returning struct by value");
}
+
+ // ToDo: Refactor this common code sequence into its own method as it is used 4+ times
+ if ((returnType == TYP_LONG) && (compLongUsed == false))
+ compLongUsed = true;
+ else if (((returnType == TYP_FLOAT) || (returnType == TYP_DOUBLE)) && (compFloatingPointUsed == false))
+ compFloatingPointUsed = true;
#endif // !FEATURE_UNIX_AMD64_STRUCT_PASSING
}
}
@@ -557,6 +565,10 @@ void Compiler::lvaInitUserArgs(InitVarDscInfo * varDscInfo)
// For ARM, ARM64, and AMD64 varargs, all arguments go in integer registers
var_types argType = mangleVarArgsType(varDsc->TypeGet());
var_types origArgType = argType;
+ // ARM softfp calling convention should affect only the floating point arguments.
+ // Otherwise there appear too many surplus pre-spills and other memory operations
+ // with the associated locations .
+ bool isSoftFPPreSpill = opts.compUseSoftFP && varTypeIsFloating(varDsc->TypeGet());
unsigned argSize = eeGetArgSize(argLst, &info.compMethodInfo->args);
unsigned cSlots = argSize / TARGET_POINTER_SIZE; // the total number of slots of this argument
bool isHfaArg = false;
@@ -574,7 +586,7 @@ void Compiler::lvaInitUserArgs(InitVarDscInfo * varDscInfo)
}
if (isHfaArg)
{
- // We have an HFA argument, so from here on our treat the type as a float or double.
+ // We have an HFA argument, so from here on out treat the type as a float or double.
// The orginal struct type is available by using origArgType
// We also update the cSlots to be the number of float/double fields in the HFA
argType = hfaType;
@@ -591,7 +603,7 @@ void Compiler::lvaInitUserArgs(InitVarDscInfo * varDscInfo)
// But we pre-spill user arguments in varargs methods and structs.
//
unsigned cAlign;
- bool preSpill = info.compIsVarArgs || opts.compUseSoftFP;
+ bool preSpill = info.compIsVarArgs || isSoftFPPreSpill;
switch (origArgType)
{
@@ -708,7 +720,7 @@ void Compiler::lvaInitUserArgs(InitVarDscInfo * varDscInfo)
}
#endif // FEATURE_UNIX_AMD64_STRUCT_PASSING
- // The final home for this incoming register might be our local stack frame
+ // The final home for this incoming register might be our local stack frame.
// For System V platforms the final home will always be on the local stack frame.
varDsc->lvOnFrame = true;
@@ -921,7 +933,7 @@ void Compiler::lvaInitUserArgs(InitVarDscInfo * varDscInfo)
#else // !FEATURE_UNIX_AMD64_STRUCT_PASSING
compArgSize += argSize;
#endif // !FEATURE_UNIX_AMD64_STRUCT_PASSING
- if (info.compIsVarArgs || isHfaArg || opts.compUseSoftFP)
+ if (info.compIsVarArgs || isHfaArg || isSoftFPPreSpill)
{
#if defined(_TARGET_X86_)
varDsc->lvStkOffs = compArgSize;
@@ -2848,8 +2860,10 @@ var_types LclVarDsc::lvaArgType()
}
}
+#elif defined(_TARGET_X86_)
+ // Nothing to do; use the type as is.
#else
- NYI("unknown target");
+ NYI("lvaArgType");
#endif //_TARGET_AMD64_
return type;
diff --git a/src/jit/lower.cpp b/src/jit/lower.cpp
index e54130e077..f644b930ec 100755..100644
--- a/src/jit/lower.cpp
+++ b/src/jit/lower.cpp
@@ -25,6 +25,10 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
#include "lower.h"
+#if !defined(_TARGET_64BIT_)
+#include "decomposelongs.h"
+#endif // !defined(_TARGET_64BIT_)
+
//------------------------------------------------------------------------
// MakeSrcContained: Make "tree" a contained node
//
@@ -119,13 +123,7 @@ bool Lowering::IsSafeToContainMem(GenTree* parentNode, GenTree* childNode)
//------------------------------------------------------------------------
-Compiler::fgWalkResult Lowering::DecompNodeHelper(GenTreePtr* pTree, Compiler::fgWalkData* data)
-{
- Lowering* lower = (Lowering*)data->pCallbackData;
- lower->DecomposeNode(pTree, data);
- return Compiler::WALK_CONTINUE;
-}
-
+//static
Compiler::fgWalkResult Lowering::LowerNodeHelper(GenTreePtr* pTree, Compiler::fgWalkData* data)
{
Lowering* lower = (Lowering*)data->pCallbackData;
@@ -133,774 +131,6 @@ Compiler::fgWalkResult Lowering::LowerNodeHelper(GenTreePtr* pTree, Compiler::fg
return Compiler::WALK_CONTINUE;
}
-#if !defined(_TARGET_64BIT_)
-genTreeOps getHiOper(genTreeOps oper)
-{
- switch(oper)
- {
- case GT_ADD: return GT_ADD_HI; break;
- case GT_SUB: return GT_SUB_HI; break;
- case GT_MUL: return GT_MUL_HI; break;
- case GT_DIV: return GT_DIV_HI; break;
- case GT_MOD: return GT_MOD_HI; break;
- case GT_OR: return GT_OR; break;
- case GT_AND: return GT_AND; break;
- case GT_XOR: return GT_XOR; break;
- default:
- assert(!"getHiOper called for invalid oper");
- return GT_NONE;
- }
-}
-#endif // !defined(_TARGET_64BIT_)
-
-//------------------------------------------------------------------------
-// DecomposeNode: Decompose long-type trees into lower & upper halves.
-//
-// Arguments:
-// *pTree - A node that may or may not require decomposition.
-// data - The tree-walk data that provides the context.
-//
-// Return Value:
-// None.
-//
-// Notes: The rationale behind this is to avoid adding code complexity
-// downstream caused by the introduction of handling longs as special cases, especially in
-// LSRA.
-// This function is called just prior to the more general purpose lowering.
-//
-void Lowering::DecomposeNode(GenTreePtr* pTree, Compiler::fgWalkData* data)
-{
-#if !defined(_TARGET_64BIT_)
- GenTree* tree = *(pTree);
-
- // Handle the case where we are implicitly using the lower half of a long lclVar.
- if ((tree->TypeGet() == TYP_INT) && tree->OperIsLocal())
- {
- LclVarDsc * varDsc = comp->lvaTable + tree->AsLclVarCommon()->gtLclNum;
- if (varTypeIsLong(varDsc) && varDsc->lvPromoted)
- {
-#ifdef DEBUG
- if (comp->verbose)
- {
- printf("Changing implicit reference to lo half of long lclVar to an explicit reference of its promoted half:\n");
- comp->gtDispTree(tree);
- }
-#endif
- comp->lvaDecRefCnts(tree);
- unsigned loVarNum = varDsc->lvFieldLclStart;
- tree->AsLclVarCommon()->SetLclNum(loVarNum);
- comp->lvaIncRefCnts(tree);
- return;
- }
- }
- if (tree->TypeGet() != TYP_LONG)
- {
- return;
- }
-#ifdef DEBUG
- if (comp->verbose)
- {
- printf("Decomposing TYP_LONG tree. BEFORE:\n");
- comp->gtDispTree(tree);
- }
-#endif
- // The most common pattern is that we will create a loResult and a hiResult, where
- // the loResult reuses some or all of the existing tree, and the hiResult is new.
- // For these, we will set loResult and hiResult in the switch case below, ensuring
- // that loResult is correctly linked into the statement, and hiResult is not, but
- // is internally sequenced appropriately (if it is not a single node).
- // Common code after the switch will link in hiResult and create a GT_LONG node.
-
- GenTree* newTree = nullptr;
- GenTree* loResult = nullptr;
- GenTree* hiResult = nullptr;
- GenTreeStmt* curStmt = comp->compCurStmt->AsStmt();
- genTreeOps oper = tree->OperGet();
- switch(oper)
- {
- case GT_PHI:
- case GT_PHI_ARG:
- break;
- case GT_LCL_VAR:
- {
- loResult = tree;
- unsigned varNum = tree->AsLclVarCommon()->gtLclNum;
- LclVarDsc * varDsc = comp->lvaTable + varNum;
- comp->lvaDecRefCnts(tree);
- hiResult = comp->gtNewLclLNode(varNum, TYP_INT);
-
- if (varDsc->lvPromoted)
- {
- assert(varDsc->lvFieldCnt == 2);
- unsigned loVarNum = varDsc->lvFieldLclStart;
- unsigned hiVarNum = loVarNum + 1;
- tree->AsLclVarCommon()->SetLclNum(loVarNum);
- hiResult->AsLclVarCommon()->SetLclNum(hiVarNum);
- }
- else
- {
- noway_assert(varDsc->lvLRACandidate == false);
- tree->SetOper(GT_LCL_FLD);
- tree->AsLclFld()->gtLclOffs = 0;
- tree->AsLclFld()->gtFieldSeq = FieldSeqStore::NotAField();
- hiResult->SetOper(GT_LCL_FLD);
- hiResult->AsLclFld()->gtLclOffs = 4;
- hiResult->AsLclFld()->gtFieldSeq = FieldSeqStore::NotAField();
- }
- tree->gtType = TYP_INT;
-
- comp->lvaIncRefCnts(loResult);
- comp->lvaIncRefCnts(hiResult);
- break;
- }
- case GT_LCL_FLD:
- loResult = tree;
- loResult->gtType = TYP_INT;
-
- hiResult = comp->gtNewLclFldNode(loResult->AsLclFld()->gtLclNum,
- TYP_INT,
- loResult->AsLclFld()->gtLclOffs + 4);
- break;
- case GT_STORE_LCL_VAR:
- {
- GenTree* nextTree = tree->gtNext;
- GenTree* rhs = tree->gtGetOp1();
- if (rhs->OperGet() == GT_PHI || rhs->OperGet() == GT_CALL)
- {
- // GT_CALLs are not decomposed, so will not be converted to GT_LONG
- // GT_STORE_LCL_VAR = GT_CALL are handled in genMultiRegCallStoreToLocal
- break;
- }
- noway_assert(rhs->OperGet() == GT_LONG);
- unsigned varNum = tree->AsLclVarCommon()->gtLclNum;
- LclVarDsc * varDsc = comp->lvaTable + varNum;
- comp->lvaDecRefCnts(tree);
- GenTree* loRhs = rhs->gtGetOp1();
- GenTree* hiRhs = rhs->gtGetOp2();
- GenTree* hiStore = comp->gtNewLclLNode(varNum, TYP_INT);
- if (varDsc->lvPromoted)
- {
- assert(varDsc->lvFieldCnt == 2);
- unsigned loVarNum = varDsc->lvFieldLclStart;
- unsigned hiVarNum = loVarNum + 1;
- tree->AsLclVarCommon()->SetLclNum(loVarNum);
- hiStore->SetOper(GT_STORE_LCL_VAR);
- hiStore->AsLclVarCommon()->SetLclNum(hiVarNum);
- }
- else
- {
- noway_assert(varDsc->lvLRACandidate == false);
- tree->SetOper(GT_STORE_LCL_FLD);
- tree->AsLclFld()->gtLclOffs = 0;
- tree->AsLclFld()->gtFieldSeq = FieldSeqStore::NotAField();
- hiStore->SetOper(GT_STORE_LCL_FLD);
- hiStore->AsLclFld()->gtLclOffs = 4;
- hiStore->AsLclFld()->gtFieldSeq = FieldSeqStore::NotAField();
- }
- tree->gtOp.gtOp1 = loRhs;
- tree->gtType = TYP_INT;
-
- loRhs->gtNext = tree;
- tree->gtPrev = loRhs;
-
- hiStore->gtOp.gtOp1 = hiRhs;
- hiStore->CopyCosts(tree);
- hiStore->gtFlags |= GTF_VAR_DEF;
-
- comp->lvaIncRefCnts(tree);
- comp->lvaIncRefCnts(hiStore);
-
- tree->gtNext = hiRhs;
- hiRhs->gtPrev = tree;
- hiRhs->gtNext = hiStore;
- hiStore->gtPrev = hiRhs;
- hiStore->gtNext = nextTree;
- if (nextTree != nullptr)
- {
- nextTree->gtPrev = hiStore;
- }
- nextTree = hiRhs;
- GenTreeStmt* currStmt = comp->compCurStmt->AsStmt();
- bool isEmbeddedStmt = !currStmt->gtStmtIsTopLevel();
- if (!isEmbeddedStmt)
- {
- tree->gtNext = nullptr;
- hiRhs->gtPrev = nullptr;
- }
-
- // TODO-Cleanup: DecomposeStoreInd contains identical code,
- // this should be moved to a common function
- if (isEmbeddedStmt)
- {
- // Find a parent statment containing storeIndHigh.
- GenTree* parentStmt = currStmt;
- while ((parentStmt != nullptr) && (!parentStmt->AsStmt()->gtStmtIsTopLevel()))
- {
- parentStmt = parentStmt->gtPrev;
- }
- assert(parentStmt);
-
- GenTreeStmt* stmt = comp->fgMakeEmbeddedStmt(comp->compCurBB, hiStore, parentStmt);
- stmt->gtStmtILoffsx = comp->compCurStmt->gtStmt.gtStmtILoffsx;
-#ifdef DEBUG
- stmt->gtStmtLastILoffs = comp->compCurStmt->gtStmt.gtStmtLastILoffs;
-#endif // DEBUG
- }
- else
- {
- GenTreeStmt* stmt = comp->fgNewStmtFromTree(hiStore);
- stmt->gtStmtILoffsx = comp->compCurStmt->gtStmt.gtStmtILoffsx;
-#ifdef DEBUG
- stmt->gtStmtLastILoffs = comp->compCurStmt->gtStmt.gtStmtLastILoffs;
-#endif // DEBUG
-
- // Find an insert point. Skip all embedded statements.
- GenTree* insertPt = currStmt;
- while ((insertPt->gtNext != nullptr) && (!insertPt->gtNext->AsStmt()->gtStmtIsTopLevel()))
- {
- insertPt = insertPt->gtNext;
- }
-
- comp->fgInsertStmtAfter(comp->compCurBB, insertPt, stmt);
- }
- }
- break;
- case GT_CAST:
- {
- assert(tree->gtPrev == tree->gtGetOp1());
- NYI_IF(tree->gtOverflow(), "TYP_LONG cast with overflow");
- switch (tree->AsCast()->CastFromType())
- {
- case TYP_INT:
- if (tree->gtFlags & GTF_UNSIGNED)
- {
- loResult = tree->gtGetOp1();
- hiResult = new (comp, GT_CNS_INT) GenTreeIntCon(TYP_INT, 0);
- comp->fgSnipNode(curStmt, tree);
- }
- else
- {
- NYI("Lowering of signed cast TYP_INT->TYP_LONG");
- }
- break;
- default:
- NYI("Unimplemented type for Lowering of cast to TYP_LONG");
- break;
- }
- break;
- }
- case GT_CNS_LNG:
- {
- INT32 hiVal = tree->AsLngCon()->HiVal();
-
- loResult = tree;
- loResult->ChangeOperConst(GT_CNS_INT);
- loResult->gtType = TYP_INT;
-
- hiResult = new (comp, GT_CNS_INT) GenTreeIntCon(TYP_INT, hiVal);
- hiResult->CopyCosts(tree);
- }
- break;
- case GT_CALL:
- {
- GenTree* parent = data->parent;
-
- // We only need to force var = call() if the call is not a top-level node.
- if (parent != nullptr)
- {
- if (parent->gtOper == GT_STORE_LCL_VAR)
- {
- // If parent is already a STORE_LCL_VAR, we can skip it if
- // it is already marked as lvIsMultiRegRet
- unsigned varNum = parent->AsLclVarCommon()->gtLclNum;
- if (comp->lvaTable[varNum].lvIsMultiRegRet)
- {
- break;
- }
- else if (!comp->lvaTable[varNum].lvPromoted)
- {
- // If var wasn't promoted, we can just set lvIsMultiRegRet
- comp->lvaTable[varNum].lvIsMultiRegRet = true;
- break;
- }
- }
-
- // Otherwise, we need to force var = call()
- GenTreePtr* treePtr = nullptr;
- parent = tree->gtGetParent(&treePtr);
-
- assert(treePtr != nullptr);
-
- GenTreeStmt* asgStmt = comp->fgInsertEmbeddedFormTemp(treePtr);
- GenTreePtr stLclVar = asgStmt->gtStmtExpr;
- assert(stLclVar->OperIsLocalStore());
-
- unsigned varNum = stLclVar->AsLclVarCommon()->gtLclNum;
- comp->lvaTable[varNum].lvIsMultiRegRet = true;
- comp->fgFixupIfCallArg(data->parentStack, tree, *treePtr);
-
- // Decompose new node
- DecomposeNode(treePtr, data);
- }
- break;
- }
- case GT_RETURN:
- assert(tree->gtOp.gtOp1->OperGet() == GT_LONG);
- break;
- case GT_STOREIND:
- DecomposeStoreInd(tree);
- break;
- case GT_STORE_LCL_FLD:
- assert(tree->gtOp.gtOp1->OperGet() == GT_LONG);
- NYI("st.lclFld of of TYP_LONG");
- break;
- case GT_IND:
- NYI("GT_IND of TYP_LONG");
- break;
- case GT_NOT:
- {
- GenTree* op1 = tree->gtGetOp1();
- noway_assert(op1->OperGet() == GT_LONG);
- GenTree* loOp1 = op1->gtGetOp1();
- GenTree* hiOp1 = op1->gtGetOp2();
- comp->fgSnipNode(curStmt, op1);
- loResult = tree;
- loResult->gtType = TYP_INT;
- loResult->gtOp.gtOp1 = loOp1;
- loOp1->gtNext = loResult;
- loResult->gtPrev = loOp1;
-
- hiResult = new (comp, oper) GenTreeOp(oper, TYP_INT, hiOp1, nullptr);
- hiOp1->gtNext = hiResult;
- hiResult->gtPrev = hiOp1;
- }
- break;
- case GT_NEG:
- NYI("GT_NEG of TYP_LONG");
- break;
- // Binary operators. Those that require different computation for upper and lower half are
- // handled by the use of getHiOper().
- case GT_ADD:
- case GT_SUB:
- case GT_OR:
- case GT_XOR:
- case GT_AND:
- {
- NYI_IF((tree->gtFlags & GTF_REVERSE_OPS) != 0, "Binary operator with GTF_REVERSE_OPS");
- GenTree* op1 = tree->gtGetOp1();
- GenTree* op2 = tree->gtGetOp2();
- // Both operands must have already been decomposed into GT_LONG operators.
- noway_assert((op1->OperGet() == GT_LONG) && (op2->OperGet() == GT_LONG));
- // Capture the lo and hi halves of op1 and op2.
- GenTree* loOp1 = op1->gtGetOp1();
- GenTree* hiOp1 = op1->gtGetOp2();
- GenTree* loOp2 = op2->gtGetOp1();
- GenTree* hiOp2 = op2->gtGetOp2();
-
- // We don't have support to decompose a TYP_LONG node that already has a child that has
- // been decomposed into parts, where the high part depends on the value generated by the
- // low part (via the flags register). For example, if we have:
- // +(gt_long(+(lo3, lo4), +Hi(hi3, hi4)), gt_long(lo2, hi2))
- // We would decompose it here to:
- // gt_long(+(+(lo3, lo4), lo2), +Hi(+Hi(hi3, hi4), hi2))
- // But this would generate incorrect code, because the "+Hi(hi3, hi4)" code generation
- // needs to immediately follow the "+(lo3, lo4)" part. Also, if this node is one that
- // requires a unique high operator, and the child nodes are not simple locals (e.g.,
- // they are decomposed nodes), then we also can't decompose the node, as we aren't
- // guaranteed the high and low parts will be executed immediately after each other.
-
- NYI_IF(hiOp1->OperIsHigh() ||
- hiOp2->OperIsHigh() ||
- (GenTree::OperIsHigh(getHiOper(oper)) &&
- (!loOp1->OperIsLeaf() ||
- !hiOp1->OperIsLeaf() ||
- !loOp1->OperIsLeaf() ||
- !hiOp2->OperIsLeaf())),
- "Can't decompose expression tree TYP_LONG node");
-
- // Now, remove op1 and op2 from the node list.
- comp->fgSnipNode(curStmt, op1);
- comp->fgSnipNode(curStmt, op2);
-
- // We will reuse "tree" for the loResult, which will now be of TYP_INT, and its operands
- // will be the lo halves of op1 from above.
- loResult = tree;
- loResult->gtType = TYP_INT;
- loResult->gtOp.gtOp1 = loOp1;
- loResult->gtOp.gtOp2 = loOp2;
-
- // The various halves will be correctly threaded internally. We simply need to
- // relink them into the proper order, i.e. loOp1 is followed by loOp2, and then
- // the loResult node.
- // (This rethreading, and that below, are where we need to address the reverse ops case).
- // The current order is (after snipping op1 and op2):
- // ... loOp1-> ... hiOp1->loOp2First ... loOp2->hiOp2First ... hiOp2
- // The order we want is:
- // ... loOp1->loOp2First ... loOp2->loResult
- // ... hiOp1->hiOp2First ... hiOp2->hiResult
- // i.e. we swap hiOp1 and loOp2, and create (for now) separate loResult and hiResult trees
- GenTree* loOp2First = hiOp1->gtNext;
- GenTree* hiOp2First = loOp2->gtNext;
-
- // First, we will NYI if both hiOp1 and loOp2 have side effects.
- NYI_IF(((loOp2->gtFlags & GTF_ALL_EFFECT) != 0) && ((hiOp1->gtFlags & GTF_ALL_EFFECT) != 0),
- "Binary long operator with non-reorderable sub expressions");
-
- // Now, we reorder the loOps and the loResult.
- loOp1->gtNext = loOp2First;
- loOp2First->gtPrev = loOp1;
- loOp2->gtNext = loResult;
- loResult->gtPrev = loOp2;
-
- // Next, reorder the hiOps and the hiResult.
- hiResult = new (comp, oper) GenTreeOp(getHiOper(oper), TYP_INT, hiOp1, hiOp2);
- hiOp1->gtNext = hiOp2First;
- hiOp2First->gtPrev = hiOp1;
- hiOp2->gtNext = hiResult;
- hiResult->gtPrev = hiOp2;
-
- if (oper == GT_ADD || oper == GT_SUB)
- {
- if (loResult->gtOverflow())
- {
- hiResult->gtFlags |= GTF_OVERFLOW;
- loResult->gtFlags &= ~GTF_OVERFLOW;
- }
- if (loResult->gtFlags & GTF_UNSIGNED)
- {
- hiResult->gtFlags |= GTF_UNSIGNED;
- }
- }
- // Below, we'll put the loResult and hiResult trees together, using the more
- // general fgInsertTreeInListAfter() method.
- }
- break;
- case GT_MUL:
- NYI("Arithmetic binary operators on TYP_LONG - GT_MUL");
- break;
- case GT_DIV:
- NYI("Arithmetic binary operators on TYP_LONG - GT_DIV");
- break;
- case GT_MOD:
- NYI("Arithmetic binary operators on TYP_LONG - GT_MOD");
- break;
- case GT_UDIV:
- NYI("Arithmetic binary operators on TYP_LONG - GT_UDIV");
- break;
- case GT_UMOD:
- NYI("Arithmetic binary operators on TYP_LONG - GT_UMOD");
- break;
- case GT_LSH:
- case GT_RSH:
- case GT_RSZ:
- NYI("Arithmetic binary operators on TYP_LONG - SHIFT");
- break;
- case GT_ROL:
- case GT_ROR:
- NYI("Arithmetic binary operators on TYP_LONG - ROTATE");
- break;
- case GT_MULHI:
- NYI("Arithmetic binary operators on TYP_LONG - MULHI");
- break;
- case GT_LOCKADD:
- case GT_XADD:
- case GT_XCHG:
- case GT_CMPXCHG:
- NYI("Interlocked operations on TYP_LONG");
- break;
- default:
- {
- JITDUMP("Illegal TYP_LONG node %s in Lowering.", GenTree::NodeName(tree->OperGet()));
- noway_assert(!"Illegal TYP_LONG node in Lowering.");
- break;
- }
- }
- if (loResult != nullptr)
- {
- noway_assert(hiResult != nullptr);
- comp->fgInsertTreeInListAfter(hiResult, loResult, curStmt);
- hiResult->CopyCosts(tree);
-
- newTree = new (comp, GT_LONG) GenTreeOp(GT_LONG, TYP_LONG, loResult, hiResult);
- SimpleLinkNodeAfter(hiResult, newTree);
- }
- if (newTree != nullptr)
- {
- comp->fgFixupIfCallArg(data->parentStack, tree, newTree);
- newTree->CopyCosts(tree);
- *pTree = newTree;
- }
-#ifdef DEBUG
- if (comp->verbose)
- {
- printf(" AFTER:\n");
- comp->gtDispTree(*pTree);
- }
-#endif
-#endif // //_TARGET_64BIT_
-}
-
-// Decompose 64-bit storeIndir tree into multiple 32-bit trees.
-#if !defined(_TARGET_64BIT_)
-void Lowering::DecomposeStoreInd(GenTree* tree)
-{
- assert(tree->gtOp.gtOp2->OperGet() == GT_LONG);
-
- GenTreeStmt* currStmt = comp->compCurStmt->AsStmt();
- bool isEmbeddedStmt = !currStmt->gtStmtIsTopLevel();
-
- // Example input trees (a nested embedded statement case)
- //
- // <linkBegin Node>
- // * stmtExpr void (top level) (IL ???... ???)
- // | /--* argPlace ref $280
- // | +--* argPlace int $4a
- // | | { * stmtExpr void (embedded) (IL ???... ???)
- // | | { | /--* lclVar ref V11 tmp9 u:3 $21c
- // | | { | +--* const int 4 $44
- // | | { | /--* + byref $2c8
- // | | { | | { * stmtExpr void (embedded) (IL ???... ???)
- // | | { | | { | /--* lclFld long V01 arg1 u:2[+8] Fseq[i] $380
- // | | { | | { \--* st.lclVar long (P) V21 cse8
- // | | { | | { \--* int V21.hi (offs=0x00) -> V22 rat0
- // | | { | | { \--* int V21.hi (offs=0x04) -> V23 rat1
- // | | { | | /--* lclVar int V22 rat0 $380
- // | | { | | +--* lclVar int V23 rat1
- // | | { | +--* gt_long long
- // | | { \--* storeIndir long
- // | +--* lclVar ref V11 tmp9 u:3 (last use) $21c
- // | +--* lclVar ref V02 tmp0 u:3 $280
- // | +--* const int 8 $4a
- // \--* call help void HELPER.CORINFO_HELP_ARRADDR_ST $205
- // <linkEndNode>
-
- GenTree* linkBegin = comp->fgGetFirstNode(tree)->gtPrev;
- GenTree* linkEnd = tree->gtNext;
- GenTree* gtLong = tree->gtOp.gtOp2;
-
- // Save address to a temp. It is used in storeIndLow and storeIndHigh trees.
- GenTreeStmt* addrStmt = comp->fgInsertEmbeddedFormTemp(&tree->gtOp.gtOp1);
-#ifdef DEBUG
- if (comp->verbose)
- {
- printf("[DecomposeStoreInd]: Saving address tree to a temp var:\n");
- comp->gtDispTree(addrStmt);
- }
-#endif
-
- // If we have made a new top-level statement, and it has inherited any
- // embedded statements from curStmt, they have not yet been decomposed.
- if (addrStmt->gtStmtIsTopLevel())
- {
- for (GenTreePtr nextEmbeddedStmt = addrStmt->gtStmtNextIfEmbedded();
- nextEmbeddedStmt != nullptr;
- nextEmbeddedStmt = nextEmbeddedStmt->gtStmt.gtStmtNextIfEmbedded())
- {
- comp->compCurStmt = nextEmbeddedStmt;
- comp->fgWalkTreePost(&nextEmbeddedStmt->gtStmt.gtStmtExpr, &Lowering::DecompNodeHelper, this, true);
- }
- }
-
- // Restore curStmt.
- comp->compCurStmt = currStmt;
-
- if (!gtLong->gtOp.gtOp1->OperIsLeaf())
- {
- GenTreeStmt* dataLowStmt = comp->fgInsertEmbeddedFormTemp(&gtLong->gtOp.gtOp1);
-#ifdef DEBUG
- if (comp->verbose)
- {
- printf("[DecomposeStoreInd]: Saving low data tree to a temp var:\n");
- comp->gtDispTree(dataLowStmt);
- }
-#endif
- // If we have made a new top-level statement, and it has inherited any
- // embedded statements from curStmt, they have not yet been decomposed.
- if (dataLowStmt->gtStmtIsTopLevel())
- {
- for (GenTreePtr nextEmbeddedStmt = dataLowStmt->gtStmtNextIfEmbedded();
- nextEmbeddedStmt != nullptr;
- nextEmbeddedStmt = nextEmbeddedStmt->gtStmt.gtStmtNextIfEmbedded())
- {
- comp->compCurStmt = nextEmbeddedStmt;
- comp->fgWalkTreePost(&nextEmbeddedStmt->gtStmt.gtStmtExpr, &Lowering::DecompNodeHelper, this, true);
- }
- }
-
- // Restore curStmt.
- comp->compCurStmt = currStmt;
- }
-
- if (!gtLong->gtOp.gtOp2->OperIsLeaf())
- {
- GenTreeStmt* dataHighStmt = comp->fgInsertEmbeddedFormTemp(&gtLong->gtOp.gtOp2);
-#ifdef DEBUG
- if (comp->verbose)
- {
- printf("[DecomposeStoreInd]: Saving high data tree to a temp var:\n");
- comp->gtDispTree(dataHighStmt);
- }
-#endif
- }
-
- // Example trees after embedded statements for address and data are added.
- // This example saves all address and data trees into temp variables
- // to show how those embedded statements are created.
- //
- // * stmtExpr void (top level) (IL ???... ???)
- // | /--* argPlace ref $280
- // | +--* argPlace int $4a
- // | | { * stmtExpr void (embedded) (IL ???... ???)
- // | | { | /--* lclVar ref V11 tmp9 u:3 $21c
- // | | { | +--* const int 4 $44
- // | | { | /--* + byref $2c8
- // | | { \--* st.lclVar byref V24 rat2
- // | | { * stmtExpr void (embedded) (IL ???... ???)
- // | | { | /--* lclVar byref V24 rat2
- // | | { | | { * stmtExpr void (embedded) (IL ???... ???)
- // | | { | | { | /--* lclFld long V01 arg1 u:2[+8] Fseq[i] $380380
- // | | { | | { \--* st.lclVar long (P) V21 cse8
- // | | { | | { \--* int V21.hi (offs=0x00) -> V22 rat0
- // | | { | | { \--* int V21.hi (offs=0x04) -> V23 rat1
- // | | { | | { * stmtExpr void (embedded) (IL ???... ???)
- // | | { | | { | /--* lclVar int V22 rat0 $380
- // | | { | | { \--* st.lclVar int V25 rat3
- // | | { | | /--* lclVar int V25 rat3
- // | | { | | | { * stmtExpr void (embedded) (IL ???... ???)
- // | | { | | | { | /--* lclVar int V23 rat1
- // | | { | | | { \--* st.lclVar int V26 rat4
- // | | { | | +--* lclVar int V26 rat4
- // | | { | +--* gt_long long
- // | | { \--* storeIndir long
- // | +--* lclVar ref V11 tmp9 u:3 (last use) $21c
- // | +--* lclVar ref V02 tmp0 u:3 $280
- // | +--* const int 8 $4a
- // \--* call help void HELPER.CORINFO_HELP_ARRADDR_ST $205
-
- GenTree* addrBase = tree->gtOp.gtOp1;
- GenTree* dataHigh = gtLong->gtOp.gtOp2;
- GenTree* dataLow = gtLong->gtOp.gtOp1;
- GenTree* storeIndLow = tree;
-
- // Rewrite storeIndLow tree to save only lower 32-bit data.
- //
- // | | { | /--* lclVar byref V24 rat2 (address)
- // ...
- // | | { | +--* lclVar int V25 rat3 (lower 32-bit data)
- // | | { | { * stmtExpr void (embedded) (IL ???... ???)
- // | | { | { | /--* lclVar int V23 rat1
- // | | { | { \--* st.lclVar int V26 rat4
- // | | { \--* storeIndir int
- comp->fgSnipNode(currStmt, gtLong);
- comp->fgSnipNode(currStmt, dataHigh);
- storeIndLow->gtOp.gtOp2 = dataLow;
- storeIndLow->gtType = TYP_INT;
-
- // Construct storeIndHigh tree
- //
- // | | { *stmtExpr void (embedded)(IL ? ? ? ... ? ? ? )
- // | | { | / --* lclVar int V26 rat4
- // | | { | | / --* lclVar byref V24 rat2
- // | | { | +--* lea(b + 4) ref
- // | | { \--* storeIndir int
- GenTree* addrBaseHigh = new(comp, GT_LCL_VAR) GenTreeLclVar(GT_LCL_VAR,
- addrBase->TypeGet(), addrBase->AsLclVarCommon()->GetLclNum(), BAD_IL_OFFSET);
- GenTree* addrHigh = new(comp, GT_LEA) GenTreeAddrMode(TYP_REF, addrBaseHigh, nullptr, 0, genTypeSize(TYP_INT));
- GenTree* storeIndHigh = new(comp, GT_STOREIND) GenTreeStoreInd(TYP_INT, addrHigh, dataHigh);
- storeIndHigh->gtFlags = (storeIndLow->gtFlags & (GTF_ALL_EFFECT | GTF_LIVENESS_MASK));
- storeIndHigh->gtFlags |= GTF_REVERSE_OPS;
- storeIndHigh->CopyCosts(storeIndLow);
-
- // Internal links of storeIndHigh tree
- dataHigh->gtPrev = dataHigh->gtNext = nullptr;
- SimpleLinkNodeAfter(dataHigh, addrBaseHigh);
- SimpleLinkNodeAfter(addrBaseHigh, addrHigh);
- SimpleLinkNodeAfter(addrHigh, storeIndHigh);
-
- // External links of storeIndHigh tree
- //dataHigh->gtPrev = nullptr;
- if (isEmbeddedStmt)
- {
- // If storeIndTree is an embedded statement, connect storeIndLow
- // and dataHigh
- storeIndLow->gtNext = dataHigh;
- dataHigh->gtPrev = storeIndLow;
- }
- storeIndHigh->gtNext = linkEnd;
- if (linkEnd != nullptr)
- {
- linkEnd->gtPrev = storeIndHigh;
- }
-
- if (isEmbeddedStmt)
- {
- // Find a parent statment containing storeIndHigh.
- GenTree* parentStmt = currStmt;
- while ((parentStmt != nullptr) && (!parentStmt->AsStmt()->gtStmtIsTopLevel()))
- {
- parentStmt = parentStmt->gtPrev;
- }
- assert(parentStmt);
-
- GenTreeStmt* stmt = comp->fgMakeEmbeddedStmt(comp->compCurBB, storeIndHigh, parentStmt);
- stmt->gtStmtILoffsx = comp->compCurStmt->gtStmt.gtStmtILoffsx;
- }
- else
- {
- GenTreeStmt* stmt = comp->fgNewStmtFromTree(storeIndHigh);
- stmt->gtStmtILoffsx = comp->compCurStmt->gtStmt.gtStmtILoffsx;
-
- // Find an insert point. Skip all embedded statements.
- GenTree* insertPt = currStmt;
- while ((insertPt->gtNext != nullptr) && (!insertPt->gtNext->AsStmt()->gtStmtIsTopLevel()))
- {
- insertPt = insertPt->gtNext;
- }
-
- comp->fgInsertStmtAfter(comp->compCurBB, insertPt, stmt);
- }
-
- // Example final output
- //
- // * stmtExpr void (top level) (IL ???... ???)
- // | /--* argPlace ref $280
- // | +--* argPlace int $4a
- // | | { * stmtExpr void (embedded) (IL ???... ???)
- // | | { | /--* lclVar ref V11 tmp9 u:3 $21c
- // | | { | +--* const int 4 $44
- // | | { | /--* + byref $2c8
- // | | { \--* st.lclVar byref V24 rat2
- // | | { * stmtExpr void (embedded) (IL ???... ???)
- // | | { | /--* lclVar byref V24 rat2
- // | | { | | { * stmtExpr void (embedded) (IL ???... ???)
- // | | { | | { | /--* lclFld int V01 arg1 u:2[+8] Fseq[i] $380
- // | | { | | { | +--* lclFld int V01 arg1 [+12]
- // | | { | | { | /--* gt_long long
- // | | { | | { \--* st.lclVar long (P) V21 cse8
- // | | { | | { \--* int V21.hi (offs=0x00) -> V22 rat0
- // | | { | | { \--* int V21.hi (offs=0x04) -> V23 rat1
- // | | { | | { * stmtExpr void (embedded) (IL ???... ???)
- // | | { | | { | /--* lclVar int V22 rat0 $380
- // | | { | | { \--* st.lclVar int V25 rat3
- // | | { | +--* lclVar int V25 rat3
- // | | { | { * stmtExpr void (embedded) (IL ???... ???)
- // | | { | { | /--* lclVar int V23 rat1
- // | | { | { \--* st.lclVar int V26 rat4
- // | | { \--* storeIndir int
- // | | { * stmtExpr void (embedded) (IL ???... ???)
- // | | { | /--* lclVar int V26 rat4
- // | | { | | /--* lclVar byref V24 rat2
- // | | { | +--* lea(b+4) ref
- // | | { \--* storeIndir int
- // | | /--* lclVar ref V11 tmp9 u:3 (last use) $21c
- // | +--* putarg_stk [+0x00] ref
- // | | /--* lclVar ref V02 tmp0 u:3 $280
- // | +--* putarg_reg ref
- // | | /--* const int 8 $4a
- // | +--* putarg_reg int
- // \--* call help void HELPER.CORINFO_HELP_ARRADDR_ST $205
-}
-#endif //!_TARGET_64BIT_
/** Creates an assignment of an existing tree to a new temporary local variable
* and the specified reference count for the new variable.
@@ -1917,7 +1147,10 @@ void Lowering::LowerArg(GenTreeCall* call, GenTreePtr* ppArg)
GenTreePtr argLo = arg->gtGetOp1();
GenTreePtr argHi = arg->gtGetOp2();
- NYI_IF(argHi->OperGet() == GT_ADD_HI || argHi->OperGet() == GT_SUB_HI, "Hi and Lo cannot be reordered");
+ NYI_IF((argHi->OperGet() == GT_ADD_HI) ||
+ (argHi->OperGet() == GT_SUB_HI) ||
+ (argHi->OperGet() == GT_NEG),
+ "Hi and Lo cannot be reordered");
GenTreePtr putArgLo = NewPutArg(call, argLo, info, type);
GenTreePtr putArgHi = NewPutArg(call, argHi, info, type);
@@ -1994,7 +1227,6 @@ void Lowering::LowerArg(GenTreeCall* call, GenTreePtr* ppArg)
// do lowering steps for each arg of a call
void Lowering::LowerArgsForCall(GenTreeCall* call)
{
- JITDUMP("\n");
JITDUMP("objp:\n======\n");
if (call->gtCallObjp)
{
@@ -2014,9 +1246,6 @@ void Lowering::LowerArgsForCall(GenTreeCall* call)
{
LowerArg(call, &args->Current());
}
-
- JITDUMP("\nafter:\n=====\n");
- DISPTREE(call);
}
// helper that create a node representing a relocatable physical address computation
@@ -2056,14 +1285,9 @@ void Lowering::LowerCall(GenTree* node)
{
GenTreeCall* call = node->AsCall();
GenTreeStmt* callStmt = comp->compCurStmt->AsStmt();
- //assert(comp->fgTreeIsInStmt(call, callStmt));
- if (!comp->fgTreeIsInStmt(call, callStmt))
- {
- printf("fgTreeIsInStmt error\n");
- comp->fgTreeIsInStmt(call, callStmt);
- }
+ assert(comp->fgTreeIsInStmt(call, callStmt));
- JITDUMP("lowering call:\n");
+ JITDUMP("lowering call (before):\n");
DISPTREE(call);
JITDUMP("\n");
@@ -2119,7 +1343,6 @@ void Lowering::LowerCall(GenTree* node)
}
}
-
#ifdef DEBUG
comp->fgDebugCheckNodeLinks(comp->compCurBB, comp->compCurStmt);
#endif
@@ -2145,11 +1368,14 @@ void Lowering::LowerCall(GenTree* node)
result = LowerTailCallViaHelper(call, result);
- // We got a new call target constructed, so resequence it.
- comp->gtSetEvalOrder(result);
- comp->fgSetTreeSeq(result, nullptr);
- JITDUMP("results of lowering tail call via helper:\n");
- DISPTREE(result);
+ if (result != nullptr)
+ {
+ // We got a new call target constructed, so resequence it.
+ comp->gtSetEvalOrder(result);
+ comp->fgSetTreeSeq(result, nullptr);
+ JITDUMP("results of lowering tail call via helper:\n");
+ DISPTREE(result);
+ }
}
else if (call->IsFastTailCall())
{
@@ -2188,6 +1414,10 @@ void Lowering::LowerCall(GenTree* node)
{
CheckVSQuirkStackPaddingNeeded(call);
}
+
+ JITDUMP("lowering call (after):\n");
+ DISPTREE(call);
+ JITDUMP("\n");
}
// Though the below described issue gets fixed in intellitrace dll of VS2015 (a.k.a Dev14),
@@ -2598,18 +1828,34 @@ void Lowering::LowerFastTailCall(GenTreeCall *call)
#endif
}
-// Lower tail.call(void *copyRoutine, void *dummyArg, ...) as Jit_TailCall(void *copyRoutine, void *callTarget, ...).
+
+//------------------------------------------------------------------------
+// LowerTailCallViaHelper: lower a call via the tailcall helper. Morph
+// has already inserted tailcall helper special arguments. This function
+// inserts actual data for some placeholders.
+//
+// For AMD64, lower
+// tail.call(void* copyRoutine, void* dummyArg, ...)
+// as
+// Jit_TailCall(void* copyRoutine, void* callTarget, ...)
+//
+// For x86, lower
+// tail.call(<function args>, int numberOfOldStackArgs, int dummyNumberOfNewStackArgs, int flags, void* dummyArg)
+// as
+// JIT_TailCall(<function args>, int numberOfOldStackArgsWords, int numberOfNewStackArgsWords, int flags, void* callTarget)
+// Note that the special arguments are on the stack, whereas the function arguments follow the normal convention.
+//
// Also inserts PInvoke method epilog if required.
//
-// Params
+// Arguments:
// call - The call node
-// callTarget - The real call target. This is used to replace the dummyArg during lowering.
+// callTarget - The real call target. This is used to replace the dummyArg during lowering.
+//
+// Return Value:
+// Returns control expression tree for making a call to helper Jit_TailCall.
//
-// Returns control expr for making a call to helper Jit_TailCall.
GenTree* Lowering::LowerTailCallViaHelper(GenTreeCall* call, GenTree *callTarget)
{
- NYI_X86("Lower tail call dispatched via helper");
-
// Tail call restrictions i.e. conditions under which tail prefix is ignored.
// Most of these checks are already done by importer or fgMorphTailCall().
// This serves as a double sanity check.
@@ -2623,8 +1869,8 @@ GenTree* Lowering::LowerTailCallViaHelper(GenTreeCall* call, GenTree *callTarget
assert(call->IsTailCallViaHelper());
assert(callTarget != nullptr);
- // TailCall helper though is a call never returns to caller nor GC interruptible.
- // Therefore the block containg the tail call should be a GC-SafePoint to avoid
+ // The TailCall helper call never returns to the caller and is not GC interruptible.
+ // Therefore the block containing the tail call should be a GC safe point to avoid
// GC starvation.
assert(comp->compCurBB->bbFlags & BBF_GC_SAFE_POINT);
@@ -2643,9 +1889,12 @@ GenTree* Lowering::LowerTailCallViaHelper(GenTreeCall* call, GenTree *callTarget
comp->fgDeleteTreeFromList(callStmt, call->gtCallAddr);
}
- // In case of helper based tail calls, first argument is CopyRoutine and second argument
- // is a place holder node.
fgArgTabEntry* argEntry;
+
+#if defined(_TARGET_AMD64_)
+
+ // For AMD64, first argument is CopyRoutine and second argument is a place holder node.
+
#ifdef DEBUG
argEntry = comp->gtArgEntryByArgNum(call, 0);
assert(argEntry != nullptr);
@@ -2659,26 +1908,82 @@ GenTree* Lowering::LowerTailCallViaHelper(GenTreeCall* call, GenTree *callTarget
assert(argEntry != nullptr);
assert(argEntry->node->gtOper == GT_PUTARG_REG);
GenTree *secondArg = argEntry->node->gtOp.gtOp1;
-
+
comp->fgInsertTreeInListAfter(callTarget, secondArg, callStmt);
comp->fgDeleteTreeFromList(callStmt, secondArg);
argEntry->node->gtOp.gtOp1 = callTarget;
+#elif defined(_TARGET_X86_)
+
+ // Verify the special args are what we expect, and replace the dummy args with real values.
+ // We need to figure out the size of the outgoing stack arguments, not including the special args.
+ // The number of 4-byte words is passed to the helper for the incoming and outgoing argument sizes.
+ // This number is exactly the next slot number in the call's argument info struct.
+ unsigned nNewStkArgsWords = call->fgArgInfo->GetNextSlotNum();
+ assert(nNewStkArgsWords >= 4); // There must be at least the four special stack args.
+ nNewStkArgsWords -= 4;
+
+ unsigned numArgs = call->fgArgInfo->ArgCount();
+
+ // arg 0 == callTarget.
+ argEntry = comp->gtArgEntryByArgNum(call, numArgs - 1);
+ assert(argEntry != nullptr);
+ assert(argEntry->node->gtOper == GT_PUTARG_STK);
+ GenTree* arg0 = argEntry->node->gtOp.gtOp1;
+
+ comp->fgInsertTreeInListAfter(callTarget, arg0, callStmt);
+ comp->fgDeleteTreeFromList(callStmt, arg0);
+ argEntry->node->gtOp.gtOp1 = callTarget;
+
+ // arg 1 == flags
+ argEntry = comp->gtArgEntryByArgNum(call, numArgs - 2);
+ assert(argEntry != nullptr);
+ assert(argEntry->node->gtOper == GT_PUTARG_STK);
+ GenTree* arg1 = argEntry->node->gtOp.gtOp1;
+ assert(arg1->gtOper == GT_CNS_INT);
+
+ ssize_t tailCallHelperFlags =
+ 1 | // always restore EDI,ESI,EBX
+ (call->IsVirtualStub() ? 0x2 : 0x0); // Stub dispatch flag
+ arg1->gtIntCon.gtIconVal = tailCallHelperFlags;
+
+ // arg 2 == numberOfNewStackArgsWords
+ argEntry = comp->gtArgEntryByArgNum(call, numArgs - 3);
+ assert(argEntry != nullptr);
+ assert(argEntry->node->gtOper == GT_PUTARG_STK);
+ GenTree* arg2 = argEntry->node->gtOp.gtOp1;
+ assert(arg2->gtOper == GT_CNS_INT);
+
+ arg2->gtIntCon.gtIconVal = nNewStkArgsWords;
+
+#ifdef DEBUG
+ // arg 3 == numberOfOldStackArgsWords
+ argEntry = comp->gtArgEntryByArgNum(call, numArgs - 4);
+ assert(argEntry != nullptr);
+ assert(argEntry->node->gtOper == GT_PUTARG_STK);
+ GenTree* arg3 = argEntry->node->gtOp.gtOp1;
+ assert(arg3->gtOper == GT_CNS_INT);
+#endif // DEBUG
+
+#else
+ NYI("LowerTailCallViaHelper");
+#endif // _TARGET_*
+
// Transform this call node into a call to Jit tail call helper.
call->gtCallType = CT_HELPER;
call->gtCallMethHnd = comp->eeFindHelper(CORINFO_HELP_TAILCALL);
call->gtFlags &= ~GTF_CALL_VIRT_KIND_MASK;
// Lower this as if it were a pure helper call.
- call->gtFlags &= ~(GTF_CALL_M_TAILCALL | GTF_CALL_M_TAILCALL_VIA_HELPER);
+ call->gtCallMoreFlags &= ~(GTF_CALL_M_TAILCALL | GTF_CALL_M_TAILCALL_VIA_HELPER);
GenTree *result = LowerDirectCall(call);
// Now add back tail call flags for identifying this node as tail call dispatched via helper.
- call->gtFlags |= GTF_CALL_M_TAILCALL | GTF_CALL_M_TAILCALL_VIA_HELPER;
+ call->gtCallMoreFlags |= GTF_CALL_M_TAILCALL | GTF_CALL_M_TAILCALL_VIA_HELPER;
// Insert profiler tail call hook if needed.
// Since we don't know the insertion point, pass null for second param.
- if(comp->compIsProfilerHookNeeded())
+ if (comp->compIsProfilerHookNeeded())
{
InsertProfTailCallHook(call, nullptr);
}
@@ -2772,7 +2077,7 @@ GenTree* Lowering::LowerDirectCall(GenTreeCall* call)
if (call->IsSameThis())
aflags = (CORINFO_ACCESS_FLAGS)(aflags | CORINFO_ACCESS_THIS);
- if ((call->NeedsNullCheck()) == 0)
+ if (!call->NeedsNullCheck())
aflags = (CORINFO_ACCESS_FLAGS)(aflags | CORINFO_ACCESS_NONNULL);
CORINFO_CONST_LOOKUP addrInfo;
@@ -2847,56 +2152,72 @@ GenTree* Lowering::LowerDelegateInvoke(GenTreeCall* call)
assert((comp->info.compCompHnd->getMethodAttribs(call->gtCallMethHnd) & (CORINFO_FLG_DELEGATE_INVOKE|CORINFO_FLG_FINAL)) == (CORINFO_FLG_DELEGATE_INVOKE|CORINFO_FLG_FINAL));
- GenTree* thisNode;
+ GenTree* thisArgNode;
if (call->IsTailCallViaHelper())
{
+#ifdef _TARGET_X86_ // x86 tailcall via helper follows normal calling convention, but with extra stack args.
+ const unsigned argNum = 0;
+#else // !_TARGET_X86_
// In case of helper dispatched tail calls, "thisptr" will be the third arg.
// The first two args are: real call target and addr of args copy routine.
const unsigned argNum = 2;
+#endif // !_TARGET_X86_
+
fgArgTabEntryPtr thisArgTabEntry = comp->gtArgEntryByArgNum(call, argNum);
- thisNode = thisArgTabEntry->node;
+ thisArgNode = thisArgTabEntry->node;
}
else
{
- thisNode = comp->gtGetThisArg(call);
+ thisArgNode = comp->gtGetThisArg(call);
}
- assert(thisNode->gtOper == GT_PUTARG_REG);
- GenTree** pThisExpr = &(thisNode->gtOp.gtOp1);
+ assert(thisArgNode->gtOper == GT_PUTARG_REG);
+ GenTree* originalThisExpr = thisArgNode->gtOp.gtOp1;
+
+ // If what we are passing as the thisptr is not already a local, make a new local to place it in
+ // because we will be creating expressions based on it.
+ unsigned lclNum;
+ if (originalThisExpr->IsLocal())
+ {
+ lclNum = originalThisExpr->AsLclVarCommon()->GetLclNum();
+ }
+ else
+ {
+ unsigned delegateInvokeTmp = comp->lvaGrabTemp(true DEBUGARG("delegate invoke call"));
+ GenTreeStmt* newStmt = comp->fgInsertEmbeddedFormTemp(&thisArgNode->gtOp.gtOp1, delegateInvokeTmp);
+ originalThisExpr = thisArgNode->gtOp.gtOp1; // it's changed; reload it.
+ newStmt->gtFlags |= GTF_STMT_SKIP_LOWER; // we're in postorder so we have already processed this subtree
+ GenTree* stLclVar = newStmt->gtStmtExpr;
+ assert(stLclVar->OperIsLocalStore());
+ lclNum = stLclVar->AsLclVarCommon()->GetLclNum();
+ }
// replace original expression feeding into thisPtr with
// [originalThis + offsetOfDelegateInstance]
- GenTreeStmt* newStmt = comp->fgInsertEmbeddedFormTemp(pThisExpr);
- GenTree* stloc = newStmt->gtStmtExpr;
- newStmt->gtFlags |= GTF_STMT_SKIP_LOWER;
-
- unsigned originalThisLclNum = stloc->AsLclVarCommon()->GetLclNum();
-
- GenTree* originalThisValue = *pThisExpr;
-
GenTree* newThisAddr = new(comp, GT_LEA) GenTreeAddrMode(TYP_REF,
- originalThisValue,
+ originalThisExpr,
nullptr,
0,
comp->eeGetEEInfo()->offsetOfDelegateInstance);
- originalThisValue->InsertAfterSelf(newThisAddr);
+ originalThisExpr->InsertAfterSelf(newThisAddr);
GenTree* newThis = comp->gtNewOperNode(GT_IND, TYP_REF, newThisAddr);
newThis->SetCosts(IND_COST_EX, 2);
newThisAddr->InsertAfterSelf(newThis);
- *pThisExpr = newThis;
+ thisArgNode->gtOp.gtOp1 = newThis;
// the control target is
// [originalThis + firstTgtOffs]
- GenTree* base = new (comp, GT_LCL_VAR) GenTreeLclVar(originalThisValue->TypeGet(), originalThisLclNum, BAD_IL_OFFSET);
+ GenTree* base = new (comp, GT_LCL_VAR) GenTreeLclVar(originalThisExpr->TypeGet(), lclNum, BAD_IL_OFFSET);
unsigned targetOffs = comp->eeGetEEInfo()->offsetOfDelegateFirstTarget;
GenTree* result = new(comp, GT_LEA) GenTreeAddrMode(TYP_REF, base, nullptr, 0, targetOffs);
GenTree* callTarget = Ind(result);
// don't need to sequence and insert this tree, caller will do it
+
return callTarget;
}
@@ -3600,17 +2921,15 @@ GenTree* Lowering::LowerVirtualVtableCall(GenTreeCall* call)
// If this is a tail call via helper, thisPtr will be the third argument.
int thisPtrArgNum;
regNumber thisPtrArgReg;
+
+#ifndef _TARGET_X86_ // x86 tailcall via helper follows normal calling convention, but with extra stack args.
if (call->IsTailCallViaHelper())
{
thisPtrArgNum = 2;
-#ifdef _TARGET_X86_
- NYI("Tail call via helper for x86");
- thisPtrArgReg = REG_NA;
-#else // !_TARGET_X86_
thisPtrArgReg = REG_ARG_2;
-#endif // !_TARGET_X86_
}
else
+#endif // !_TARGET_X86_
{
thisPtrArgNum = 0;
thisPtrArgReg = comp->codeGen->genGetThisArgReg(call);
@@ -3634,7 +2953,7 @@ GenTree* Lowering::LowerVirtualVtableCall(GenTreeCall* call)
// Split off the thisPtr and store to a temporary variable.
if (vtableCallTemp == BAD_VAR_NUM)
{
- vtableCallTemp = comp->lvaGrabTemp(true DEBUGARG("temp for virtual vtable call"));
+ vtableCallTemp = comp->lvaGrabTemp(true DEBUGARG("virtual vtable call"));
}
GenTreeStmt* newStmt = comp->fgInsertEmbeddedFormTemp(&(argEntry->node->gtOp.gtOp1), vtableCallTemp);
newStmt->gtFlags |= GTF_STMT_SKIP_LOWER; // we're in postorder so we have already processed this subtree
@@ -3752,17 +3071,31 @@ GenTree* Lowering::LowerVirtualStubCall(GenTreeCall* call)
// Direct stub calls, though the stubAddr itself may still need to be
// accesed via an indirection.
GenTree* addr = AddrGen(stubAddr);
- GenTree* indir = Ind(addr);
- // On x86 we generate this:
- // call dword ptr [rel32] ; FF 15 ---rel32----
- // So we don't use a register.
+#ifdef _TARGET_X86_
+ // On x86, for tailcall via helper, the JIT_TailCall helper takes the stubAddr as
+ // the target address, and we set a flag that it's a VSD call. The helper then
+ // handles any necessary indirection.
+ if (call->IsTailCallViaHelper())
+ {
+ result = addr;
+ }
+#endif // _TARGET_X86_
+
+ if (result == nullptr)
+ {
+ GenTree* indir = Ind(addr);
+
+ // On x86 we generate this:
+ // call dword ptr [rel32] ; FF 15 ---rel32----
+ // So we don't use a register.
#ifndef _TARGET_X86_
- // on x64 we must materialize the target using specific registers.
- addr->gtRegNum = REG_VIRTUAL_STUB_PARAM;
- indir->gtRegNum = REG_JUMP_THUNK_PARAM;
+ // on x64 we must materialize the target using specific registers.
+ addr->gtRegNum = REG_VIRTUAL_STUB_PARAM;
+ indir->gtRegNum = REG_JUMP_THUNK_PARAM;
#endif
- result = indir;
+ result = indir;
+ }
}
// TODO-Cleanup: start emitting random NOPS
@@ -4455,7 +3788,8 @@ void Lowering::DoPhase()
#endif
#if !defined(_TARGET_64BIT_)
- comp->lvaPromoteLongVars();
+ DecomposeLongs decomp(comp); // Initialize the long decomposition class.
+ decomp.PrepareForDecomposition();
#endif // !defined(_TARGET_64BIT_)
for (BasicBlock* block = comp->fgFirstBB; block; block = block->bbNext)
@@ -4467,24 +3801,7 @@ void Lowering::DoPhase()
comp->compCurBB = block;
#if !defined(_TARGET_64BIT_)
- // Walk the statement trees in this basic block
- // Decompose all long trees first before lowering. Decomposition could
- // insert statements before current statement.
- for (stmt = block->bbTreeList; stmt; stmt = stmt->gtNext)
- {
- if (stmt->gtFlags & GTF_STMT_SKIP_LOWER)
- {
- continue;
- }
-#ifdef DEBUG
- if (comp->verbose)
- {
- printf("Decomposing BB%02u, stmt id %u\n", block->bbNum, stmt->gtTreeID);
- }
-#endif
- comp->compCurStmt = stmt;
- comp->fgWalkTreePost(&stmt->gtStmt.gtStmtExpr, &Lowering::DecompNodeHelper, this, true);
- }
+ decomp.DecomposeBlock(block);
#endif //!_TARGET_64BIT_
// Walk the statement trees in this basic block
@@ -4504,7 +3821,7 @@ void Lowering::DoPhase()
comp->fgWalkTreePost(&stmt->gtStmt.gtStmtExpr, &Lowering::LowerNodeHelper, this, true);
// We may have removed "stmt" in LowerNode().
stmt = comp->compCurStmt;
- }
+ }
}
// If we have any PInvoke calls, insert the one-time prolog code. We've already inserted the epilog code in the appropriate spots.
@@ -4785,7 +4102,7 @@ bool Lowering::NodesAreEquivalentLeaves(GenTreePtr tree1, GenTreePtr tree2)
}
/**
- * Takes care of replaing a GenTree node's child with a new tree.
+ * Takes care of replacing a GenTree node's child with a new tree.
*
* Assumptions:
* a) replacementNode has been unlinked (orphaned) and the expression it represents
@@ -4861,18 +4178,6 @@ void Lowering::UnlinkNode(GenTree** ppParentLink, GenTree* stmt, BasicBlock* blo
ReplaceNode(ppParentLink, comp->gtNewNothingNode(), stmt, block);
}
-void Lowering::SimpleLinkNodeAfter(GenTree* prevTree, GenTree* newTree)
-{
- GenTree* nextTree = prevTree->gtNext;
- newTree->gtPrev = prevTree;
- prevTree->gtNext = newTree;
- if (nextTree != nullptr)
- {
- newTree->gtNext = nextTree;
- nextTree->gtPrev = newTree;
- }
-}
-
#ifdef _TARGET_64BIT_
/**
diff --git a/src/jit/lower.h b/src/jit/lower.h
index 9419557ad5..9f62978a62 100644
--- a/src/jit/lower.h
+++ b/src/jit/lower.h
@@ -52,11 +52,9 @@ public:
private:
// Friends
static Compiler::fgWalkResult LowerNodeHelper (GenTreePtr* ppTree, Compiler::fgWalkData* data);
- static Compiler::fgWalkResult DecompNodeHelper (GenTreePtr* ppTree, Compiler::fgWalkData* data);
static Compiler::fgWalkResult TreeInfoInitHelper(GenTreePtr* ppTree, Compiler::fgWalkData* data);
// Member Functions
- void DecomposeNode(GenTreePtr* tree, Compiler::fgWalkData* data);
void LowerNode(GenTreePtr* tree, Compiler::fgWalkData* data);
GenTreeStmt* LowerMorphAndSeqTree(GenTree *tree);
void CheckVSQuirkStackPaddingNeeded(GenTreeCall* call);
@@ -145,8 +143,62 @@ private:
void TreeNodeInfoInit(GenTreePtr* tree, GenTree* parent);
#if defined(_TARGET_XARCH_)
void TreeNodeInfoInitSimple(GenTree* tree);
- void SetRegOptionalForBinOp(GenTree* tree);
- void TryToSetRegOptional(GenTree* operand);
+
+ //----------------------------------------------------------------------
+ // SetRegOptional - sets a bit to indicate to LSRA that register
+ // for a given tree node is optional for codegen purpose. If no
+ // register is allocated to such a tree node, its parent node treats
+ // it as a contained memory operand during codegen.
+ //
+ // Arguments:
+ // tree - GenTree node
+ //
+ // Returns
+ // None
+ void SetRegOptional(GenTree* tree)
+ {
+ tree->gtLsraInfo.regOptional = true;
+ }
+
+ GenTree* PreferredRegOptionalOperand(GenTree* tree);
+
+ // ------------------------------------------------------------------
+ // SetRegOptionalBinOp - Indicates which of the operands of a bin-op
+ // register requirement is optional. Xarch instruction set allows
+ // either of op1 or op2 of binary operation (e.g. add, mul etc) to be
+ // a memory operand. This routine provides info to register allocator
+ // which of its operands optionally require a register. Lsra might not
+ // allocate a register to RefTypeUse positions of such operands if it
+ // is beneficial. In such a case codegen will treat them as memory
+ // operands.
+ //
+ // Arguments:
+ // tree - Gentree of a bininary operation.
+ //
+ // Returns
+ // None.
+ //
+ // Note: On xarch at most only one of the operands will be marked as
+ // reg optional, even when both operands could be considered register
+ // optional.
+ void SetRegOptionalForBinOp(GenTree* tree)
+ {
+ assert(GenTree::OperIsBinary(tree->OperGet()));
+
+ GenTree* op1 = tree->gtGetOp1();
+ GenTree* op2 = tree->gtGetOp2();
+
+ if (tree->OperIsCommutative() &&
+ tree->TypeGet() == op1->TypeGet())
+ {
+ GenTree* preferredOp = PreferredRegOptionalOperand(tree);
+ SetRegOptional(preferredOp);
+ }
+ else if (tree->TypeGet() == op2->TypeGet())
+ {
+ SetRegOptional(op2);
+ }
+ }
#endif // defined(_TARGET_XARCH_)
void TreeNodeInfoInitReturn(GenTree* tree);
void TreeNodeInfoInitShiftRotate(GenTree* tree);
@@ -197,13 +249,6 @@ private:
void LowerArrElem(GenTree **ppTree, Compiler::fgWalkData* data);
void LowerRotate(GenTree *tree);
- // ------------------------------
- // Decompose helper functions
- // ------------------------------
-#if !defined(_TARGET_64BIT_)
- void DecomposeStoreInd(GenTree* tree);
-#endif //!_TARGET_64BIT_
-
// Utility functions
void MorphBlkIntoHelperCall (GenTreePtr pTree, GenTreePtr treeStmt);
public:
@@ -220,7 +265,6 @@ private:
BasicBlock* block);
void UnlinkNode (GenTree** ppParentLink, GenTree* stmt, BasicBlock* block);
- void SimpleLinkNodeAfter (GenTree* prevTree, GenTree* newTree);
// return true if 'childNode' is an immediate that can be contained
// by the 'parentNode' (i.e. folded into an instruction)
diff --git a/src/jit/lowerxarch.cpp b/src/jit/lowerxarch.cpp
index e410a6916a..3580b43e0b 100644
--- a/src/jit/lowerxarch.cpp
+++ b/src/jit/lowerxarch.cpp
@@ -344,6 +344,12 @@ void Lowering::TreeNodeInfoInit(GenTree* stmt)
info->dstCount = 0;
break;
+#if !defined(_TARGET_64BIT_)
+ case GT_ADD_LO:
+ case GT_ADD_HI:
+ case GT_SUB_LO:
+ case GT_SUB_HI:
+#endif
case GT_ADD:
case GT_SUB:
// SSE2 arithmetic instructions doesn't support the form "op mem, xmm".
@@ -555,7 +561,7 @@ void Lowering::TreeNodeInfoInit(GenTree* stmt)
info->srcCount = 2;
info->dstCount = 0;
- GenTreePtr other = nullptr;
+ GenTreePtr other;
if (CheckImmedAndMakeContained(tree, node->gtIndex))
{
other = node->gtArrLen;
@@ -573,17 +579,17 @@ void Lowering::TreeNodeInfoInit(GenTree* stmt)
other = node->gtArrLen;
}
- if (other->isMemoryOp())
+ if (node->gtIndex->TypeGet() == node->gtArrLen->TypeGet())
{
- if (node->gtIndex->TypeGet() == node->gtArrLen->TypeGet())
+ if (other->isMemoryOp())
{
MakeSrcContained(tree, other);
}
- }
- else
- {
- // since 'other' operand is not contained, we can mark it as reg optional
- TryToSetRegOptional(other);
+ else
+ {
+ // We can mark 'other' as reg optional, since it is not contained.
+ SetRegOptional(other);
+ }
}
}
break;
@@ -1392,13 +1398,29 @@ Lowering::TreeNodeInfoInitCall(GenTreeCall* call)
// If the child of GT_PUTARG_STK is a constant, we don't need a register to
// move it to memory (stack location).
- // We don't want to make 0 contained, because we can generate smaller code
- // by zeroing a register and then storing it.
+ //
+ // On AMD64, we don't want to make 0 contained, because we can generate smaller code
+ // by zeroing a register and then storing it. E.g.:
+ // xor rdx, rdx
+ // mov gword ptr [rsp+28H], rdx
+ // is 2 bytes smaller than:
+ // mov gword ptr [rsp+28H], 0
+ //
+ // On x86, we push stack arguments; we don't use 'mov'. So:
+ // push 0
+ // is 1 byte smaller than:
+ // xor rdx, rdx
+ // push rdx
+
argInfo->dstCount = 0;
if (arg->gtOper == GT_PUTARG_STK)
{
GenTree* op1 = arg->gtOp.gtOp1;
- if (IsContainableImmed(arg, op1) && !op1->IsIntegralConst(0))
+ if (IsContainableImmed(arg, op1)
+#if defined(_TARGET_AMD64_)
+ && !op1->IsIntegralConst(0)
+#endif // _TARGET_AMD64_
+ )
{
MakeSrcContained(arg, op1);
}
@@ -1895,9 +1917,9 @@ Lowering::TreeNodeInfoInitLclHeap(GenTree* tree)
//
// Size? Init Memory? # temp regs
// 0 - 0
- // const and <=6 ptr words - 0
- // const and >6 ptr words Yes 0
- // const and <PageSize No 0
+ // const and <=6 reg words - 0
+ // const and >6 reg words Yes 0
+ // const and <PageSize No 0 (amd64) 1 (x86)
// const and >=PageSize No 2
// Non-const Yes 0
// Non-const No 2
@@ -1919,11 +1941,12 @@ Lowering::TreeNodeInfoInitLclHeap(GenTree* tree)
// Note: The Gentree node is not updated here as it is cheap to recompute stack aligned size.
// This should also help in debugging as we can examine the original size specified with localloc.
sizeVal = AlignUp(sizeVal, STACK_ALIGN);
- size_t cntStackAlignedWidthItems = (sizeVal >> STACK_ALIGN_SHIFT);
// For small allocations up to 6 pointer sized words (i.e. 48 bytes of localloc)
// we will generate 'push 0'.
- if (cntStackAlignedWidthItems <= 6)
+ assert((sizeVal % REGSIZE_BYTES) == 0);
+ size_t cntRegSizedWords = sizeVal / REGSIZE_BYTES;
+ if (cntRegSizedWords <= 6)
{
info->internalIntCount = 0;
}
@@ -1932,7 +1955,11 @@ Lowering::TreeNodeInfoInitLclHeap(GenTree* tree)
// No need to initialize allocated stack space.
if (sizeVal < compiler->eeGetPageSize())
{
+#ifdef _TARGET_X86_
+ info->internalIntCount = 1; // x86 needs a register here to avoid generating "sub" on ESP.
+#else // !_TARGET_X86_
info->internalIntCount = 0;
+#endif // !_TARGET_X86_
}
else
{
@@ -2076,7 +2103,8 @@ Lowering::TreeNodeInfoInitModDiv(GenTree* tree)
else
{
// If there are no containable operands, we can make an operand reg optional.
- SetRegOptionalForBinOp(tree);
+ // SSE2 allows only op2 to be a memory-op.
+ SetRegOptional(op2);
}
return;
@@ -2117,7 +2145,8 @@ Lowering::TreeNodeInfoInitModDiv(GenTree* tree)
op2->gtLsraInfo.setSrcCandidates(l, l->allRegs(TYP_INT) & ~(RBM_RAX | RBM_RDX));
// If there are no containable operands, we can make an operand reg optional.
- SetRegOptionalForBinOp(tree);
+ // Div instruction allows only op2 to be a memory op.
+ SetRegOptional(op2);
}
}
@@ -2156,7 +2185,7 @@ Lowering::TreeNodeInfoInitIntrinsic(GenTree* tree)
{
// Mark the operand as reg optional since codegen can still
// generate code if op1 is on stack.
- TryToSetRegOptional(op1);
+ SetRegOptional(op1);
}
break;
@@ -2492,7 +2521,7 @@ Lowering::TreeNodeInfoInitCast(GenTree* tree)
{
// Mark castOp as reg optional to indicate codegen
// can still generate code if it is on stack.
- TryToSetRegOptional(castOp);
+ SetRegOptional(castOp);
}
}
}
@@ -2850,18 +2879,16 @@ void Lowering::LowerCmp(GenTreePtr tree)
{
MakeSrcContained(tree, otherOp);
}
- else if (otherOp->isMemoryOp())
+ else if (otherOp->isMemoryOp() &&
+ ((otherOp == op2) || IsSafeToContainMem(tree, otherOp)))
{
- if ((otherOp == op2) || IsSafeToContainMem(tree, otherOp))
- {
- MakeSrcContained(tree, otherOp);
- }
+ MakeSrcContained(tree, otherOp);
}
else
{
- // Mark otherOp as reg optional to indicate codgen can still generate
- // code even if otherOp is on stack.
- TryToSetRegOptional(otherOp);
+ // SSE2 allows only otherOp to be a memory-op. Since otherOp is not
+ // contained, we can mark it reg-optional.
+ SetRegOptional(otherOp);
}
return;
@@ -2939,6 +2966,7 @@ void Lowering::LowerCmp(GenTreePtr tree)
}
}
}
+
if (op1CanBeContained)
{
if (op1->isMemoryOp())
@@ -2946,7 +2974,9 @@ void Lowering::LowerCmp(GenTreePtr tree)
MakeSrcContained(tree, op1);
}
else
- {
+ {
+ bool op1IsMadeContained = false;
+
// When op1 is a GT_AND we can often generate a single "test" instruction
// instead of two instructions (an "and" instruction followed by a "cmp"/"test")
//
@@ -3072,6 +3102,7 @@ void Lowering::LowerCmp(GenTreePtr tree)
}
// Mark the 'op1' (the GT_AND) operand as contained
MakeSrcContained(tree, op1);
+ op1IsMadeContained = true;
// During Codegen we will now generate "test andOp1, andOp2CnsVal"
}
@@ -3116,8 +3147,8 @@ void Lowering::LowerCmp(GenTreePtr tree)
assert(!castOp1->gtOverflowEx()); // Must not be an overflow checking operation
GenTreePtr removeTreeNode = op1;
- GenTreePtr removeTreeNodeChild = castOp1;
tree->gtOp.gtOp1 = castOp1;
+ op1 = castOp1;
castOp1->gtType = TYP_UBYTE;
// trim down the value if castOp1 is an int constant since its type changed to UBYTE.
@@ -3139,6 +3170,7 @@ void Lowering::LowerCmp(GenTreePtr tree)
if (castOp1->isMemoryOp())
{
MakeSrcContained(tree, op1);
+ op1IsMadeContained = true;
}
}
}
@@ -3152,6 +3184,12 @@ void Lowering::LowerCmp(GenTreePtr tree)
#endif
}
}
+
+ // If not made contained, op1 can be marked as reg-optional.
+ if (!op1IsMadeContained)
+ {
+ SetRegOptional(op1);
+ }
}
}
}
@@ -3170,12 +3208,7 @@ void Lowering::LowerCmp(GenTreePtr tree)
// One of op1 or op2 could be marked as reg optional
// to indicate that codgen can still generate code
// if one of them is on stack.
- TryToSetRegOptional(op2);
-
- if (!op2->IsRegOptional())
- {
- TryToSetRegOptional(op1);
- }
+ SetRegOptional(PreferredRegOptionalOperand(tree));
}
if (varTypeIsSmall(op1Type) && varTypeIsUnsigned(op1Type))
@@ -3706,6 +3739,10 @@ void Lowering::SetMulOpCounts(GenTreePtr tree)
bool requiresOverflowCheck = tree->gtOverflowEx();
bool useLeaEncoding = false;
GenTreePtr memOp = nullptr;
+
+ bool hasImpliedFirstOperand = false;
+ GenTreeIntConCommon* imm = nullptr;
+ GenTreePtr other = nullptr;
// There are three forms of x86 multiply:
// one-op form: RDX:RAX = RAX * r/m
@@ -3729,26 +3766,25 @@ void Lowering::SetMulOpCounts(GenTreePtr tree)
// In LSRA we set the kill set for this operation to RBM_RAX|RBM_RDX
//
info->setDstCandidates(m_lsra,RBM_RAX);
+ hasImpliedFirstOperand = true;
}
else if (tree->gtOper == GT_MULHI)
{
// have to use the encoding:RDX:RAX = RAX * rm
info->setDstCandidates(m_lsra, RBM_RAX);
+ hasImpliedFirstOperand = true;
}
else if (IsContainableImmed(tree, op2) || IsContainableImmed(tree, op1))
{
- GenTreeIntConCommon* imm;
- GenTreePtr other;
-
if (IsContainableImmed(tree, op2))
{
imm = op2->AsIntConCommon();
- other = op1;
+ other = op1;
}
else
{
imm = op1->AsIntConCommon();
- other = op2;
+ other = op2;
}
// CQ: We want to rewrite this into a LEA
@@ -3759,11 +3795,12 @@ void Lowering::SetMulOpCounts(GenTreePtr tree)
}
MakeSrcContained(tree, imm); // The imm is always contained
- if (other->isIndir())
+ if (other->isMemoryOp())
{
memOp = other; // memOp may be contained below
}
}
+
// We allow one operand to be a contained memory operand.
// The memory op type must match with the 'tree' type.
// This is because during codegen we use 'tree' type to derive EmitTypeSize.
@@ -3779,17 +3816,28 @@ void Lowering::SetMulOpCounts(GenTreePtr tree)
//
if (!useLeaEncoding)
{
- if (memOp != nullptr)
+ if ((memOp != nullptr) &&
+ (memOp->TypeGet() == tree->TypeGet()) &&
+ IsSafeToContainMem(tree, memOp))
{
- if ((memOp->TypeGet() == tree->TypeGet()) &&
- IsSafeToContainMem(tree, memOp))
- {
- MakeSrcContained(tree, memOp);
- }
+ MakeSrcContained(tree, memOp);
+ }
+ else if (imm != nullptr)
+ {
+ // Has a contained immediate operand.
+ // Only 'other' operand can be marked as reg optional.
+ assert(other != nullptr);
+ SetRegOptional(other);
+ }
+ else if (hasImpliedFirstOperand)
+ {
+ // Only op2 can be marke as reg optional.
+ SetRegOptional(op2);
}
else
{
- // If there are no containable operands, we can make an operand reg optional.
+ // If there are no containable operands, we can make either of op1 or op2
+ // as reg optional.
SetRegOptionalForBinOp(tree);
}
}
@@ -3858,67 +3906,128 @@ bool Lowering:: IsContainableImmed(GenTree* parentNode, GenTree* childNode)
return true;
}
-//----------------------------------------------------------------------
-// TryToSetRegOptional - sets a bit to indicate to LSRA that register
-// for a given tree node is optional for codegen purpose. If no
-// register is allocated to such a tree node, its parent node treats
-// it as a contained memory operand during codegen.
-//
-// Arguments:
-// tree - GenTree node
+//-----------------------------------------------------------------------
+// PreferredRegOptionalOperand: returns one of the operands of given
+// binary oper that is to be preferred for marking as reg optional.
//
-// Returns
-// None
-//
-// Note: Right now a tree node is marked as reg optional only
-// if is it a GT_LCL_VAR. This routine needs to be modified if
-// in future if lower/codegen needs to support other tree node
-// types.
-void Lowering::TryToSetRegOptional(GenTree* tree)
-{
- if (tree->OperGet() == GT_LCL_VAR)
- {
- tree->gtLsraInfo.regOptional = true;
- }
-}
-
-// ------------------------------------------------------------------
-// SetRegOptionalBinOp - Indicates which of the operands of a bin-op
-// register requirement is optional. Xarch instruction set allows
-// either of op1 or op2 of binary operation (e.g. add, mul etc) to be
-// a memory operand. This routine provides info to register allocator
-// which of its operands optionally require a register. Lsra might not
-// allocate a register to RefTypeUse positions of such operands if it
-// is beneficial. In such a case codegen will treat them as memory
-// operands.
+// Since only one of op1 or op2 can be a memory operand on xarch, only
+// one of them have to be marked as reg optional. Since Lower doesn't
+// know apriori which of op1 or op2 is not likely to get a register, it
+// has to make a guess. This routine encapsulates heuristics that
+// guess whether it is likely to be beneficial to mark op1 or op2 as
+// reg optional.
+//
//
// Arguments:
-// tree - Gentree of a bininary operation.
+// tree - a binary-op tree node that is either commutative
+// or a compare oper.
//
-// Returns
-// None.
-//
-// Note: On xarch at most only one of the operands will be marked as
-// reg optional, even when both operands could be considered register
-// optional.
-void Lowering::SetRegOptionalForBinOp(GenTree* tree)
+// Returns:
+// Returns op1 or op2 of tree node that is preferred for
+// marking as reg optional.
+//
+// Note: if the tree oper is neither commutative nor a compare oper
+// then only op2 can be reg optional on xarch and hence no need to
+// call this routine.
+GenTree* Lowering::PreferredRegOptionalOperand(GenTree* tree)
{
assert(GenTree::OperIsBinary(tree->OperGet()));
+ assert(tree->OperIsCommutative() || tree->OperIsCompare());
GenTree* op1 = tree->gtGetOp1();
GenTree* op2 = tree->gtGetOp2();
+ GenTree* preferredOp = nullptr;
- if (tree->TypeGet() == op2->TypeGet())
+ // This routine uses the following heuristics:
+ //
+ // a) If both are tracked locals, marking the one with lower weighted
+ // ref count as reg-optional would likely be beneficial as it has
+ // higher probability of not getting a register.
+ //
+ // b) op1 = tracked local and op2 = untracked local: LSRA creates two
+ // ref positions for op2: a def and use position. op2's def position
+ // requires a reg and it is allocated a reg by spilling another
+ // interval (if required) and that could be even op1. For this reason
+ // it is beneficial to mark op1 as reg optional.
+ //
+ // TODO: It is not always mandatory for a def position of an untracked
+ // local to be allocated a register if it is on rhs of an assignment
+ // and its use position is reg-optional and has not been assigned a
+ // register. Reg optional def positions is currently not yet supported.
+ //
+ // c) op1 = untracked local and op2 = tracked local: marking op1 as
+ // reg optional is beneficial, since its use position is less likely
+ // to get a register.
+ //
+ // d) If both are untracked locals (i.e. treated like tree temps by
+ // LSRA): though either of them could be marked as reg optional,
+ // marking op1 as reg optional is likely to be beneficial because
+ // while allocating op2's def position, there is a possibility of
+ // spilling op1's def and in which case op1 is treated as contained
+ // memory operand rather than requiring to reload.
+ //
+ // e) If only one of them is a local var, prefer to mark it as
+ // reg-optional. This is heuristic is based on the results
+ // obtained against CQ perf benchmarks.
+ //
+ // f) If neither of them are local vars (i.e. tree temps), prefer to
+ // mark op1 as reg optional for the same reason as mentioned in (d) above.
+ if (op1->OperGet() == GT_LCL_VAR &&
+ op2->OperGet() == GT_LCL_VAR)
{
- TryToSetRegOptional(op2);
- }
+ LclVarDsc* v1 = comp->lvaTable + op1->AsLclVarCommon()->GetLclNum();
+ LclVarDsc* v2 = comp->lvaTable + op2->AsLclVarCommon()->GetLclNum();
- if (!op2->IsRegOptional() &&
- tree->OperIsCommutative() &&
- tree->TypeGet() == op1->TypeGet())
+ if (v1->lvTracked && v2->lvTracked)
+ {
+ // Both are tracked locals. The one with lower weight is less likely
+ // to get a register and hence beneficial to mark the one with lower
+ // weight as reg optional.
+ if (v1->lvRefCntWtd < v2->lvRefCntWtd)
+ {
+ preferredOp = op1;
+ }
+ else
+ {
+ preferredOp = op2;
+ }
+ }
+ else if (v2->lvTracked)
+ {
+ // v1 is an untracked lcl and it is use position is less likely to
+ // get a register.
+ preferredOp = op1;
+ }
+ else if (v1->lvTracked)
+ {
+ // v2 is an untracked lcl and its def position always
+ // needs a reg. Hence it is better to mark v1 as
+ // reg optional.
+ preferredOp = op1;
+ }
+ else
+ {
+ preferredOp = op1;;
+ }
+ }
+ else if (op1->OperGet() == GT_LCL_VAR)
+ {
+ preferredOp = op1;
+ }
+ else if (op2->OperGet() == GT_LCL_VAR)
{
- TryToSetRegOptional(op1);
+ preferredOp = op2;
}
+ else
+ {
+ // Neither of the operands is a local, prefer marking
+ // operand that is evaluated first as reg optional
+ // since its use position is less likely to get a register.
+ bool reverseOps = ((tree->gtFlags & GTF_REVERSE_OPS) != 0);
+ preferredOp = reverseOps ? op2 : op1;
+ }
+
+ return preferredOp;
}
#endif // _TARGET_XARCH_
diff --git a/src/jit/lsra.cpp b/src/jit/lsra.cpp
index 3298eb6986..266d68ec60 100644
--- a/src/jit/lsra.cpp
+++ b/src/jit/lsra.cpp
@@ -752,6 +752,7 @@ LinearScan::newRefPosition(regNumber reg,
newRP->registerAssignment = mask;
newRP->setMultiRegIdx(0);
+ newRP->setAllocateIfProfitable(0);
associateRefPosWithInterval(newRP);
@@ -835,6 +836,7 @@ LinearScan::newRefPosition(Interval* theInterval,
newRP->registerAssignment = mask;
newRP->setMultiRegIdx(multiRegIdx);
+ newRP->setAllocateIfProfitable(0);
associateRefPosWithInterval(newRP);
@@ -3023,6 +3025,7 @@ LinearScan::buildRefPositionsForNode(GenTree *tree,
pos->isLocalDefUse = true;
bool isLastUse = ((tree->gtFlags & GTF_VAR_DEATH) != 0);
pos->lastUse = isLastUse;
+ pos->setAllocateIfProfitable(tree->IsRegOptional());
DBEXEC(VERBOSE, pos->dump());
return;
}
@@ -3216,6 +3219,7 @@ LinearScan::buildRefPositionsForNode(GenTree *tree,
prefSrcInterval = i;
}
+ bool regOptionalAtUse = useNode->IsRegOptional();
bool isLastUse = true;
if (isCandidateLocalRef(useNode))
{
@@ -3224,7 +3228,7 @@ LinearScan::buildRefPositionsForNode(GenTree *tree,
else
{
// For non-localVar uses we record nothing,
- // as nothing needs to be written back to the tree)
+ // as nothing needs to be written back to the tree.
useNode = nullptr;
}
@@ -3260,7 +3264,15 @@ LinearScan::buildRefPositionsForNode(GenTree *tree,
pos->delayRegFree = true;
}
- if (isLastUse) pos->lastUse = true;
+ if (isLastUse)
+ {
+ pos->lastUse = true;
+ }
+
+ if (regOptionalAtUse)
+ {
+ pos->setAllocateIfProfitable(1);
+ }
}
JITDUMP("\n");
@@ -4903,7 +4915,7 @@ LinearScan::tryAllocateFreeReg(Interval *currentInterval, RefPosition *refPositi
// Arguments:
// current The interval for the current allocation
// refPosition The RefPosition of the current Interval for which a register is being allocated
-// allocationOptional If true, a reg may not be allocated if all other ref positions currently
+// allocateIfProfitable If true, a reg may not be allocated if all other ref positions currently
// occupying registers are more important than the 'refPosition'.
//
// Return Value:
@@ -4911,20 +4923,20 @@ LinearScan::tryAllocateFreeReg(Interval *currentInterval, RefPosition *refPositi
//
// Note: Currently this routine uses weight and farthest distance of next reference
// to select a ref position for spilling.
-// a) if allocationOptional = false
+// a) if allocateIfProfitable = false
// The ref position chosen for spilling will be the lowest weight
// of all and if there is is more than one ref position with the
// same lowest weight, among them choses the one with farthest
// distance to its next reference.
//
-// b) if allocationOptional = true
+// b) if allocateIfProfitable = true
// The ref position chosen for spilling will not only be lowest weight
// of all but also has a weight lower than 'refPosition'. If there is
// no such ref position, reg will not be allocated.
regNumber
LinearScan::allocateBusyReg(Interval* current,
RefPosition* refPosition,
- bool allocationOptional)
+ bool allocateIfProfitable)
{
regNumber foundReg = REG_NA;
@@ -4951,7 +4963,7 @@ LinearScan::allocateBusyReg(Interval* current,
LsraLocation farthestLocation = MinLocation;
LsraLocation refLocation = refPosition->nodeLocation;
unsigned farthestRefPosWeight;
- if (allocationOptional)
+ if (allocateIfProfitable)
{
// If allocating a reg is optional, we will consider those ref positions
// whose weight is less than 'refPosition' for spilling.
@@ -5132,19 +5144,39 @@ LinearScan::allocateBusyReg(Interval* current,
// the farthest.
assert(recentAssignedRefWeight == farthestRefPosWeight);
- // If allocation is optional, the first spill candidate selected
+ // If allocateIfProfitable=true, the first spill candidate selected
// will be based on weight alone. After we have found a spill
// candidate whose weight is less than the 'refPosition', we will
// consider farthest distance when there is a tie in weights.
// This is to ensure that we don't spill a ref position whose
// weight is equal to weight of 'refPosition'.
- if (allocationOptional && farthestRefPhysRegRecord == nullptr)
+ if (allocateIfProfitable && farthestRefPhysRegRecord == nullptr)
{
isBetterLocation = false;
}
else
{
isBetterLocation = (nextLocation > farthestLocation);
+
+ if (nextLocation > farthestLocation)
+ {
+ isBetterLocation = true;
+ }
+ else if (nextLocation == farthestLocation)
+ {
+ // Both weight and distance are equal.
+ // Prefer that ref position which is marked both reload and
+ // allocate if profitable. These ref positions don't need
+ // need to be spilled as they are already in memory and
+ // codegen considers them as contained memory operands.
+ isBetterLocation = (recentAssignedRef != nullptr) &&
+ recentAssignedRef->reload &&
+ recentAssignedRef->AllocateIfProfitable();
+ }
+ else
+ {
+ isBetterLocation = false;
+ }
}
}
@@ -5157,7 +5189,7 @@ LinearScan::allocateBusyReg(Interval* current,
}
#if DEBUG
- if (allocationOptional)
+ if (allocateIfProfitable)
{
// There may not be a spill candidate or if one is found
// its weight must be less than the weight of 'refPosition'
@@ -5312,7 +5344,10 @@ LinearScan::spillInterval(Interval* interval, RefPosition* fromRefPosition, RefP
if (!fromRefPosition->lastUse)
{
- if (!fromRefPosition->IsActualRef())
+ // If not allocated a register, Lcl var def/use ref positions even if reg optional
+ // should be marked as spillAfter.
+ if (!fromRefPosition->RequiresRegister() &&
+ !(interval->isLocalVar && fromRefPosition->IsActualRef()))
{
fromRefPosition->registerAssignment = RBM_NONE;
}
@@ -6607,12 +6642,12 @@ LinearScan::allocateRegisters()
{
bool allocateReg = true;
- if (currentRefPosition->IsRegOptional())
+ if (currentRefPosition->AllocateIfProfitable())
{
- if (currentRefPosition->lastUse &&
+ // We can avoid allocating a register if it is a the last use requiring a reload.
+ if (currentRefPosition->lastUse &&
currentRefPosition->reload)
{
- // We can avoid allocating a register if it is a the last use requiring a reload
allocateReg = false;
}
@@ -6653,26 +6688,25 @@ LinearScan::allocateRegisters()
}
else
#endif // FEATURE_SIMD
- if (currentRefPosition->IsActualRef())
+ if (currentRefPosition->RequiresRegister() ||
+ currentRefPosition->AllocateIfProfitable())
{
if (allocateReg)
{
- // Though Lower/Codegen has indicated that it can generate code even if
- // no reg is allocated to this ref position, we will make an attempt
- // to get a busy reg if it is allocated to a lesser important ref position.
- // If all the refpositions currently occupying registers are more
- // important than currentRefPosition, no reg will be allocated.
- assignedRegister = allocateBusyReg(currentInterval, currentRefPosition, currentRefPosition->IsRegOptional());
+ assignedRegister = allocateBusyReg(currentInterval,
+ currentRefPosition,
+ currentRefPosition->AllocateIfProfitable());
}
if (assignedRegister != REG_NA)
{
INDEBUG(dumpLsraAllocationEvent(LSRA_EVENT_ALLOC_SPILLED_REG, currentInterval, assignedRegister));
}
- else
+ else
{
- // This can happen only if ref position requires a reg optionally
- noway_assert(currentRefPosition->IsRegOptional());
+ // This can happen only for those ref positions that are to be allocated
+ // only if profitable.
+ noway_assert(currentRefPosition->AllocateIfProfitable());
currentRefPosition->registerAssignment = RBM_NONE;
currentRefPosition->reload = false;
@@ -6867,9 +6901,7 @@ LinearScan::resolveLocalRef(GenTreePtr treeNode, RefPosition * currentRefPositio
if (currentRefPosition->registerAssignment == RBM_NONE)
{
- // Either requires no register or reg is optional.
- assert(!currentRefPosition->IsActualRef() ||
- currentRefPosition->IsRegOptional());
+ assert(!currentRefPosition->RequiresRegister());
interval->isSpilled = true;
varDsc->lvRegNum = REG_STK;
@@ -6930,7 +6962,27 @@ LinearScan::resolveLocalRef(GenTreePtr treeNode, RefPosition * currentRefPositio
if (treeNode != nullptr)
{
treeNode->gtFlags |= GTF_SPILLED;
- if (spillAfter) treeNode->gtFlags |= GTF_SPILL;
+ if (spillAfter)
+ {
+ if (currentRefPosition->AllocateIfProfitable())
+ {
+ // This is a use of lclVar that is flagged as reg-optional
+ // by lower/codegen and marked for both reload and spillAfter.
+ // In this case we can avoid unnecessary reload and spill
+ // by setting reg on lclVar to REG_STK and reg on tree node
+ // to REG_NA. Codegen will generate the code by considering
+ // it as a contained memory operand.
+ //
+ // Note that varDsc->lvRegNum is already to REG_STK above.
+ interval->physReg = REG_NA;
+ treeNode->gtRegNum = REG_NA;
+ treeNode->gtFlags &= ~GTF_SPILLED;
+ }
+ else
+ {
+ treeNode->gtFlags |= GTF_SPILL;
+ }
+ }
}
else
{
@@ -6963,7 +7015,9 @@ LinearScan::resolveLocalRef(GenTreePtr treeNode, RefPosition * currentRefPositio
interval->physReg = REG_NA;
if (treeNode != nullptr)
treeNode->gtRegNum = REG_NA;
- } else {
+ }
+ else
+ {
// Not reload and Not pure-def that's spillAfter
if (currentRefPosition->copyReg || currentRefPosition->moveReg)
@@ -7373,7 +7427,11 @@ LinearScan::recordMaxSpill()
void
LinearScan::updateMaxSpill(RefPosition* refPosition)
{
- if (refPosition->spillAfter || refPosition->reload)
+ RefType refType = refPosition->refType;
+
+ if (refPosition->spillAfter ||
+ refPosition->reload ||
+ (refPosition->AllocateIfProfitable() && refPosition->assignedReg() == REG_NA))
{
Interval* interval = refPosition->getInterval();
if (!interval->isLocalVar)
@@ -7384,8 +7442,8 @@ LinearScan::updateMaxSpill(RefPosition* refPosition)
// 8-byte non-GC items, and 16-byte or 32-byte SIMD vectors.
// LSRA is agnostic to those choices but needs
// to know what they are here.
- RefType refType = refPosition->refType;
var_types typ;
+
#if FEATURE_PARTIAL_SIMD_CALLEE_SAVE
if ((refType == RefTypeUpperVectorSaveDef) || (refType == RefTypeUpperVectorSaveUse))
{
@@ -7397,7 +7455,7 @@ LinearScan::updateMaxSpill(RefPosition* refPosition)
GenTreePtr treeNode = refPosition->treeNode;
if (treeNode == nullptr)
{
- assert(RefTypeIsUse(refPosition->refType));
+ assert(RefTypeIsUse(refType));
treeNode = interval->firstRefPosition->treeNode;
}
assert(treeNode != nullptr);
@@ -7429,6 +7487,17 @@ LinearScan::updateMaxSpill(RefPosition* refPosition)
assert(currentSpill[typ] > 0);
currentSpill[typ]--;
}
+ else if (refPosition->AllocateIfProfitable() &&
+ refPosition->assignedReg() == REG_NA)
+ {
+ // A spill temp not getting reloaded into a reg because it is
+ // marked as allocate if profitable and getting used from its
+ // memory location. To properly account max spill for typ we
+ // decrement spill count.
+ assert(RefTypeIsUse(refType));
+ assert(currentSpill[typ] > 0);
+ currentSpill[typ]--;
+ }
JITDUMP(" Max spill for %s is %d\n", varTypeName(typ), maxSpill[typ]);
}
}
@@ -7647,18 +7716,20 @@ LinearScan::resolveRegisters()
if (treeNode == nullptr)
{
// This is either a use, a dead def, or a field of a struct
- Interval * interval = currentRefPosition->getInterval();
+ Interval* interval = currentRefPosition->getInterval();
assert(currentRefPosition->refType == RefTypeUse ||
currentRefPosition->registerAssignment == RBM_NONE ||
interval->isStructField);
+
// TODO-Review: Need to handle the case where any of the struct fields
// are reloaded/spilled at this use
assert(!interval->isStructField ||
(currentRefPosition->reload == false &&
currentRefPosition->spillAfter == false));
+
if (interval->isLocalVar && !interval->isStructField)
{
- LclVarDsc * varDsc = interval->getLocalVar(compiler);
+ LclVarDsc* varDsc = interval->getLocalVar(compiler);
// This must be a dead definition. We need to mark the lclVar
// so that it's not considered a candidate for lvRegister, as
@@ -7666,6 +7737,7 @@ LinearScan::resolveRegisters()
assert(currentRefPosition->refType == RefTypeDef);
varDsc->lvRegNum = REG_STK;
}
+
JITDUMP("No tree node to write back to\n");
continue;
}
@@ -7762,7 +7834,25 @@ LinearScan::resolveRegisters()
if (INDEBUG(alwaysInsertReload() ||)
nextRefPosition->assignedReg() != currentRefPosition->assignedReg())
{
- insertCopyOrReload(treeNode, currentRefPosition->getMultiRegIdx(), nextRefPosition);
+ if (nextRefPosition->assignedReg() != REG_NA)
+ {
+ insertCopyOrReload(treeNode, currentRefPosition->getMultiRegIdx(), nextRefPosition);
+ }
+ else
+ {
+ assert(nextRefPosition->AllocateIfProfitable());
+
+ // In case of tree temps, if def is spilled and use didn't
+ // get a register, set a flag on tree node to be treated as
+ // contained at the point of its use.
+ if (currentRefPosition->spillAfter &&
+ currentRefPosition->refType == RefTypeDef &&
+ nextRefPosition->refType == RefTypeUse)
+ {
+ assert(nextRefPosition->treeNode == nullptr);
+ treeNode->gtFlags |= GTF_NOREG_AT_USE;
+ }
+ }
}
}
@@ -10761,14 +10851,15 @@ LinearScan::verifyFinalAllocation()
interval->physReg = REG_NA;
interval->assignedReg = nullptr;
- // regRegcord could be null if RefPosition requires a reg optionally
+ // regRegcord could be null if RefPosition is to be allocated a
+ // reg only if profitable.
if (regRecord != nullptr)
{
regRecord->assignedInterval = nullptr;
}
else
{
- assert(currentRefPosition->IsRegOptional());
+ assert(currentRefPosition->AllocateIfProfitable());
}
}
}
diff --git a/src/jit/lsra.h b/src/jit/lsra.h
index dc6d689d2e..9ce2bd79c7 100644
--- a/src/jit/lsra.h
+++ b/src/jit/lsra.h
@@ -538,8 +538,8 @@ private:
LsraSpill getLsraSpill() { return (LsraSpill) (lsraStressMask & LSRA_SPILL_MASK); }
bool spillAlways() { return getLsraSpill() == LSRA_SPILL_ALWAYS; }
- // This controls whether RefPositions that require a register optionally should
- // be allocated a reg at all.
+ // This controls whether RefPositions that lower/codegen indicated as reg optional be
+ // allocated a reg at all.
enum LsraRegOptionalControl { LSRA_REG_OPTIONAL_DEFAULT = 0,
LSRA_REG_OPTIONAL_NO_ALLOC = 0x1000,
LSRA_REG_OPTIONAL_MASK = 0x1000 };
@@ -768,7 +768,7 @@ private:
regNumber tryAllocateFreeReg(Interval *current, RefPosition *refPosition);
RegRecord* findBestPhysicalReg(RegisterType regType, LsraLocation endLocation,
regMaskTP candidates, regMaskTP preferences);
- regNumber allocateBusyReg(Interval* current, RefPosition* refPosition, bool allocationOptional);
+ regNumber allocateBusyReg(Interval* current, RefPosition* refPosition, bool allocateIfProfitable);
regNumber assignCopyReg(RefPosition * refPosition);
void checkAndAssignInterval(RegRecord * regRec, Interval * interval);
@@ -1355,15 +1355,46 @@ public:
RefType refType;
+ // Returns true if it is a reference on a gentree node.
bool IsActualRef()
{
return (refType == RefTypeDef ||
- refType == RefTypeUse
+ refType == RefTypeUse);
+ }
+
+ bool RequiresRegister()
+ {
+ return (IsActualRef()
#if FEATURE_PARTIAL_SIMD_CALLEE_SAVE
- || refType == RefTypeUpperVectorSaveDef
+ || refType == RefTypeUpperVectorSaveDef
|| refType == RefTypeUpperVectorSaveUse
#endif // FEATURE_PARTIAL_SIMD_CALLEE_SAVE
- );
+ ) && !AllocateIfProfitable();
+ }
+
+ // Indicates whether this ref position is to be allocated
+ // a reg only if profitable. Currently these are the
+ // ref positions that lower/codegen has indicated as reg
+ // optional and is considered a contained memory operand if
+ // no reg is allocated.
+ unsigned allocRegIfProfitable : 1;
+
+ void setAllocateIfProfitable(unsigned val)
+ {
+ allocRegIfProfitable = val;
+ }
+
+ // Returns true whether this ref position is to be allocated
+ // a reg only if it is profitable.
+ bool AllocateIfProfitable()
+ {
+ // TODO-CQ: Right now if a ref position is marked as
+ // copyreg or movereg, then it is not treated as
+ // 'allocate if profitable'. This is an implementation
+ // limitation that needs to be addressed.
+ return allocRegIfProfitable &&
+ !copyReg &&
+ !moveReg;
}
// Used by RefTypeDef/Use positions of a multi-reg call node.
@@ -1381,22 +1412,6 @@ public:
unsigned getMultiRegIdx() { return multiRegIdx; }
- // Returns true if codegen has indicated that the tree node
- // referred to by RefPosition can be treated as a contained
- // memory operand if no register was allocated.
- bool IsRegOptional()
- {
- // TODO-CQ: Right now if a ref position is marked as
- // copyreg or movereg, then it is always allocated a
- // register, though it is marked as reg optional.
- // This is an implementation limitation that needs to
- // be addressed.
- return (refType == RefTypeUse) &&
- !copyReg &&
- !moveReg &&
- (treeNode != nullptr) &&
- treeNode->IsRegOptional();
- }
// Last Use - this may be true for multiple RefPositions in the same Interval
bool lastUse : 1;
diff --git a/src/jit/morph.cpp b/src/jit/morph.cpp
index 99cf633cad..f5c8d083ab 100644..100755
--- a/src/jit/morph.cpp
+++ b/src/jit/morph.cpp
@@ -1366,22 +1366,6 @@ void fgArgInfo::ArgsComplete()
assert(curArgTabEntry != NULL);
GenTreePtr argx = curArgTabEntry->node;
-#if defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
- // If this is a struct, mark it for needing a tempVar.
- // In the copyblk and store this should have minimal perf impact since
- // the local vars where we copy/store to already exist and the logic for temp
- // var will not create a new one if it creates a tempVar from another tempVar.
- // (Debugging through the code, there was no new copy of data created, neither a new tempVar.)
- // The need for this arise from Lower::LowerArg.
- // In case of copyblk and store operation, the NewPutArg method will
- // not be invoked and the struct will not be loaded to be passed in
- // registers or by value on the stack.
- if (varTypeIsStruct(argx) FEATURE_UNIX_AMD64_STRUCT_PASSING_ONLY( || curArgTabEntry->isStruct))
- {
- curArgTabEntry->needTmp = true;
- }
-#endif // defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
-
if (curArgTabEntry->regNum == REG_STK)
{
hasStackArgs = true;
@@ -2598,21 +2582,125 @@ GenTreeCall* Compiler::fgMorphArgs(GenTreeCall* callNode)
bool callIsVararg = call->IsVarargs();
#endif
+#ifdef FEATURE_UNIX_AMD64_STRUCT_PASSING
+ // If fgMakeOutgoingStructArgCopy is called and copies are generated, hasStackArgCopy is set
+ // to make sure to call EvalArgsToTemp. fgMakeOutgoingStructArgCopy just marks the argument
+ // to need a temp variable, and EvalArgsToTemp actually creates the temp variable node.
+ bool hasStackArgCopy = false;
+#endif
+
#ifndef LEGACY_BACKEND
// Data structure for keeping track of non-standard args. Non-standard args are those that are not passed
// following the normal calling convention or in the normal argument registers. We either mark existing
// arguments as non-standard (such as the x8 return buffer register on ARM64), or we manually insert the
// non-standard arguments into the argument list, below.
- struct NonStandardArg
+ class NonStandardArgs
{
- regNumber reg; // The register to be assigned to this non-standard argument.
- GenTree* node; // The tree node representing this non-standard argument.
- // Note that this must be updated if the tree node changes due to morphing!
- };
+ struct NonStandardArg
+ {
+ regNumber reg; // The register to be assigned to this non-standard argument.
+ GenTree* node; // The tree node representing this non-standard argument.
+ // Note that this must be updated if the tree node changes due to morphing!
+ };
+
+ ArrayStack<NonStandardArg> args;
+
+ public:
+ NonStandardArgs(Compiler* compiler)
+ : args(compiler, 3) // We will have at most 3 non-standard arguments
+ {
+ }
+
+ //-----------------------------------------------------------------------------
+ // Add: add a non-standard argument to the table of non-standard arguments
+ //
+ // Arguments:
+ // node - a GenTree node that has a non-standard argument.
+ // reg - the register to assign to this node.
+ //
+ // Return Value:
+ // None.
+ //
+ void Add(GenTree* node, regNumber reg)
+ {
+ NonStandardArg nsa = { reg, node };
+ args.Push(nsa);
+ }
+
+ //-----------------------------------------------------------------------------
+ // Find: Look for a GenTree* in the set of non-standard args.
+ //
+ // Arguments:
+ // node - a GenTree node to look for
+ //
+ // Return Value:
+ // The index of the non-standard argument (a non-negative, unique, stable number).
+ // If the node is not a non-standard argument, return -1.
+ //
+ int Find(GenTree* node)
+ {
+ for (int i = 0; i < args.Height(); i++)
+ {
+ if (node == args.Index(i).node)
+ {
+ return i;
+ }
+ }
+ return -1;
+ }
- ArrayStack<NonStandardArg> nonStandardArgs(this, 3); // We will have at most 3 non-standard arguments
+ //-----------------------------------------------------------------------------
+ // FindReg: Look for a GenTree node in the non-standard arguments set. If found,
+ // set the register to use for the node.
+ //
+ // Arguments:
+ // node - a GenTree node to look for
+ // pReg - an OUT argument. *pReg is set to the non-standard register to use if
+ // 'node' is found in the non-standard argument set.
+ //
+ // Return Value:
+ // 'true' if 'node' is a non-standard argument. In this case, *pReg is set to the
+ // register to use.
+ // 'false' otherwise (in this case, *pReg is unmodified).
+ //
+ bool FindReg(GenTree* node, regNumber* pReg)
+ {
+ for (int i = 0; i < args.Height(); i++)
+ {
+ NonStandardArg& nsa = args.IndexRef(i);
+ if (node == nsa.node)
+ {
+ *pReg = nsa.reg;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ //-----------------------------------------------------------------------------
+ // Replace: Replace the non-standard argument node at a given index. This is done when
+ // the original node was replaced via morphing, but we need to continue to assign a
+ // particular non-standard arg to it.
+ //
+ // Arguments:
+ // index - the index of the non-standard arg. It must exist.
+ // node - the new GenTree node.
+ //
+ // Return Value:
+ // None.
+ //
+ void Replace(int index, GenTree* node)
+ {
+ args.IndexRef(index).node = node;
+ }
+
+ } nonStandardArgs(this);
#endif // !LEGACY_BACKEND
+ // Count of args. On first morph, this is counted before we've filled in the arg table.
+ // On remorph, we grab it from the arg table.
+ unsigned numArgs = 0;
+
// Process the late arguments (which were determined by a previous caller).
// Do this before resetting fgPtrArgCntCur as fgMorphTree(call->gtCallLateArgs)
// may need to refer to it.
@@ -2640,11 +2728,12 @@ GenTreeCall* Compiler::fgMorphArgs(GenTreeCall* callNode)
fgPtrArgCntCur -= callStkLevel;
assert(call->fgArgInfo != nullptr);
call->fgArgInfo->RemorphReset();
+
+ numArgs = call->fgArgInfo->ArgCount();
}
else
{
// First we need to count the args
- unsigned numArgs = 0;
if (call->gtCallObjp)
numArgs++;
for (args = call->gtCallArgs; (args != nullptr); args = args->gtOp.gtOp2)
@@ -2669,8 +2758,7 @@ GenTreeCall* Compiler::fgMorphArgs(GenTreeCall* callNode)
GenTreeArgList* args = call->gtCallArgs;
GenTree* arg1 = args->Current();
assert(arg1 != nullptr);
- NonStandardArg nsa = { REG_PINVOKE_FRAME, arg1 };
- nonStandardArgs.Push(nsa);
+ nonStandardArgs.Add(arg1, REG_PINVOKE_FRAME);
}
#endif // !defined(LEGACY_BACKEND) && defined(_TARGET_X86_)
@@ -2691,8 +2779,7 @@ GenTreeCall* Compiler::fgMorphArgs(GenTreeCall* callNode)
// We don't increment numArgs here, since we already counted this argument above.
- NonStandardArg nsa = {theFixedRetBuffReg(), argx};
- nonStandardArgs.Push(nsa);
+ nonStandardArgs.Add(argx, theFixedRetBuffReg());
}
// We are allowed to have a Fixed Return Buffer argument combined
@@ -2708,8 +2795,7 @@ GenTreeCall* Compiler::fgMorphArgs(GenTreeCall* callNode)
call->gtCallArgs = gtNewListNode(cns, call->gtCallArgs);
numArgs++;
- NonStandardArg nsa = {REG_PINVOKE_COOKIE_PARAM, cns};
- nonStandardArgs.Push(nsa);
+ nonStandardArgs.Add(cns, REG_PINVOKE_COOKIE_PARAM);
}
else if (call->IsVirtualStub() &&
(call->gtCallType == CT_INDIRECT) &&
@@ -2741,8 +2827,7 @@ GenTreeCall* Compiler::fgMorphArgs(GenTreeCall* callNode)
call->gtCallArgs = gtNewListNode(arg, call->gtCallArgs);
numArgs++;
- NonStandardArg nsa = {REG_VIRTUAL_STUB_PARAM, arg};
- nonStandardArgs.Push(nsa);
+ nonStandardArgs.Add(arg, REG_VIRTUAL_STUB_PARAM);
}
else if (call->gtCallType == CT_INDIRECT && call->gtCallCookie)
{
@@ -2756,16 +2841,14 @@ GenTreeCall* Compiler::fgMorphArgs(GenTreeCall* callNode)
call->gtCallArgs = gtNewListNode(arg, call->gtCallArgs);
numArgs++;
- NonStandardArg nsa = {REG_PINVOKE_COOKIE_PARAM, arg};
- nonStandardArgs.Push(nsa);
+ nonStandardArgs.Add(arg, REG_PINVOKE_COOKIE_PARAM);
// put destination into R10
arg = gtClone(call->gtCallAddr, true);
call->gtCallArgs = gtNewListNode(arg, call->gtCallArgs);
numArgs++;
- NonStandardArg nsa2 = {REG_PINVOKE_TARGET_PARAM, arg};
- nonStandardArgs.Push(nsa2);
+ nonStandardArgs.Add(arg, REG_PINVOKE_TARGET_PARAM);
// finally change this call to a helper call
call->gtCallType = CT_HELPER;
@@ -2939,20 +3022,10 @@ GenTreeCall* Compiler::fgMorphArgs(GenTreeCall* callNode)
#endif // FEATURE_MULTIREG_ARGS
#ifndef LEGACY_BACKEND
- int nonStandard_index = -1;
+ // Record the index of any nonStandard arg that we may be processing here, as we are
+ // about to call fgMorphTree on it and fgMorphTree may replace it with a new tree.
GenTreePtr orig_argx = *parentArgx;
- // Record the index of any nonStandard arg that we may be processing here
- // as we are about to call fgMorphTree on it
- // and fgMorphTree may replace it with a new tree
- //
- for (int i = 0; i < nonStandardArgs.Height(); i++)
- {
- if (orig_argx == nonStandardArgs.Index(i).node)
- {
- nonStandard_index = i;
- break;
- }
- }
+ int nonStandard_index = nonStandardArgs.Find(orig_argx);
#endif // !LEGACY_BACKEND
argx = fgMorphTree(*parentArgx);
@@ -2967,7 +3040,7 @@ GenTreeCall* Compiler::fgMorphArgs(GenTreeCall* callNode)
{
// We need to update the node field for this nonStandard arg here
// as it was changed by the call to fgMorphTree
- nonStandardArgs.IndexRef(nonStandard_index).node = argx;
+ nonStandardArgs.Replace(nonStandard_index, argx);
}
#endif // !LEGACY_BACKEND
@@ -3193,7 +3266,7 @@ GenTreeCall* Compiler::fgMorphArgs(GenTreeCall* callNode)
}
}
// Note that there are some additional rules for multireg structs.
- // (i.e they cannot be split betwen registers and the stack)
+ // (i.e they cannot be split between registers and the stack)
}
else
{
@@ -3285,15 +3358,15 @@ GenTreeCall* Compiler::fgMorphArgs(GenTreeCall* callNode)
bool passStructByRef = false;
#endif // !FEATURE_UNIX_AMD64_STRUCT_PASSING
- // The following if-then-else needs to be carefully refactored
- // Basically the else portion wants to turn a struct load (a GT_OBJ)'
+ // The following if-then-else needs to be carefully refactored.
+ // Basically the else portion wants to turn a struct load (a GT_OBJ)
// into a GT_IND of the appropriate size.
- // It can do this with structs sizes that are 1,2,4, or 8 bytes
+ // It can do this with structs sizes that are 1, 2, 4, or 8 bytes.
// It can't do this when FEATURE_UNIX_AMD64_STRUCT_PASSING is defined (Why?)
- // TODO-Cleanup: Remove the #ifndef FEATURE_UNIX_AMD64_STRUCT_PASSING below
+ // TODO-Cleanup: Remove the #ifndef FEATURE_UNIX_AMD64_STRUCT_PASSING below.
// It also can't do this if we have a HFA arg,
- // unless we have a 1-elem HFA in which case we want to do the optization
- //
+ // unless we have a 1-elem HFA in which case we want to do the optimization.
+
#ifndef _TARGET_X86_
#ifndef FEATURE_UNIX_AMD64_STRUCT_PASSING
// Check for struct argument with size 1, 2, 4 or 8 bytes
@@ -3312,15 +3385,64 @@ GenTreeCall* Compiler::fgMorphArgs(GenTreeCall* callNode)
#else // FEATURE_UNIX_AMD64_STRUCT_PASSING
if (!structDesc.passedInRegisters)
{
+ GenTreePtr lclVar = fgIsIndirOfAddrOfLocal(argObj);
+ bool needCpyBlk = false;
+ if (lclVar != nullptr)
+ {
+ // If the struct is promoted to registers, it has to be materialized
+ // on stack. We may want to support promoted structures in
+ // codegening pugarg_stk instead of creating a copy here.
+ LclVarDsc* varDsc = &lvaTable[lclVar->gtLclVarCommon.gtLclNum];
+ needCpyBlk = varDsc->lvPromoted;
+ }
+ else
+ {
+ // If simd16 comes from vector<t>, eeGetSystemVAmd64PassStructInRegisterDescriptor
+ // sets structDesc.passedInRegisters to be false.
+ //
+ // GT_ADDR(GT_SIMD) is not a rationalized IR form and is not handled
+ // by rationalizer. For now we will let SIMD struct arg to be copied to
+ // a local. As part of cpblk rewrite, rationalizer will handle GT_ADDR(GT_SIMD)
+ //
+ // +--* obj simd16
+ // | \--* addr byref
+ // | | /--* lclVar simd16 V05 loc4
+ // | \--* simd simd16 int -
+ // | \--* lclVar simd16 V08 tmp1
+ //
+ // TODO-Amd64-Unix: The rationalizer can be updated to handle this pattern,
+ // so that we don't need to generate a copy here.
+ GenTree* addr = argObj->gtOp.gtOp1;
+ if (addr->OperGet() == GT_ADDR)
+ {
+ GenTree* addrChild = addr->gtOp.gtOp1;
+ if (addrChild->OperGet() == GT_SIMD)
+ {
+ needCpyBlk = true;
+ }
+ }
+ }
passStructInRegisters = false;
- copyBlkClass = NO_CLASS_HANDLE;
+ if (needCpyBlk)
+ {
+ copyBlkClass = objClass;
+ }
+ else
+ {
+ copyBlkClass = NO_CLASS_HANDLE;
+ }
}
else
{
// The objClass is used to materialize the struct on stack.
+ // For SystemV, the code below generates copies for struct arguments classified
+ // as register argument.
+ // TODO-Amd64-Unix: We don't always need copies for this case. Struct arguments
+ // can be passed on registers or can be copied directly to outgoing area.
passStructInRegisters = true;
copyBlkClass = objClass;
}
+
#endif // FEATURE_UNIX_AMD64_STRUCT_PASSING
#elif defined(_TARGET_ARM64_)
if ((size > 2) && !isHfaArg)
@@ -3350,17 +3472,25 @@ GenTreeCall* Compiler::fgMorphArgs(GenTreeCall* callNode)
#endif // _TARGET_ARM_
}
#ifndef FEATURE_UNIX_AMD64_STRUCT_PASSING
+ // TODO-Amd64-Unix: Since the else part below is disabled for UNIX_AMD64, copies are always
+ // generated for struct 1, 2, 4, or 8.
else // We have a struct argument with size 1, 2, 4 or 8 bytes
{
// change our GT_OBJ into a GT_IND of the correct type.
// We've already ensured above that size is a power of 2, and less than or equal to pointer size.
- structBaseType = argOrReturnTypeForStruct(originalSize, objClass, false /* forReturn */);
+
+ structPassingKind howToPassStruct;
+ structBaseType = getArgTypeForStruct(objClass, &howToPassStruct, originalSize);
+ assert(howToPassStruct == SPK_PrimitiveType);
+
+ // ToDo: remove this block as getArgTypeForStruct properly handles turning one element HFAs into primitives
if (isHfaArg)
{
// If we reach here with an HFA arg it has to be a one element HFA
assert(hfaSlots == 1);
structBaseType = hfaType; // change the indirection type to a floating point type
}
+
noway_assert(structBaseType != TYP_UNKNOWN);
argObj->ChangeOper(GT_IND);
@@ -3506,10 +3636,14 @@ GenTreeCall* Compiler::fgMorphArgs(GenTreeCall* callNode)
}
}
}
+
+#ifndef _TARGET_X86_
+ // TODO-Arm: Does this apply for _TARGET_ARM_, where structs passed by value can be split between registers and stack?
if (size > 1)
{
hasMultiregStructArgs = true;
}
+#endif // !_TARGET_X86_
}
// The 'size' value has now must have been set. (the original value of zero is an invalid value)
@@ -3621,7 +3755,22 @@ GenTreeCall* Compiler::fgMorphArgs(GenTreeCall* callNode)
{
isRegArg = false;
}
- }
+
+#if defined(_TARGET_X86_) && !defined(LEGACY_BACKEND)
+ if (call->IsTailCallViaHelper())
+ {
+ // We have already (before calling fgMorphArgs()) appended the 4 special args
+ // required by the x86 tailcall helper. These args are required to go on the
+ // stack. Force them to the stack here.
+ assert(numArgs >= 4);
+ if (argIndex >= numArgs - 4)
+ {
+ isRegArg = false;
+ }
+ }
+#endif // defined(_TARGET_X86_) && !defined(LEGACY_BACKEND)
+
+ } // end !lateArgsComputed
//
// Now we know if the argument goes in registers or not and how big it is,
@@ -3714,15 +3863,7 @@ GenTreeCall* Compiler::fgMorphArgs(GenTreeCall* callNode)
//
// They should not affect the placement of any other args or stack space required.
// Example: on AMD64 R10 and R11 are used for indirect VSD (generic interface) and cookie calls.
- for (int i = 0; i < nonStandardArgs.Height(); i++)
- {
- if (argx == nonStandardArgs.Index(i).node)
- {
- nextRegNum = nonStandardArgs.Index(i).reg;
- isNonStandard = true;
- break;
- }
- }
+ isNonStandard = nonStandardArgs.FindReg(argx, &nextRegNum);
#endif // !LEGACY_BACKEND
// This is a register argument - put it in the table
@@ -3826,10 +3967,23 @@ GenTreeCall* Compiler::fgMorphArgs(GenTreeCall* callNode)
call->fgArgInfo->AddStkArg(argIndex, argx, args, size, argAlign FEATURE_UNIX_AMD64_STRUCT_PASSING_ONLY_ARG(isStructArg));
}
}
+
if (copyBlkClass != NO_CLASS_HANDLE)
{
noway_assert(!lateArgsComputed);
fgMakeOutgoingStructArgCopy(call, args, argIndex, copyBlkClass FEATURE_UNIX_AMD64_STRUCT_PASSING_ONLY_ARG(&structDesc));
+
+ // This can cause a GTF_EXCEPT flag to be set.
+ // TODO-CQ: Fix the cases where this happens. We shouldn't be adding any new flags.
+ // This currently occurs in the case where we are re-morphing the args on x86/RyuJIT, and
+ // there are no register arguments. Then lateArgsComputed is never true, so we keep re-copying
+ // any struct arguments.
+ // i.e. assert(((call->gtFlags & GTF_EXCEPT) != 0) || ((args->Current()->gtFlags & GTF_EXCEPT) == 0)
+ flagsSummary |= (args->Current()->gtFlags & GTF_EXCEPT);
+
+#ifdef FEATURE_UNIX_AMD64_STRUCT_PASSING
+ hasStackArgCopy = true;
+#endif
}
#ifndef LEGACY_BACKEND
@@ -3975,12 +4129,13 @@ GenTreeCall* Compiler::fgMorphArgs(GenTreeCall* callNode)
// or we have no register arguments then we don't need to
// call SortArgs() and EvalArgsToTemps()
//
- // Note that we do this for UNIX_AMD64 when we have a struct argument
- //
+ // For UNIX_AMD64, the condition without hasStackArgCopy cannot catch
+ // all cases of fgMakeOutgoingStructArgCopy() being called. hasStackArgCopy
+ // is added to make sure to call EvalArgsToTemp.
if (!lateArgsComputed && (call->fgArgInfo->HasRegArgs()
-#ifdef FEATURE_UNIX_AMD64_STRUCT_PASSING
- || hasStructArgument
-#endif // FEATURE_UNIX_AMD64_STRUCT_PASSING
+ #ifdef FEATURE_UNIX_AMD64_STRUCT_PASSING
+ || hasStackArgCopy
+ #endif // FEATURE_UNIX_AMD64_STRUCT_PASSING
))
{
// This is the first time that we morph this call AND it has register arguments.
@@ -4250,14 +4405,14 @@ void Compiler::fgMorphMultiregStructArgs(GenTreeCall* call)
NYI_ARM("fgMorphMultiregStructArgs");
#endif
#ifdef _TARGET_X86_
- assert("Logic error: no MultiregStructArgs for X86");
+ assert(!"Logic error: no MultiregStructArgs for X86");
#endif
#ifdef _TARGET_AMD64_
#if defined(UNIX_AMD64_ABI)
NYI_AMD64("fgMorphMultiregStructArgs (UNIX ABI)");
-#else
-#endif
- assert("Logic error: no MultiregStructArgs for Windows X64 ABI");
+#else // !UNIX_AMD64_ABI
+ assert(!"Logic error: no MultiregStructArgs for Windows X64 ABI");
+#endif // !UNIX_AMD64_ABI
#endif
for (args = call->gtCallArgs; args != nullptr; args = args->gtOp.gtOp2)
@@ -4730,29 +4885,30 @@ Compiler::fgMakeOutgoingStructArgCopy(GenTreeCall* call,
// See if we need to insert a copy at all
// Case 1: don't need a copy if it is the last use of a local. We can't determine that all of the time
// but if there is only one use and no loops, the use must be last.
- if (argx->gtOper == GT_OBJ)
+ GenTreeLclVarCommon* lcl = nullptr;
+ if ((argx->OperGet() == GT_OBJ) && argx->AsObj()->Addr()->OperIsLocal())
+ {
+ lcl = argx->AsObj()->Addr()->AsLclVarCommon();
+ }
+ if (lcl != nullptr)
{
- GenTree* lcl = argx->gtOp.gtOp1;
- if (lcl->OperIsLocal())
+ unsigned varNum = lcl->AsLclVarCommon()->GetLclNum();
+ if (lvaIsImplicitByRefLocal(varNum))
{
- unsigned varNum = lcl->AsLclVarCommon()->GetLclNum();
- if (lvaIsImplicitByRefLocal(varNum))
+ LclVarDsc* varDsc = &lvaTable[varNum];
+ // JIT_TailCall helper has an implicit assumption that all tail call arguments live
+ // on the caller's frame. If an argument lives on the caller caller's frame, it may get
+ // overwritten if that frame is reused for the tail call. Therefore, we should always copy
+ // struct parameters if they are passed as arguments to a tail call.
+ if (!call->IsTailCallViaHelper() && (varDsc->lvRefCnt == 1) && !fgMightHaveLoop())
{
- LclVarDsc* varDsc = &lvaTable[varNum];
- // JIT_TailCall helper has an implicit assumption that all tail call arguments live
- // on the caller's frame. If an argument lives on the caller caller's frame, it may get
- // overwritten if that frame is reused for the tail call. Therefore, we should always copy
- // struct parameters if they are passed as arguments to a tail call.
- if (!call->IsTailCallViaHelper() && (varDsc->lvRefCnt == 1) && !fgMightHaveLoop())
- {
- varDsc->lvRefCnt = 0;
- args->gtOp.gtOp1 = lcl;
- fgArgTabEntryPtr fp = Compiler::gtArgEntryByNode(call, argx);
- fp->node = lcl;
+ varDsc->lvRefCnt = 0;
+ args->gtOp.gtOp1 = lcl;
+ fgArgTabEntryPtr fp = Compiler::gtArgEntryByNode(call, argx);
+ fp->node = lcl;
- JITDUMP("did not have to make outgoing copy for V%2d", varNum);
- return;
- }
+ JITDUMP("did not have to make outgoing copy for V%2d", varNum);
+ return;
}
}
}
@@ -5847,13 +6003,14 @@ GenTreePtr Compiler::fgMorphField(GenTreePtr tree, MorphAddrContext* ma
lclNum = objRef->gtLclVarCommon.gtLclNum;
}
- // Create the "nullchk" node
- nullchk = gtNewOperNode(GT_NULLCHECK,
- TYP_BYTE, // Make it TYP_BYTE so we only deference it for 1 byte.
- gtNewLclvNode(lclNum, objRefType));
+ // Create the "nullchk" node.
+ // Make it TYP_BYTE so we only deference it for 1 byte.
+ GenTreePtr lclVar = gtNewLclvNode(lclNum, objRefType);
+ nullchk = new(this, GT_NULLCHECK) GenTreeIndir(GT_NULLCHECK, TYP_BYTE, lclVar, nullptr);
+
nullchk->gtFlags |= GTF_DONT_CSE; // Don't try to create a CSE for these TYP_BYTE indirections
- /* An indirection will cause a GPF if the address is null */
+ // An indirection will cause a GPF if the address is null.
nullchk->gtFlags |= GTF_EXCEPT;
if (asg)
@@ -6358,12 +6515,15 @@ bool Compiler::fgCanFastTailCall(GenTreeCall* callee)
}
// Get the size of the struct and see if it is register passable.
+ CORINFO_CLASS_HANDLE objClass = nullptr;
+
if (argx->OperGet() == GT_OBJ)
{
+ objClass = argx->AsObj()->gtClass;
#if defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_)
unsigned typeSize = 0;
- hasMultiByteArgs = !VarTypeIsMultiByteAndCanEnreg(argx->TypeGet(), argx->gtObj.gtClass, &typeSize, false);
+ hasMultiByteArgs = !VarTypeIsMultiByteAndCanEnreg(argx->TypeGet(), objClass, &typeSize, false);
#if defined(FEATURE_UNIX_AMD64_STRUCT_PASSING) || defined(_TARGET_ARM64_)
// On System V/arm64 the args could be a 2 eightbyte struct that is passed in two registers.
@@ -6425,10 +6585,10 @@ bool Compiler::fgCanFastTailCall(GenTreeCall* callee)
*/
void Compiler::fgMorphTailCall(GenTreeCall* call)
{
- // x86 classic codegen doesn't require any morphing
-#if defined(_TARGET_X86_) && !defined(LEGACY_BACKEND)
- NYI_X86("Tail call morphing");
-#elif defined(_TARGET_ARM_)
+ JITDUMP("fgMorphTailCall (before):\n");
+ DISPTREE(call);
+
+#if defined(_TARGET_ARM_)
// For the helper-assisted tail calls, we need to push all the arguments
// into a single list, and then add a few extra at the beginning
@@ -6475,13 +6635,7 @@ void Compiler::fgMorphTailCall(GenTreeCall* call)
call->gtFlags &= ~GTF_CALL_NULLCHECK;
}
- GenTreeArgList** pList = &call->gtCallArgs;
-#if RETBUFARG_PRECEDES_THIS
- if (call->HasRetBufArg()) {
- pList = &(*pList)->Rest();
- }
-#endif // RETBUFARG_PRECEDES_THIS
- *pList = gtNewListNode(objp, *pList);
+ call->gtCallArgs = gtNewListNode(objp, call->gtCallArgs);
}
// Add the extra VSD parameter if needed
@@ -6562,14 +6716,47 @@ void Compiler::fgMorphTailCall(GenTreeCall* call)
call->gtCallMoreFlags = GTF_CALL_M_VARARGS | GTF_CALL_M_TAILCALL;
call->gtFlags &= ~GTF_CALL_POP_ARGS;
-#elif defined(_TARGET_AMD64_)
+#elif defined(_TARGET_XARCH_) && !defined(LEGACY_BACKEND)
+
+ // x86 classic codegen doesn't require any morphing
+
// For the helper-assisted tail calls, we need to push all the arguments
- // into a single list, and then add a few extra at the beginning.
+ // into a single list, and then add a few extra at the beginning or end.
+ //
+ // For AMD64, the tailcall helper (JIT_TailCall) is defined as:
+ //
+ // JIT_TailCall(void* copyRoutine, void* callTarget, <function args>)
+ //
+ // We need to add "copyRoutine" and "callTarget" extra params at the beginning.
+ // But callTarget is determined by the Lower phase. Therefore, we add a placeholder arg
+ // for callTarget here which will be replaced later with callTarget in tail call lowering.
+ //
+ // For x86, the tailcall helper is defined as:
//
- // TailCallHelper(void *copyRoutine, void *callTarget, ....) - i.e We need to add
- // copyRoutine and callTarget extra params at the beginning. But callTarget is
- // determined by Lower phase. Therefore, we add a place holder arg for callTarget
- // here which will be later replaced with callTarget in tail call lowering.
+ // JIT_TailCall(<function args>, int numberOfOldStackArgsWords, int numberOfNewStackArgsWords, int flags, void* callTarget)
+ //
+ // Note that the special arguments are on the stack, whereas the function arguments follow
+ // the normal convention: there might be register arguments in ECX and EDX. The stack will
+ // look like (highest address at the top):
+ // first normal stack argument
+ // ...
+ // last normal stack argument
+ // numberOfOldStackArgs
+ // numberOfNewStackArgs
+ // flags
+ // callTarget
+ //
+ // Each special arg is 4 bytes.
+ //
+ // 'flags' is a bitmask where:
+ // 1 == restore callee-save registers (EDI,ESI,EBX). The JIT always saves all
+ // callee-saved registers for tailcall functions. Note that the helper assumes
+ // that the callee-saved registers live immediately below EBP, and must have been
+ // pushed in this order: EDI, ESI, EBX.
+ // 2 == call target is a virtual stub dispatch.
+ //
+ // The x86 tail call helper lives in VM\i386\jithelp.asm. See that function for more details
+ // on the custom calling convention.
// Check for PInvoke call types that we don't handle in codegen yet.
assert(!call->IsUnmanaged());
@@ -6585,17 +6772,56 @@ void Compiler::fgMorphTailCall(GenTreeCall* call)
assert(!call->IsImplicitTailCall());
assert(!fgCanFastTailCall(call));
- // First move the this pointer (if any) onto the regular arg list
+ // First move the 'this' pointer (if any) onto the regular arg list. We do this because
+ // we are going to prepend special arguments onto the argument list (for non-x86 platforms),
+ // and thus shift where the 'this' pointer will be passed to a later argument slot. In
+ // addition, for all platforms, we are going to change the call into a helper call. Our code
+ // generation code for handling calls to helpers does not handle 'this' pointers. So, when we
+ // do this transformation, we must explicitly create a null 'this' pointer check, if required,
+ // since special 'this' pointer handling will no longer kick in.
+ //
+ // Some call types, such as virtual vtable calls, require creating a call address expression
+ // that involves the "this" pointer. Lowering will sometimes create an embedded statement
+ // to create a temporary that is assigned to the "this" pointer expression, and then use
+ // that temp to create the call address expression. This temp creation embedded statement
+ // will occur immediately before the "this" pointer argument, and then will be used for both
+ // the "this" pointer argument as well as the call address expression. In the normal ordering,
+ // the embedded statement establishing the "this" pointer temp will execute before both uses
+ // of the temp. However, for tail calls via a helper, we move the "this" pointer onto the
+ // normal call argument list, and insert a placeholder which will hold the call address
+ // expression. For non-x86, things are ok, because the order of execution of these is not
+ // altered. However, for x86, the call address expression is inserted as the *last* argument
+ // in the argument list, *after* the "this" pointer. It will be put on the stack, and be
+ // evaluated first. To ensure we don't end up with out-of-order temp definition and use,
+ // for those cases where call lowering creates an embedded form temp of "this", we will
+ // create a temp here, early, that will later get morphed correctly.
+
if (call->gtCallObjp)
{
GenTreePtr thisPtr = nullptr;
GenTreePtr objp = call->gtCallObjp;
call->gtCallObjp = nullptr;
+#ifdef _TARGET_X86_
+ if ((call->IsDelegateInvoke() || call->IsVirtualVtable()) && !objp->IsLocal())
+ {
+ // tmp = "this"
+ unsigned lclNum = lvaGrabTemp(true DEBUGARG("tail call thisptr"));
+ GenTreePtr asg = gtNewTempAssign(lclNum, objp);
+
+ // COMMA(tmp = "this", tmp)
+ var_types vt = objp->TypeGet();
+ GenTreePtr tmp = gtNewLclvNode(lclNum, vt);
+ thisPtr = gtNewOperNode(GT_COMMA, vt, asg, tmp);
+
+ objp = thisPtr;
+ }
+#endif // _TARGET_X86_
+
if (call->NeedsNullCheck())
- {
+ {
// clone "this" if "this" has no side effects.
- if (!(objp->gtFlags & GTF_SIDE_EFFECT))
+ if ((thisPtr == nullptr) && !(objp->gtFlags & GTF_SIDE_EFFECT))
{
thisPtr = gtClone(objp, true);
}
@@ -6631,19 +6857,14 @@ void Compiler::fgMorphTailCall(GenTreeCall* call)
thisPtr = objp;
}
- GenTreeArgList** pList = &call->gtCallArgs;
-#if RETBUFARG_PRECEDES_THIS
- if (call->HasRetBufArg()) {
- pList = &(*pList)->Rest();
- }
-#endif // RETBUFARG_PRECEDES_THIS
-
// During rationalization tmp="this" and null check will
// materialize as embedded stmts in right execution order.
assert(thisPtr != nullptr);
- *pList = gtNewListNode(thisPtr, *pList);
+ call->gtCallArgs = gtNewListNode(thisPtr, call->gtCallArgs);
}
+#if defined(_TARGET_AMD64_)
+
// Add the extra VSD parameter to arg list in case of VSD calls.
// Tail call arg copying thunk will move this extra VSD parameter
// to R11 before tail calling VSD stub. See CreateTailCallCopyArgsThunk()
@@ -6682,12 +6903,50 @@ void Compiler::fgMorphTailCall(GenTreeCall* call)
arg = gtNewIconHandleNode(ssize_t(pfnCopyArgs), GTF_ICON_FTN_ADDR);
call->gtCallArgs = gtNewListNode(arg, call->gtCallArgs);
+#else // !_TARGET_AMD64_
+
+ // Find the end of the argument list. ppArg will point at the last pointer; setting *ppArg will
+ // append to the list.
+ GenTreeArgList** ppArg = &call->gtCallArgs;
+ for (GenTreeArgList* args = call->gtCallArgs; args != nullptr; args = args->Rest())
+ {
+ ppArg = (GenTreeArgList**)&args->gtOp2;
+ }
+ assert(ppArg != nullptr);
+ assert(*ppArg == nullptr);
+
+ unsigned nOldStkArgsWords = (compArgSize - (codeGen->intRegState.rsCalleeRegArgCount * REGSIZE_BYTES)) / REGSIZE_BYTES;
+ GenTree* arg3 = gtNewIconNode((ssize_t)nOldStkArgsWords, TYP_I_IMPL);
+ *ppArg = gtNewListNode(arg3, nullptr); // numberOfOldStackArgs
+ ppArg = (GenTreeArgList**)&((*ppArg)->gtOp2);
+
+ // Inject a placeholder for the count of outgoing stack arguments that the Lowering phase will generate.
+ // The constant will be replaced.
+ GenTree* arg2 = gtNewIconNode(9, TYP_I_IMPL);
+ *ppArg = gtNewListNode(arg2, nullptr); // numberOfNewStackArgs
+ ppArg = (GenTreeArgList**)&((*ppArg)->gtOp2);
+
+ // Inject a placeholder for the flags.
+ // The constant will be replaced.
+ GenTree* arg1 = gtNewIconNode(8, TYP_I_IMPL);
+ *ppArg = gtNewListNode(arg1, nullptr);
+ ppArg = (GenTreeArgList**)&((*ppArg)->gtOp2);
+
+ // Inject a placeholder for the real call target that the Lowering phase will generate.
+ // The constant will be replaced.
+ GenTree* arg0 = gtNewIconNode(7, TYP_I_IMPL);
+ *ppArg = gtNewListNode(arg0, nullptr);
+
+#endif // !_TARGET_AMD64_
+
// It is now a varargs tail call dispatched via helper.
call->gtCallMoreFlags |= GTF_CALL_M_VARARGS | GTF_CALL_M_TAILCALL | GTF_CALL_M_TAILCALL_VIA_HELPER;
call->gtFlags &= ~GTF_CALL_POP_ARGS;
-#endif //_TARGET_AMD64_
+#endif // _TARGET_*
+ JITDUMP("fgMorphTailCall (after):\n");
+ DISPTREE(call);
}
//------------------------------------------------------------------------------
@@ -9240,7 +9499,7 @@ GenTreePtr Compiler::fgMorphFieldAssignToSIMDIntrinsicSet(GenTreePtr tree)
simdIntrinsicID = SIMDIntrinsicSetW;
break;
default:
- noway_assert("There is no set intrinsic for index bigger than 3");
+ noway_assert(!"There is no set intrinsic for index bigger than 3");
}
@@ -15973,7 +16232,11 @@ Compiler::fgWalkResult Compiler::fgMorphLocalField(GenTreePtr tree, fgWalkD
tree->gtLclFld.SetLclNum(fieldLclIndex);
// We need to keep the types 'compatible'. If we can switch back to a GT_LCL_VAR
+#ifdef ARM_SOFTFP
+ assert(varTypeIsIntegralOrI(tree->TypeGet()) || varTypeIsFloating(tree->TypeGet()));
+#else
assert(varTypeIsIntegralOrI(tree->TypeGet()));
+#endif
if (varTypeCanReg(fldVarDsc->TypeGet()))
{
// If the type is integer-ish, then we can use it as-is
@@ -16097,7 +16360,7 @@ void Compiler::fgMarkImplicitByRefArgs()
* Morph irregular parameters
* for x64 and ARM64 this means turning them into byrefs, adding extra indirs.
*/
-bool Compiler::fgMorphImplicitByRefArgs(GenTreePtr tree, fgWalkData* fgWalkPre)
+bool Compiler::fgMorphImplicitByRefArgs(GenTreePtr *pTree, fgWalkData* fgWalkPre)
{
#if !defined(_TARGET_AMD64_) && !defined(_TARGET_ARM64_)
@@ -16105,6 +16368,7 @@ bool Compiler::fgMorphImplicitByRefArgs(GenTreePtr tree, fgWalkData* fgWalkPre)
#else // _TARGET_AMD64_ || _TARGET_ARM64_
+ GenTree* tree = *pTree;
assert((tree->gtOper == GT_LCL_VAR) ||
((tree->gtOper == GT_ADDR) && (tree->gtOp.gtOp1->gtOper == GT_LCL_VAR)));
@@ -16132,6 +16396,9 @@ bool Compiler::fgMorphImplicitByRefArgs(GenTreePtr tree, fgWalkData* fgWalkPre)
// We are overloading the lvRefCnt field here because real ref counts have not been set.
lclVarDsc->lvRefCnt++;
+ // This is no longer a def of the lclVar, even if it WAS a def of the struct.
+ lclVarTree->gtFlags &= ~(GTF_LIVENESS_MASK);
+
if (isAddr)
{
// change &X into just plain X
@@ -16176,6 +16443,7 @@ bool Compiler::fgMorphImplicitByRefArgs(GenTreePtr tree, fgWalkData* fgWalkPre)
#endif // DEBUG
}
+ *pTree = tree;
return true;
#endif // _TARGET_AMD64_ || _TARGET_ARM64_
@@ -16377,7 +16645,7 @@ Compiler::fgWalkResult Compiler::fgMarkAddrTakenLocalsPreCB(GenTreePtr* pTr
// If we have ADDR(lcl), and "lcl" is an implicit byref parameter, fgMorphImplicitByRefArgs will
// convert to just "lcl". This is never an address-context use, since the local is already a
// byref after this transformation.
- if (tree->gtOp.gtOp1->OperGet() == GT_LCL_VAR && comp->fgMorphImplicitByRefArgs(tree, fgWalkPre))
+ if (tree->gtOp.gtOp1->OperGet() == GT_LCL_VAR && comp->fgMorphImplicitByRefArgs(pTree, fgWalkPre))
{
// Push something to keep the PostCB, which will pop it, happy.
axcStack->Push(AXC_None);
@@ -16478,7 +16746,7 @@ Compiler::fgWalkResult Compiler::fgMarkAddrTakenLocalsPreCB(GenTreePtr* pTr
case GT_LCL_VAR:
// On some architectures, some arguments are passed implicitly by reference.
// Modify the trees to reflect that, if this local is one of those.
- if (comp->fgMorphImplicitByRefArgs(tree, fgWalkPre))
+ if (comp->fgMorphImplicitByRefArgs(pTree, fgWalkPre))
{
// We can't be in an address context; the ADDR(lcl), where lcl is an implicit byref param, was
// handled earlier. (And we can't have added anything to this address, since it was implicit.)
diff --git a/src/jit/optcse.cpp b/src/jit/optcse.cpp
index fa19445aa5..c424e7e178 100644
--- a/src/jit/optcse.cpp
+++ b/src/jit/optcse.cpp
@@ -313,17 +313,24 @@ void Compiler::optCSE_GetMaskData(GenTreePtr tree, optCSE_MaskDat
}
-// Given a binary tree node return true if it is safe to swap the order of evaluation for op1 and op2
-// It only considers the locations of the CSE defs and uses for op1 and op2 to decide this
+//------------------------------------------------------------------------
+// optCSE_canSwap: Determine if the execution order of two nodes can be swapped.
//
-bool Compiler::optCSE_canSwap(GenTreePtr tree)
+// Arguments:
+// op1 - The first node
+// op2 - The second node
+//
+// Return Value:
+// Return true iff it safe to swap the execution order of 'op1' and 'op2',
+// considering only the locations of the CSE defs and uses.
+//
+// Assumptions:
+// 'op1' currently occurse before 'op2' in the execution order.
+//
+bool Compiler::optCSE_canSwap(GenTree* op1, GenTree* op2)
{
- assert((tree->OperKind() & GTK_SMPOP) != 0);
-
- GenTreePtr op1 = tree->gtOp.gtOp1;
- GenTreePtr op2 = tree->gtGetOp2();
-
- assert(op1 != nullptr); // We must have a binary treenode with non-null op1 and op2
+ // op1 and op2 must be non-null.
+ assert(op1 != nullptr);
assert(op2 != nullptr);
bool canSwap = true; // the default result unless proven otherwise.
@@ -341,7 +348,7 @@ bool Compiler::optCSE_canSwap(GenTreePtr tree)
}
else
{
- // We also cannot swap if op2 contains a CSE def that is used by op1
+ // We also cannot swap if op2 contains a CSE def that is used by op1.
if ((op2MaskData.CSE_defMask & op1MaskData.CSE_useMask) != 0)
{
canSwap = false;
@@ -351,6 +358,26 @@ bool Compiler::optCSE_canSwap(GenTreePtr tree)
return canSwap;
}
+//------------------------------------------------------------------------
+// optCSE_canSwap: Determine if the execution order of a node's operands can be swapped.
+//
+// Arguments:
+// tree - The node of interest
+//
+// Return Value:
+// Return true iff it safe to swap the execution order of the operands of 'tree',
+// considering only the locations of the CSE defs and uses.
+//
+bool Compiler::optCSE_canSwap(GenTreePtr tree)
+{
+ // We must have a binary treenode with non-null op1 and op2
+ assert((tree->OperKind() & GTK_SMPOP) != 0);
+
+ GenTreePtr op1 = tree->gtOp.gtOp1;
+ GenTreePtr op2 = tree->gtGetOp2();
+
+ return optCSE_canSwap(op1, op2);
+}
/*****************************************************************************
*
diff --git a/src/jit/rationalize.cpp b/src/jit/rationalize.cpp
index 4a669d4237..6c322fb88d 100644
--- a/src/jit/rationalize.cpp
+++ b/src/jit/rationalize.cpp
@@ -70,134 +70,6 @@ struct SplitData
bool continueSubtrees; // whether to continue after splitting off a tree (in pre-order)
};
-
-//------------------------------------------------------------------------------
-// RewriteOneQuestion - split a question op into three parts: the test and branch,
-// and true and false parts, with accompanying flow
-//------------------------------------------------------------------------------
-
-Location Rationalizer::RewriteOneQuestion(BasicBlock *block, GenTree *qmarkTree, GenTree *stmt, GenTree *dst)
-{
- // First create all the blocks this is going to turn into.
- // We end the current block here and insert a diamond
- // consisting of the then/else blocks and the remainder, which is
- // the point where flow merges back and the rest of the current block will end up
-
- // TODO-Cleanup: avoid creating one of these blocks if that part of the qmark is a NOP
- BasicBlock* remainderBlock = comp->fgSplitBlockAfterStatement(block, stmt);
- BasicBlock* elseBlock = comp->fgSplitBlockAfterStatement(block, stmt);
- BasicBlock* thenBlock = comp->fgSplitBlockAfterStatement(block, stmt);
-
- // wire up the flow between the blocks and adjust their preds
- block->bbJumpKind = BBJ_COND;
- block->bbJumpDest = elseBlock;
-
- thenBlock->bbJumpKind = BBJ_ALWAYS;
- thenBlock->bbJumpDest = remainderBlock;
- thenBlock->bbFlags &= ~BBF_JMP_TARGET;
-
- elseBlock->bbJumpKind = BBJ_NONE; // falls through to remainder
- elseBlock->bbFlags |= (BBF_JMP_TARGET | BBF_HAS_LABEL);
- comp->fgAddRefPred(elseBlock, block);
-
- //JITDUMP("after splitting Q1");
- //dumpMethod();
-
- remainderBlock->bbFlags |= (BBF_JMP_TARGET | BBF_HAS_LABEL);
- comp->fgAddRefPred(remainderBlock, thenBlock);
- comp->fgRemoveRefPred(elseBlock, thenBlock);
-
- //JITDUMP("after splitting Q2");
- //dumpMethod();
-
- // remove flag marking this as a question conditional
- GenTree *conditionExpr = qmarkTree->gtGetOp1();
- assert(conditionExpr->gtFlags & GTF_RELOP_QMARK);
- conditionExpr->gtFlags &= ~GTF_RELOP_QMARK;
-
- comp->gtReverseCond(conditionExpr);
-
- // Wire up the jmp part.
- // Note that, unlike later Rationalizer passes, the QMarks are done prior to the comma
- // processing, and therefore prior to the creation of embedded statements.
- // So we can safely re-sequence.
- GenTree *jmpStmt = comp->fgNewStmtFromTree(comp->gtNewOperNode(GT_JTRUE, TYP_VOID, qmarkTree->gtGetOp1()), qmarkTree->gtStmt.gtStmtILoffsx);
- comp->fgInsertStmtAtEnd(block, jmpStmt);
-
- DBEXEC(TRUE, ValidateStatement(Location(jmpStmt, block)));
-
- //JITDUMP("before splitting Q3");
- //dumpMethod();
- //DBEXEC(TRUE, comp->fgDebugCheckBBlist());
-
- GenTree *trueExpr = qmarkTree->gtGetOp2()->gtGetOp2();
- GenTree *falseExpr = qmarkTree->gtGetOp2()->gtGetOp1();
-
- IL_OFFSETX ilOffset = stmt->gtStmt.gtStmtILoffsx;
- comp->fgRemoveStmt(block, stmt, false);
-
- unsigned lclNum = 0;
- bool resultUsed = false;
-
- // if the dst of the qmark was a local then we can write directly to it
- // otherwise make a temp and then do the indir/field/whatever writeback
- if (dst && dst->IsLocal())
- {
- resultUsed = true;
- lclNum = dst->gtLclVarCommon.gtLclNum;
-
- // Increment its lvRefCnt and lvRefCntWtd
- comp->lvaTable[lclNum].incRefCnts(block->getBBWeight(comp), comp);
- }
- else if (qmarkTree->TypeGet() != TYP_VOID)
- {
- resultUsed = true; // just guessing here
- lclNum = comp->lvaGrabTemp(true DEBUGARG("lower question"));
- comp->lvaTable[lclNum].lvType = qmarkTree->TypeGet();
-
- // Increment its lvRefCnt and lvRefCntWtd twice, one for the def and one for the use
- comp->lvaTable[lclNum].incRefCnts(block->getBBWeight(comp), comp);
- comp->lvaTable[lclNum].incRefCnts(block->getBBWeight(comp), comp);
- }
-
- // assign the trueExpr into the dst or tmp, insert in thenBlock
- if (trueExpr->OperGet() != GT_NOP)
- {
- if (trueExpr->TypeGet() != TYP_VOID)
- {
- assert(resultUsed);
- trueExpr = CreateTempAssignment(comp, lclNum, trueExpr);
- }
- GenTree *trueStmt = comp->fgNewStmtFromTree(trueExpr, thenBlock, ilOffset);
- comp->fgInsertStmtAtEnd(thenBlock, trueStmt);
- }
-
- // assign the falseExpr into the dst or tmp, insert in elseBlock
- if (falseExpr->OperGet() != GT_NOP)
- {
- if (falseExpr->TypeGet() != TYP_VOID)
- {
- assert(resultUsed);
- falseExpr = CreateTempAssignment(comp, lclNum, falseExpr);
- }
- GenTree *falseStmt = comp->fgNewStmtFromTree(falseExpr, elseBlock, ilOffset);
- comp->fgInsertStmtAtEnd(elseBlock, falseStmt);
- }
-
- // if the dst is a local we have just written it out
- // but if not (like an indir or something) then we copy from the temp we allocated
- if (dst && !dst->IsLocal())
- {
- GenTree *writeback = comp->gtNewAssignNode(dst, comp->gtNewLclvNode(lclNum, qmarkTree->TypeGet()));
- GenTree *writeStmt = comp->fgNewStmtFromTree(writeback, remainderBlock, ilOffset);
- comp->fgInsertStmtAtBeg(remainderBlock, writeStmt);
- }
-
- //JITDUMP("after splitting all");
- //dumpMethod();
-
- return Location(jmpStmt, block);
-}
//------------------------------------------------------------------------------
// isNodeCallArg - given a context (stack of parent nodes), determine if the TOS is an arg to a call
@@ -239,91 +111,6 @@ GenTree *isNodeCallArg(ArrayStack<GenTree *> *parentStack)
}
//------------------------------------------------------------------------------
-// shouldSplitRationalPre - invoked in preorder in a tree walk to determine if
-// we should split at this point in the tree, and at this
-// point in the walk
-//------------------------------------------------------------------------------
-
-bool shouldSplitRationalPre(GenTree *tree, GenTree *parent,
- Compiler::fgWalkData *data)
-{
- if (!parent || parent->gtOper == GT_STMT)
- return false;
-
- // the only thing we split in preorder are qmark ops
- if ((tree->OperGet() == GT_QMARK)
- && parent->gtOper != GT_ASG)
- return true;
-
- return false;
-}
-
-
-//------------------------------------------------------------------------------
-// shouldSplitRationalPost - invoked in postorder in a tree walk to determine if
-// we should split at this point in the tree, and at this
-// point in the walk
-//------------------------------------------------------------------------------
-
-bool shouldSplitRationalPost(GenTree *tree, GenTree *parent,
- Compiler::fgWalkData *data)
-{
- if (!parent || parent->gtOper == GT_STMT)
- return false;
-
- SplitData *splitData = (SplitData *) data->pCallbackData;
- auto phase = splitData->thisPhase;
-
-#ifndef _TARGET_AMD64_
- if (tree->OperIsAssignment()
- // late args are not truly embedded assigns... or at least they are very limited ones
- && !( isNodeCallArg(data->parentStack) && (tree->gtFlags & GTF_LATE_ARG)))
- {
- JITDUMP("splitting at assignment\n");
- return true;
- }
-
- if (tree->IsCall() && !parent->OperIsAssignment())
- {
- JITDUMP("splitting a nested call\n");
- return true;
- }
-#endif
-
- if ((tree->OperGet() == GT_QMARK)
- && parent->gtOper != GT_ASG)
- {
- JITDUMP("splitting a question\n");
- return true;
- }
-
- return false;
-}
-
-//------------------------------------------------------------------------------
-// fgSpliceTreeBefore - insert the given subtree 'tree' as a top level statement
-// placed before top level statement 'insertionPoint'
-//------------------------------------------------------------------------------
-
-GenTreeStmt *
-Compiler::fgSpliceTreeBefore(BasicBlock* block, GenTreeStmt* insertionPoint, GenTree* tree, IL_OFFSETX ilOffset)
-{
- assert(tree->gtOper != GT_STMT);
- assert(fgBlockContainsStatementBounded(block, insertionPoint));
-
- GenTreeStmt* newStmt = gtNewStmt(tree, ilOffset);
- newStmt->CopyCosts(tree);
- GenTreePtr newStmtFirstNode = Compiler::fgGetFirstNode(tree);
- newStmt->gtStmt.gtStmtList = newStmtFirstNode;
- newStmtFirstNode->gtPrev = nullptr;
- tree->gtNext = nullptr;
-
- fgInsertStmtBefore(block, insertionPoint, newStmt);
-
- return newStmt;
-}
-
-//------------------------------------------------------------------------------
// fgMakeEmbeddedStmt: insert the given subtree as an embedded statement
//
// Arguments:
@@ -418,7 +205,7 @@ Compiler::fgMakeEmbeddedStmt(BasicBlock* block, GenTree* tree, GenTree* parentSt
// For this case, we are actually going to insert it BEFORE parentStmt.
// However if we have a new prevStmt (i.e. there are some embedded statements
// to be included in newStmt) then those need to be moved as well.
- // Note, however, that all the tree links have alraedy been fixed up.
+ // Note, however, that all the tree links have already been fixed up.
fgInsertStmtBefore(block, parentStmt, newStmt);
if (foundEmbeddedStmts)
{
@@ -500,7 +287,7 @@ Compiler::fgInsertLinearNodeBefore(GenTreePtr newNode, GenTreePtr before)
// The new statement.
//
// Assumptions:
-// The callee must ensure that '*ppTree' is part of compCurStmt, and that
+// The caller must ensure that '*ppTree' is part of compCurStmt, and that
// compCurStmt is in compCurBB;
GenTreeStmt*
@@ -541,138 +328,6 @@ Compiler::fgInsertEmbeddedFormTemp(GenTree** ppTree, unsigned lclNum)
return stmt;
}
-//------------------------------------------------------------------------------
-// RenameUpdatedVars - detect trees that have internal assignments with preceding reads
-// of the variables being written.
-// Replace the preceding reads with references to copies made in advance
-// in order to make breaking out the assignments legal
-//------------------------------------------------------------------------------
-
-void Rationalizer::RenameUpdatedVars(Location loc)
-{
- // A variable which is assigned within the tree will have different
- // values at different points in the tree. The rationalizer tries to
- // break internal assignments out into their own tree and place those trees before
- // the original tree. This could result in changed meaning unless
- // we have a way of differentiating between original and modified values
-
- GenTree *statement = loc.tree;
- assert(statement->IsStatement());
-
- GenTree *tree = loc.tree->gtStmt.gtStmtExpr;
-
- use->ZeroAll();
- usedef->ZeroAll();
- rename->ZeroAll();
- unexp->ZeroAll();
-
- int *renameMap = (int *) alloca(sizeof(int) * comp->lvaCount);
- var_types *renameTypeMap = (var_types *) alloca(sizeof(var_types) * comp->lvaCount);
-
- // find locals that are redefined within the tree
- foreach_treenode_execution_order(tree, statement)
- {
- if (tree->IsLocal())
- {
- int varIdx = tree->gtLclVarCommon.gtLclNum;
- if (tree->gtFlags & GTF_VAR_DEF // definition
- || tree->gtFlags & GTF_VAR_USEDEF // this is a use/def as in x=x+y (only the lhs x is tagged)
- || tree->gtFlags & GTF_VAR_USEASG)// this is a use/def for a x<op>=y
- {
- if (use->testBit(varIdx))
- {
- usedef->setBit(varIdx);
- }
- else
- {
- unexp->setBit(varIdx);
- }
- }
- else
- {
- if (usedef->testBit(varIdx))
- {
- rename->setBit(varIdx);
- renameTypeMap[varIdx] = tree->TypeGet();
- }
- else
- {
- use->setBit(varIdx); // it's a plain use
- }
- }
- }
- }
-
- if (!rename->anySet())
- return;
-
- indexType index;
-
- // create the new variables and establish the mapping
- // also insert copies before the statement
- FOREACH_HBV_BIT_SET(index, rename)
- {
- JITDUMP("had to rename idx:%d in tree!\n", index);
- DISPTREE(statement);
-
- unsigned tmpIndex =
- renameMap[index] =
- comp->lvaGrabTemp(true DEBUGARG("rationalize renaming"));
-
- LclVarDsc *newVar = &comp->lvaTable[tmpIndex];
-
- newVar->lvType = renameTypeMap[index];
-
- // Increment its lvRefCnt and lvRefCntWtd
- comp->lvaTable[tmpIndex].incRefCnts(loc.block->getBBWeight(comp), comp);
-
- // only need a copy for exposed uses, otherwise a def is the first occurence
- if (!unexp->testBit(index))
- {
- GenTree *write = comp->gtNewAssignNode(comp->gtNewLclvNode(renameMap[index], newVar->TypeGet()),
- comp->gtNewLclvNode((int)index, newVar->TypeGet()));
-
- write = comp->fgNewStmtFromTree(write, statement->gtStmt.gtStmtILoffsx);
- comp->fgInsertStmtBefore(loc.block, statement, write);
-
- JITDUMP("New write tree:\n");
- DISPTREE(write);
- }
- }
- NEXT_HBV_BIT_SET;
-
- hashBv *seenUse = hashBv::Create(this->comp);
- hashBv *seenRedef = hashBv::Create(this->comp);
-
- // we are looking for a def after use
- // don't just start renaming if it kicks off with a def
- foreach_treenode_execution_order(tree, statement)
- {
- if (tree->IsLocal())
- {
- int varIdx = tree->gtLclVarCommon.gtLclNum;
- if (rename->testBit(varIdx))
- {
- if (tree->gtFlags & GTF_VAR_DEF
- //|| tree->gtFlags & GTF_VAR_USEDEF
- || tree->gtFlags & GTF_VAR_USEASG)
- {
- if (seenUse->testBit(varIdx))
- seenRedef->setBit(varIdx);
- }
- else
- {
- seenUse->setBit(varIdx);
- }
- if (!seenRedef->testBit(varIdx))
- {
- tree->gtLclVarCommon.SetLclNum(renameMap[varIdx]);
- }
- }
- }
- }
-}
-
// return op that is the store equivalent of the given load opcode
genTreeOps storeForm(genTreeOps loadForm)
{
@@ -714,118 +369,60 @@ void copyFlags(GenTree *dst, GenTree *src, unsigned mask)
}
-//------------------------------------------------------------------------------
-// RewriteQuestions - transform qmark ops, expanding them into multiple blocks
-// They should all be at the top level or immediately under an
-// assignment at this point
-//------------------------------------------------------------------------------
-
-Location Rationalizer::RewriteQuestions(Location loc)
-{
- GenTree *topNode = loc.tree->gtStmt.gtStmtExpr;
- // we should have things broken up so all questions are at top level
- if (topNode->gtOper == GT_QMARK)
- {
- loc = RewriteOneQuestion(loc.block, topNode, loc.tree, NULL);
- return loc;
- }
- else if (topNode->gtOper == GT_ASG)
- {
- // hope there's never a QMARK on the LHS
- assert(topNode->gtGetOp1()->gtOper != GT_QMARK);
-
- GenTree *questionOp = topNode->gtGetOp2();
- if (questionOp->gtOper != GT_QMARK)
- return loc;
-
- loc = RewriteOneQuestion(loc.block, questionOp, loc.tree, topNode->gtGetOp1());
- return loc;
- }
- else
- {
- return loc;
- }
-}
-
-
//--------------------------------------------------------------------------------------
-// RewriteTopLevelComma - split a top-level comma into two top level statements.
-// returns (as out params) the two new locations
+// RewriteTopLevelComma - remove a top-level comma by creating a new preceding statement
+// from its LHS and replacing the comma with its RHS (unless the
+// comma's RHS is a NOP, in which case the comma is replaced with
+// its LHS and no new statement is created)
+//
+// Returns the location of the statement that contains the LHS of the removed comma.
//--------------------------------------------------------------------------------------
-void Rationalizer::RewriteTopLevelComma(Location loc, Location* out1, Location* out2)
+Location Rationalizer::RewriteTopLevelComma(Location loc)
{
GenTreeStmt* commaStmt = loc.tree->AsStmt();
- GenTree* commaOp = commaStmt->gtStmtExpr;
+ GenTree* commaOp = commaStmt->gtStmtExpr;
assert(commaOp->OperGet() == GT_COMMA);
- JITDUMP("splitting top level comma!\n");
-
- GenTreeStmt* newStatement1 = comp->fgSpliceTreeBefore(loc.block, commaStmt, commaOp->gtGetOp1(), commaStmt->gtStmtILoffsx);
- GenTreeStmt* newStatement2 = comp->fgSpliceTreeBefore(loc.block, commaStmt, commaOp->gtGetOp2(), commaStmt->gtStmtILoffsx);
-
- comp->fgRemoveStmt(loc.block, commaStmt, false);
-
- // these two subtrees still need to be processed
- loc = Location(newStatement1, loc.block);
- *out1 = Location(newStatement1, loc.block);
- *out2 = Location(newStatement2, loc.block);
-}
+ GenTree* commaOp1 = commaOp->gtGetOp1();
+ GenTree* commaOp2 = commaOp->gtGetOp2();
-//--------------------------------------------------------------------------------------
-// TreeTransformRationalization - Run the set of rationalizations on one statement that
-// transforms its underlying trees but doesn't perform
-// tree walks to introduce new statements.
-//--------------------------------------------------------------------------------------
-
-Location Rationalizer::TreeTransformRationalization(Location loc)
-{
-top:
- assert(loc.tree);
-
- DBEXEC(TRUE, didSplit = false);
-
- JITDUMP("Tree Transform Rationalization: BB%02u\n", loc.block->bbNum);
- DISPTREE(loc.tree);
- JITDUMP("\n");
-
- comp->compCurStmt = loc.tree;
- comp->compCurBB = loc.block;
-
- // top level comma is a special case
- if (loc.tree->gtStmt.gtStmtExpr->OperGet() == GT_COMMA)
+ if (commaOp2->IsNothingNode())
{
- Location loc1, loc2;
- RewriteTopLevelComma(loc, &loc1, &loc2);
-
- loc = loc1;
- goto top;
- }
+#ifdef DEBUG
+ if (comp->verbose)
+ {
+ printf("Replacing GT_COMMA(X, GT_NOP) by X\n");
+ comp->gtDispTree(commaOp);
+ printf("\n");
+ }
+#endif // DEBUG
- DBEXEC(TRUE, loc.Validate());
+ comp->fgSnipNode(commaStmt, commaOp);
+ comp->fgDeleteTreeFromList(commaStmt, commaOp2);
+ commaStmt->gtStmtExpr = commaOp1;
-#ifdef LEGACY_BACKEND
- if (comp->compQmarkUsed)
- {
- loc = RewriteQuestions(loc);
+ return loc;
}
-#endif // LEGACY_BACKEND
- DBEXEC(TRUE, ValidateStatement(loc));
+ JITDUMP("splitting top level comma!\n");
- loc = RewriteSimpleTransforms(loc);
- DBEXEC(TRUE, ValidateStatement(loc));
+ // Replace the comma node in the original statement with the RHS of the comma node.
+ comp->fgDeleteTreeFromList(commaStmt, commaOp1);
+ comp->fgSnipNode(commaStmt, commaOp);
+ commaStmt->gtStmtExpr = commaOp2;
- JITDUMP("comma processing top level statment:\n");
- DISPTREE(loc.tree);
- JITDUMP("\n");
+ // Create and insert a new preceding statement from the LHS of the comma node.
+ GenTreeStmt* newStatement = comp->gtNewStmt(commaOp1, commaStmt->gtStmtILoffsx);
+ newStatement->CopyCosts(commaOp1);
+ newStatement->gtStmtList = Compiler::fgGetFirstNode(commaOp1);
+ newStatement->gtStmtList->gtPrev = nullptr;
+ commaOp1->gtNext = nullptr;
- DuplicateCommaProcessOneTree(comp, this, loc.block, loc.tree);
-
- DBEXEC(didSplit, comp->fgDebugCheckBBlist());
-
- return loc;
+ comp->fgInsertStmtBefore(loc.block, commaStmt, newStatement);
+
+ return Location(newStatement, loc.block);
}
@@ -1083,26 +680,41 @@ Compiler::fgWalkResult Rationalizer::CommaHelper(GenTree **ppTree, Compiler::fgW
// rewrite ASG nodes as either local store or indir store forms
// also remove ADDR nodes
-Location Rationalizer::RewriteSimpleTransforms(Location loc)
+Location Rationalizer::TreeTransformRationalization(Location loc)
{
- GenTreeStmt * statement = (loc.tree)->AsStmt();
- GenTree * tree = statement->gtStmt.gtStmtExpr;
+ GenTree* savedCurStmt = comp->compCurStmt;
+ GenTreeStmt* statement = (loc.tree)->AsStmt();
+ GenTree* tree = statement->gtStmt.gtStmtExpr;
- JITDUMP("RewriteSimpleTransforms, with statement:\n");
+ JITDUMP("TreeTransformRationalization, with statement:\n");
DISPTREE(statement);
JITDUMP("\n");
+ DBEXEC(TRUE, loc.Validate());
+ DBEXEC(TRUE, ValidateStatement(loc));
+
if (statement->gtStmtIsTopLevel())
{
- if (tree->OperGet() == GT_COMMA)
+ comp->compCurBB = loc.block;
+ comp->compCurStmt = statement;
+
+ while (tree->OperGet() == GT_COMMA)
{
- Location loc1, loc2;
- RewriteTopLevelComma(loc, &loc1, &loc2);
- RewriteSimpleTransforms(loc1);
- RewriteSimpleTransforms(loc2);
- return loc1;
+ // RewriteTopLevelComma may create a new preceding statement for the LHS of a
+ // top-level comma. If it does, we need to process that statement now.
+ Location newLoc = RewriteTopLevelComma(loc);
+ if (newLoc.tree != statement)
+ {
+ (void)TreeTransformRationalization(newLoc);
+ }
+
+ // RewriteTopLevelComma also replaces the tree for this statement with the RHS
+ // of the comma (or the LHS, if the RHS is a NOP), so we must reload it for
+ // correctness.
+ tree = statement->gtStmt.gtStmtExpr;
}
- else if (tree->OperKind() & GTK_CONST)
+
+ if (tree->OperKind() & GTK_CONST)
{
// Don't bother generating a top level statement that is just a constant.
// We can get these if we decide to hoist a large constant value out of a loop.
@@ -1128,10 +740,15 @@ Location Rationalizer::RewriteSimpleTransforms(Location loc)
tree->gtBashToNOP();
}
+ DuplicateCommaProcessOneTree(comp, this, loc.block, loc.tree);
+
JITDUMP("After simple transforms:\n");
DISPTREE(statement);
JITDUMP("\n");
+ DBEXEC(TRUE, ValidateStatement(loc));
+
+ comp->compCurStmt = savedCurStmt;
return loc;
}
@@ -1200,7 +817,7 @@ void Rationalizer::RecursiveRewriteComma(GenTree **ppTree, Compiler::fgWalkData
DISPTREE(stmt);
JITDUMP("\n");
- (void) ((Rationalizer *)tmpState->thisPhase)->RewriteSimpleTransforms(Location(newStmt, tmpState->block));
+ (void) ((Rationalizer *)tmpState->thisPhase)->TreeTransformRationalization(Location(newStmt, tmpState->block));
// In a sense, assignment nodes have two destinations: 1) whatever they are writing to
// and 2) they also produce the value that was written so their parent can consume it.
@@ -1233,12 +850,12 @@ void Rationalizer::RecursiveRewriteComma(GenTree **ppTree, Compiler::fgWalkData
DISPTREE(stmt);
JITDUMP("\n");
- (void) ((Rationalizer *)tmpState->thisPhase)->RewriteSimpleTransforms(Location(newStmt, tmpState->block));
+ (void) ((Rationalizer *)tmpState->thisPhase)->TreeTransformRationalization(Location(newStmt, tmpState->block));
if (!nested)
comp->fgFixupIfCallArg(data->parentStack, comma, newSrc);
- (void) ((Rationalizer *)tmpState->thisPhase)->RewriteSimpleTransforms(Location(newStmt, tmpState->block));
+ (void) ((Rationalizer *)tmpState->thisPhase)->TreeTransformRationalization(Location(newStmt, tmpState->block));
return;
}
@@ -1903,31 +1520,6 @@ Compiler::fgWalkResult Rationalizer::SimpleTransformHelper(GenTree **ppTree, Com
JITDUMP("\n");
return SimpleTransformHelper(ppTree, data);
}
- else if (tree->gtOper == GT_QMARK)
- {
- // only certain forms of qmarks are allowed
- // qmark(conditionExpr, 1, 0) is equivalent to conditionExpr
- GenTree* colonNode = tree->gtOp.gtOp2;
- GenTree* thenNode = colonNode->AsColon()->ThenNode();
- GenTree* elseNode = colonNode->AsColon()->ElseNode();
- assert(thenNode->IsCnsIntOrI());
- assert(elseNode->IsCnsIntOrI());
- assert(thenNode->gtIntConCommon.IconValue() == 1);
- assert(elseNode->gtIntConCommon.IconValue() == 0);
-
- Compiler::fgSnipNode(tmpState->root->AsStmt(), elseNode);
- Compiler::fgSnipNode(tmpState->root->AsStmt(), thenNode);
- Compiler::fgSnipNode(tmpState->root->AsStmt(), colonNode);
- Compiler::fgSnipNode(tmpState->root->AsStmt(), tree);
-
- *ppTree = tree->gtOp.gtOp1;
- (*ppTree)->gtFlags &= ~GTF_RELOP_QMARK;
- comp->fgFixupIfCallArg(data->parentStack, tree, *ppTree);
-
- JITDUMP("Rewriting GT_QMARK(conditionExpr, 1, 0) to conditionExpr:\n");
- DISPTREE(*ppTree);
- JITDUMP("\n");
- }
#ifdef _TARGET_XARCH_
else if (tree->gtOper == GT_CLS_VAR)
{
@@ -2174,6 +1766,9 @@ void Rationalizer::SanityCheck()
tree;
tree = tree->gtNext)
{
+ // QMARK nodes should have been removed before this phase.
+ assert(tree->OperGet() != GT_QMARK);
+
if (tree->OperGet() == GT_ASG)
{
if (tree->gtGetOp1()->OperGet() == GT_LCL_VAR)
@@ -2206,74 +1801,10 @@ void Rationalizer::DoPhase()
comp->compCurBB = NULL;
comp->fgOrder = Compiler::FGOrderLinear;
- // If the first block is BBF_INTERNAL, it is special. Zero-inits must be placed in
- // this block, and it must fall through to the next block.
- // If there is a question op in the block (as can be the case with a just-my-code helper)
- // then the rationalizer will expand that to flow and break the fallthrough invariant.
- // However, we need to still keep the zero-inits in the original block, so only split before
- // the statement containing the qmark.
-
- if (comp->fgFirstBB->bbFlags & BBF_INTERNAL)
- {
- BasicBlock* const block = comp->fgFirstBB;
- for (GenTree* stmt = block->bbTreeList; stmt; stmt = stmt->gtNext)
- {
- GenTreePtr node;
- foreach_treenode_execution_order(node, stmt)
- {
- if (node->gtOper == GT_QMARK)
- {
- BasicBlock* newBlock;
- if (stmt == block->bbTreeList)
- newBlock = comp->fgSplitBlockAtBeginning(comp->fgFirstBB);
- else
- newBlock = comp->fgSplitBlockAfterStatement(block, stmt);
- newBlock->bbFlags &= ~BBF_INTERNAL;
- }
- }
- }
- }
-
- use = hashBv::Create(this->comp); // is used
- usedef = hashBv::Create(this->comp); // is used and then defined
- rename = hashBv::Create(this->comp); // is used, defined and used again
- unexp = hashBv::Create(this->comp); // is unexposed - there is a def in this tree before any uses
-
// break up the trees at side effects, etc
Location loc(comp->fgFirstBB);
while (loc.block)
{
- RenameUpdatedVars(loc);
-
- // If we have a top-level GT_COMMA(X, GT_NOP), replace it by X.
- if (loc.tree->gtStmt.gtStmtExpr->OperGet() == GT_COMMA)
- {
- GenTree* commaStmt = loc.tree;
- GenTree* commaOp = commaStmt->gtStmt.gtStmtExpr;
- if (commaOp->gtGetOp2()->OperGet() == GT_NOP)
- {
-#ifdef DEBUG
- if (comp->verbose)
- {
- printf("Replacing GT_COMMA(X, GT_NOP) by X\n");
- comp->gtDispTree(commaOp);
- printf("\n");
- }
-#endif // DEBUG
-
- comp->fgSnipNode(commaStmt->AsStmt(), commaOp);
- comp->fgDeleteTreeFromList(commaStmt->AsStmt(), commaOp->gtGetOp2());
- commaStmt->gtStmt.gtStmtExpr = commaOp->gtGetOp1();
- }
- }
-
- loc = loc.Next();
- }
-
- loc.Reset(comp);
-
- while (loc.block)
- {
loc = TreeTransformRationalization(loc);
loc = loc.Next();
}
diff --git a/src/jit/rationalize.h b/src/jit/rationalize.h
index 90f39c32d0..7d3b00b051 100644
--- a/src/jit/rationalize.h
+++ b/src/jit/rationalize.h
@@ -5,14 +5,6 @@
//===============================================================================
#include "phase.h"
-enum Rationalizations
-{
- Questions = 0x1,
- NestedCalls = 0x2,
- NestedAssigns = 0x4,
- Commas = 0x8
-};
-
//------------------------------------------------------------------------------
// Location - (tree, block) tuple is minimum context required to manipulate trees in the JIT
//------------------------------------------------------------------------------
@@ -97,29 +89,11 @@ private:
class Rationalizer : public Phase
{
//===============================================================================
- // Data members
-
-#ifdef DEBUG
- // keep track of whether a split happened so we can avoid expensive debug checks
- bool didSplit;
-#endif
-
- // used for renaming updated variables
- hashBv *use;
- hashBv *usedef;
- hashBv *rename;
- hashBv *unexp;
-
-
- //===============================================================================
// Methods
public:
Rationalizer(Compiler* comp);
- Location TreeSplitRationalization (Location loc);
Location TreeTransformRationalization (Location loc);
- void RenameUpdatedVars(Location loc);
-
#ifdef DEBUG
static void ValidateStatement(Location loc);
@@ -145,7 +119,6 @@ private:
static bool RewriteArrElem (GenTree** ppTree, Compiler::fgWalkData* data);
static Compiler::fgWalkResult SimpleTransformHelper(GenTree** ppTree, Compiler::fgWalkData* data);
- static Compiler::fgWalkResult QuestionHelper (GenTree** ppTree, Compiler::fgWalkData* data);
static void DuplicateCommaProcessOneTree (Compiler* comp, Rationalizer* irt, BasicBlock* block, GenTree* tree);
@@ -159,13 +132,7 @@ private:
unsigned lclNum,
GenTreePtr rhs);
- // Question related
- Location RewriteQuestions (Location loc);
- void RewriteTopLevelComma (Location loc, Location* out1, Location* out2);
- Location RewriteSimpleTransforms (Location loc);
- Location RewriteOneQuestion (BasicBlock* block, GenTree* op, GenTree* stmt, GenTree* dest);
- void RewriteQuestions (BasicBlock* block, GenTree* stmt);
- bool BreakFirstLevelQuestions (BasicBlock* block, GenTree* tree);
+ Location RewriteTopLevelComma(Location loc);
// SIMD related transformations
static void RewriteObj(GenTreePtr* ppTree, Compiler::fgWalkData* data);
diff --git a/src/jit/simdcodegenxarch.cpp b/src/jit/simdcodegenxarch.cpp
index f512b46a19..f6218bdee2 100644
--- a/src/jit/simdcodegenxarch.cpp
+++ b/src/jit/simdcodegenxarch.cpp
@@ -1233,7 +1233,7 @@ CodeGen::genSIMDIntrinsicRelOp(GenTreeSIMD* simdNode)
break;
default:
- noway_assert("Unimplemented SIMD relational operation.");
+ noway_assert(!"Unimplemented SIMD relational operation.");
unreached();
}
@@ -2147,7 +2147,7 @@ CodeGen::genSIMDIntrinsic(GenTreeSIMD* simdNode)
break;
default:
- noway_assert("Unimplemented SIMD intrinsic.");
+ noway_assert(!"Unimplemented SIMD intrinsic.");
unreached();
}
}
diff --git a/src/jit/target.h b/src/jit/target.h
index 9a3621c8bb..dcb18dbe32 100644
--- a/src/jit/target.h
+++ b/src/jit/target.h
@@ -384,11 +384,14 @@ typedef unsigned short regPairNoSmall; // arm: need 12 bits
#ifdef LEGACY_BACKEND
#define FEATURE_MULTIREG_ARGS_OR_RET 0 // Support for passing and/or returning single values in more than one register
#define FEATURE_MULTIREG_ARGS 0 // Support for passing a single argument in more than one register
- #define FEATURE_MULTIREG_RET 0 // Support for returning a single value in more than one register
+ #define FEATURE_MULTIREG_RET 0 // Support for returning a single value in more than one register
+ #define MAX_PASS_MULTIREG_BYTES 0 // No multireg arguments
+ #define MAX_RET_MULTIREG_BYTES 0 // No multireg return values
#else
#define FEATURE_MULTIREG_ARGS_OR_RET 1 // Support for passing and/or returning single values in more than one register
#define FEATURE_MULTIREG_ARGS 0 // Support for passing a single argument in more than one register
- #define FEATURE_MULTIREG_RET 1 // Support for returning a single value in more than one register
+ #define FEATURE_MULTIREG_RET 1 // Support for returning a single value in more than one register
+ #define MAX_PASS_MULTIREG_BYTES 0 // No multireg arguments (note this seems wrong as MAX_ARG_REG_COUNT is 2)
#define MAX_RET_MULTIREG_BYTES 8 // Maximum size of a struct that could be returned in more than one register
#endif
@@ -482,6 +485,7 @@ typedef unsigned short regPairNoSmall; // arm: need 12 bits
#define CODE_ALIGN 1 // code alignment requirement
#define STACK_ALIGN 4 // stack alignment requirement
#define STACK_ALIGN_SHIFT 2 // Shift-right amount to convert stack size in bytes to size in DWORD_PTRs
+ #define STACK_ALIGN_SHIFT_ALL 2 // Shift-right amount to convert stack size in bytes to size in STACK_ALIGN units
#define RBM_INT_CALLEE_SAVED (RBM_EBX|RBM_ESI|RBM_EDI)
#define RBM_INT_CALLEE_TRASH (RBM_EAX|RBM_ECX|RBM_EDX)
@@ -728,7 +732,9 @@ typedef unsigned short regPairNoSmall; // arm: need 12 bits
#else // !UNIX_AMD64_ABI
#define FEATURE_MULTIREG_ARGS_OR_RET 0 // Support for passing and/or returning single values in more than one register
#define FEATURE_MULTIREG_ARGS 0 // Support for passing a single argument in more than one register
- #define FEATURE_MULTIREG_RET 0 // Support for returning a single value in more than one register
+ #define FEATURE_MULTIREG_RET 0 // Support for returning a single value in more than one register
+ #define MAX_PASS_MULTIREG_BYTES 0 // No multireg arguments
+ #define MAX_RET_MULTIREG_BYTES 0 // No multireg return values
#define MAX_ARG_REG_COUNT 1 // Maximum registers used to pass a single argument (no arguments are passed using multiple registers)
#define MAX_RET_REG_COUNT 1 // Maximum registers used to return a value.
#endif // !UNIX_AMD64_ABI
@@ -775,6 +781,7 @@ typedef unsigned short regPairNoSmall; // arm: need 12 bits
#define CODE_ALIGN 1 // code alignment requirement
#define STACK_ALIGN 16 // stack alignment requirement
#define STACK_ALIGN_SHIFT 3 // Shift-right amount to convert stack size in bytes to size in pointer sized words
+ #define STACK_ALIGN_SHIFT_ALL 4 // Shift-right amount to convert stack size in bytes to size in STACK_ALIGN units
#if ETW_EBP_FRAMED
#define RBM_ETW_FRAMED_EBP RBM_NONE
diff --git a/src/jit/unwind.h b/src/jit/unwind.h
index 68a06fc15c..0327e97c24 100644
--- a/src/jit/unwind.h
+++ b/src/jit/unwind.h
@@ -30,6 +30,7 @@ const unsigned MAX_EPILOG_SIZE_BYTES = 40;
const unsigned MAX_PROLOG_SIZE_BYTES = 100;
const unsigned MAX_EPILOG_SIZE_BYTES = 100;
#define UWC_END 0xE4 // "end" unwind code
+#define UWC_END_C 0xE5 // "end_c" unwind code
#define UW_MAX_FRAGMENT_SIZE_BYTES (1U << 20)
#define UW_MAX_CODE_WORDS_COUNT 31
#define UW_MAX_EPILOG_START_INDEX 0x3FFU
diff --git a/src/jit/unwindarm.cpp b/src/jit/unwindarm.cpp
index 745c3ac57a..29cbdcfa0e 100644
--- a/src/jit/unwindarm.cpp
+++ b/src/jit/unwindarm.cpp
@@ -996,9 +996,11 @@ void UnwindFragmentInfo::AddEpilog()
void UnwindFragmentInfo::CopyPrologCodes(UnwindFragmentInfo* pCopyFrom)
{
ufiPrologCodes.CopyFrom(&pCopyFrom->ufiPrologCodes);
+#ifdef _TARGET_ARM64_
+ ufiPrologCodes.AddCode(UWC_END_C);
+#endif
}
-
// Split the epilog codes that currently exist in 'pSplitFrom'. The ones that represent
// epilogs that start at or after the location represented by 'emitLoc' are removed
// from 'pSplitFrom' and moved to this fragment. Note that this fragment should not have
diff --git a/src/md/compiler/disp.cpp b/src/md/compiler/disp.cpp
index 0f0bf88e6d..b091729744 100644
--- a/src/md/compiler/disp.cpp
+++ b/src/md/compiler/disp.cpp
@@ -152,7 +152,7 @@ Disp::DefineScope(
BOOL fResult = SUCCEEDED(hr);
// print out a message so people know what's happening
printf("Defining scope for EnC using %S %s\n",
- szFileNameSuffix, fResult ? "succeeded" : "failed");
+ static_cast<LPCWSTR>(szFileNameSuffix), fResult ? "succeeded" : "failed");
goto ErrExit;
}
diff --git a/src/mscorlib/Tools/BclRewriter/BclRewriter.targets b/src/mscorlib/Tools/BclRewriter/BclRewriter.targets
index 75c5f592c4..5515b000a7 100644
--- a/src/mscorlib/Tools/BclRewriter/BclRewriter.targets
+++ b/src/mscorlib/Tools/BclRewriter/BclRewriter.targets
@@ -9,22 +9,23 @@
<BclRewriterWorkDir>$(IntermediateOutputPath)\BclRewriter</BclRewriterWorkDir>
<BclRewriterSymbolOutput>$(IntermediateOutputPath)\BclRewriter\$(TargetName).pdb</BclRewriterSymbolOutput>
<BclRewriterOutput>$(IntermediateOutputPath)\BclRewriter\$(TargetName)$(TargetExt)</BclRewriterOutput>
+ <TargetPath>$(BclRewriterOutput)</TargetPath>
</PropertyGroup>
-
+
<ItemGroup>
<RewrittenAssembly Include="$(BclRewriterOutput)" />
</ItemGroup>
-
- <Target Name="RewriteWithBclRewriter"
- Inputs="@(AnnotatedAssembly)" Outputs="@(RewrittenAssembly)" DependsOnTargets="$(BclRewriterDependencyTargets)">
+
+ <Target Name="RewriteWithBclRewriter"
+ Inputs="$(BclRewriterModelFile);@(AnnotatedAssembly)" Outputs="@(RewrittenAssembly)" DependsOnTargets="$(BclRewriterDependencyTargets)">
<PropertyGroup>
<OSPlatform Condition="'$(TargetsWindows)' == 'true'">win</OSPlatform>
<OSPlatform Condition="'$(TargetsWindows)' != 'true'">unix</OSPlatform>
- <BclRewriterCommand Condition="'$(BclRewriterCommand)'==''">"$(ToolRuntimePath)$(ToolHost)" "$(ToolsDir)BclRewriter.exe"</BclRewriterCommand>
+ <BclRewriterCommand Condition="'$(BclRewriterCommand)'==''">"$(ToolRuntimePath)dotnetcli/$(ToolHost)" "$(ToolsDir)BclRewriter.exe"</BclRewriterCommand>
</PropertyGroup>
-
- <Exec Command="$(BclRewriterCommand) -in:&quot;@(AnnotatedAssembly)&quot; -out:&quot;$(BclRewriterOutput)&quot; -include:&quot;$(BclRewriterModelFile)&quot; -platform:$(OSPlatform) -architecture:$(Platform) -flavor:$(_BuildType) -define:&quot;$(DefineConstants)&quot; -keepTempFiles+" StandardOutputImportance="Normal" />
+
+ <Exec Command="$(BclRewriterCommand) -in:&quot;@(AnnotatedAssembly)&quot; -out:&quot;$(BclRewriterOutput)&quot; -include:&quot;$(BclRewriterModelFile)&quot; -platform:$(OSPlatform) -architecture:$(Platform) -flavor:$(_BuildType) -removeSerializable- -define:&quot;$(DefineConstants)&quot; -keepTempFiles+" StandardOutputImportance="Normal" />
<!-- Update the location of the symbol file-->
<PropertyGroup>
diff --git a/src/mscorlib/corefx/System/Globalization/Calendar.cs b/src/mscorlib/corefx/System/Globalization/Calendar.cs
index 6b67e92ab1..861ecc7acc 100644
--- a/src/mscorlib/corefx/System/Globalization/Calendar.cs
+++ b/src/mscorlib/corefx/System/Globalization/Calendar.cs
@@ -31,7 +31,7 @@ namespace System.Globalization
[System.Runtime.InteropServices.ComVisible(true)]
- public abstract class Calendar
+ public abstract class Calendar : ICloneable
{
// Number of 100ns (10E-7 second) ticks per time unit
internal const long TicksPerMillisecond = 10000;
@@ -143,11 +143,11 @@ namespace System.Globalization
//
// Clone
//
- // Is the implementation of IColnable.
+ // Is the implementation of ICloneable.
//
////////////////////////////////////////////////////////////////////////
[System.Runtime.InteropServices.ComVisible(false)]
- internal virtual Object Clone()
+ public virtual object Clone()
{
object o = MemberwiseClone();
((Calendar)o).SetReadOnlyState(false);
diff --git a/src/mscorlib/corefx/System/Globalization/CultureInfo.cs b/src/mscorlib/corefx/System/Globalization/CultureInfo.cs
index e5e01be032..611ffdeedb 100644
--- a/src/mscorlib/corefx/System/Globalization/CultureInfo.cs
+++ b/src/mscorlib/corefx/System/Globalization/CultureInfo.cs
@@ -47,7 +47,7 @@ namespace System.Globalization
using StringCultureInfoDictionary = LowLevelDictionary<string, CultureInfo>;
#endif
- public partial class CultureInfo : IFormatProvider
+ public partial class CultureInfo : IFormatProvider, ICloneable
{
//--------------------------------------------------------------------//
// Internal Information //
diff --git a/src/mscorlib/corefx/System/Globalization/DateTimeFormatInfo.cs b/src/mscorlib/corefx/System/Globalization/DateTimeFormatInfo.cs
index ca1caacef6..e4f4f85f1b 100644
--- a/src/mscorlib/corefx/System/Globalization/DateTimeFormatInfo.cs
+++ b/src/mscorlib/corefx/System/Globalization/DateTimeFormatInfo.cs
@@ -55,7 +55,7 @@ namespace System.Globalization
[System.Runtime.InteropServices.ComVisible(true)]
- public sealed class DateTimeFormatInfo : IFormatProvider
+ public sealed class DateTimeFormatInfo : IFormatProvider, ICloneable
{
// cache for the invariant culture.
// invariantInfo is constant irrespective of your current culture.
diff --git a/src/mscorlib/corefx/System/Globalization/NumberFormatInfo.cs b/src/mscorlib/corefx/System/Globalization/NumberFormatInfo.cs
index 344eeadde7..859e3423d2 100644
--- a/src/mscorlib/corefx/System/Globalization/NumberFormatInfo.cs
+++ b/src/mscorlib/corefx/System/Globalization/NumberFormatInfo.cs
@@ -41,7 +41,7 @@ namespace System.Globalization
//
[System.Runtime.InteropServices.ComVisible(true)]
- sealed public class NumberFormatInfo : IFormatProvider
+ sealed public class NumberFormatInfo : IFormatProvider, ICloneable
{
// invariantInfo is constant irrespective of your current culture.
private static volatile NumberFormatInfo invariantInfo;
diff --git a/src/mscorlib/corefx/System/Globalization/TextInfo.cs b/src/mscorlib/corefx/System/Globalization/TextInfo.cs
index 35c4a93fc4..6e14499bb5 100644
--- a/src/mscorlib/corefx/System/Globalization/TextInfo.cs
+++ b/src/mscorlib/corefx/System/Globalization/TextInfo.cs
@@ -25,7 +25,7 @@ using System.Runtime.CompilerServices;
namespace System.Globalization
{
- public partial class TextInfo
+ public partial class TextInfo : ICloneable
{
////--------------------------------------------------------------------//
//// Internal Information //
@@ -145,7 +145,7 @@ namespace System.Globalization
//// Is the implementation of IColnable.
////
//////////////////////////////////////////////////////////////////////////
- internal virtual Object Clone()
+ public virtual Object Clone()
{
object o = MemberwiseClone();
((TextInfo)o).SetReadOnlyState(false);
diff --git a/src/mscorlib/model.xml b/src/mscorlib/model.xml
index 2df044a757..4208b3903f 100644
--- a/src/mscorlib/model.xml
+++ b/src/mscorlib/model.xml
@@ -181,13 +181,19 @@
<Member Name="Clear(System.Array,System.Int32,System.Int32)" />
<Member Name="Clone" />
<Member Name="ConstrainedCopy(System.Array,System.Int32,System.Array,System.Int32,System.Int32)" />
+ <Member Name="ConvertAll&lt;TInput,TOutput&gt;(TInput[],System.Converter&lt;TInput,TOutput&gt;)" />
<Member Name="Copy(System.Array,System.Array,System.Int32)" />
+ <Member Name="Copy(System.Array,System.Array,System.Int64)" />
<Member Name="Copy(System.Array,System.Int32,System.Array,System.Int32,System.Int32)" />
+ <Member Name="Copy(System.Array,System.Int64,System.Array,System.Int64,System.Int64)" />
<Member Name="CopyTo(System.Array,System.Int32)" />
+ <Member Name="CopyTo(System.Array,System.Int64)" />
<Member Name="CreateInstance(System.Type,System.Int32)" />
+ <Member Name="CreateInstance(System.Type,System.Int32,System.Int32)" />
+ <Member Name="CreateInstance(System.Type,System.Int32,System.Int32,System.Int32)" />
<Member Name="CreateInstance(System.Type,System.Int32[])" />
<Member Name="CreateInstance(System.Type,System.Int32[],System.Int32[])" />
- <Member Name="ForEach&lt;T&gt;(T[],System.Action&lt;T&gt;)" />
+ <Member Name="CreateInstance(System.Type,System.Int64[])" />
<Member Name="Empty&lt;T&gt;" />
<Member Name="Exists&lt;T&gt;(T[],System.Predicate&lt;T&gt;)" />
<Member Name="Find&lt;T&gt;(T[],System.Predicate&lt;T&gt;)" />
@@ -199,18 +205,27 @@
<Member Name="FindLastIndex&lt;T&gt;(T[],System.Int32,System.Int32,System.Predicate&lt;T&gt;)" />
<Member Name="FindLastIndex&lt;T&gt;(T[],System.Int32,System.Predicate&lt;T&gt;)" />
<Member Name="FindLastIndex&lt;T&gt;(T[],System.Predicate&lt;T&gt;)" />
+ <Member Name="ForEach&lt;T&gt;(T[],System.Action&lt;T&gt;)" />
<Member Name="get_IsFixedSize" />
<Member Name="get_IsReadOnly" />
<Member Name="get_IsSynchronized" />
<Member Name="get_Length" />
+ <Member Name="get_LongLength" />
<Member Name="get_Rank" />
<Member Name="get_SyncRoot" />
<Member Name="GetEnumerator" />
<Member Name="GetLength(System.Int32)" />
+ <Member Name="GetLongLength(System.Int32)" />
<Member Name="GetLowerBound(System.Int32)" />
<Member Name="GetUpperBound(System.Int32)" />
<Member Name="GetValue(System.Int32)" />
+ <Member Name="GetValue(System.Int32,System.Int32)" />
+ <Member Name="GetValue(System.Int32,System.Int32,System.Int32)" />
<Member Name="GetValue(System.Int32[])" />
+ <Member Name="GetValue(System.Int64)" />
+ <Member Name="GetValue(System.Int64,System.Int64)" />
+ <Member Name="GetValue(System.Int64,System.Int64,System.Int64)" />
+ <Member Name="GetValue(System.Int64[])" />
<Member Name="IndexOf(System.Array,System.Object)" />
<Member Name="IndexOf(System.Array,System.Object,System.Int32)" />
<Member Name="IndexOf(System.Array,System.Object,System.Int32,System.Int32)" />
@@ -228,7 +243,13 @@
<Member Name="Reverse(System.Array)" />
<Member Name="Reverse(System.Array,System.Int32,System.Int32)" />
<Member Name="SetValue(System.Object,System.Int32)" />
+ <Member Name="SetValue(System.Object,System.Int32,System.Int32)" />
+ <Member Name="SetValue(System.Object,System.Int32,System.Int32,System.Int32)" />
<Member Name="SetValue(System.Object,System.Int32[])" />
+ <Member Name="SetValue(System.Object,System.Int64)" />
+ <Member Name="SetValue(System.Object,System.Int64,System.Int64)" />
+ <Member Name="SetValue(System.Object,System.Int64,System.Int64,System.Int64)" />
+ <Member Name="SetValue(System.Object,System.Int64[])" />
<Member Name="Sort(System.Array)" />
<Member Name="Sort(System.Array,System.Array)" />
<Member Name="Sort(System.Array,System.Array,System.Collections.IComparer)" />
@@ -251,6 +272,7 @@
<Member MemberType="Property" Name="IsReadOnly" />
<Member MemberType="Property" Name="IsSynchronized" />
<Member MemberType="Property" Name="Length" />
+ <Member MemberType="Property" Name="LongLength" />
<Member MemberType="Property" Name="Rank" />
<Member MemberType="Property" Name="SyncRoot" />
<Member Status="ImplRoot" Name="GetDataPtrOffsetInternal" /> <!-- EE -->
@@ -349,6 +371,11 @@
<Member MemberType="Property" Name="Inherited" />
<Member MemberType="Property" Name="ValidOn" />
</Type>
+ <Type Name="System.Base64FormattingOptions">
+ <Member MemberType="Field" Name="InsertLineBreaks" />
+ <Member MemberType="Field" Name="None" />
+ <Member MemberType="Field" Name="value__" />
+ </Type>
<Type Name="System.BitConverter">
<Member Name="DoubleToInt64Bits(System.Double)" />
<Member Name="Int64BitsToDouble(System.Int64)" />
@@ -492,6 +519,16 @@
<Member Name="ToUpperInvariant(System.Char)" />
<Member Name="TryParse(System.String,System.Char@)" />
</Type>
+ <Type Name="System.CharEnumerator">
+ <Member Name="Clone" />
+ <Member Name="Dispose" />
+ <Member Name="get_Current" />
+ <Member Name="MoveNext" />
+ <Member Name="Reset" />
+ <Member MemberType="Property" Name="Current" />
+ <Member Name="System.Collections.IEnumerator.get_Current" />
+ <Member MemberType="Property" Name="System.Collections.IEnumerator.Current" />
+ </Type>
<Type Name="System.CLSCompliantAttribute">
<Member Name="#ctor(System.Boolean)" />
<Member Name="get_IsCompliant" />
@@ -512,7 +549,7 @@
<Member Name="Xor(System.Collections.BitArray)" />
<Member Name="Not" />
<Member Name="set_Item(System.Int32,System.Boolean)" />
- <Member Name="get_Item(System.Int32)" />
+ <Member Name="get_Item(System.Int32)" />
<Member MemberType="Property" Name="Item(System.Int32)" />
<Member Name="get_Length" />
<Member Name="set_Length(System.Int32)" />
@@ -703,6 +740,7 @@
<Member Name="BinarySearch(T,System.Collections.Generic.IComparer&lt;T&gt;)" />
<Member Name="Clear" />
<Member Name="Contains(T)" />
+ <Member Name="ConvertAll&lt;TOutput&gt;(System.Converter&lt;T,TOutput&gt;)" />
<Member Name="CopyTo(System.Int32,T[],System.Int32,System.Int32)" />
<Member Name="CopyTo(T[])" />
<Member Name="CopyTo(T[],System.Int32)" />
@@ -775,12 +813,12 @@
<Member Status="ImplRoot" Name="#ctor(System.Collections.Generic.IDictionary&lt;K,V&gt;)" />
<Member Status="ImplRoot" Name="get_Items" />
<Member Status="ImplRoot" MemberType="Property" Name="Items" />
- </Type>
+ </Type>
<Type Status="ImplRoot" Name="System.Collections.Generic.Mscorlib_KeyedCollectionDebugView&lt;K,T&gt;">
<Member Status="ImplRoot" Name="#ctor(System.Collections.ObjectModel.KeyedCollection&lt;K,T&gt;)" />
<Member Status="ImplRoot" Name="get_Items" />
<Member Status="ImplRoot" MemberType="Property" Name="Items" />
- </Type>
+ </Type>
<Type Name="System.Collections.ICollection">
<Member Name="CopyTo(System.Array,System.Int32)" />
<Member Name="get_Count" />
@@ -911,7 +949,7 @@
<Member MemberType="Property" Name="Item(System.Int32)" />
<Member MemberType="Property" Name="Items" />
</Type>
-
+
<Type Name="System.Collections.ObjectModel.ReadOnlyDictionary&lt;TKey,TValue&gt;">
<Member Name="#ctor(System.Collections.Generic.IDictionary&lt;TKey,TValue&gt;)" />
<Member Name="ContainsKey(TKey)" />
@@ -925,13 +963,12 @@
<Member MemberType="Property" Name="Dictionary" />
<Member MemberType="Property" Name="Item(TKey)" />
</Type>
-
<Type Name="System.GCCollectionMode">
<Member MemberType="Field" Name="Default" />
<Member MemberType="Field" Name="Optimized" />
<Member MemberType="Field" Name="Forced" />
</Type>
-
+
<Type Name="System.Comparison&lt;T&gt;">
<Member Name="#ctor(System.Object,System.IntPtr)" />
<Member Name="BeginInvoke(T,T,System.AsyncCallback,System.Object)" />
@@ -975,17 +1012,22 @@
<Member MemberType="Field" Name="DBNull" />
<Member Name="ChangeType(System.Object,System.Type)" />
<Member Name="ChangeType(System.Object,System.Type,System.IFormatProvider)" />
+ <Member Name="ChangeType(System.Object,System.TypeCode)" />
<Member Name="ChangeType(System.Object,System.TypeCode,System.IFormatProvider)" />
<Member Name="FromBase64CharArray(System.Char[],System.Int32,System.Int32)" />
<Member Name="FromBase64String(System.String)" />
<Member Name="GetTypeCode(System.Object)" />
<Member Name="IsDBNull(System.Object)" />
<Member Name="ToBase64CharArray(System.Byte[],System.Int32,System.Int32,System.Char[],System.Int32)" />
+ <Member Name="ToBase64CharArray(System.Byte[],System.Int32,System.Int32,System.Char[],System.Int32,System.Base64FormattingOptions)" />
<Member Name="ToBase64String(System.Byte[])" />
+ <Member Name="ToBase64String(System.Byte[],System.Base64FormattingOptions)" />
<Member Name="ToBase64String(System.Byte[],System.Int32,System.Int32)" />
+ <Member Name="ToBase64String(System.Byte[],System.Int32,System.Int32,System.Base64FormattingOptions)" />
<Member Name="ToBoolean(System.Boolean)" />
<Member Name="ToBoolean(System.Byte)" />
<Member Name="ToBoolean(System.Char)" />
+ <Member Name="ToBoolean(System.DateTime)" />
<Member Name="ToBoolean(System.Decimal)" />
<Member Name="ToBoolean(System.Double)" />
<Member Name="ToBoolean(System.Int16)" />
@@ -1003,6 +1045,7 @@
<Member Name="ToByte(System.Boolean)" />
<Member Name="ToByte(System.Byte)" />
<Member Name="ToByte(System.Char)" />
+ <Member Name="ToByte(System.DateTime)" />
<Member Name="ToByte(System.Decimal)" />
<Member Name="ToByte(System.Double)" />
<Member Name="ToByte(System.Int16)" />
@@ -1018,8 +1061,10 @@
<Member Name="ToByte(System.UInt16)" />
<Member Name="ToByte(System.UInt32)" />
<Member Name="ToByte(System.UInt64)" />
+ <Member Name="ToChar(System.Boolean)" />
<Member Name="ToChar(System.Byte)" />
<Member Name="ToChar(System.Char)" />
+ <Member Name="ToChar(System.DateTime)" />
<Member Name="ToChar(System.Decimal)" />
<Member Name="ToChar(System.Double)" />
<Member Name="ToChar(System.Int16)" />
@@ -1034,10 +1079,24 @@
<Member Name="ToChar(System.UInt16)" />
<Member Name="ToChar(System.UInt32)" />
<Member Name="ToChar(System.UInt64)" />
+ <Member Name="ToDateTime(System.Boolean)" />
+ <Member Name="ToDateTime(System.Byte)" />
+ <Member Name="ToDateTime(System.Char)" />
+ <Member Name="ToDateTime(System.DateTime)" />
+ <Member Name="ToDateTime(System.Decimal)" />
+ <Member Name="ToDateTime(System.Double)" />
+ <Member Name="ToDateTime(System.Int16)" />
+ <Member Name="ToDateTime(System.Int32)" />
+ <Member Name="ToDateTime(System.Int64)" />
<Member Name="ToDateTime(System.Object)" />
<Member Name="ToDateTime(System.Object,System.IFormatProvider)" />
+ <Member Name="ToDateTime(System.SByte)" />
+ <Member Name="ToDateTime(System.Single)" />
<Member Name="ToDateTime(System.String)" />
<Member Name="ToDateTime(System.String,System.IFormatProvider)" />
+ <Member Name="ToDateTime(System.UInt16)" />
+ <Member Name="ToDateTime(System.UInt32)" />
+ <Member Name="ToDateTime(System.UInt64)" />
<Member Name="ToDecimal(System.Boolean)" />
<Member Name="ToDecimal(System.Byte)" />
<Member Name="ToDecimal(System.Char)" />
@@ -1059,6 +1118,7 @@
<Member Name="ToDouble(System.Boolean)" />
<Member Name="ToDouble(System.Byte)" />
<Member Name="ToDouble(System.Char)" />
+ <Member Name="ToDouble(System.DateTime)" />
<Member Name="ToDouble(System.Decimal)" />
<Member Name="ToDouble(System.Double)" />
<Member Name="ToDouble(System.Int16)" />
@@ -1076,6 +1136,7 @@
<Member Name="ToInt16(System.Boolean)" />
<Member Name="ToInt16(System.Byte)" />
<Member Name="ToInt16(System.Char)" />
+ <Member Name="ToInt16(System.DateTime)" />
<Member Name="ToInt16(System.Decimal)" />
<Member Name="ToInt16(System.Double)" />
<Member Name="ToInt16(System.Int16)" />
@@ -1094,6 +1155,7 @@
<Member Name="ToInt32(System.Boolean)" />
<Member Name="ToInt32(System.Byte)" />
<Member Name="ToInt32(System.Char)" />
+ <Member Name="ToInt32(System.DateTime)" />
<Member Name="ToInt32(System.Decimal)" />
<Member Name="ToInt32(System.Double)" />
<Member Name="ToInt32(System.Int16)" />
@@ -1112,6 +1174,7 @@
<Member Name="ToInt64(System.Boolean)" />
<Member Name="ToInt64(System.Byte)" />
<Member Name="ToInt64(System.Char)" />
+ <Member Name="ToInt64(System.DateTime)" />
<Member Name="ToInt64(System.Decimal)" />
<Member Name="ToInt64(System.Double)" />
<Member Name="ToInt64(System.Int16)" />
@@ -1130,6 +1193,7 @@
<Member Name="ToSByte(System.Boolean)" />
<Member Name="ToSByte(System.Byte)" />
<Member Name="ToSByte(System.Char)" />
+ <Member Name="ToSByte(System.DateTime)" />
<Member Name="ToSByte(System.Decimal)" />
<Member Name="ToSByte(System.Double)" />
<Member Name="ToSByte(System.Int16)" />
@@ -1148,6 +1212,7 @@
<Member Name="ToSingle(System.Boolean)" />
<Member Name="ToSingle(System.Byte)" />
<Member Name="ToSingle(System.Char)" />
+ <Member Name="ToSingle(System.DateTime)" />
<Member Name="ToSingle(System.Decimal)" />
<Member Name="ToSingle(System.Double)" />
<Member Name="ToSingle(System.Int16)" />
@@ -1190,6 +1255,8 @@
<Member Name="ToString(System.SByte,System.IFormatProvider)" />
<Member Name="ToString(System.Single)" />
<Member Name="ToString(System.Single,System.IFormatProvider)" />
+ <Member Name="ToString(System.String)" />
+ <Member Name="ToString(System.String,System.IFormatProvider)" />
<Member Name="ToString(System.UInt16)" />
<Member Name="ToString(System.UInt16,System.IFormatProvider)" />
<Member Name="ToString(System.UInt32)" />
@@ -1199,6 +1266,7 @@
<Member Name="ToUInt16(System.Boolean)" />
<Member Name="ToUInt16(System.Byte)" />
<Member Name="ToUInt16(System.Char)" />
+ <Member Name="ToUInt16(System.DateTime)" />
<Member Name="ToUInt16(System.Decimal)" />
<Member Name="ToUInt16(System.Double)" />
<Member Name="ToUInt16(System.Int16)" />
@@ -1217,6 +1285,7 @@
<Member Name="ToUInt32(System.Boolean)" />
<Member Name="ToUInt32(System.Byte)" />
<Member Name="ToUInt32(System.Char)" />
+ <Member Name="ToUInt32(System.DateTime)" />
<Member Name="ToUInt32(System.Decimal)" />
<Member Name="ToUInt32(System.Double)" />
<Member Name="ToUInt32(System.Int16)" />
@@ -1235,6 +1304,7 @@
<Member Name="ToUInt64(System.Boolean)" />
<Member Name="ToUInt64(System.Byte)" />
<Member Name="ToUInt64(System.Char)" />
+ <Member Name="ToUInt64(System.DateTime)" />
<Member Name="ToUInt64(System.Decimal)" />
<Member Name="ToUInt64(System.Double)" />
<Member Name="ToUInt64(System.Int16)" />
@@ -1335,10 +1405,6 @@
<Member Name="ParseExact(System.String,System.String,System.IFormatProvider)" />
<Member Name="ParseExact(System.String,System.String,System.IFormatProvider,System.Globalization.DateTimeStyles)" />
<Member Name="ParseExact(System.String,System.String[],System.IFormatProvider,System.Globalization.DateTimeStyles)" />
- <Member Name="TryParse(System.String,System.DateTime@)" />
- <Member Name="TryParse(System.String,System.IFormatProvider,System.Globalization.DateTimeStyles,System.DateTime@)" />
- <Member Name="TryParseExact(System.String,System.String,System.IFormatProvider,System.Globalization.DateTimeStyles,System.DateTime@)" />
- <Member Name="TryParseExact(System.String,System.String[],System.IFormatProvider,System.Globalization.DateTimeStyles,System.DateTime@)" />
<Member Name="SpecifyKind(System.DateTime,System.DateTimeKind)" />
<Member Name="Subtract(System.DateTime)" />
<Member Name="Subtract(System.TimeSpan)" />
@@ -1356,6 +1422,10 @@
<Member Name="ToString(System.String)" />
<Member Name="ToString(System.String,System.IFormatProvider)" />
<Member Name="ToUniversalTime" />
+ <Member Name="TryParse(System.String,System.DateTime@)" />
+ <Member Name="TryParse(System.String,System.IFormatProvider,System.Globalization.DateTimeStyles,System.DateTime@)" />
+ <Member Name="TryParseExact(System.String,System.String,System.IFormatProvider,System.Globalization.DateTimeStyles,System.DateTime@)" />
+ <Member Name="TryParseExact(System.String,System.String[],System.IFormatProvider,System.Globalization.DateTimeStyles,System.DateTime@)" />
<Member MemberType="Property" Name="Date" />
<Member MemberType="Property" Name="Day" />
<Member MemberType="Property" Name="DayOfWeek" />
@@ -1373,6 +1443,12 @@
<Member MemberType="Property" Name="UtcNow" />
<Member MemberType="Property" Name="Year" />
</Type>
+ <Type Name="System.DateTimeKind">
+ <Member MemberType="Field" Name="Local" />
+ <Member MemberType="Field" Name="Unspecified" />
+ <Member MemberType="Field" Name="Utc" />
+ <Member MemberType="Field" Name="value__" />
+ </Type>
<Type Name="System.DateTimeOffset">
<Member MemberType="Field" Name="MaxValue" />
<Member MemberType="Field" Name="MinValue" />
@@ -1472,12 +1548,6 @@
<Member MemberType="Property" Name="UtcNow" />
<Member MemberType="Property" Name="Year" />
</Type>
- <Type Name="System.DateTimeKind">
- <Member MemberType="Field" Name="Local" />
- <Member MemberType="Field" Name="Unspecified" />
- <Member MemberType="Field" Name="Utc" />
- <Member MemberType="Field" Name="value__" />
- </Type>
<Type Name="System.DayOfWeek">
<Member MemberType="Field" Name="Friday" />
<Member MemberType="Field" Name="Monday" />
@@ -1554,6 +1624,7 @@
<Member Name="Equals(System.Decimal,System.Decimal)" />
<Member Name="Equals(System.Object)" />
<Member Name="Floor(System.Decimal)" />
+ <Member Name="FromOACurrency(System.Int64)" />
<Member Name="GetBits(System.Decimal)" />
<Member Name="GetHashCode" />
<Member Name="GetTypeCode" />
@@ -1603,13 +1674,17 @@
<Member Name="TryParse(System.String,System.Decimal@)" />
<Member Name="TryParse(System.String,System.Globalization.NumberStyles,System.IFormatProvider,System.Decimal@)" />
<Member Name="Remainder(System.Decimal,System.Decimal)" />
+ <Member Name="Round(System.Decimal)" />
<Member Name="Round(System.Decimal,System.Int32)" />
+ <Member Name="Round(System.Decimal,System.Int32,System.MidpointRounding)" />
+ <Member Name="Round(System.Decimal,System.MidpointRounding)" />
<Member Name="Subtract(System.Decimal,System.Decimal)" />
<Member Name="ToByte(System.Decimal)" />
<Member Name="ToDouble(System.Decimal)" />
<Member Name="ToInt16(System.Decimal)" />
<Member Name="ToInt32(System.Decimal)" />
<Member Name="ToInt64(System.Decimal)" />
+ <Member Name="ToOACurrency(System.Decimal)" />
<Member Name="ToSByte(System.Decimal)" />
<Member Name="ToSingle(System.Decimal)" />
<Member Name="ToString" />
@@ -1622,6 +1697,9 @@
<Member Name="Truncate(System.Decimal)" />
</Type>
<Type Name="System.Delegate">
+ <Member Name="#ctor(System.Object,System.String)" />
+ <Member Name="#ctor(System.Type,System.String)" />
+ <Member Name="Clone" />
<Member Name="Combine(System.Delegate,System.Delegate)" />
<Member Name="Combine(System.Delegate[])" />
<Member Name="CombineImpl(System.Delegate)" />
@@ -1636,18 +1714,18 @@
<Member Name="CreateDelegate(System.Type,System.Type,System.String,System.Boolean)" />
<Member Name="CreateDelegate(System.Type,System.Type,System.String,System.Boolean,System.Boolean)" />
<Member Name="DynamicInvoke(System.Object[])" />
+ <Member Name="DynamicInvokeImpl(System.Object[])" />
<Member Name="Equals(System.Object)" />
+ <Member Name="get_Method" />
+ <Member Name="get_Target" />
<Member Name="GetHashCode" />
<Member Name="GetInvocationList" />
+ <Member Name="GetMethodImpl" />
<Member Name="op_Equality(System.Delegate,System.Delegate)" />
<Member Name="op_Inequality(System.Delegate,System.Delegate)" />
<Member Name="Remove(System.Delegate,System.Delegate)" />
<Member Name="RemoveAll(System.Delegate,System.Delegate)" />
<Member Name="RemoveImpl(System.Delegate)" />
- <Member Name="#ctor(System.Object,System.String)" />
- <Member Name="#ctor(System.Type,System.String)" />
- <Member Name="get_Target" />
- <Member Name="get_Method" />
<Member MemberType="Property" Name="Target" />
<Member MemberType="Property" Name="Method" />
<Member Status="ImplRoot" Name="DelegateConstruct(System.Object,System.IntPtr)" /> <!-- EE -->
@@ -1656,10 +1734,16 @@
<Member Name="#ctor(System.String)" />
<Member Name="get_ConditionString" />
<Member MemberType="Property" Name="ConditionString" />
- </Type>
+ </Type>
<Type Name="System.Diagnostics.DebuggableAttribute">
<Member Name="#ctor(System.Boolean,System.Boolean)" />
<Member Name="#ctor(System.Diagnostics.DebuggableAttribute+DebuggingModes)" />
+ <Member Name="get_IsJITTrackingEnabled" />
+ <Member Name="get_IsJITOptimizerDisabled" />
+ <Member Name="get_DebuggingFlags" />
+ <Member MemberType="Property" Name="IsJITTrackingEnabled" />
+ <Member MemberType="Property" Name="IsJITOptimizerDisabled" />
+ <Member MemberType="Property" Name="DebuggingFlags" />
</Type>
<Type Name="System.Diagnostics.DebuggableAttribute+DebuggingModes">
<Member MemberType="Field" Name="Default" />
@@ -1767,6 +1851,12 @@
<Member Name="ToString(System.String)" />
<Member Name="ToString(System.String,System.IFormatProvider)" />
</Type>
+ <Type Name="System.DuplicateWaitObjectException">
+ <Member Name="#ctor" />
+ <Member Name="#ctor(System.String)" />
+ <Member Name="#ctor(System.String,System.Exception)" />
+ <Member Name="#ctor(System.String,System.String)" />
+ </Type>
<Type Name="System.EntryPointNotFoundException">
<Member Name="#ctor" />
<Member Name="#ctor(System.String)" />
@@ -1779,7 +1869,7 @@
<Member Name="Format(System.Type,System.Object,System.String)" />
<Member Name="GetHashCode" />
<Member Name="GetName(System.Type,System.Object)" />
- <Member Name="GetNames(System.Type)" />
+ <Member Name="GetNames(System.Type)" />
<Member Name="GetTypeCode" />
<Member Name="GetValues(System.Type)" />
<Member Name="GetUnderlyingType(System.Type)" />
@@ -1787,9 +1877,19 @@
<Member Name="IsDefined(System.Type,System.Object)" />
<Member Name="Parse(System.Type,System.String)" />
<Member Name="Parse(System.Type,System.String,System.Boolean)" />
+ <Member Name="ToObject(System.Type,System.Byte)" />
+ <Member Name="ToObject(System.Type,System.Int16)" />
+ <Member Name="ToObject(System.Type,System.Int32)" />
+ <Member Name="ToObject(System.Type,System.Int64)" />
<Member Name="ToObject(System.Type,System.Object)" />
+ <Member Name="ToObject(System.Type,System.SByte)" />
+ <Member Name="ToObject(System.Type,System.UInt16)" />
+ <Member Name="ToObject(System.Type,System.UInt32)" />
+ <Member Name="ToObject(System.Type,System.UInt64)" />
<Member Name="ToString" />
+ <Member Name="ToString(System.IFormatProvider)" />
<Member Name="ToString(System.String)" />
+ <Member Name="ToString(System.String,System.IFormatProvider)" />
<Member Name="TryParse&lt;TEnum&gt;(System.String,TEnum@)" />
<Member Name="TryParse&lt;TEnum&gt;(System.String,System.Boolean,TEnum@)" />
</Type>
@@ -1797,7 +1897,7 @@
<Member Name="get_CurrentManagedThreadId" />
<Member Name="get_MachineName" />
<Member Name="get_OSVersion" />
- <Member Name="get_ProcessorCount" />
+ <Member Name="get_ProcessorCount" />
<Member Name="get_StackTrace" />
<Member Name="GetEnvironmentVariable(System.String)" />
<Member Name="GetEnvironmentVariables" />
@@ -1819,6 +1919,22 @@
<Member Name="FailFast(System.String,System.Exception)" />
<Member Name="Exit(System.Int32)" />
</Type>
+ <Type Name="Internal.Runtime.Augments.EnvironmentAugments">
+ <Member MemberType="Property" Name="CurrentManagedThreadId" />
+ <Member MemberType="Property" Name="ExitCode" />
+ <Member MemberType="Property" Name="HasShutdownStarted" />
+ <Member MemberType="Property" Name="StackTrace" />
+ <Member MemberType="Property" Name="TickCount" />
+ <Member Name="get_CurrentManagedThreadId" />
+ <Member Name="get_ExitCode" />
+ <Member Name="set_ExitCode(System.Int32)" />
+ <Member Name="get_HasShutdownStarted" />
+ <Member Name="get_StackTrace" />
+ <Member Name="get_TickCount" />
+ <Member Name="Exit(System.Int32)" />
+ <Member Name="FailFast(System.String,System.Exception)" />
+ <Member Name="GetCommandLineArgs" />
+ </Type>
<Type Name="System.EventArgs">
<Member MemberType="Field" Name="Empty" />
<Member Name="#ctor" />
@@ -1846,6 +1962,7 @@
<Member Name="get_Message" />
<Member Name="get_StackTrace" />
<Member Name="get_Source" />
+ <Member Name="get_TargetSite" />
<Member Name="GetBaseException" />
<Member Name="set_HelpLink(System.String)" />
<Member Name="set_HResult(System.Int32)" />
@@ -1858,6 +1975,7 @@
<Member MemberType="Property" Name="Message" />
<Member MemberType="Property" Name="Source" />
<Member MemberType="Property" Name="StackTrace" />
+ <Member MemberType="Property" Name="TargetSite" />
<Member Status="ImplRoot" Name="InternalToString" />
<Member Status="ImplRoot" Name="InternalPreserveStackTrace" />
<Member Status="ImplRoot" MemberType="Field" Name="_remoteStackIndex" /> <!-- EE -->
@@ -1869,9 +1987,12 @@
<Member Status="ImplRoot" MemberType="Field" Name="_HResult" /> <!-- EE -->
<Member Status="ImplRoot" Name="AddExceptionDataForRestrictedErrorInfo(System.String,System.String,System.String,System.Object,System.Boolean)" Condition="FEATURE_COMINTEROP" />
<Member Status="ImplRoot" Name="TryGetRestrictedLanguageErrorObject(System.Object@)" Condition="FEATURE_COMINTEROP" />
-
</Type>
- <Type Name="System.ExecutionEngineException" />
+ <Type Name="System.ExecutionEngineException">
+ <Member Name="#ctor" />
+ <Member Name="#ctor(System.String)" />
+ <Member Name="#ctor(System.String,System.Exception)" />
+ </Type>
<Type Name="System.FieldAccessException">
<Member Name="#ctor" />
<Member Name="#ctor(System.String)" />
@@ -1959,6 +2080,7 @@
<Member Name="Collect(System.Int32,System.GCCollectionMode,System.Boolean,System.Boolean)" />
<Member Name="CollectionCount(System.Int32)" />
<Member Name="GetGeneration(System.Object)" />
+ <Member Name="GetGeneration(System.WeakReference)" />
<Member Name="get_MaxGeneration" />
<Member Name="GetTotalMemory(System.Boolean)" />
<Member Name="KeepAlive(System.Object)" />
@@ -2251,7 +2373,6 @@
<Member MemberType="Property" Name="UniversalSortableDateTimePattern" />
<Member MemberType="Property" Name="YearMonthPattern" />
</Type>
-
<Type Name="System.Globalization.DateTimeStyles">
<Member MemberType="Field" Name="AdjustToUniversal" />
<Member MemberType="Field" Name="AllowInnerWhite" />
@@ -2265,7 +2386,7 @@
<Member MemberType="Field" Name="RoundtripKind" />
<Member MemberType="Field" Name="value__" />
</Type>
-
+
<Type Name="System.Globalization.PersianCalendar">
<Member MemberType="Field" Name="PersianEra" />
<Member Name="#ctor" />
@@ -2298,7 +2419,7 @@
<Member MemberType="Property" Name="MinSupportedDateTime" />
<Member MemberType="Property" Name="TwoDigitYearMax" />
</Type>
-
+
<Type Name="System.Globalization.TimeSpanStyles">
<Member MemberType="Field" Name="None" />
<Member MemberType="Field" Name="AssumeNegative" />
@@ -2506,7 +2627,7 @@
<Member MemberType="Property" Name="MaxSupportedDateTime" />
<Member MemberType="Property" Name="MinSupportedDateTime" />
<Member MemberType="Property" Name="TwoDigitYearMax" />
- </Type>
+ </Type>
<Type Name="System.Globalization.KoreanCalendar">
<Member MemberType="Field" Name="KoreanEra" />
<Member Name="#ctor" />
@@ -2578,7 +2699,7 @@
<Member MemberType="Property" Name="MaxSupportedDateTime" />
<Member MemberType="Property" Name="MinSupportedDateTime" />
<Member MemberType="Property" Name="TwoDigitYearMax" />
- </Type>
+ </Type>
<Type Name="System.Globalization.NumberFormatInfo">
<Member Name="#ctor" />
<Member Name="Clone" />
@@ -2894,6 +3015,9 @@
<Member MemberType="Property" Name="CompletedSynchronously" />
<Member MemberType="Property" Name="IsCompleted" />
</Type>
+ <Type Name="System.ICloneable">
+ <Member Name="Clone" />
+ </Type>
<Type Name="System.IComparable">
<Member Name="CompareTo(System.Object)" />
</Type>
@@ -3066,7 +3190,7 @@
<Member Name="#ctor(System.String)" />
<Member Name="#ctor(System.String,System.Exception)" />
<Member Name="#ctor(System.String,System.String)" />
- <Member Name="#ctor(System.String,System.String,System.Exception)" />
+ <Member Name="#ctor(System.String,System.String,System.Exception)" />
<Member Name="#ctor(System.String,System.String,System.Int32)" /> <!-- Used by EE, do not remove -->
<Member Name="get_FileName" />
</Type>
@@ -3086,6 +3210,7 @@
</Type>
<Type Name="System.Lazy&lt;T&gt;">
<Member Name="#ctor"/>
+ <Member Name="#ctor(T)"/>
<Member Name="#ctor(System.Func&lt;T&gt;)"/>
<Member Name="#ctor(System.Boolean)"/>
<Member Name="#ctor(System.Threading.LazyThreadSafetyMode)"/>
@@ -3121,10 +3246,13 @@
<Member Name="Asin(System.Double)" />
<Member Name="Atan(System.Double)" />
<Member Name="Atan2(System.Double,System.Double)" />
+ <Member Name="BigMul(System.Int32,System.Int32)" />
<Member Name="Ceiling(System.Decimal)" />
<Member Name="Ceiling(System.Double)"/>
<Member Name="Cos(System.Double)" />
<Member Name="Cosh(System.Double)" />
+ <Member Name="DivRem(System.Int32,System.Int32,System.Int32@)" />
+ <Member Name="DivRem(System.Int64,System.Int64,System.Int64@)" />
<Member Name="Exp(System.Double)" />
<Member Name="Floor(System.Decimal)" />
<Member Name="Floor(System.Double)" />
@@ -3213,10 +3341,12 @@
</Type>
<Type Name="System.MulticastDelegate">
<Member Name="#ctor(System.Object,System.String)" />
+ <Member Name="#ctor(System.Type,System.String)" />
<Member Name="CombineImpl(System.Delegate)" />
<Member Name="Equals(System.Object)" />
<Member Name="GetHashCode" />
<Member Name="GetInvocationList" />
+ <Member Name="GetMethodImpl" />
<Member Name="op_Equality(System.MulticastDelegate,System.MulticastDelegate)" />
<Member Name="op_Inequality(System.MulticastDelegate,System.MulticastDelegate)" />
<Member Name="RemoveImpl(System.Delegate)" />
@@ -3239,10 +3369,18 @@
<Member Name="#ctor(System.String)" />
<Member Name="#ctor(System.String,System.Exception)" />
</Type>
+ <Type Name="System.NonSerializedAttribute">
+ <Member Name="#ctor" />
+ </Type>
<Type Name="System.NotFiniteNumberException">
<Member Name="#ctor" />
+ <Member Name="#ctor(System.Double)" />
<Member Name="#ctor(System.String)" />
+ <Member Name="#ctor(System.String,System.Double)" />
<Member Name="#ctor(System.String,System.Exception)" />
+ <Member Name="#ctor(System.String,System.Double,System.Exception)" />
+ <Member Name="get_OffendingNumber" />
+ <Member MemberType="Property" Name="OffendingNumber" />
</Type>
<Type Name="System.NotImplementedException">
<Member Name="#ctor" />
@@ -3293,8 +3431,8 @@
</Type>
<Type Name="System.ObjectDisposedException">
<Member Name="#ctor(System.String)" />
- <Member Name="#ctor(System.String,System.String)" />
<Member Name="#ctor(System.String,System.Exception)" />
+ <Member Name="#ctor(System.String,System.String)" />
<Member Name="get_ObjectName" />
<Member MemberType="Property" Name="ObjectName" />
</Type>
@@ -3378,13 +3516,12 @@
<Member MemberType="Field" Name="WindowsRuntime"/>
<Member MemberType="Field" Name="value__"/>
</Type>
-
<Type Name="System.Reflection.Assembly">
- <Member Name="#ctor" />
+ <Member Name="#ctor" />
<Member Name="CreateInstance(System.String)" />
<Member Name="CreateInstance(System.String,System.Boolean)" />
<Member Name="CreateQualifiedName(System.String,System.String)" />
- <Member Name="GetReferencedAssemblies" />
+ <Member Name="GetReferencedAssemblies" />
<Member Name="get_EntryPoint" />
<Member Name="get_FullName" />
<Member Name="get_ImageRuntimeVersion" />
@@ -3432,10 +3569,10 @@
<Member Status="ImplRoot" MemberType="Event" Name="ModuleResolve" />
</Type>
<Type Name="System.Reflection.IntrospectionExtensions">
- <Member Name="GetTypeInfo(System.Type)" />
+ <Member Name="GetTypeInfo(System.Type)" />
</Type>
<Type Name="System.Reflection.IReflectableType">
- <Member Name="GetTypeInfo" />
+ <Member Name="GetTypeInfo" />
</Type>
<Type Name="System.Reflection.ProcessorArchitecture">
<Member MemberType="Field" Name="None" />
@@ -3446,9 +3583,9 @@
<Member MemberType="Field" Name="Arm" />
</Type>
<Type Name="System.Reflection.ReflectionContext">
- <Member Name="#ctor" />
- <Member Name="MapAssembly(System.Reflection.Assembly)" />
- <Member Name="MapType(System.Reflection.TypeInfo)" />
+ <Member Name="#ctor" />
+ <Member Name="MapAssembly(System.Reflection.Assembly)" />
+ <Member Name="MapType(System.Reflection.TypeInfo)" />
<Member Name="GetTypeForObject(System.Object)" />
</Type>
<Type Status="ApiRoot" Name="System.Reflection.ResourceLocation">
@@ -3465,9 +3602,9 @@
<Member Status="ImplRoot" Name="InternalLoadFrom(System.String,System.Security.Policy.Evidence,System.Byte[],System.Configuration.Assemblies.AssemblyHashAlgorithm,System.Boolean,System.Boolean,System.Threading.StackCrawlMark@)" Condition="FEATURE_WINDOWSPHONE" />
</Type>
<Type Name="System.Reflection.TypeInfo">
- <Member Name="#ctor" />
- <Member Name="AsType" />
- <Member MemberType="Property" Name="GenericTypeParameters" />
+ <Member Name="#ctor" />
+ <Member Name="AsType" />
+ <Member MemberType="Property" Name="GenericTypeParameters" />
<Member Name="IsAssignableFrom(System.Reflection.TypeInfo)" />
<Member Name="GetDeclaredEvent(System.String)" />
<Member Name="GetDeclaredField(System.String)" />
@@ -3475,13 +3612,13 @@
<Member Name="GetDeclaredMethods(System.String)" />
<Member Name="GetDeclaredNestedType(System.String)" />
<Member Name="GetDeclaredProperty(System.String)" />
- <Member MemberType="Property" Name="DeclaredConstructors" />
- <Member MemberType="Property" Name="DeclaredEvents" />
- <Member MemberType="Property" Name="DeclaredFields" />
- <Member MemberType="Property" Name="DeclaredMembers" />
- <Member MemberType="Property" Name="DeclaredMethods" />
- <Member MemberType="Property" Name="DeclaredNestedTypes" />
- <Member MemberType="Property" Name="DeclaredProperties" />
+ <Member MemberType="Property" Name="DeclaredConstructors" />
+ <Member MemberType="Property" Name="DeclaredEvents" />
+ <Member MemberType="Property" Name="DeclaredFields" />
+ <Member MemberType="Property" Name="DeclaredMembers" />
+ <Member MemberType="Property" Name="DeclaredMethods" />
+ <Member MemberType="Property" Name="DeclaredNestedTypes" />
+ <Member MemberType="Property" Name="DeclaredProperties" />
<Member MemberType="Property" Name="ImplementedInterfaces" />
</Type>
<Type Name="System.Reflection.AssemblyAlgorithmIdAttribute">
@@ -3564,7 +3701,7 @@
<Member Name="get_ProcessorArchitecture" />
<Member Name="get_Version" />
<Member Name="GetPublicKey" />
- <Member Name="GetPublicKeyToken" />
+ <Member Name="GetPublicKeyToken" />
<Member Name="set_CultureInfo(System.Globalization.CultureInfo)" />
<Member Name="set_Flags(System.Reflection.AssemblyNameFlags)" />
<Member Name="set_HashAlgorithm(System.Configuration.Assemblies.AssemblyHashAlgorithm)" />
@@ -3677,13 +3814,12 @@
<Member Name="GetCustomAttributes(System.Reflection.Assembly)" />
<Member Name="GetCustomAttributes(System.Reflection.MemberInfo)" />
<Member Name="GetCustomAttributes(System.Reflection.Module)" />
- <Member Name="GetCustomAttributes(System.Reflection.ParameterInfo)" />
+ <Member Name="GetCustomAttributes(System.Reflection.ParameterInfo)" />
<Member MemberType="Property" Name="AttributeType" />
<Member MemberType="Property" Name="Constructor" />
<Member MemberType="Property" Name="ConstructorArguments" />
- <Member MemberType="Property" Name="NamedArguments" />
+ <Member MemberType="Property" Name="NamedArguments" />
</Type>
-
<Type Name="System.Reflection.CustomAttributeExtensions">
<Member Name="GetCustomAttribute(System.Reflection.Assembly,System.Type)" />
<Member Name="GetCustomAttribute(System.Reflection.MemberInfo,System.Type)" />
@@ -3722,7 +3858,6 @@
<Member Name="IsDefined(System.Reflection.ParameterInfo,System.Type)" />
<Member Name="IsDefined(System.Reflection.ParameterInfo,System.Type,System.Boolean)" />
</Type>
-
<Type Name="System.Reflection.RuntimeReflectionExtensions">
<Member Name="GetMethodInfo(System.Delegate)" />
<Member Name="GetRuntimeBaseDefinition(System.Reflection.MethodInfo)" />
@@ -3735,17 +3870,16 @@
<Member Name="GetRuntimeMethods(System.Type)" />
<Member Name="GetRuntimeProperties(System.Type)" />
<Member Name="GetRuntimeProperty(System.Type,System.String)" />
- </Type>
-
+ </Type>
<Type Name="System.Reflection.CustomAttributeNamedArgument">
<Member Name="get_IsField" />
<Member Name="get_MemberName" />
<Member Name="get_TypedValue" />
- <Member Name="op_Equality(System.Reflection.CustomAttributeNamedArgument,System.Reflection.CustomAttributeNamedArgument)" />
- <Member Name="op_Inequality(System.Reflection.CustomAttributeNamedArgument,System.Reflection.CustomAttributeNamedArgument)" />
+ <Member Name="op_Equality(System.Reflection.CustomAttributeNamedArgument,System.Reflection.CustomAttributeNamedArgument)" />
+ <Member Name="op_Inequality(System.Reflection.CustomAttributeNamedArgument,System.Reflection.CustomAttributeNamedArgument)" />
<Member MemberType="Property" Name="IsField" />
<Member MemberType="Property" Name="MemberName" />
- <Member MemberType="Property" Name="TypedValue" />
+ <Member MemberType="Property" Name="TypedValue" />
</Type>
<Type Name="System.Reflection.CustomAttributeTypedArgument">
<Member Name="get_ArgumentType" />
@@ -3755,7 +3889,6 @@
<Member MemberType="Property" Name="ArgumentType" />
<Member MemberType="Property" Name="Value" />
</Type>
-
<Type Name="System.Reflection.CustomAttributeFormatException">
<Member Name="#ctor" />
<Member Name="#ctor(System.String)" />
@@ -3960,7 +4093,7 @@
<Member Name="MakeArrayType" />
<Member Name="MakeArrayType(System.Int32)" />
<Member Name="MakeByRefType" />
- <Member Name="MakePointerType" />
+ <Member Name="MakePointerType" />
<Member Name="SetCustomAttribute(System.Reflection.ConstructorInfo,System.Byte[])" />
<Member Name="SetCustomAttribute(System.Reflection.Emit.CustomAttributeBuilder)" />
<Member MemberType="Property" Name="Assembly" />
@@ -3981,8 +4114,8 @@
<Type Name="System.Reflection.Emit.EventBuilder">
<Member Name="AddOtherMethod(System.Reflection.Emit.MethodBuilder)" />
<Member Name="GetEventToken" />
- <Member Name="SetAddOnMethod(System.Reflection.Emit.MethodBuilder)" />
- <Member Name="SetCustomAttribute(System.Reflection.ConstructorInfo,System.Byte[])" />
+ <Member Name="SetAddOnMethod(System.Reflection.Emit.MethodBuilder)" />
+ <Member Name="SetCustomAttribute(System.Reflection.ConstructorInfo,System.Byte[])" />
<Member Name="SetCustomAttribute(System.Reflection.Emit.CustomAttributeBuilder)" />
<Member Name="SetRaiseMethod(System.Reflection.Emit.MethodBuilder)" />
<Member Name="SetRemoveOnMethod(System.Reflection.Emit.MethodBuilder)" />
@@ -4093,7 +4226,7 @@
<Member Name="InvokeMember(System.String,System.Reflection.BindingFlags,System.Reflection.Binder,System.Object,System.Object[],System.Reflection.ParameterModifier[],System.Globalization.CultureInfo,System.String[])" />
<Member Name="IsArrayImpl" />
<Member Name="IsAssignableFrom(System.Type)" />
- <Member Name="IsAssignableFrom(System.Reflection.TypeInfo)" />
+ <Member Name="IsAssignableFrom(System.Reflection.TypeInfo)" />
<Member Name="IsByRefImpl" />
<Member Name="IsCOMObjectImpl" />
<Member Name="IsDefined(System.Type,System.Boolean)" />
@@ -4106,7 +4239,7 @@
<Member Name="MakeByRefType" />
<Member Name="MakeGenericType(System.Type[])" />
<Member Name="MakePointerType" />
- <Member Name="SetBaseTypeConstraint(System.Type)" />
+ <Member Name="SetBaseTypeConstraint(System.Type)" />
<Member Name="SetCustomAttribute(System.Reflection.ConstructorInfo,System.Byte[])" />
<Member Name="SetCustomAttribute(System.Reflection.Emit.CustomAttributeBuilder)" />
<Member Name="SetGenericParameterAttributes(System.Reflection.GenericParameterAttributes)" />
@@ -4170,7 +4303,7 @@
<Member Name="get_ILOffset" />
<Member Name="ThrowException(System.Type)" />
<Member Name="UsingNamespace(System.String)" />
- <Member MemberType="Property" Name="ILOffset" />
+ <Member MemberType="Property" Name="ILOffset" />
</Type>
<Type Name="System.Diagnostics.CodeAnalysis.SuppressMessageAttribute">
<Member Name="#ctor(System.String,System.String)" />
@@ -4275,7 +4408,7 @@
<Member Name="DefineGlobalMethod(System.String,System.Reflection.MethodAttributes,System.Reflection.CallingConventions,System.Type,System.Type[])" />
<Member Name="DefineGlobalMethod(System.String,System.Reflection.MethodAttributes,System.Reflection.CallingConventions,System.Type,System.Type[],System.Type[],System.Type[],System.Type[][],System.Type[][])" />
<Member Name="DefineGlobalMethod(System.String,System.Reflection.MethodAttributes,System.Type,System.Type[])" />
- <Member Name="DefineInitializedData(System.String,System.Byte[],System.Reflection.FieldAttributes)" />
+ <Member Name="DefineInitializedData(System.String,System.Byte[],System.Reflection.FieldAttributes)" />
<Member Name="DefineType(System.String)" />
<Member Name="DefineType(System.String,System.Reflection.TypeAttributes)" />
<Member Name="DefineType(System.String,System.Reflection.TypeAttributes,System.Type)" />
@@ -4302,7 +4435,7 @@
<Member Name="IsTransient" />
<Member Name="SetCustomAttribute(System.Reflection.ConstructorInfo,System.Byte[])" />
<Member Name="SetCustomAttribute(System.Reflection.Emit.CustomAttributeBuilder)" />
- <Member MemberType="Property" Name="FullyQualifiedName" />
+ <Member MemberType="Property" Name="FullyQualifiedName" />
</Type>
<Type Name="System.Reflection.Emit.OpCode">
<Member Name="Equals(System.Object)" />
@@ -4776,7 +4909,7 @@
<Member Name="DefineNestedType(System.String,System.Reflection.TypeAttributes,System.Type)" />
<Member Name="DefineNestedType(System.String,System.Reflection.TypeAttributes,System.Type,System.Int32)" />
<Member Name="DefineNestedType(System.String,System.Reflection.TypeAttributes,System.Type,System.Reflection.Emit.PackingSize)" />
- <Member Name="DefineNestedType(System.String,System.Reflection.TypeAttributes,System.Type,System.Reflection.Emit.PackingSize,System.Int32)" />
+ <Member Name="DefineNestedType(System.String,System.Reflection.TypeAttributes,System.Type,System.Reflection.Emit.PackingSize,System.Int32)" />
<Member Name="DefineNestedType(System.String,System.Reflection.TypeAttributes,System.Type,System.Type[])" />
<Member Name="DefineProperty(System.String,System.Reflection.PropertyAttributes,System.Type,System.Type[])" />
<Member Name="DefineProperty(System.String,System.Reflection.PropertyAttributes,System.Type,System.Type[],System.Type[],System.Type[],System.Type[][],System.Type[][])" />
@@ -4909,12 +5042,12 @@
<Member Name="GetRemoveMethod" />
<Member Name="GetRemoveMethod(System.Boolean)" />
<Member Name="Equals(System.Object)" />
- <Member Name="GetHashCode" />
+ <Member Name="GetHashCode" />
<Member Name="RemoveEventHandler(System.Object,System.Delegate)" />
<Member MemberType="Property" Name="Attributes" />
- <Member MemberType="Property" Name="AddMethod" />
- <Member MemberType="Property" Name="RaiseMethod" />
- <Member MemberType="Property" Name="RemoveMethod" />
+ <Member MemberType="Property" Name="AddMethod" />
+ <Member MemberType="Property" Name="RaiseMethod" />
+ <Member MemberType="Property" Name="RemoveMethod" />
<Member MemberType="Property" Name="EventHandlerType" />
<Member MemberType="Property" Name="IsMulticast" />
<Member MemberType="Property" Name="IsSpecialName" />
@@ -4967,7 +5100,7 @@
<Member Name="GetRequiredCustomModifiers" />
<Member Name="GetRawConstantValue" />
<Member Name="Equals(System.Object)" />
- <Member Name="GetHashCode" />
+ <Member Name="GetHashCode" />
<Member Name="SetValue(System.Object,System.Object)" />
<Member Name="SetValue(System.Object,System.Object,System.Reflection.BindingFlags,System.Reflection.Binder,System.Globalization.CultureInfo)" />
<Member MemberType="Property" Name="Attributes" />
@@ -5017,7 +5150,7 @@
</Type>
<Type Name="System.Reflection.MemberInfo">
<Member Name="#ctor" />
- <Member Name="get_CustomAttributes" />
+ <Member Name="get_CustomAttributes" />
<Member Name="get_DeclaringType" />
<Member Name="get_MemberType" />
<Member Name="get_MetadataToken" />
@@ -5026,7 +5159,7 @@
<Member Name="GetCustomAttributes(System.Boolean)" />
<Member Name="GetCustomAttributes(System.Type,System.Boolean)" />
<Member Name="Equals(System.Object)" />
- <Member Name="GetHashCode" />
+ <Member Name="GetHashCode" />
<Member Name="IsDefined(System.Type,System.Boolean)" />
<Member MemberType="Property" Name="CustomAttributes" />
<Member MemberType="Property" Name="DeclaringType" />
@@ -5093,7 +5226,7 @@
<Member Name="get_IsSpecialName" />
<Member Name="get_IsStatic" />
<Member Name="get_IsVirtual" />
- <Member Name="get_MethodHandle" />
+ <Member Name="get_MethodHandle" />
<Member Name="get_MethodImplementationFlags" />
<Member Name="GetGenericArguments" />
<Member Status="ImplRoot" Name="GetMethodDesc" />
@@ -5124,7 +5257,7 @@
<Member MemberType="Property" Name="IsStatic" />
<Member MemberType="Property" Name="IsVirtual" />
<Member MemberType="Property" Name="MethodHandle" />
- <Member MemberType="Property" Name="MethodImplementationFlags" />
+ <Member MemberType="Property" Name="MethodImplementationFlags" />
<Member Name="GetCurrentMethod" />
</Type>
<Type Name="System.Reflection.MethodImplAttributes">
@@ -5155,7 +5288,7 @@
<Member Name="GetGenericArguments" />
<Member Name="GetGenericMethodDefinition" />
<Member Name="Equals(System.Object)" />
- <Member Name="GetHashCode" />
+ <Member Name="GetHashCode" />
<Member Name="MakeGenericMethod(System.Type[])" />
<Member MemberType="Property" Name="MemberType" />
<Member MemberType="Property" Name="ReturnParameter" />
@@ -5192,7 +5325,7 @@
<Member Name="GetType(System.String,System.Boolean,System.Boolean)" />
<Member Name="GetTypes" />
<Member Name="Equals(System.Object)" />
- <Member Name="GetHashCode" />
+ <Member Name="GetHashCode" />
<Member Name="IsDefined(System.Type,System.Boolean)" />
<Member Name="ResolveMethod(System.Int32)" />
<Member Name="ResolveMethod(System.Int32,System.Type[],System.Type[])" />
@@ -5203,7 +5336,7 @@
<Member Name="ResolveType(System.Int32,System.Type[],System.Type[])" />
<Member Name="ToString" />
<Member MemberType="Property" Name="Assembly" />
- <Member MemberType="Property" Name="CustomAttributes" />
+ <Member MemberType="Property" Name="CustomAttributes" />
<Member MemberType="Property" Name="FullyQualifiedName" />
<Member MemberType="Property" Name="MetadataToken" />
<Member MemberType="Property" Name="ModuleVersionId" />
@@ -5235,13 +5368,13 @@
<Type Name="System.Reflection.ParameterInfo">
<Member Name="#ctor" />
<Member Name="get_Attributes" />
- <Member Name="get_CustomAttributes" />
+ <Member Name="get_CustomAttributes" />
<Member Name="get_DefaultValue" />
<Member Name="get_HasDefaultValue" />
<Member Name="get_IsOptional" />
- <Member Name="get_IsOut" />
- <Member Name="get_IsIn" />
- <Member Name="get_IsRetval" />
+ <Member Name="get_IsOut" />
+ <Member Name="get_IsIn" />
+ <Member Name="get_IsRetval" />
<Member Name="get_Member" />
<Member Name="get_MetadataToken" />
<Member Name="get_Name" />
@@ -5254,18 +5387,18 @@
<Member Name="GetCustomAttributes(System.Type,System.Boolean)" />
<Member Name="IsDefined(System.Type,System.Boolean)" />
<Member MemberType="Property" Name="Attributes" />
- <Member MemberType="Property" Name="CustomAttributes" />
+ <Member MemberType="Property" Name="CustomAttributes" />
<Member MemberType="Property" Name="DefaultValue" />
<Member MemberType="Property" Name="HasDefaultValue" />
<Member MemberType="Property" Name="IsOptional" />
- <Member MemberType="Property" Name="IsOut" />
- <Member MemberType="Property" Name="IsIn" />
- <Member MemberType="Property" Name="IsRetval" />
+ <Member MemberType="Property" Name="IsOut" />
+ <Member MemberType="Property" Name="IsIn" />
+ <Member MemberType="Property" Name="IsRetval" />
<Member MemberType="Property" Name="Member" />
<Member MemberType="Property" Name="MetadataToken" />
<Member MemberType="Property" Name="Name" />
<Member MemberType="Property" Name="ParameterType" />
- <Member MemberType="Property" Name="Position" />
+ <Member MemberType="Property" Name="Position" />
<Member MemberType="Property" Name="RawDefaultValue" />
</Type>
<Type Name="System.Reflection.ParameterModifier">
@@ -5290,11 +5423,11 @@
<Member Name="get_Attributes" />
<Member Name="get_CanRead" />
<Member Name="get_CanWrite" />
- <Member Name="get_GetMethod" />
+ <Member Name="get_GetMethod" />
<Member Name="get_IsSpecialName" />
<Member Name="get_MemberType" />
<Member Name="get_PropertyType" />
- <Member Name="get_SetMethod" />
+ <Member Name="get_SetMethod" />
<Member Name="GetAccessors" />
<Member Name="GetAccessors(System.Boolean)" />
<Member Name="GetConstantValue" />
@@ -5310,16 +5443,15 @@
<Member Name="GetValue(System.Object,System.Object[])" />
<Member Name="GetValue(System.Object,System.Reflection.BindingFlags,System.Reflection.Binder,System.Object[],System.Globalization.CultureInfo)" />
<Member Name="Equals(System.Object)" />
- <Member Name="GetHashCode" />
- <Member Name="SetValue(System.Object,System.Object)" />
+ <Member Name="GetHashCode" />
+ <Member Name="SetValue(System.Object,System.Object)" />
<Member Name="SetValue(System.Object,System.Object,System.Object[])" />
<Member Name="SetValue(System.Object,System.Object,System.Reflection.BindingFlags,System.Reflection.Binder,System.Object[],System.Globalization.CultureInfo)" />
-
<Member MemberType="Property" Name="Attributes" />
<Member MemberType="Property" Name="CanRead" />
<Member MemberType="Property" Name="CanWrite" />
<Member MemberType="Property" Name="GetMethod" />
- <Member MemberType="Property" Name="SetMethod" />
+ <Member MemberType="Property" Name="SetMethod" />
<Member MemberType="Property" Name="IsSpecialName" />
<Member MemberType="Property" Name="MemberType" />
<Member MemberType="Property" Name="PropertyType" />
@@ -5385,7 +5517,7 @@
<Member Name="get_RequestingAssembly" />
<Member MemberType="Property" Name="RequestingAssembly" />
</Type>
- <Type Name="System.ResolveEventHandler" Condition="FEATURE_LEGACYNETCF">
+ <Type Name="System.ResolveEventHandler">
<Member Name="#ctor(System.Object,System.IntPtr)" />
<Member Name="BeginInvoke(System.Object,System.ResolveEventArgs,System.AsyncCallback,System.Object)" />
<Member Name="EndInvoke(System.IAsyncResult)" />
@@ -5423,7 +5555,7 @@
<Member Name="GetResourceSet(System.Globalization.CultureInfo,System.Boolean,System.Boolean)" />
<Member Name="GetSatelliteContractVersion(System.Reflection.Assembly)" />
<Member Name="GetStream(System.String)" />
- <Member Name="GetStream(System.String,System.Globalization.CultureInfo)" />
+ <Member Name="GetStream(System.String,System.Globalization.CultureInfo)" />
<Member Name="GetString(System.String)" />
<Member Name="GetString(System.String,System.Globalization.CultureInfo)" />
<Member Name="InternalGetResourceSet(System.Globalization.CultureInfo,System.Boolean,System.Boolean)" />
@@ -5509,7 +5641,7 @@
<Member MemberType="Property" Name="Length" />
</Type>
<Type Name="System.Runtime.CompilerServices.FixedAddressValueTypeAttribute">
- <Member Name="#ctor" />
+ <Member Name="#ctor" />
</Type>
<Type Name="System.Runtime.CompilerServices.FormattableStringFactory">
<Member Name="Create(System.String,System.Object[])" />
@@ -5548,11 +5680,11 @@
</Type>
<Type Name="System.Runtime.CompilerServices.IsCopyConstructed"> <!-- for MC++ -->
</Type>
- <Type Name="System.Runtime.CompilerServices.ICastable">
+ <Type Name="System.Runtime.CompilerServices.ICastable">
<Member Name="IsInstanceOfInterface(System.RuntimeTypeHandle,System.Exception@)" /> <!-- EE -->
<Member Name="GetImplType(System.RuntimeTypeHandle)" /> <!-- EE -->
</Type>
- <Type Name="System.Runtime.CompilerServices.ICastableHelpers">
+ <Type Name="System.Runtime.CompilerServices.ICastableHelpers">
<Member Name="IsInstanceOfInterface(System.Runtime.CompilerServices.ICastable,System.RuntimeType,System.Exception@)" /> <!-- EE -->
<Member Name="GetImplType(System.Runtime.CompilerServices.ICastable,System.RuntimeType)" /> <!-- EE -->
</Type>
@@ -5569,7 +5701,7 @@
<Type Name="System.Runtime.CompilerServices.IsUdtReturn"> <!-- for MC++ -->
</Type>
<Type Name="System.Runtime.CompilerServices.NativeCppClassAttribute"> <!-- for MC++ -->
- <Member Name="#ctor" />
+ <Member Name="#ctor" />
</Type>
<Type Name="System.Runtime.CompilerServices.IsVolatile" /> <!-- for MC++ -->
<Type Name="System.Runtime.CompilerServices.MethodCodeType">
@@ -5677,7 +5809,7 @@
<Member Name="#ctor(System.Decimal)" />
<Member Name="#ctor(System.Object)" />
<Member Name="get_WrappedObject" />
- <Member MemberType="Property" Name="WrappedObject" />
+ <Member MemberType="Property" Name="WrappedObject" />
</Type>
<Type Name="System.Runtime.InteropServices.DispatchWrapper">
<Member Name="#ctor(System.Object)" />
@@ -5814,6 +5946,7 @@
<Member Name="#ctor" />
<Member Name="#ctor(System.String)" />
<Member Name="#ctor(System.String,System.Exception)" />
+ <Member Name="#ctor(System.String,System.Int32)" />
<Member Name="get_ErrorCode" />
<Member MemberType="Property" Name="ErrorCode" />
</Type>
@@ -5829,7 +5962,7 @@
<Member Name="Free" />
<Member Name="FromIntPtr(System.IntPtr)" />
<Member Name="get_IsAllocated" />
- <Member Name="get_Target" />
+ <Member Name="get_Target" />
<Member Name="op_Explicit(System.IntPtr)" ReturnType="System.Runtime.InteropServices.GCHandle" />
<Member Name="op_Explicit(System.Runtime.InteropServices.GCHandle)" ReturnType="System.IntPtr" />
<Member Name="set_Target(System.Object)" />
@@ -5886,7 +6019,7 @@
<Member MemberType="Field" Name="Sequential" />
<Member MemberType="Field" Name="value__" />
</Type>
- <Type Name="System.Runtime.InteropServices.NativeCallableAttribute">
+ <Type Name="System.Runtime.InteropServices.NativeCallableAttribute">
<Member Name="#ctor" />
<Member MemberType="Field" Name="CallingConvention" /> <!-- EE -->
<Member MemberType="Field" Name="EntryPoint" /> <!-- EE -->
@@ -5955,23 +6088,23 @@
<Member Name="ReleaseComObject(System.Object)" />
<Member Name="SetLastWin32Error(System.Int32)" />
<Member Name="SizeOf(System.Object)" />
- <Member Name="SizeOf(System.Type)" />
+ <Member Name="SizeOf(System.Type)" />
<Member Name="StructureToPtr(System.Object,System.IntPtr,System.Boolean)" />
<Member Name="ThrowExceptionForHR(System.Int32)" />
<Member Name="ThrowExceptionForHR(System.Int32,System.IntPtr)" />
<Member Name="UnsafeAddrOfPinnedArrayElement(System.Array,System.Int32)" />
<Member Name="WriteByte(System.IntPtr,System.Byte)" />
<Member Name="WriteByte(System.IntPtr,System.Int32,System.Byte)" />
- <Member Name="WriteInt16(System.IntPtr,System.Char)" />
+ <Member Name="WriteInt16(System.IntPtr,System.Char)" />
<Member Name="WriteInt16(System.IntPtr,System.Int16)" />
- <Member Name="WriteInt16(System.IntPtr,System.Int32,System.Char)" />
+ <Member Name="WriteInt16(System.IntPtr,System.Int32,System.Char)" />
<Member Name="WriteInt16(System.IntPtr,System.Int32,System.Int16)" />
<Member Name="WriteInt32(System.IntPtr,System.Int32)" />
<Member Name="WriteInt32(System.IntPtr,System.Int32,System.Int32)" />
<Member Name="WriteInt64(System.IntPtr,System.Int32,System.Int64)" />
- <Member Name="WriteInt64(System.IntPtr,System.Int64)" />
+ <Member Name="WriteInt64(System.IntPtr,System.Int64)" />
<Member Name="WriteIntPtr(System.IntPtr,System.Int32,System.IntPtr)" />
- <Member Name="WriteIntPtr(System.IntPtr,System.IntPtr)" />
+ <Member Name="WriteIntPtr(System.IntPtr,System.IntPtr)" />
<Member Name="ZeroFreeCoTaskMemUnicode(System.IntPtr)" />
<Member Status="ImplRoot" Name="InitializeWrapperForWinRT(System.Object,System.IntPtr@)" Condition="FEATURE_COMINTEROP" />
<Member Status="ImplRoot" Name="LoadLicenseManager" Condition="FEATURE_COMINTEROP" /><Member MemberType="Field" Name="SystemMaxDBCSCharSize" />
@@ -6177,7 +6310,7 @@
<Member MemberType="Field" Name="value__" />
</Type>
<Type Name="System.RuntimeFieldHandle">
- <Member Name="Equals(System.RuntimeFieldHandle)" />
+ <Member Name="Equals(System.RuntimeFieldHandle)" />
<Member Name="op_Equality(System.RuntimeFieldHandle,System.RuntimeFieldHandle)" />
<Member Name="op_Inequality(System.RuntimeFieldHandle,System.RuntimeFieldHandle)" />
</Type>
@@ -6222,6 +6355,9 @@
<Member Name="IsStateAvailable" />
<Member Name="EnsureState" />
</Type>
+ <Type Name="System.SerializableAttribute">
+ <Member Name="#ctor" />
+ </Type>
<Type Name="System.Single">
<Member MemberType="Field" Name="Epsilon" />
<Member MemberType="Field" Name="MaxValue" />
@@ -6273,11 +6409,17 @@
<Member Name="#ctor(System.Char[])" />
<Member Name="#ctor(System.Char[],System.Int32,System.Int32)" />
<Member Name="#ctor(System.SByte*)" />
+ <Member Name="#ctor(System.SByte*,System.Int32,System.Int32)" />
+ <Member Name="#ctor(System.SByte*,System.Int32,System.Int32,System.Text.Encoding)" />
+ <Member Name="Clone" />
<Member Name="Compare(System.String,System.Int32,System.String,System.Int32,System.Int32)" />
+ <Member Name="Compare(System.String,System.Int32,System.String,System.Int32,System.Int32,System.Boolean)" />
+ <Member Name="Compare(System.String,System.Int32,System.String,System.Int32,System.Int32,System.Boolean,System.Globalization.CultureInfo)" />
<Member Name="Compare(System.String,System.Int32,System.String,System.Int32,System.Int32,System.Globalization.CultureInfo,System.Globalization.CompareOptions)" />
<Member Name="Compare(System.String,System.Int32,System.String,System.Int32,System.Int32,System.StringComparison)" />
<Member Name="Compare(System.String,System.String)" />
<Member Name="Compare(System.String,System.String,System.Boolean)" />
+ <Member Name="Compare(System.String,System.String,System.Boolean,System.Globalization.CultureInfo)" />
<Member Name="Compare(System.String,System.String,System.Globalization.CultureInfo,System.Globalization.CompareOptions)" />
<Member Name="Compare(System.String,System.String,System.StringComparison)" />
<Member Name="CompareOrdinal(System.String,System.Int32,System.String,System.Int32,System.Int32)" />
@@ -6331,6 +6473,10 @@
<Member Name="Insert(System.Int32,System.String)" />
<Member Name="Intern(System.String)" />
<Member Name="IsInterned(System.String)" />
+<!--
+ <Member Name="IsNormalized" />
+ <Member Name="IsNormalized(System.Text.NormalizationForm)" />
+-->
<Member Name="IsNullOrEmpty(System.String)" />
<Member Name="IsNullOrWhiteSpace(System.String)" />
<Member Name="Join(System.String,System.Object[])" />
@@ -6350,6 +6496,10 @@
<Member Name="LastIndexOfAny(System.Char[])" />
<Member Name="LastIndexOfAny(System.Char[],System.Int32)" />
<Member Name="LastIndexOfAny(System.Char[],System.Int32,System.Int32)" />
+<!--
+ <Member Name="Normalize" />
+ <Member Name="Normalize(System.Text.NormalizationForm)" />
+-->
<Member Name="op_Equality(System.String,System.String)" />
<Member Name="op_Inequality(System.String,System.String)" />
<Member Name="PadLeft(System.Int32)" />
@@ -6367,6 +6517,7 @@
<Member Name="Split(System.String[],System.Int32,System.StringSplitOptions)" />
<Member Name="Split(System.String[],System.StringSplitOptions)"/>
<Member Name="StartsWith(System.String)" />
+ <Member Name="StartsWith(System.String,System.Boolean,System.Globalization.CultureInfo)" />
<Member Name="StartsWith(System.String,System.StringComparison)" />
<Member Name="Substring(System.Int32)" />
<Member Name="Substring(System.Int32,System.Int32)" />
@@ -6474,15 +6625,23 @@
<Member MemberType="Property" Name="Fallback" />
<Member MemberType="Property" Name="FallbackBuffer" />
</Type>
+ <Type Name="System.Text.DecoderExceptionFallbackBuffer">
+ <Member Name="#ctor" />
+ <Member Name="Fallback(System.Byte[],System.Int32)" />
+ <Member Name="get_Remaining" />
+ <Member Name="GetNextChar" />
+ <Member Name="MovePrevious" />
+ <Member MemberType="Property" Name="Remaining" />
+ </Type>
<Type Name="System.Text.DecoderFallback">
<Member Name="#ctor" />
<Member Name="CreateFallbackBuffer" />
<Member Name="get_MaxCharCount" />
- <Member Name="get_ReplacementFallback" />
+ <Member Name="get_ReplacementFallback" />
<Member MemberType="Property" Name="MaxCharCount" />
<Member MemberType="Property" Name="ReplacementFallback" />
<Member Name="get_ExceptionFallback" />
- <Member MemberType="Property" Name="ExceptionFallback" />
+ <Member MemberType="Property" Name="ExceptionFallback" />
</Type>
<Type Name="System.Text.DecoderFallbackBuffer">
<Member Name="#ctor" />
@@ -6504,6 +6663,15 @@
<Member MemberType="Property" Name="DefaultString" />
<Member MemberType="Property" Name="MaxCharCount" />
</Type>
+ <Type Name="System.Text.DecoderReplacementFallbackBuffer">
+ <Member Name="#ctor(System.Text.DecoderReplacementFallback)" />
+ <Member Name="Fallback(System.Byte[],System.Int32)" />
+ <Member Name="get_Remaining" />
+ <Member Name="GetNextChar" />
+ <Member Name="MovePrevious" />
+ <Member Name="Reset" />
+ <Member MemberType="Property" Name="Remaining" />
+ </Type>
<Type Name="System.Text.DecoderExceptionFallback">
<Member Name="#ctor" />
<Member Name="CreateFallbackBuffer" />
@@ -6521,9 +6689,9 @@
<Member Name="get_Index" />
<Member MemberType="Property" Name="BytesUnknown" />
<Member MemberType="Property" Name="Index" />
- </Type>
+ </Type>
<Type Name="System.Text.Encoder">
- <Member Name="#ctor" />
+ <Member Name="#ctor" />
<Member Name="Convert(System.Char*,System.Int32,System.Byte*,System.Int32,System.Boolean,System.Int32@,System.Int32@,System.Boolean@)" />
<Member Name="Convert(System.Char[],System.Int32,System.Int32,System.Byte[],System.Int32,System.Int32,System.Boolean,System.Int32@,System.Int32@,System.Boolean@)" />
<Member Name="get_Fallback" />
@@ -6545,7 +6713,7 @@
<Member MemberType="Property" Name="MaxCharCount" />
<Member MemberType="Property" Name="ReplacementFallback" />
<Member Name="get_ExceptionFallback" />
- <Member MemberType="Property" Name="ExceptionFallback" />
+ <Member MemberType="Property" Name="ExceptionFallback" />
</Type>
<Type Name="System.Text.EncoderFallbackBuffer">
<Member Name="#ctor" />
@@ -6588,10 +6756,20 @@
<Member Name="get_CharUnknownLow" />
<Member Name="get_Index" />
<Member MemberType="Property" Name="CharUnknown" />
- <Member MemberType="Property" Name="CharUnknownHigh" />
+ <Member MemberType="Property" Name="CharUnknownHigh" />
<Member MemberType="Property" Name="CharUnknownLow" />
- <Member MemberType="Property" Name="Index" />
- </Type>
+ <Member MemberType="Property" Name="Index" />
+ </Type>
+ <Type Name="System.Text.EncoderReplacementFallbackBuffer">
+ <Member Name="#ctor(System.Text.EncoderReplacementFallback)" />
+ <Member Name="Fallback(System.Char,System.Char,System.Int32)" />
+ <Member Name="Fallback(System.Char,System.Int32)" />
+ <Member Name="get_Remaining" />
+ <Member Name="GetNextChar" />
+ <Member Name="MovePrevious" />
+ <Member Name="Reset" />
+ <Member MemberType="Property" Name="Remaining" />
+ </Type>
<Type Name="System.Text.EncodingProvider">
<Member Name="#ctor" />
<Member Name="GetEncoding(System.Int32)" />
@@ -6609,25 +6787,34 @@
<Member Name="Equals(System.Object)" />
<Member Name="get_ASCII" />
<Member Name="get_BigEndianUnicode" />
+ <Member Name="get_BodyName" />
<Member Name="get_CodePage" />
<Member Name="get_DecoderFallback" />
+ <Member Name="get_Default" />
<Member Name="get_EncoderFallback" />
<Member Name="get_EncodingName" />
+ <Member Name="get_HeaderName" />
+ <Member Name="get_IsBrowserDisplay" />
+ <Member Name="get_IsBrowserSave" />
+ <Member Name="get_IsMailNewsDisplay" />
+ <Member Name="get_IsMailNewsSave" />
+ <Member Name="get_IsReadOnly" />
<Member Name="get_IsSingleByte" />
<Member Name="get_Unicode" />
<Member Name="get_UTF32" />
<Member Name="get_UTF7" />
<Member Name="get_UTF8" />
<Member Name="get_WebName" />
+ <Member Name="get_WindowsCodePage" />
<Member Name="GetByteCount(System.Char*,System.Int32)" />
<Member Name="GetByteCount(System.Char[])" />
<Member Name="GetByteCount(System.Char[],System.Int32,System.Int32)" />
<Member Name="GetByteCount(System.String)" />
<Member Name="GetBytes(System.Char[])" />
<Member Name="GetBytes(System.Char[],System.Int32,System.Int32)" />
- <Member Name="GetBytes(System.Char[],System.Int32,System.Int32,System.Byte[],System.Int32)" />
+ <Member Name="GetBytes(System.Char[],System.Int32,System.Int32,System.Byte[],System.Int32)" />
<Member Name="GetBytes(System.String)" />
- <Member Name="GetBytes(System.String,System.Int32,System.Int32,System.Byte[],System.Int32)" />
+ <Member Name="GetBytes(System.String,System.Int32,System.Int32,System.Byte[],System.Int32)" />
<Member Name="GetBytes(System.Char*,System.Int32,System.Byte*,System.Int32)" />
<Member Name="GetCharCount(System.Byte[])" />
<Member Name="GetCharCount(System.Byte[],System.Int32,System.Int32)" />
@@ -6643,18 +6830,33 @@
<Member Name="GetEncoding(System.Int32,System.Text.EncoderFallback,System.Text.DecoderFallback)" />
<Member Name="GetEncoding(System.String)" />
<Member Name="GetEncoding(System.String,System.Text.EncoderFallback,System.Text.DecoderFallback)" />
+ <Member Name="GetEncodings" />
<Member Name="GetHashCode" />
<Member Name="GetMaxByteCount(System.Int32)" />
<Member Name="GetMaxCharCount(System.Int32)" />
<Member Name="GetPreamble" />
<Member Name="GetString(System.Byte[])" />
<Member Name="GetString(System.Byte[],System.Int32,System.Int32)" />
+<!--
+ <Member Name="IsAlwaysNormalized" />
+ <Member Name="IsAlwaysNormalized(System.Text.NormalizationForm)" />
+ -->
+ <Member Name="set_DecoderFallback(System.Text.DecoderFallback)" />
+ <Member Name="set_EncoderFallback(System.Text.EncoderFallback)" />
<Member MemberType="Property" Name="ASCII" />
<Member MemberType="Property" Name="BigEndianUnicode" />
+ <Member MemberType="Property" Name="BodyName" />
<Member MemberType="Property" Name="CodePage" />
<Member MemberType="Property" Name="DecoderFallback" />
+ <Member MemberType="Property" Name="Default" />
<Member MemberType="Property" Name="EncoderFallback" />
<Member MemberType="Property" Name="EncodingName" />
+ <Member MemberType="Property" Name="HeaderName" />
+ <Member MemberType="Property" Name="IsBrowserDisplay" />
+ <Member MemberType="Property" Name="IsBrowserSave" />
+ <Member MemberType="Property" Name="IsMailNewsDisplay" />
+ <Member MemberType="Property" Name="IsMailNewsSave" />
+ <Member MemberType="Property" Name="IsReadOnly" />
<Member MemberType="Property" Name="IsSingleByte" />
<Member MemberType="Property" Name="Unicode" />
<Member MemberType="Property" Name="UTF32" />
@@ -6748,11 +6950,15 @@
<Member Name="#ctor(System.Boolean,System.Boolean)" />
<Member Name="#ctor(System.Boolean,System.Boolean,System.Boolean)" />
<Member Name="Equals(System.Object)" />
+ <Member Name="GetByteCount(System.Char*,System.Int32)" />
<Member Name="GetByteCount(System.Char[],System.Int32,System.Int32)" />
<Member Name="GetByteCount(System.String)" />
+ <Member Name="GetBytes(System.Char*,System.Int32,System.Byte*,System.Int32)" />
<Member Name="GetBytes(System.Char[],System.Int32,System.Int32,System.Byte[],System.Int32)" />
<Member Name="GetBytes(System.String,System.Int32,System.Int32,System.Byte[],System.Int32)" />
+ <Member Name="GetCharCount(System.Byte*,System.Int32)" />
<Member Name="GetCharCount(System.Byte[],System.Int32,System.Int32)" />
+ <Member Name="GetChars(System.Byte*,System.Int32,System.Char*,System.Int32)" />
<Member Name="GetChars(System.Byte[],System.Int32,System.Int32,System.Char[],System.Int32)" />
<Member Name="GetDecoder" />
<Member Name="GetHashCode" />
@@ -7030,7 +7236,7 @@
<Member MemberType="Field" Name="EventHandle" />
</Type>
<Type Name="System.Threading.Overlapped">
- <Member Name="#ctor" />
+ <Member Name="#ctor" />
<Member MemberType="Property" Name="AsyncResult" />
<Member MemberType="Property" Name="OffsetLow" />
<Member MemberType="Property" Name="OffsetHigh" />
@@ -7127,7 +7333,7 @@
<Type Name="System.Threading.WaitHandleExtensions">
<Member Name="GetSafeWaitHandle(System.Threading.WaitHandle)" />
<Member Name="SetSafeWaitHandle(System.Threading.WaitHandle,Microsoft.Win32.SafeHandles.SafeWaitHandle)" />
- </Type>
+ </Type>
<Type Name="System.Threading.WaitHandleCannotBeOpenedException">
<Member Name="#ctor" />
<Member Name="#ctor(System.String)" />
@@ -7216,14 +7422,34 @@
<Member MemberType="Property" Name="TotalSeconds" />
</Type>
<Type Name="System.TimeZoneInfo">
+ <Member Name="ClearCachedData" />
+ <Member Name="ConvertTime(System.DateTime,System.TimeZoneInfo)" />
+ <Member Name="ConvertTime(System.DateTime,System.TimeZoneInfo,System.TimeZoneInfo)" />
+ <Member Name="ConvertTime(System.DateTimeOffset,System.TimeZoneInfo)" />
+<!-- Need Linux implementation
+ <Member Name="ConvertTimeBySystemTimeZoneId(System.DateTime,System.String)" />
+ <Member Name="ConvertTimeBySystemTimeZoneId(System.DateTime,System.String,System.String)" />
+ <Member Name="ConvertTimeBySystemTimeZoneId(System.DateTimeOffset,System.String)" />
+-->
+ <Member Name="ConvertTimeFromUtc(System.DateTime,System.TimeZoneInfo)" />
+ <Member Name="ConvertTimeToUtc(System.DateTime)" />
+ <Member Name="ConvertTimeToUtc(System.DateTime,System.TimeZoneInfo)" />
+ <Member Name="CreateCustomTimeZone(System.String,System.TimeSpan,System.String,System.String)" />
+ <Member Name="CreateCustomTimeZone(System.String,System.TimeSpan,System.String,System.String,System.String,System.TimeZoneInfo+AdjustmentRule[])" />
+ <Member Name="CreateCustomTimeZone(System.String,System.TimeSpan,System.String,System.String,System.String,System.TimeZoneInfo+AdjustmentRule[],System.Boolean)" />
+ <Member Name="Equals(System.Object)" />
+ <Member Name="Equals(System.TimeZoneInfo)" />
+ <Member Name="FindSystemTimeZoneById(System.String)" />
+ <Member Name="FromSerializedString(System.String)" />
+ <Member Name="get_BaseUtcOffset" />
<Member Name="get_DisplayName" />
- <Member Name="get_StandardName" />
<Member Name="get_DaylightName" />
+ <Member Name="get_StandardName" />
<Member Name="get_Id" />
- <Member Name="get_BaseUtcOffset" />
- <Member Name="get_SupportsDaylightSavingTime" />
<Member Name="get_Local" />
+ <Member Name="get_SupportsDaylightSavingTime" />
<Member Name="get_Utc" />
+ <Member Name="GetAdjustmentRules" />
<Member Name="GetAmbiguousTimeOffsets(System.DateTimeOffset)" />
<Member Name="GetAmbiguousTimeOffsets(System.DateTime)" />
<Member Name="GetUtcOffset(System.DateTimeOffset)" />
@@ -7233,21 +7459,16 @@
<Member Name="IsDaylightSavingTime(System.DateTimeOffset)" />
<Member Name="IsDaylightSavingTime(System.DateTime)" />
<Member Name="IsInvalidTime(System.DateTime)" />
- <Member Name="ConvertTime(System.DateTimeOffset,System.TimeZoneInfo)" />
- <Member Name="ConvertTime(System.DateTime,System.TimeZoneInfo)" />
- <Member Name="ConvertTime(System.DateTime,System.TimeZoneInfo,System.TimeZoneInfo)" />
- <Member Name="Equals(System.TimeZoneInfo)" />
- <Member Name="FindSystemTimeZoneById(System.String)" />
<Member Name="GetHashCode" />
<Member Name="GetSystemTimeZones" />
<Member Name="ToString" />
- <Member MemberType="Property" Name="DisplayName" />
- <Member MemberType="Property" Name="StandardName" />
<Member MemberType="Property" Name="DaylightName" />
+ <Member MemberType="Property" Name="DisplayName" />
<Member MemberType="Property" Name="Id" />
+ <Member MemberType="Property" Name="Local" />
+ <Member MemberType="Property" Name="StandardName" />
<Member MemberType="Property" Name="BaseUtcOffset" />
<Member MemberType="Property" Name="SupportsDaylightSavingTime" />
- <Member MemberType="Property" Name="Local" />
<Member MemberType="Property" Name="Utc" />
</Type>
<Type Name="System.TimeZoneInfo+AdjustmentRule">
@@ -7255,6 +7476,31 @@
<Member Status="ApiRoot" Name="CreateAdjustmentRule(System.DateTime,System.DateTime,System.TimeSpan,System.TimeZoneInfo+TransitionTime,System.TimeZoneInfo+TransitionTime)" />
</Type>
<Type Name="System.TimeZoneInfo+TransitionTime">
+ <Member Name="CreateFixedDateRule(System.DateTime,System.Int32,System.Int32)" />
+ <Member Name="CreateFloatingDateRule(System.DateTime,System.Int32,System.Int32,System.DayOfWeek)" />
+ <Member Name="Equals(System.Object)" />
+ <Member Name="Equals(System.TimeZoneInfo+TransitionTime)" />
+ <Member Name="get_Day" />
+ <Member Name="get_DayOfWeek" />
+ <Member Name="get_IsFixedDateRule" />
+ <Member Name="get_Month" />
+ <Member Name="get_TimeOfDay" />
+ <Member Name="get_Week" />
+ <Member Name="GetHashCode" />
+ <Member Name="op_Equality(System.TimeZoneInfo+TransitionTime,System.TimeZoneInfo+TransitionTime)" />
+ <Member Name="op_Inequality(System.TimeZoneInfo+TransitionTime,System.TimeZoneInfo+TransitionTime)" />
+ <Member MemberType="Property" Name="Day" />
+ <Member MemberType="Property" Name="DayOfWeek" />
+ <Member MemberType="Property" Name="IsFixedDateRule" />
+ <Member MemberType="Property" Name="Month" />
+ <Member MemberType="Property" Name="TimeOfDay" />
+ <Member MemberType="Property" Name="Week" />
+ </Type>
+ <Type Name="System.TimeZoneNotFoundException">
+ <Member Name="#ctor" />
+ <Member Name="#ctor(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext)" />
+ <Member Name="#ctor(System.String)" />
+ <Member Name="#ctor(System.String,System.Exception)" />
</Type>
<Type Name="System.Tuple">
<Member Name="Create&lt;T1&gt;(T1)" />
@@ -7590,9 +7836,9 @@
<Member Name="IsEnumDefined(System.Object)" />
<Member Name="get_StructLayoutAttribute" />
<Member Name="get_TypeInitializer" />
- <Member Name="FindInterfaces(System.Reflection.TypeFilter,System.Object)" />
+ <Member Name="FindInterfaces(System.Reflection.TypeFilter,System.Object)" />
<Member MemberType="Property" Name="TypeInitializer" />
- <Member MemberType="Property" Name="StructLayoutAttribute" />
+ <Member MemberType="Property" Name="StructLayoutAttribute" />
</Type>
<Type Name="System.TypeAccessException">
<Member Name="#ctor" />
@@ -7731,7 +7977,7 @@
<Member Name="get_IsTerminating" />
<Member MemberType="Property" Name="ExceptionObject" />
<Member MemberType="Property" Name="IsTerminating" />
- </Type>
+ </Type>
<Type Name="System.UnhandledExceptionEventHandler">
<Member Name="#ctor(System.Object,System.IntPtr)" />
<Member Name="BeginInvoke(System.Object,System.UnhandledExceptionEventArgs,System.AsyncCallback,System.Object)" />
@@ -7806,7 +8052,6 @@
<Member Name="TryGetTarget(T@)" />
<Member Status="ImplRoot" Name="Finalize" />
</Type>
-
<!-- SMOSIER ADDED API ROOTS FOR C# -->
<Type Name="System.Runtime.CompilerServices.RuntimeCompatibilityAttribute">
<Member MemberType="Property" Name="WrapNonExceptionThrows" />
@@ -7835,7 +8080,6 @@
<Type Name="System.Runtime.CompilerServices.CompilerGeneratedAttribute">
<Member Name="#ctor" />
</Type>
-
<!-- SMOSIER ADDED API ROOTS FOR our build process -->
<Type Name="System.Runtime.InteropServices.ComVisibleAttribute">
<Member Name="#ctor(System.Boolean)" />
@@ -7847,7 +8091,6 @@
<Member Name="get_Version" />
<Member MemberType="Property" Name="Version" />
</Type>
-
<Type Status="ImplRoot" Name="System.Security.Permissions.HostProtectionAttribute">
<Member Name="#ctor" />
<Member Name="#ctor(System.Security.Permissions.SecurityAction)" />
@@ -7883,7 +8126,6 @@
<Member MemberType="Property" Name="UI" />
</Type>
<Type Status="ImplRoot" Name="System.Security.Permissions.HostProtectionResource" />
-
<Type Name="System.IO.BinaryReader">
<Member Name="#ctor(System.IO.Stream)" />
<Member Name="#ctor(System.IO.Stream,System.Text.Encoding)" />
@@ -8335,10 +8577,10 @@
<Member Name="get_CanRead" />
<Member Name="get_CanSeek" />
<Member Name="get_CanWrite" />
- <Member Name="get_Capacity" />
+ <Member Name="get_Capacity" />
<Member Name="get_Length" />
- <Member Name="get_Position" />
- <Member Name="get_PositionPointer" />
+ <Member Name="get_Position" />
+ <Member Name="get_PositionPointer" />
<Member Name="Initialize(System.Byte*,System.Int64,System.Int64,System.IO.FileAccess)" />
<Member Name="Initialize(System.Runtime.InteropServices.SafeBuffer,System.Int64,System.Int64,System.IO.FileAccess)" />
<Member Name="Read(System.Byte[],System.Int32,System.Int32)" />
@@ -8353,9 +8595,9 @@
<Member MemberType="Property" Name="CanWrite" />
<Member MemberType="Property" Name="Capacity" />
<Member MemberType="Property" Name="Length" />
- <Member MemberType="Property" Name="Position" />
- <Member MemberType="Property" Name="PositionPointer" />
- </Type>
+ <Member MemberType="Property" Name="Position" />
+ <Member MemberType="Property" Name="PositionPointer" />
+ </Type>
<Type Name="System.Security.Permissions.SecurityAttribute">
<Member Name="#ctor(System.Security.Permissions.SecurityAction)" />
<Member Name="get_Action" />
@@ -8366,7 +8608,6 @@
<Member MemberType="Property" Name="Action" />
<Member MemberType="Property" Name="Unrestricted" />
</Type>
-
<Type Status="ApiRoot" Name="System.Diagnostics.Contracts.Contract" >
<Member MemberType="Event" Name="ContractFailed" />
<Member Name="Assert(System.Boolean)" />
@@ -8482,34 +8723,30 @@
</Type>
<Type Status="ImplRoot" Name="System.Currency">
<Member Status="ImplRoot" Name="#ctor(System.Decimal)" /> <!-- EE - il stubs -->
- </Type>
+ </Type>
<Type Status="ImplRoot" Name="System.Diagnostics.EditAndContinueHelper">
<Member MemberType="Field" Name="_objectReference" />
</Type>
<Type Status="ImplRoot" Name="System.Diagnostics.StackFrameHelper" />
-
<Type Name="System.Diagnostics.Tracing.EventAttribute">
<Member Name="#ctor(System.Int32)" />
<Member Name="get_EventId" />
<Member MemberType="Property" Name="ActivityOptions" />
<Member MemberType="Property" Name="Channel" />
- <Member MemberType="Property" Name="Keywords" />
- <Member MemberType="Property" Name="Level" />
- <Member MemberType="Property" Name="Message" />
- <Member MemberType="Property" Name="Opcode" />
- <Member MemberType="Property" Name="Task" />
+ <Member MemberType="Property" Name="Keywords" />
+ <Member MemberType="Property" Name="Level" />
+ <Member MemberType="Property" Name="Message" />
+ <Member MemberType="Property" Name="Opcode" />
+ <Member MemberType="Property" Name="Task" />
<Member MemberType="Property" Name="Version" />
<Member MemberType="Property" Name="Tags" />
</Type>
-
<Type Name="System.Diagnostics.Tracing.EventActivityOptions">
<Member MemberType="Field" Name="None" />
<Member MemberType="Field" Name="Detachable" />
<Member MemberType="Field" Name="Disable" />
<Member MemberType="Field" Name="Recursive" />
</Type>
-
-
<Type Name="System.Diagnostics.Tracing.EventFieldFormat">
<Member MemberType="Field" Name="Boolean" />
<Member MemberType="Field" Name="Default" />
@@ -8519,20 +8756,19 @@
<Member MemberType="Field" Name="String" />
<Member MemberType="Field" Name="Xml" />
</Type>
-
<Type Name="System.Diagnostics.Tracing.EventDescriptor">
<Member Name="#ctor(System.Int32,System.Byte,System.Byte,System.Int64)" />
<Member Name="#ctor(System.Int32,System.Byte,System.Byte,System.Byte,System.Byte,System.Int32,System.Int64)" />
<Member Name="get_EventId" />
- <Member Name="get_Channel" />
- <Member Name="get_Level" />
+ <Member Name="get_Channel" />
+ <Member Name="get_Level" />
<Member Name="get_Opcode" />
<Member Name="get_Task" />
<Member Name="get_Version" />
<Member Name="Equals(System.Object)" />
<Member Name="Equals(System.Diagnostics.Tracing.EventDescriptor)" />
- </Type>
-
+ </Type>
+
<Type Name="System.Diagnostics.Tracing.EventChannel">
<Member MemberType="Field" Name="Admin" />
<Member MemberType="Field" Name="Analytic" />
@@ -8540,30 +8776,26 @@
<Member MemberType="Field" Name="None" />
<Member MemberType="Field" Name="Operational" />
</Type>
-
<Type Name="System.Diagnostics.Tracing.EventCommand">
<Member MemberType="Field" Name="Disable" />
<Member MemberType="Field" Name="Enable" />
<Member MemberType="Field" Name="SendManifest" />
<Member MemberType="Field" Name="Update" />
</Type>
-
<Type Name="System.Diagnostics.Tracing.EventCommandEventArgs">
<Member Name="get_Arguments" />
<Member Name="get_Command" />
<Member Name="DisableEvent(System.Int32)" />
<Member Name="EnableEvent(System.Int32)" />
</Type>
-
<Type Name="System.Diagnostics.Tracing.EventDataAttribute">
<Member Name="#ctor" />
- <Member MemberType="Property" Name="Name" />
- <Member MemberType="Property" Name="Level" />
- <Member MemberType="Property" Name="Opcode" />
- <Member MemberType="Property" Name="Keywords" />
- <Member MemberType="Property" Name="Tags" />
+ <Member MemberType="Property" Name="Name" />
+ <Member MemberType="Property" Name="Level" />
+ <Member MemberType="Property" Name="Opcode" />
+ <Member MemberType="Property" Name="Keywords" />
+ <Member MemberType="Property" Name="Tags" />
</Type>
-
<Type Name="System.Diagnostics.Tracing.EventKeywords">
<Member MemberType="Field" Name="AuditFailure" />
<Member MemberType="Field" Name="AuditSuccess" />
@@ -8575,51 +8807,49 @@
<Member MemberType="Field" Name="WdiContext" />
<Member MemberType="Field" Name="WdiDiagnostic" />
</Type>
-
<Type Name="System.Diagnostics.Tracing.EventLevel">
<Member MemberType="Field" Name="Critical" />
<Member MemberType="Field" Name="Error" />
<Member MemberType="Field" Name="Informational" />
<Member MemberType="Field" Name="LogAlways" />
<Member MemberType="Field" Name="Verbose" />
- <Member MemberType="Field" Name="Warning" />
+ <Member MemberType="Field" Name="Warning" />
</Type>
-
<Type Name="System.Diagnostics.Tracing.EventListener">
<Member Name="#ctor" />
<Member Name="DisableEvents(System.Diagnostics.Tracing.EventSource)" />
<Member Name="Dispose" />
<Member Name="EnableEvents(System.Diagnostics.Tracing.EventSource,System.Diagnostics.Tracing.EventLevel)" />
- <Member Name="EnableEvents(System.Diagnostics.Tracing.EventSource,System.Diagnostics.Tracing.EventLevel,System.Diagnostics.Tracing.EventKeywords)" />
- <Member Name="EnableEvents(System.Diagnostics.Tracing.EventSource,System.Diagnostics.Tracing.EventLevel,System.Diagnostics.Tracing.EventKeywords,System.Collections.Generic.IDictionary&lt;System.String,System.String&gt;)" />
+ <Member Name="EnableEvents(System.Diagnostics.Tracing.EventSource,System.Diagnostics.Tracing.EventLevel,System.Diagnostics.Tracing.EventKeywords)" />
+ <Member Name="EnableEvents(System.Diagnostics.Tracing.EventSource,System.Diagnostics.Tracing.EventLevel,System.Diagnostics.Tracing.EventKeywords,System.Collections.Generic.IDictionary&lt;System.String,System.String&gt;)" />
<Member Name="EventSourceIndex(System.Diagnostics.Tracing.EventSource)" />
<Member Name="OnEventSourceCreated(System.Diagnostics.Tracing.EventSource)" />
<Member Name="OnEventWritten(System.Diagnostics.Tracing.EventWrittenEventArgs)" />
- </Type>
-
+ </Type>
+
<Type Name="System.Diagnostics.Tracing.EventManifestOptions">
<Member MemberType="Field" Name="AllCultures" />
<Member MemberType="Field" Name="AllowEventSourceOverride" />
<Member MemberType="Field" Name="None" />
<Member MemberType="Field" Name="OnlyIfNeededForRegistration" />
<Member MemberType="Field" Name="Strict" />
- </Type>
-
+ </Type>
+
<Type Name="System.Diagnostics.Tracing.EventOpcode">
<Member MemberType="Field" Name="DataCollectionStart" />
<Member MemberType="Field" Name="DataCollectionStop" />
<Member MemberType="Field" Name="Extension" />
<Member MemberType="Field" Name="Info" />
<Member MemberType="Field" Name="Receive" />
- <Member MemberType="Field" Name="Reply" />
- <Member MemberType="Field" Name="Resume" />
- <Member MemberType="Field" Name="Send" />
- <Member MemberType="Field" Name="Start" />
- <Member MemberType="Field" Name="Stop" />
- <Member MemberType="Field" Name="Suspend" />
+ <Member MemberType="Field" Name="Reply" />
+ <Member MemberType="Field" Name="Resume" />
+ <Member MemberType="Field" Name="Send" />
+ <Member MemberType="Field" Name="Start" />
+ <Member MemberType="Field" Name="Stop" />
+ <Member MemberType="Field" Name="Suspend" />
</Type>
-
- <Type Name="System.Diagnostics.Tracing.EventSource">
+
+ <Type Name="System.Diagnostics.Tracing.EventSource">
<Member Name="#ctor" />
<Member Name="#ctor(System.Boolean)" />
<Member Name="#ctor(System.Diagnostics.Tracing.EventSourceSettings)" />
@@ -8676,31 +8906,27 @@
<Member Name="WriteEventCore(System.Int32,System.Int32,System.Diagnostics.Tracing.EventSource+EventData*)" />
<Member Name="WriteEventWithRelatedActivityId(System.Int32,System.Guid,System.Object[])" />
<Member Name="WriteEventWithRelatedActivityIdCore(System.Int32,System.Guid*,System.Int32,System.Diagnostics.Tracing.EventSource+EventData*)" />
- <Member Name="get_Settings" />
+ <Member Name="get_Settings" />
</Type>
-
<Type Name="System.Diagnostics.Tracing.EventSource+EventData">
- <Member MemberType="Property" Name="DataPointer" />
- <Member MemberType="Property" Name="Size" />
+ <Member MemberType="Property" Name="DataPointer" />
+ <Member MemberType="Property" Name="Size" />
</Type>
-
+
<Type Name="System.Diagnostics.Tracing.EventSourceAttribute">
<Member Name="#ctor" />
- <Member MemberType="Property" Name="Guid" />
- <Member MemberType="Property" Name="LocalizationResources" />
- <Member MemberType="Property" Name="Name" />
+ <Member MemberType="Property" Name="Guid" />
+ <Member MemberType="Property" Name="LocalizationResources" />
+ <Member MemberType="Property" Name="Name" />
</Type>
-
<Type Name="System.Diagnostics.Tracing.EventIgnoreAttribute">
<Member Name="#ctor" />
</Type>
-
<Type Name="System.Diagnostics.Tracing.EventSourceException">
<Member Name="#ctor" />
<Member Name="#ctor(System.String)" />
<Member Name="#ctor(System.String,System.Exception)" />
</Type>
-
<Type Name="System.Diagnostics.Tracing.EventSourceOptions">
<Member MemberType="Property" Name="Keywords" />
<Member MemberType="Property" Name="Level" />
@@ -8708,33 +8934,27 @@
<Member MemberType="Property" Name="Tags" />
<Member MemberType="Property" Name="ActivityOptions" />
</Type>
-
<Type Name="System.Diagnostics.Tracing.EventSourceSettings">
<Member MemberType="Field" Name="Default" />
<Member MemberType="Field" Name="EtwManifestEventFormat" />
<Member MemberType="Field" Name="EtwSelfDescribingEventFormat" />
<Member MemberType="Field" Name="ThrowOnEventWriteErrors" />
</Type>
-
<Type Name="System.Diagnostics.Tracing.EventTask">
- <Member MemberType="Field" Name="None" />
- </Type>
-
+ <Member MemberType="Field" Name="None" />
+ </Type>
<Type Name="System.Diagnostics.Tracing.EventTags">
- <Member MemberType="Field" Name="None" />
- </Type>
-
+ <Member MemberType="Field" Name="None" />
+ </Type>
<Type Name="System.Diagnostics.Tracing.EventFieldTags">
- <Member MemberType="Field" Name="None" />
- </Type>
-
+ <Member MemberType="Field" Name="None" />
+ </Type>
<Type Name="System.Diagnostics.Tracing.EventFieldAttribute">
<Member Name="#ctor" />
<Member MemberType="Property" Name="Tags" />
<Member MemberType="Property" Name="Name" />
<Member MemberType="Property" Name="Format" />
</Type>
-
<Type Name="System.Diagnostics.Tracing.EventWrittenEventArgs">
<Member Name="get_Channel" />
<Member Name="get_EventId" />
@@ -8752,17 +8972,15 @@
<Member MemberType="Property" Name="EventName" />
<Member MemberType="Property" Name="RelatedActivityId" />
</Type>
-
<Type Name="System.Diagnostics.Tracing.NonEventAttribute">
<Member Name="#ctor" />
</Type>
-
+
<Type Name="System.Diagnostics.Tracing.FrameworkEventSource+Tasks">
<Member MemberType="Field" Name="GetResponse" />
<Member MemberType="Field" Name="GetRequestStream" />
<Member MemberType="Field" Name="ThreadTransfer" />
</Type>
-
<Type Name="System.Diagnostics.Tracing.FrameworkEventSource+Keywords">
<Member MemberType="Field" Name="Loader" />
<Member MemberType="Field" Name="ThreadPool" />
@@ -8770,15 +8988,10 @@
<Member MemberType="Field" Name="DynamicTypeUsage" />
<Member MemberType="Field" Name="ThreadTransfer" />
</Type>
-
<Type Name="System.Diagnostics.Tracing.FrameworkEventSource+Opcodes">
<Member MemberType="Field" Name="ReceiveHandled" />
</Type>
-
-
- <Type Status="ImplRoot" Name="System.DuplicateWaitObjectException" />
-
- <Type Status="ImplRoot" Name="System.IO.Stream+SynchronousAsyncResult">
+ <Type Status="ImplRoot" Name="System.IO.Stream+SynchronousAsyncResult">
<Member Name="get_AsyncState" />
<Member Name="get_AsyncWaitHandle" />
<Member Name="get_CompletedSynchronously" />
@@ -8807,7 +9020,6 @@
<Type Status="ImplRoot" Name="System.Reflection.Emit.DynamicScope" />
<Type Status="ImplRoot" Name="System.Reflection.ExceptionHandlingClause" />
-
<Type Status="ApiRoot" Name="System.Reflection.LocalVariableInfo">
<Member Name="#ctor" />
<Member Name="get_IsPinned" />
@@ -8834,7 +9046,7 @@
</Type>
<Type Name="System.Reflection.ReflectionTypeLoadException">
<Member Name="#ctor(System.Type[],System.Exception[])" />
- <Member Name="#ctor(System.Type[],System.Exception[],System.String)" />
+ <Member Name="#ctor(System.Type[],System.Exception[],System.String)" />
<Member MemberType="Property" Name="LoaderExceptions" />
<Member MemberType="Property" Name="Types" />
<Member Name="get_LoaderExceptions" />
@@ -8916,7 +9128,7 @@
<Member Name="get_HasCurrent" />
<Member Name="MoveNext"/>
<Member Name="GetMany(T[])"/>
- </Type>
+ </Type>
<Type Status="ImplRoot" Name="System.Runtime.InteropServices.WindowsRuntime.BindableIterableToEnumerableAdapter" Condition="FEATURE_COMINTEROP">
<Member Name="GetEnumerator_Stub" />
</Type>
@@ -9320,10 +9532,97 @@
<Type Name="System.Runtime.Serialization.FormatterServices">
<Member Name="GetUninitializedObject(System.Type)" />
</Type>
+ <Type Name="System.Runtime.Serialization.OptionalFieldAttribute">
+ <Member Name="#ctor" />
+ <Member MemberType="Property" Name="VersionAdded" />
+ </Type>
+ <Type Name="System.Runtime.Serialization.SerializationEntry">
+ <Member MemberType="Property" Name="Value" />
+ <Member MemberType="Property" Name="Name" />
+ <Member MemberType="Property" Name="ObjectType" />
+ </Type>
<Type Name="System.Runtime.Serialization.SerializationException">
<Member Name="#ctor" />
<Member Name="#ctor(System.String)" />
- <Member Name="#ctor(System.String,System.Exception)" />
+ <Member Name="#ctor(System.String,System.Exception)" />
+ </Type>
+ <Type Name="System.Runtime.Serialization.SerializationInfo">
+ <Member Name="#ctor(System.Type,System.Runtime.Serialization.IFormatterConverter)" />
+ <Member Name="#ctor(System.Type,System.Runtime.Serialization.IFormatterConverter,System.Boolean)" />
+ <Member Name="SetType(System.Type)" />
+ <Member Name="GetEnumerator" />
+ <Member Name="AddValue(System.String,System.Object,System.Type)" />
+ <Member Name="AddValue(System.String,System.Object)" />
+ <Member Name="AddValue(System.String,System.Boolean)" />
+ <Member Name="AddValue(System.String,System.Char)" />
+ <Member Name="AddValue(System.String,System.SByte)" />
+ <Member Name="AddValue(System.String,System.Byte)" />
+ <Member Name="AddValue(System.String,System.Int16)" />
+ <Member Name="AddValue(System.String,System.UInt16)" />
+ <Member Name="AddValue(System.String,System.Int32)" />
+ <Member Name="AddValue(System.String,System.UInt32)" />
+ <Member Name="AddValue(System.String,System.Int64)" />
+ <Member Name="AddValue(System.String,System.UInt64)" />
+ <Member Name="AddValue(System.String,System.Single)" />
+ <Member Name="AddValue(System.String,System.Double)" />
+ <Member Name="AddValue(System.String,System.Decimal)" />
+ <Member Name="AddValue(System.String,System.DateTime)" />
+ <Member Name="GetValue(System.String,System.Type)" />
+ <Member Name="GetBoolean(System.String)" />
+ <Member Name="GetChar(System.String)" />
+ <Member Name="GetSByte(System.String)" />
+ <Member Name="GetByte(System.String)" />
+ <Member Name="GetInt16(System.String)" />
+ <Member Name="GetUInt16(System.String)" />
+ <Member Name="GetInt32(System.String)" />
+ <Member Name="GetUInt32(System.String)" />
+ <Member Name="GetInt64(System.String)" />
+ <Member Name="GetUInt64(System.String)" />
+ <Member Name="GetSingle(System.String)" />
+ <Member Name="GetDouble(System.String)" />
+ <Member Name="GetDecimal(System.String)" />
+ <Member Name="GetDateTime(System.String)" />
+ <Member Name="GetString(System.String)" />
+ <Member MemberType="Property" Name="FullTypeName" />
+ <Member MemberType="Property" Name="AssemblyName" />
+ <Member MemberType="Property" Name="MemberCount" />
+ <Member MemberType="Property" Name="ObjectType" />
+ <Member MemberType="Property" Name="IsFullTypeNameSetExplicit" />
+ <Member MemberType="Property" Name="IsAssemblyNameSetExplicit" />
+ </Type>
+ <Type Name="System.Runtime.Serialization.SerializationInfoEnumerator">
+ <Member Name="MoveNext" />
+ <Member Name="Reset" />
+ <Member Name="System.Collections.IEnumerator.get_Current" />
+ <Member MemberType="Property" Name="Current" />
+ <Member MemberType="Property" Name="Name" />
+ <Member MemberType="Property" Name="Value" />
+ <Member MemberType="Property" Name="ObjectType" />
+ </Type>
+ <Type Name="System.Runtime.Serialization.ISerializable">
+ <Member Name="GetObjectData(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext)" />
+ </Type>
+ <Type Name="System.Runtime.Serialization.IFormatterConverter">
+ <Member Name="Convert(System.Object,System.Type)" />
+ <Member Name="Convert(System.Object,System.TypeCode)" />
+ <Member Name="ToBoolean(System.Object)" />
+ <Member Name="ToChar(System.Object)" />
+ <Member Name="ToSByte(System.Object)" />
+ <Member Name="ToByte(System.Object)" />
+ <Member Name="ToInt16(System.Object)" />
+ <Member Name="ToUInt16(System.Object)" />
+ <Member Name="ToInt32(System.Object)" />
+ <Member Name="ToUInt32(System.Object)" />
+ <Member Name="ToInt64(System.Object)" />
+ <Member Name="ToUInt64(System.Object)" />
+ <Member Name="ToSingle(System.Object)" />
+ <Member Name="ToDouble(System.Object)" />
+ <Member Name="ToDecimal(System.Object)" />
+ <Member Name="ToDateTime(System.Object)" />
+ <Member Name="ToString(System.Object)" />
+ </Type>
+ <Type Name="System.Runtime.Serialization.IDeserializationCallback">
+ <Member Name="OnDeserialization(System.Object)" />
</Type>
<Type Status="ApiRoot" Name="System.Runtime.Serialization.OnSerializingAttribute">
<Member Name="#ctor" />
@@ -9482,7 +9781,6 @@
</Type>
<Type Status="ImplRoot" Name="System.Threading.InternalCrossContextDelegate" />
<Type Status="ImplRoot" Name="System.Threading.OverlappedData" />
-
<Type Status="ImplRoot" Name="System.Threading.ThreadInterruptedException" />
<Type Name="System.ThreadStaticAttribute">
<Member Name="#ctor" />
@@ -10056,7 +10354,6 @@
<Member MemberType="Field" Name="VAR_PERINSTANCE" />
<Member MemberType="Field" Name="VAR_STATIC" />
</Type>
-
<Type Status="ImplRoot" Name="System.StubHelpers.StubHelpers">
<Member Name="ClearLastError" />
<Member Name="SetLastError" />
@@ -10128,11 +10425,11 @@
<Member Name="ConvertToNative(System.Int32,System.String,System.IntPtr)" />
<Member Name="ConvertToManaged(System.IntPtr)" />
<Member Name="ClearNative(System.IntPtr)" />
- </Type>
+ </Type>
<Type Status="ImplRoot" Name="System.StubHelpers.UTF8BufferMarshaler">
<Member Name="ConvertToNative(System.Text.StringBuilder,System.IntPtr,System.Int32)" />
- <Member Name="ConvertToManaged(System.Text.StringBuilder,System.IntPtr)" />
- </Type>
+ <Member Name="ConvertToManaged(System.Text.StringBuilder,System.IntPtr)" />
+ </Type>
<Type Status="ApiFxInternal" Name="System.StubHelpers.EventArgsMarshaler" Condition="FEATURE_COMINTEROP">
<Member Name="CreateNativeNCCEventArgsInstance(System.Int32,System.Object,System.Object,System.Int32,System.Int32)"/>
<Member Name="CreateNativePCEventArgsInstance(System.String)" />
@@ -10700,7 +10997,7 @@
<Member MemberType="Field" Name="Tasks" />
<Member MemberType="Field" Name="Parallel" />
</Type>
-
+
<!-- System.Runtime.CompilerServices namespace -->
<Type Name="System.Runtime.CompilerServices.TaskAwaiter">
<Member Name="get_IsCompleted" />
@@ -10791,7 +11088,7 @@
<Member Status="ImplRoot" Name="get_ObjectIdForDebugger" />
<Member Status="ImplRoot" MemberType="Field" Name="m_task" />
</Type>
-
+
<!-- System namespace -->
<Type Name="System.AggregateException">
<Member Name="#ctor"/>
@@ -10813,7 +11110,7 @@
<Member Name="#ctor"/>
<Member Name="#ctor(System.Action&lt;System.Threading.AsyncLocalValueChangedArgs&lt;T&gt;&gt;)"/>
<Member Name="get_Value"/>
- <Member Name="set_Value(T)"/>
+ <Member Name="set_Value(T)"/>
</Type>
<Type Name="System.Threading.AsyncLocalValueChangedArgs&lt;T&gt;">
<Member Name="get_PreviousValue"/>
diff --git a/src/mscorlib/mscorlib.shared.sources.props b/src/mscorlib/mscorlib.shared.sources.props
index f530a31358..eed8917cd1 100644
--- a/src/mscorlib/mscorlib.shared.sources.props
+++ b/src/mscorlib/mscorlib.shared.sources.props
@@ -451,6 +451,9 @@
<SystemSources Condition="'$(FeatureClassicCominterop)' == 'true'" Include="$(BclSourcesRoot)\System\OleAutBinder.cs" />
</ItemGroup>
<ItemGroup>
+ <SystemSources Condition="'$(FeatureCoreclr)' == 'true'" Include="$(BclSourcesRoot)\Internal\Runtime\Augments\EnvironmentAugments.cs" />
+ </ItemGroup>
+ <ItemGroup>
<ReflectionSources Include="$(BclSourcesRoot)\System\Reflection\__Filters.cs" />
<ReflectionSources Include="$(BclSourcesRoot)\System\Reflection\AmbiguousMatchException.cs" />
<ReflectionSources Include="$(BclSourcesRoot)\System\Reflection\Assembly.cs" />
@@ -982,6 +985,7 @@
<TextSources Include="$(BclSourcesRoot)\System\Text\EncoderFallback.cs" />
<TextSources Include="$(BclSourcesRoot)\System\Text\EncoderReplacementFallback.cs" />
<TextSources Include="$(BclSourcesRoot)\System\Text\Encoding.cs" />
+ <TextSources Include="$(BclSourcesRoot)\System\Text\EncodingForwarder.cs" />
<TextSources Include="$(BclSourcesRoot)\System\Text\EncodingInfo.cs" />
<TextSources Include="$(BclSourcesRoot)\System\Text\EncodingNLS.cs" />
<TextSources Include="$(BclSourcesRoot)\System\Text\EncodingProvider.cs" />
diff --git a/src/mscorlib/ref/mscorlib.cs b/src/mscorlib/ref/mscorlib.cs
index d552d48f8b..769c497373 100644
--- a/src/mscorlib/ref/mscorlib.cs
+++ b/src/mscorlib/ref/mscorlib.cs
@@ -4476,6 +4476,9 @@ namespace System.Diagnostics
IgnoreSymbolStoreSequencePoints = 2,
None = 0,
}
+ public bool IsJITTrackingEnabled { get { return default(bool); } }
+ public bool IsJITOptimizerDisabled { get { return default(bool); } }
+ public DebuggingModes DebuggingFlags { get { return default(DebuggingModes); } }
}
[System.Runtime.InteropServices.ComVisibleAttribute(true)]
public sealed partial class Debugger
diff --git a/src/mscorlib/src/Internal/Runtime/Augments/EnvironmentAugments.cs b/src/mscorlib/src/Internal/Runtime/Augments/EnvironmentAugments.cs
new file mode 100644
index 0000000000..28104683c7
--- /dev/null
+++ b/src/mscorlib/src/Internal/Runtime/Augments/EnvironmentAugments.cs
@@ -0,0 +1,21 @@
+// 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;
+
+namespace Internal.Runtime.Augments
+{
+ /// <summary>For internal use only. Exposes runtime functionality to the Environments implementation in corefx.</summary>
+ public static class EnvironmentAugments
+ {
+ public static int CurrentManagedThreadId => Environment.CurrentManagedThreadId;
+ public static void Exit(int exitCode) => Environment.Exit(exitCode);
+ public static int ExitCode { get { return Environment.ExitCode; } set { Environment.ExitCode = value; } }
+ public static void FailFast(string message, Exception error) => Environment.FailFast(message, error);
+ public static string[] GetCommandLineArgs() => Environment.GetCommandLineArgs();
+ public static bool HasShutdownStarted => Environment.HasShutdownStarted;
+ public static string StackTrace => Environment.StackTrace;
+ public static int TickCount => Environment.TickCount;
+ }
+}
diff --git a/src/mscorlib/src/System/AccessViolationException.cs b/src/mscorlib/src/System/AccessViolationException.cs
index 308d52e9ed..789e1d4f83 100644
--- a/src/mscorlib/src/System/AccessViolationException.cs
+++ b/src/mscorlib/src/System/AccessViolationException.cs
@@ -17,7 +17,9 @@ namespace System
using System;
using System.Runtime.Serialization;
[System.Runtime.InteropServices.ComVisible(true)]
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
public class AccessViolationException : SystemException
{
public AccessViolationException()
diff --git a/src/mscorlib/src/System/AggregateException.cs b/src/mscorlib/src/System/AggregateException.cs
index 064432aaaa..e852da9708 100644
--- a/src/mscorlib/src/System/AggregateException.cs
+++ b/src/mscorlib/src/System/AggregateException.cs
@@ -29,7 +29,9 @@ namespace System
/// <see cref="AggregateException"/> is used to consolidate multiple failures into a single, throwable
/// exception object.
/// </remarks>
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
[DebuggerDisplay("Count = {InnerExceptionCount}")]
public class AggregateException : Exception
{
diff --git a/src/mscorlib/src/System/AppDomain.cs b/src/mscorlib/src/System/AppDomain.cs
index abaaf48770..9c3b0f38e7 100644
--- a/src/mscorlib/src/System/AppDomain.cs
+++ b/src/mscorlib/src/System/AppDomain.cs
@@ -111,15 +111,21 @@ namespace System {
#if FEATURE_CORECLR
[System.Security.SecurityCritical] // auto-generated
#endif
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
[ComVisible(true)]
public delegate Assembly ResolveEventHandler(Object sender, ResolveEventArgs args);
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
[ComVisible(true)]
public delegate void AssemblyLoadEventHandler(Object sender, AssemblyLoadEventArgs args);
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
[ComVisible(true)]
public delegate void AppDomainInitializer(string[] args);
diff --git a/src/mscorlib/src/System/AppDomainUnloadedException.cs b/src/mscorlib/src/System/AppDomainUnloadedException.cs
index ef947662e7..37ed5b406e 100644
--- a/src/mscorlib/src/System/AppDomainUnloadedException.cs
+++ b/src/mscorlib/src/System/AppDomainUnloadedException.cs
@@ -15,8 +15,10 @@ namespace System {
using System.Runtime.Serialization;
-[System.Runtime.InteropServices.ComVisible(true)]
+ [System.Runtime.InteropServices.ComVisible(true)]
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
public class AppDomainUnloadedException : SystemException {
public AppDomainUnloadedException()
: base(Environment.GetResourceString("Arg_AppDomainUnloadedException")) {
diff --git a/src/mscorlib/src/System/ApplicationException.cs b/src/mscorlib/src/System/ApplicationException.cs
index c70440493b..a173cf6a87 100644
--- a/src/mscorlib/src/System/ApplicationException.cs
+++ b/src/mscorlib/src/System/ApplicationException.cs
@@ -22,8 +22,10 @@ namespace System {
// ApplicationException extends but adds no new functionality to
// RecoverableException.
//
-[System.Runtime.InteropServices.ComVisible(true)]
+ [System.Runtime.InteropServices.ComVisible(true)]
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
public class ApplicationException : Exception {
// Creates a new ApplicationException with its message string set to
diff --git a/src/mscorlib/src/System/ArgumentException.cs b/src/mscorlib/src/System/ArgumentException.cs
index 332758671a..79a0a51a76 100644
--- a/src/mscorlib/src/System/ArgumentException.cs
+++ b/src/mscorlib/src/System/ArgumentException.cs
@@ -23,8 +23,10 @@ namespace System {
// the contract of the method. Ideally it should give a meaningful error
// message describing what was wrong and which parameter is incorrect.
//
-[System.Runtime.InteropServices.ComVisible(true)]
+ [System.Runtime.InteropServices.ComVisible(true)]
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
public class ArgumentException : SystemException, ISerializable {
private String m_paramName;
diff --git a/src/mscorlib/src/System/ArgumentNullException.cs b/src/mscorlib/src/System/ArgumentNullException.cs
index 7b8d3b5c91..7296065736 100644
--- a/src/mscorlib/src/System/ArgumentNullException.cs
+++ b/src/mscorlib/src/System/ArgumentNullException.cs
@@ -21,8 +21,11 @@ namespace System {
// The ArgumentException is thrown when an argument
// is null when it shouldn't be.
//
-[System.Runtime.InteropServices.ComVisible(true)]
- [Serializable] public class ArgumentNullException : ArgumentException
+ [System.Runtime.InteropServices.ComVisible(true)]
+#if FEATURE_SERIALIZATION
+ [Serializable]
+#endif
+ public class ArgumentNullException : ArgumentException
{
// Creates a new ArgumentNullException with its message
// string set to a default message explaining an argument was null.
diff --git a/src/mscorlib/src/System/ArgumentOutOfRangeException.cs b/src/mscorlib/src/System/ArgumentOutOfRangeException.cs
index f7730922cc..29151a2452 100644
--- a/src/mscorlib/src/System/ArgumentOutOfRangeException.cs
+++ b/src/mscorlib/src/System/ArgumentOutOfRangeException.cs
@@ -22,8 +22,10 @@ namespace System {
// The ArgumentOutOfRangeException is thrown when an argument
// is outside the legal range for that argument.
-[System.Runtime.InteropServices.ComVisible(true)]
+ [System.Runtime.InteropServices.ComVisible(true)]
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
public class ArgumentOutOfRangeException : ArgumentException, ISerializable {
private static volatile String _rangeMessage;
diff --git a/src/mscorlib/src/System/ArithmeticException.cs b/src/mscorlib/src/System/ArithmeticException.cs
index c35a597a2a..5305616812 100644
--- a/src/mscorlib/src/System/ArithmeticException.cs
+++ b/src/mscorlib/src/System/ArithmeticException.cs
@@ -18,8 +18,11 @@ namespace System {
// The ArithmeticException is thrown when overflow or underflow
// occurs.
//
-[System.Runtime.InteropServices.ComVisible(true)]
- [Serializable] public class ArithmeticException : SystemException
+ [System.Runtime.InteropServices.ComVisible(true)]
+#if FEATURE_SERIALIZATION
+ [Serializable]
+#endif
+ public class ArithmeticException : SystemException
{
// Creates a new ArithmeticException with its message string set to
// the empty string, its HRESULT set to COR_E_ARITHMETIC,
diff --git a/src/mscorlib/src/System/ArrayTypeMismatchException.cs b/src/mscorlib/src/System/ArrayTypeMismatchException.cs
index 6568ae3129..3baa3f0f7c 100644
--- a/src/mscorlib/src/System/ArrayTypeMismatchException.cs
+++ b/src/mscorlib/src/System/ArrayTypeMismatchException.cs
@@ -18,8 +18,10 @@ namespace System {
// The ArrayMismatchException is thrown when an attempt to store
// an object of the wrong type within an array occurs.
//
-[System.Runtime.InteropServices.ComVisible(true)]
+ [System.Runtime.InteropServices.ComVisible(true)]
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
public class ArrayTypeMismatchException : SystemException {
// Creates a new ArrayMismatchException with its message string set to
diff --git a/src/mscorlib/src/System/AsyncCallback.cs b/src/mscorlib/src/System/AsyncCallback.cs
index 69a03812e1..9bf4931e1f 100644
--- a/src/mscorlib/src/System/AsyncCallback.cs
+++ b/src/mscorlib/src/System/AsyncCallback.cs
@@ -10,7 +10,9 @@
**
===========================================================*/
namespace System {
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
[System.Runtime.InteropServices.ComVisible(true)]
public delegate void AsyncCallback(IAsyncResult ar);
diff --git a/src/mscorlib/src/System/BadImageFormatException.cs b/src/mscorlib/src/System/BadImageFormatException.cs
index f6ad89fc34..b56fd17737 100644
--- a/src/mscorlib/src/System/BadImageFormatException.cs
+++ b/src/mscorlib/src/System/BadImageFormatException.cs
@@ -21,7 +21,9 @@ namespace System {
using System.Globalization;
[System.Runtime.InteropServices.ComVisible(true)]
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
public class BadImageFormatException : SystemException {
private String _fileName; // The name of the corrupt PE file.
diff --git a/src/mscorlib/src/System/CannotUnloadAppDomainException.cs b/src/mscorlib/src/System/CannotUnloadAppDomainException.cs
index 9fece37de4..638311cb08 100644
--- a/src/mscorlib/src/System/CannotUnloadAppDomainException.cs
+++ b/src/mscorlib/src/System/CannotUnloadAppDomainException.cs
@@ -16,7 +16,9 @@ namespace System {
using System.Runtime.Serialization;
[System.Runtime.InteropServices.ComVisible(true)]
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
public class CannotUnloadAppDomainException : SystemException {
public CannotUnloadAppDomainException()
: base(Environment.GetResourceString("Arg_CannotUnloadAppDomainException")) {
diff --git a/src/mscorlib/src/System/Char.cs b/src/mscorlib/src/System/Char.cs
index 9904f8443d..c7fd4b36e0 100644
--- a/src/mscorlib/src/System/Char.cs
+++ b/src/mscorlib/src/System/Char.cs
@@ -914,6 +914,7 @@ namespace System {
** Convert an UTF32 value into a surrogate pair.
==============================================================================*/
+ [System.Security.SecuritySafeCritical]
public static String ConvertFromUtf32(int utf32)
{
// For UTF32 values from U+00D800 ~ U+00DFFF, we should throw. They
@@ -927,12 +928,17 @@ namespace System {
// This is a BMP character.
return (Char.ToString((char)utf32));
}
- // This is a sumplementary character. Convert it to a surrogate pair in UTF-16.
- utf32 -= UNICODE_PLANE01_START;
- char[] surrogate = new char[2];
- surrogate[0] = (char)((utf32 / 0x400) + (int)CharUnicodeInfo.HIGH_SURROGATE_START);
- surrogate[1] = (char)((utf32 % 0x400) + (int)CharUnicodeInfo.LOW_SURROGATE_START);
- return (new String(surrogate));
+
+ unsafe
+ {
+ // This is a supplementary character. Convert it to a surrogate pair in UTF-16.
+ utf32 -= UNICODE_PLANE01_START;
+ uint surrogate = 0; // allocate 2 chars worth of stack space
+ char* address = (char*)&surrogate;
+ address[0] = (char)((utf32 / 0x400) + (int)CharUnicodeInfo.HIGH_SURROGATE_START);
+ address[1] = (char)((utf32 % 0x400) + (int)CharUnicodeInfo.LOW_SURROGATE_START);
+ return new string(address, 0, 2);
+ }
}
diff --git a/src/mscorlib/src/System/Collections/Comparer.cs b/src/mscorlib/src/System/Collections/Comparer.cs
index 269ad79b2f..fdce1827f0 100644
--- a/src/mscorlib/src/System/Collections/Comparer.cs
+++ b/src/mscorlib/src/System/Collections/Comparer.cs
@@ -19,9 +19,11 @@ namespace System.Collections {
using System.Runtime.Serialization;
using System.Security.Permissions;
using System.Diagnostics.Contracts;
-
+
+#if FEATURE_SERIALIZATION
[Serializable]
-[System.Runtime.InteropServices.ComVisible(true)]
+#endif
+ [System.Runtime.InteropServices.ComVisible(true)]
public sealed class Comparer : IComparer , ISerializable
{
private CompareInfo m_compareInfo;
diff --git a/src/mscorlib/src/System/Collections/Concurrent/ConcurrentDictionary.cs b/src/mscorlib/src/System/Collections/Concurrent/ConcurrentDictionary.cs
index d805dc8be7..c87ce79128 100644
--- a/src/mscorlib/src/System/Collections/Concurrent/ConcurrentDictionary.cs
+++ b/src/mscorlib/src/System/Collections/Concurrent/ConcurrentDictionary.cs
@@ -39,8 +39,10 @@ namespace System.Collections.Concurrent
/// concurrently from multiple threads.
/// </remarks>
#if !FEATURE_CORECLR
+#if FEATURE_SERIALIZATION
[Serializable]
#endif
+#endif
[ComVisible(false)]
[DebuggerTypeProxy(typeof(Mscorlib_DictionaryDebugView<,>))]
[DebuggerDisplay("Count = {Count}")]
diff --git a/src/mscorlib/src/System/Collections/Concurrent/ConcurrentQueue.cs b/src/mscorlib/src/System/Collections/Concurrent/ConcurrentQueue.cs
index 9164eadad1..32f9bd7177 100644
--- a/src/mscorlib/src/System/Collections/Concurrent/ConcurrentQueue.cs
+++ b/src/mscorlib/src/System/Collections/Concurrent/ConcurrentQueue.cs
@@ -39,7 +39,9 @@ namespace System.Collections.Concurrent
[DebuggerDisplay("Count = {Count}")]
[DebuggerTypeProxy(typeof(SystemCollectionsConcurrent_ProducerConsumerCollectionDebugView<>))]
[HostProtection(Synchronization = true, ExternalThreading = true)]
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
public class ConcurrentQueue<T> : IProducerConsumerCollection<T>, IReadOnlyCollection<T>
{
//fields of ConcurrentQueue
diff --git a/src/mscorlib/src/System/Collections/Concurrent/ConcurrentStack.cs b/src/mscorlib/src/System/Collections/Concurrent/ConcurrentStack.cs
index 15d4176cff..97a0a905f7 100644
--- a/src/mscorlib/src/System/Collections/Concurrent/ConcurrentStack.cs
+++ b/src/mscorlib/src/System/Collections/Concurrent/ConcurrentStack.cs
@@ -47,7 +47,9 @@ namespace System.Collections.Concurrent
[DebuggerTypeProxy(typeof(SystemCollectionsConcurrent_ProducerConsumerCollectionDebugView<>))]
[HostProtection(Synchronization = true, ExternalThreading = true)]
#if !FEATURE_CORECLR
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
#endif //!FEATURE_CORECLR
public class ConcurrentStack<T> : IProducerConsumerCollection<T>, IReadOnlyCollection<T>
{
diff --git a/src/mscorlib/src/System/Collections/Generic/Comparer.cs b/src/mscorlib/src/System/Collections/Generic/Comparer.cs
index 0b2745f4bc..ac64f780da 100644
--- a/src/mscorlib/src/System/Collections/Generic/Comparer.cs
+++ b/src/mscorlib/src/System/Collections/Generic/Comparer.cs
@@ -184,14 +184,16 @@ namespace System.Collections.Generic
return _comparison(x, y);
}
}
-
+
// Enum comparers (specialized to avoid boxing)
// NOTE: Each of these needs to implement ISerializable
// and have a SerializationInfo/StreamingContext ctor,
// since we want to serialize as ObjectComparer for
// back-compat reasons (see below).
-
+
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
internal sealed class Int32EnumComparer<T> : Comparer<T>, ISerializable where T : struct
{
public Int32EnumComparer()
@@ -226,8 +228,10 @@ namespace System.Collections.Generic
info.SetType(typeof(ObjectComparer<T>));
}
}
-
+
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
internal sealed class UInt32EnumComparer<T> : Comparer<T>, ISerializable where T : struct
{
public UInt32EnumComparer()
@@ -258,8 +262,10 @@ namespace System.Collections.Generic
info.SetType(typeof(ObjectComparer<T>));
}
}
-
+
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
internal sealed class Int64EnumComparer<T> : Comparer<T>, ISerializable where T : struct
{
public Int64EnumComparer()
@@ -290,8 +296,10 @@ namespace System.Collections.Generic
info.SetType(typeof(ObjectComparer<T>));
}
}
-
+
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
internal sealed class UInt64EnumComparer<T> : Comparer<T>, ISerializable where T : struct
{
public UInt64EnumComparer()
diff --git a/src/mscorlib/src/System/Collections/Generic/Dictionary.cs b/src/mscorlib/src/System/Collections/Generic/Dictionary.cs
index 9cbfff5a57..b5ba84b190 100644
--- a/src/mscorlib/src/System/Collections/Generic/Dictionary.cs
+++ b/src/mscorlib/src/System/Collections/Generic/Dictionary.cs
@@ -52,7 +52,9 @@ namespace System.Collections.Generic {
[DebuggerTypeProxy(typeof(Mscorlib_DictionaryDebugView<,>))]
[DebuggerDisplay("Count = {Count}")]
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
[System.Runtime.InteropServices.ComVisible(false)]
public class Dictionary<TKey,TValue>: IDictionary<TKey,TValue>, IDictionary, IReadOnlyDictionary<TKey, TValue>, ISerializable, IDeserializationCallback {
diff --git a/src/mscorlib/src/System/Collections/Generic/EqualityComparer.cs b/src/mscorlib/src/System/Collections/Generic/EqualityComparer.cs
index b845d64fed..3c0aa69217 100644
--- a/src/mscorlib/src/System/Collections/Generic/EqualityComparer.cs
+++ b/src/mscorlib/src/System/Collections/Generic/EqualityComparer.cs
@@ -388,7 +388,9 @@ namespace System.Collections.Generic
}
}
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
internal class EnumEqualityComparer<T> : EqualityComparer<T>, ISerializable where T : struct
{
[Pure]
@@ -428,7 +430,9 @@ namespace System.Collections.Generic
}
}
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
internal sealed class SByteEnumEqualityComparer<T> : EnumEqualityComparer<T>, ISerializable where T : struct
{
public SByteEnumEqualityComparer() { }
@@ -443,7 +447,9 @@ namespace System.Collections.Generic
}
}
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
internal sealed class ShortEnumEqualityComparer<T> : EnumEqualityComparer<T>, ISerializable where T : struct
{
public ShortEnumEqualityComparer() { }
@@ -458,7 +464,9 @@ namespace System.Collections.Generic
}
}
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
internal sealed class LongEnumEqualityComparer<T> : EqualityComparer<T>, ISerializable where T : struct
{
[Pure]
diff --git a/src/mscorlib/src/System/Collections/Generic/KeyNotFoundException.cs b/src/mscorlib/src/System/Collections/Generic/KeyNotFoundException.cs
index 87ae3d1665..f52adfa75c 100644
--- a/src/mscorlib/src/System/Collections/Generic/KeyNotFoundException.cs
+++ b/src/mscorlib/src/System/Collections/Generic/KeyNotFoundException.cs
@@ -19,8 +19,10 @@ namespace System.Collections.Generic {
using System.Runtime.Remoting;
using System.Runtime.Serialization;
+#if FEATURE_SERIALIZATION
[Serializable]
-[System.Runtime.InteropServices.ComVisible(true)]
+#endif
+ [System.Runtime.InteropServices.ComVisible(true)]
public class KeyNotFoundException : SystemException, ISerializable {
public KeyNotFoundException ()
diff --git a/src/mscorlib/src/System/Collections/Generic/List.cs b/src/mscorlib/src/System/Collections/Generic/List.cs
index f557003fc2..6e954c03ed 100644
--- a/src/mscorlib/src/System/Collections/Generic/List.cs
+++ b/src/mscorlib/src/System/Collections/Generic/List.cs
@@ -310,22 +310,19 @@ namespace System.Collections.Generic {
// Contains returns true if the specified element is in the List.
// It does a linear, O(n) search. Equality is determined by calling
- // item.Equals().
- //
- public bool Contains(T item) {
- if ((Object) item == null) {
- for(int i=0; i<_size; i++)
- if ((Object) _items[i] == null)
- return true;
- return false;
- }
- else {
- EqualityComparer<T> c = EqualityComparer<T>.Default;
- for(int i=0; i<_size; i++) {
- if (c.Equals(_items[i], item)) return true;
- }
- return false;
- }
+ // EqualityComparer<T>.Default.Equals().
+
+ public bool Contains(T item)
+ {
+ // PERF: IndexOf calls Array.IndexOf, which internally
+ // calls EqualityComparer<T>.Default.IndexOf, which
+ // is specialized for different types. This
+ // boosts performance since instead of making a
+ // virtual method call each iteration of the loop,
+ // via EqualityComparer<T>.Default.Equals, we
+ // only make one virtual call to EqualityComparer.IndexOf.
+
+ return _size != 0 && IndexOf(item) != -1;
}
bool System.Collections.IList.Contains(Object item)
diff --git a/src/mscorlib/src/System/Collections/Hashtable.cs b/src/mscorlib/src/System/Collections/Hashtable.cs
index 95676d0379..0ab9ae8b23 100644
--- a/src/mscorlib/src/System/Collections/Hashtable.cs
+++ b/src/mscorlib/src/System/Collections/Hashtable.cs
@@ -70,7 +70,9 @@ namespace System.Collections {
[DebuggerTypeProxy(typeof(System.Collections.Hashtable.HashtableDebugView))]
[DebuggerDisplay("Count = {Count}")]
[System.Runtime.InteropServices.ComVisible(true)]
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
public class Hashtable : IDictionary, ISerializable, IDeserializationCallback, ICloneable {
/*
Implementation Notes:
@@ -463,7 +465,7 @@ namespace System.Collections {
occupancy = 0;
UpdateVersion();
isWriterInProgress = false;
-#if !FEATURE_CORECLR
+#if !FEATURE_CORECLR
Thread.EndCriticalRegion();
#endif
}
@@ -764,9 +766,9 @@ namespace System.Collections {
loadsize = (int)(loadFactor * newsize);
UpdateVersion();
isWriterInProgress = false;
-#if !FEATURE_CORECLR
+#if !FEATURE_CORECLR
Thread.EndCriticalRegion();
-#endif
+#endif
// minimun size of hashtable is 3 now and maximum loadFactor is 0.72 now.
Contract.Assert(loadsize < newsize, "Our current implementaion means this is not possible.");
return;
@@ -915,7 +917,7 @@ namespace System.Collections {
// code until the value & key are set appropriately.
#if !FEATURE_CORECLR
Thread.BeginCriticalRegion();
-#endif
+#endif
isWriterInProgress = true;
buckets[bucketNumber].val = nvalue;
buckets[bucketNumber].key = key;
@@ -923,9 +925,9 @@ namespace System.Collections {
count++;
UpdateVersion();
isWriterInProgress = false;
-#if !FEATURE_CORECLR
+#if !FEATURE_CORECLR
Thread.EndCriticalRegion();
-#endif
+#endif
#if FEATURE_RANDOMIZED_STRING_HASHING
#if !FEATURE_CORECLR
@@ -956,14 +958,14 @@ namespace System.Collections {
}
#if !FEATURE_CORECLR
Thread.BeginCriticalRegion();
-#endif
+#endif
isWriterInProgress = true;
buckets[bucketNumber].val = nvalue;
UpdateVersion();
isWriterInProgress = false;
-#if !FEATURE_CORECLR
+#if !FEATURE_CORECLR
Thread.EndCriticalRegion();
-#endif
+#endif
#if FEATURE_RANDOMIZED_STRING_HASHING
#if !FEATURE_CORECLR
@@ -1002,7 +1004,7 @@ namespace System.Collections {
// code until the value & key are set appropriately.
#if !FEATURE_CORECLR
Thread.BeginCriticalRegion();
-#endif
+#endif
isWriterInProgress = true;
buckets[emptySlotNumber].val = nvalue;
buckets[emptySlotNumber].key = key;
@@ -1010,7 +1012,7 @@ namespace System.Collections {
count++;
UpdateVersion();
isWriterInProgress = false;
-#if !FEATURE_CORECLR
+#if !FEATURE_CORECLR
Thread.EndCriticalRegion();
#endif
@@ -1088,7 +1090,7 @@ namespace System.Collections {
KeyEquals (b.key, key)) {
#if !FEATURE_CORECLR
Thread.BeginCriticalRegion();
-#endif
+#endif
isWriterInProgress = true;
// Clear hash_coll field, then key, then value
buckets[bn].hash_coll &= unchecked((int)0x80000000);
@@ -1102,9 +1104,9 @@ namespace System.Collections {
count--;
UpdateVersion();
isWriterInProgress = false;
-#if !FEATURE_CORECLR
+#if !FEATURE_CORECLR
Thread.EndCriticalRegion();
-#endif
+#endif
return;
}
bn = (int) (((long)bn + incr)% (uint)buckets.Length);
@@ -1221,7 +1223,7 @@ namespace System.Collections {
#pragma warning disable 618
IHashCodeProvider hcp = null;
-#pragma warning restore 618
+#pragma warning restore 618
Object [] serKeys = null;
Object [] serValues = null;
@@ -1247,7 +1249,7 @@ namespace System.Collections {
case HashCodeProviderName:
#pragma warning disable 618
hcp = (IHashCodeProvider)siInfo.GetValue(HashCodeProviderName, typeof(IHashCodeProvider));
-#pragma warning restore 618
+#pragma warning restore 618
break;
case KeysName:
serKeys = (Object[])siInfo.GetValue(KeysName, typeof(Object[]));
diff --git a/src/mscorlib/src/System/ContextMarshalException.cs b/src/mscorlib/src/System/ContextMarshalException.cs
index f74a62b991..936990867c 100644
--- a/src/mscorlib/src/System/ContextMarshalException.cs
+++ b/src/mscorlib/src/System/ContextMarshalException.cs
@@ -20,7 +20,9 @@ namespace System {
using System;
using System.Runtime.Serialization;
[System.Runtime.InteropServices.ComVisible(true)]
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
public class ContextMarshalException : SystemException {
public ContextMarshalException()
: base(Environment.GetResourceString("Arg_ContextMarshalException")) {
diff --git a/src/mscorlib/src/System/DBNull.cs b/src/mscorlib/src/System/DBNull.cs
index f22b500314..747e4d4d87 100644
--- a/src/mscorlib/src/System/DBNull.cs
+++ b/src/mscorlib/src/System/DBNull.cs
@@ -12,8 +12,10 @@ namespace System {
using System.Runtime.Remoting;
using System.Runtime.Serialization;
using System.Security.Permissions;
-[System.Runtime.InteropServices.ComVisible(true)]
+ [System.Runtime.InteropServices.ComVisible(true)]
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
public sealed class DBNull : ISerializable, IConvertible {
//Package private constructor
diff --git a/src/mscorlib/src/System/DataMisalignedException.cs b/src/mscorlib/src/System/DataMisalignedException.cs
index bcaaa3e52a..51f81a9d45 100644
--- a/src/mscorlib/src/System/DataMisalignedException.cs
+++ b/src/mscorlib/src/System/DataMisalignedException.cs
@@ -14,8 +14,10 @@ namespace System
using System;
using System.Runtime.Serialization;
+#if FEATURE_SERIALIZATION
[Serializable]
-[System.Runtime.InteropServices.ComVisible(true)]
+#endif
+ [System.Runtime.InteropServices.ComVisible(true)]
public sealed class DataMisalignedException : SystemException
{
public DataMisalignedException()
diff --git a/src/mscorlib/src/System/DateTime.cs b/src/mscorlib/src/System/DateTime.cs
index 757623a9aa..c464549333 100644
--- a/src/mscorlib/src/System/DateTime.cs
+++ b/src/mscorlib/src/System/DateTime.cs
@@ -53,7 +53,8 @@ namespace System {
//
[StructLayout(LayoutKind.Auto)]
[Serializable]
- public struct DateTime : IComparable, IFormattable, IConvertible, ISerializable, IComparable<DateTime>,IEquatable<DateTime> {
+ public struct DateTime : IComparable, IFormattable, IConvertible, IComparable<DateTime>, IEquatable<DateTime>, ISerializable
+ {
// Number of 100ns ticks per time unit
private const long TicksPerMillisecond = 10000;
@@ -670,8 +671,7 @@ namespace System {
public static DateTime FromOADate(double d) {
return new DateTime(DoubleDateToTicks(d), DateTimeKind.Unspecified);
}
-
-#if FEATURE_SERIALIZATION
+
[System.Security.SecurityCritical /*auto-generated_required*/]
void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) {
if (info==null) {
@@ -682,8 +682,7 @@ namespace System {
// Serialize both the old and the new format
info.AddValue(TicksField, InternalTicks);
info.AddValue(DateDataField, dateData);
- }
-#endif
+ }
public Boolean IsDaylightSavingTime() {
if (Kind == DateTimeKind.Utc) {
diff --git a/src/mscorlib/src/System/DateTimeOffset.cs b/src/mscorlib/src/System/DateTimeOffset.cs
index 568ba249a2..28c115cb25 100644
--- a/src/mscorlib/src/System/DateTimeOffset.cs
+++ b/src/mscorlib/src/System/DateTimeOffset.cs
@@ -33,10 +33,15 @@ namespace System {
// out and for internal readability.
[StructLayout(LayoutKind.Auto)]
+#if FEATURE_SERIALIZATION
[Serializable]
- public struct DateTimeOffset : IComparable, IFormattable, ISerializable, IDeserializationCallback,
- IComparable<DateTimeOffset>, IEquatable<DateTimeOffset> {
-
+#endif
+ public struct DateTimeOffset : IComparable, IFormattable,
+ IComparable<DateTimeOffset>, IEquatable<DateTimeOffset>
+#if FEATURE_SERIALIZATION
+ , ISerializable, IDeserializationCallback
+#endif
+ {
// Constants
internal const Int64 MaxOffset = TimeSpan.TicksPerHour * 14;
internal const Int64 MinOffset = -MaxOffset;
diff --git a/src/mscorlib/src/System/Decimal.cs b/src/mscorlib/src/System/Decimal.cs
index d54279921c..254b0bc818 100644
--- a/src/mscorlib/src/System/Decimal.cs
+++ b/src/mscorlib/src/System/Decimal.cs
@@ -56,11 +56,16 @@ namespace System {
// Decimal throws an OverflowException if the value is not within
// the range of the Decimal type.
[StructLayout(LayoutKind.Sequential)]
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
[System.Runtime.InteropServices.ComVisible(true)]
[System.Runtime.Versioning.NonVersionable] // This only applies to field layout
- public struct Decimal : IFormattable, IComparable, IConvertible, IDeserializationCallback
- , IComparable<Decimal>, IEquatable<Decimal> {
+ public struct Decimal : IFormattable, IComparable, IConvertible, IComparable<Decimal>, IEquatable<Decimal>
+#if FEATURE_SERIALIZATION
+ , IDeserializationCallback
+#endif
+ {
// Sign mask for the flags field. A value of zero in this bit indicates a
// positive Decimal value, and a value of one in this bit indicates a
diff --git a/src/mscorlib/src/System/Delegate.cs b/src/mscorlib/src/System/Delegate.cs
index 110555423c..f8ea597209 100644
--- a/src/mscorlib/src/System/Delegate.cs
+++ b/src/mscorlib/src/System/Delegate.cs
@@ -14,7 +14,9 @@ namespace System {
using System.Runtime.Versioning;
using System.Diagnostics.Contracts;
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
[ClassInterface(ClassInterfaceType.AutoDual)]
[System.Runtime.InteropServices.ComVisible(true)]
public abstract class Delegate : ICloneable, ISerializable
diff --git a/src/mscorlib/src/System/DelegateSerializationHolder.cs b/src/mscorlib/src/System/DelegateSerializationHolder.cs
index 6be712eaaf..9c9f3bf66a 100644
--- a/src/mscorlib/src/System/DelegateSerializationHolder.cs
+++ b/src/mscorlib/src/System/DelegateSerializationHolder.cs
@@ -13,7 +13,9 @@ using System.Diagnostics.Contracts;
namespace System
{
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
internal sealed class DelegateSerializationHolder : IObjectReference, ISerializable
{
#region Static Members
diff --git a/src/mscorlib/src/System/Diagnostics/Eventing/ActivityTracker.cs b/src/mscorlib/src/System/Diagnostics/Eventing/ActivityTracker.cs
index 92940c10b6..e28d4686a5 100644
--- a/src/mscorlib/src/System/Diagnostics/Eventing/ActivityTracker.cs
+++ b/src/mscorlib/src/System/Diagnostics/Eventing/ActivityTracker.cs
@@ -323,7 +323,7 @@ namespace System.Diagnostics.Tracing
{
if (activityInfo == null)
return ("");
- return Path(activityInfo.m_creator) + "/" + activityInfo.m_uniqueId;
+ return Path(activityInfo.m_creator) + "/" + activityInfo.m_uniqueId.ToString();
}
public override string ToString()
diff --git a/src/mscorlib/src/System/Diagnostics/Eventing/EventSourceException.cs b/src/mscorlib/src/System/Diagnostics/Eventing/EventSourceException.cs
index 3fc9d545b8..eb3b4f9287 100644
--- a/src/mscorlib/src/System/Diagnostics/Eventing/EventSourceException.cs
+++ b/src/mscorlib/src/System/Diagnostics/Eventing/EventSourceException.cs
@@ -19,8 +19,10 @@ namespace System.Diagnostics.Tracing
/// Exception that is thrown when an error occurs during EventSource operation.
/// </summary>
#if (!ES_BUILD_PCL && !PROJECTN)
+#if FEATURE_SERIALIZATION
[Serializable]
#endif
+#endif
public class EventSourceException : Exception
{
/// <summary>
diff --git a/src/mscorlib/src/System/Diagnostics/Stacktrace.cs b/src/mscorlib/src/System/Diagnostics/Stacktrace.cs
index 4998aee873..32b1793505 100644
--- a/src/mscorlib/src/System/Diagnostics/Stacktrace.cs
+++ b/src/mscorlib/src/System/Diagnostics/Stacktrace.cs
@@ -17,12 +17,14 @@ namespace System.Diagnostics {
using System.Runtime.Serialization;
using System.Runtime.Versioning;
using System.Diagnostics.Contracts;
-
+
// READ ME:
// Modifying the order or fields of this object may require other changes
// to the unmanaged definition of the StackFrameHelper class, in
// VM\DebugDebugger.h. The binder will catch some of these layout problems.
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
internal class StackFrameHelper : IDisposable
{
[NonSerialized]
@@ -270,7 +272,9 @@ namespace System.Diagnostics {
#if !FEATURE_CORECLR
[SecurityPermission(SecurityAction.InheritanceDemand, UnmanagedCode=true)]
#endif
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
[System.Runtime.InteropServices.ComVisible(true)]
public class StackTrace
{
@@ -292,9 +296,9 @@ namespace System.Diagnostics {
// Constructs a stack trace from the current location.
//
- #if FEATURE_CORECLR
+#if FEATURE_CORECLR
[System.Security.SecurityCritical] // auto-generated
- #endif
+#endif
public StackTrace(bool fNeedFileInfo)
{
m_iNumOfFrames = 0;
@@ -305,9 +309,9 @@ namespace System.Diagnostics {
// Constructs a stack trace from the current location, in a caller's
// frame
//
- #if FEATURE_CORECLR
+#if FEATURE_CORECLR
[System.Security.SecurityCritical] // auto-generated
- #endif
+#endif
public StackTrace(int skipFrames)
{
@@ -325,9 +329,9 @@ namespace System.Diagnostics {
// Constructs a stack trace from the current location, in a caller's
// frame
//
- #if FEATURE_CORECLR
+#if FEATURE_CORECLR
[System.Security.SecurityCritical] // auto-generated
- #endif
+#endif
public StackTrace(int skipFrames, bool fNeedFileInfo)
{
@@ -357,9 +361,9 @@ namespace System.Diagnostics {
// Constructs a stack trace from the current location.
//
- #if FEATURE_CORECLR
+#if FEATURE_CORECLR
[System.Security.SecurityCritical] // auto-generated
- #endif
+#endif
public StackTrace(Exception e, bool fNeedFileInfo)
{
if (e == null)
@@ -374,9 +378,9 @@ namespace System.Diagnostics {
// Constructs a stack trace from the current location, in a caller's
// frame
//
- #if FEATURE_CORECLR
+#if FEATURE_CORECLR
[System.Security.SecurityCritical] // auto-generated
- #endif
+#endif
public StackTrace(Exception e, int skipFrames)
{
if (e == null)
@@ -396,9 +400,9 @@ namespace System.Diagnostics {
// Constructs a stack trace from the current location, in a caller's
// frame
//
- #if FEATURE_CORECLR
+#if FEATURE_CORECLR
[System.Security.SecurityCritical] // auto-generated
- #endif
+#endif
public StackTrace(Exception e, int skipFrames, bool fNeedFileInfo)
{
if (e == null)
@@ -430,9 +434,9 @@ namespace System.Diagnostics {
// Constructs a stack trace for the given thread
//
- #if FEATURE_CORECLR
+#if FEATURE_CORECLR
[System.Security.SecurityCritical] // auto-generated
- #endif
+#endif
[Obsolete("This constructor has been deprecated. Please use a constructor that does not require a Thread parameter. http://go.microsoft.com/fwlink/?linkid=14202")]
public StackTrace(Thread targetThread, bool needFileInfo)
{
@@ -596,9 +600,9 @@ namespace System.Diagnostics {
// Builds a readable representation of the stack trace, specifying
// the format for backwards compatibility.
- #if FEATURE_CORECLR
+#if FEATURE_CORECLR
[System.Security.SecurityCritical] // auto-generated
- #endif
+#endif
internal String ToString(TraceFormat traceFormat)
{
bool displayFilenames = true; // we'll try, but demand may fail
@@ -754,9 +758,9 @@ namespace System.Diagnostics {
// This helper is called from within the EE to construct a string representation
// of the current stack trace.
- #if FEATURE_CORECLR
+#if FEATURE_CORECLR
[System.Security.SecurityCritical] // auto-generated
- #endif
+#endif
private static String GetManagedStackTraceStringHelper(bool fNeedFileInfo)
{
// Note all the frames in System.Diagnostics will be skipped when capturing
diff --git a/src/mscorlib/src/System/Diagnostics/log.cs b/src/mscorlib/src/System/Diagnostics/log.cs
index 1c68aad161..c89321ef82 100644
--- a/src/mscorlib/src/System/Diagnostics/log.cs
+++ b/src/mscorlib/src/System/Diagnostics/log.cs
@@ -21,7 +21,9 @@ namespace System.Diagnostics {
// There is also a "built-in" console device which can be enabled
// programatically, by registry (specifics....) or environment
// variables.
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
[HostProtection(Synchronization=true, ExternalThreading=true)]
internal delegate void LogMessageEventHandler(LoggingLevels level, LogSwitch category,
String message,
@@ -32,7 +34,9 @@ namespace System.Diagnostics {
// NOTE: These are NOT triggered when the log switch setting is changed from the
// attached debugger.
//
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
internal delegate void LogSwitchLevelHandler(LogSwitch ls, LoggingLevels newLevel);
diff --git a/src/mscorlib/src/System/DivideByZeroException.cs b/src/mscorlib/src/System/DivideByZeroException.cs
index b975e81df6..a69b481ac4 100644
--- a/src/mscorlib/src/System/DivideByZeroException.cs
+++ b/src/mscorlib/src/System/DivideByZeroException.cs
@@ -16,7 +16,9 @@ namespace System {
using System;
using System.Runtime.Serialization;
[System.Runtime.InteropServices.ComVisible(true)]
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
public class DivideByZeroException : ArithmeticException {
public DivideByZeroException()
: base(Environment.GetResourceString("Arg_DivideByZero")) {
diff --git a/src/mscorlib/src/System/DllNotFoundException.cs b/src/mscorlib/src/System/DllNotFoundException.cs
index 22bc39cff3..caad8b257e 100644
--- a/src/mscorlib/src/System/DllNotFoundException.cs
+++ b/src/mscorlib/src/System/DllNotFoundException.cs
@@ -16,8 +16,11 @@ namespace System {
using System;
using System.Runtime.Serialization;
-[System.Runtime.InteropServices.ComVisible(true)]
- [Serializable] public class DllNotFoundException : TypeLoadException {
+ [System.Runtime.InteropServices.ComVisible(true)]
+#if FEATURE_SERIALIZATION
+ [Serializable]
+#endif
+ public class DllNotFoundException : TypeLoadException {
public DllNotFoundException()
: base(Environment.GetResourceString("Arg_DllNotFoundException")) {
SetErrorCode(__HResults.COR_E_DLLNOTFOUND);
diff --git a/src/mscorlib/src/System/DuplicateWaitObjectException.cs b/src/mscorlib/src/System/DuplicateWaitObjectException.cs
index 05b7da5648..47ae3daf29 100644
--- a/src/mscorlib/src/System/DuplicateWaitObjectException.cs
+++ b/src/mscorlib/src/System/DuplicateWaitObjectException.cs
@@ -20,8 +20,10 @@ namespace System {
// The DuplicateWaitObjectException is thrown when an object
// appears more than once in the list of objects to WaitAll or WaitAny.
//
-[System.Runtime.InteropServices.ComVisible(true)]
+ [System.Runtime.InteropServices.ComVisible(true)]
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
public class DuplicateWaitObjectException : ArgumentException {
private static volatile String _duplicateWaitObjectMessage = null;
diff --git a/src/mscorlib/src/System/Empty.cs b/src/mscorlib/src/System/Empty.cs
index f7e7486014..5dc4e00824 100644
--- a/src/mscorlib/src/System/Empty.cs
+++ b/src/mscorlib/src/System/Empty.cs
@@ -12,7 +12,9 @@ namespace System {
using System.Runtime.Remoting;
using System.Runtime.Serialization;
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
internal sealed class Empty : ISerializable
{
private Empty() {
diff --git a/src/mscorlib/src/System/EntryPointNotFoundException.cs b/src/mscorlib/src/System/EntryPointNotFoundException.cs
index 9c1b842efa..589b805e71 100644
--- a/src/mscorlib/src/System/EntryPointNotFoundException.cs
+++ b/src/mscorlib/src/System/EntryPointNotFoundException.cs
@@ -15,8 +15,11 @@ namespace System {
using System;
using System.Runtime.Serialization;
-[System.Runtime.InteropServices.ComVisible(true)]
- [Serializable] public class EntryPointNotFoundException : TypeLoadException {
+ [System.Runtime.InteropServices.ComVisible(true)]
+#if FEATURE_SERIALIZATION
+ [Serializable]
+#endif
+ public class EntryPointNotFoundException : TypeLoadException {
public EntryPointNotFoundException()
: base(Environment.GetResourceString("Arg_EntryPointNotFoundException")) {
SetErrorCode(__HResults.COR_E_ENTRYPOINTNOTFOUND);
diff --git a/src/mscorlib/src/System/EventHandler.cs b/src/mscorlib/src/System/EventHandler.cs
index 3a3d799817..3cd4641b51 100644
--- a/src/mscorlib/src/System/EventHandler.cs
+++ b/src/mscorlib/src/System/EventHandler.cs
@@ -5,10 +5,14 @@
namespace System {
using System;
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
[System.Runtime.InteropServices.ComVisible(true)]
public delegate void EventHandler(Object sender, EventArgs e);
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
public delegate void EventHandler<TEventArgs>(Object sender, TEventArgs e); // Removed TEventArgs constraint post-.NET 4
}
diff --git a/src/mscorlib/src/System/Exception.cs b/src/mscorlib/src/System/Exception.cs
index b08c12de61..f35f7c5690 100644
--- a/src/mscorlib/src/System/Exception.cs
+++ b/src/mscorlib/src/System/Exception.cs
@@ -29,7 +29,9 @@ namespace System {
[ClassInterface(ClassInterfaceType.None)]
[ComDefaultInterface(typeof(_Exception))]
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
[ComVisible(true)]
public class Exception : ISerializable, _Exception
{
@@ -321,9 +323,9 @@ namespace System {
// is true. Note that this requires FileIOPermission(PathDiscovery), and so
// will usually fail in CoreCLR. To avoid the demand and resulting
// SecurityException we can explicitly not even try to get fileinfo.
- #if FEATURE_CORECLR
+#if FEATURE_CORECLR
[System.Security.SecurityCritical] // auto-generated
- #endif
+#endif
private string GetStackTrace(bool needFileInfo)
{
string stackTraceString = _stackTraceString;
@@ -380,9 +382,9 @@ namespace System {
}
public virtual String Source {
- #if FEATURE_CORECLR
+#if FEATURE_CORECLR
[System.Security.SecurityCritical] // auto-generated
- #endif
+#endif
get {
if (_source == null)
{
@@ -411,9 +413,9 @@ namespace System {
return _source;
}
- #if FEATURE_CORECLR
+#if FEATURE_CORECLR
[System.Security.SecurityCritical] // auto-generated
- #endif
+#endif
set { _source = value; }
}
@@ -425,9 +427,9 @@ namespace System {
return ToString(true, true);
}
- #if FEATURE_CORECLR
+#if FEATURE_CORECLR
[System.Security.SecurityCritical] // auto-generated
- #endif
+#endif
private String ToString(bool needFileLineInfo, bool needMessage) {
String message = (needMessage ? Message : null);
String s;
@@ -978,7 +980,9 @@ namespace System {
// The Message field is set to the ToString() output of the original exception.
//--------------------------------------------------------------------------
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
internal sealed class CrossAppDomainMarshaledException : SystemException
{
public CrossAppDomainMarshaledException(String message, int errorCode)
@@ -990,9 +994,9 @@ namespace System {
// Normally, only Telesto's UEF will see these exceptions.
// This override prints out the original Exception's ToString()
// output and hides the fact that it is wrapped inside another excepton.
- #if FEATURE_CORECLR
+#if FEATURE_CORECLR
[System.Security.SecurityCritical] // auto-generated
- #endif
+#endif
internal override String InternalToString()
{
return Message;
diff --git a/src/mscorlib/src/System/ExecutionEngineException.cs b/src/mscorlib/src/System/ExecutionEngineException.cs
index 5b2592cca9..f026253e0a 100644
--- a/src/mscorlib/src/System/ExecutionEngineException.cs
+++ b/src/mscorlib/src/System/ExecutionEngineException.cs
@@ -21,7 +21,9 @@ namespace System {
using System.Runtime.Serialization;
[Obsolete("This type previously indicated an unspecified fatal error in the runtime. The runtime no longer raises this exception so this type is obsolete.")]
[System.Runtime.InteropServices.ComVisible(true)]
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
public sealed class ExecutionEngineException : SystemException {
public ExecutionEngineException()
: base(Environment.GetResourceString("Arg_ExecutionEngineException")) {
diff --git a/src/mscorlib/src/System/FieldAccessException.cs b/src/mscorlib/src/System/FieldAccessException.cs
index 22f51191c8..174ce353c8 100644
--- a/src/mscorlib/src/System/FieldAccessException.cs
+++ b/src/mscorlib/src/System/FieldAccessException.cs
@@ -13,8 +13,11 @@ namespace System {
using System;
using System.Runtime.Serialization;
-[System.Runtime.InteropServices.ComVisible(true)]
- [Serializable] public class FieldAccessException : MemberAccessException {
+ [System.Runtime.InteropServices.ComVisible(true)]
+#if FEATURE_SERIALIZATION
+ [Serializable]
+#endif
+ public class FieldAccessException : MemberAccessException {
public FieldAccessException()
: base(Environment.GetResourceString("Arg_FieldAccessException")) {
SetErrorCode(__HResults.COR_E_FIELDACCESS);
diff --git a/src/mscorlib/src/System/FormatException.cs b/src/mscorlib/src/System/FormatException.cs
index e526dfd4f7..3fa70df075 100644
--- a/src/mscorlib/src/System/FormatException.cs
+++ b/src/mscorlib/src/System/FormatException.cs
@@ -15,7 +15,9 @@ namespace System {
using System;
using System.Runtime.Serialization;
[System.Runtime.InteropServices.ComVisible(true)]
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
public class FormatException : SystemException {
public FormatException()
: base(Environment.GetResourceString("Arg_FormatException")) {
diff --git a/src/mscorlib/src/System/Globalization/Calendar.cs b/src/mscorlib/src/System/Globalization/Calendar.cs
index 582a079af7..d6dfdc9f4b 100644
--- a/src/mscorlib/src/System/Globalization/Calendar.cs
+++ b/src/mscorlib/src/System/Globalization/Calendar.cs
@@ -170,7 +170,7 @@ namespace System.Globalization {
//
// Clone
//
- // Is the implementation of IColnable.
+ // Is the implementation of ICloneable.
//
////////////////////////////////////////////////////////////////////////
[System.Runtime.InteropServices.ComVisible(false)]
diff --git a/src/mscorlib/src/System/Globalization/CompareInfo.cs b/src/mscorlib/src/System/Globalization/CompareInfo.cs
index 05eb061f62..96ec62945d 100644
--- a/src/mscorlib/src/System/Globalization/CompareInfo.cs
+++ b/src/mscorlib/src/System/Globalization/CompareInfo.cs
@@ -64,9 +64,10 @@ namespace System.Globalization {
}
+#if FEATURE_SERIALIZATION
[Serializable]
-[System.Runtime.InteropServices.ComVisible(true)]
-
+#endif
+ [System.Runtime.InteropServices.ComVisible(true)]
public class CompareInfo
#if FEATURE_SERIALIZATION
: IDeserializationCallback
diff --git a/src/mscorlib/src/System/Globalization/CultureInfo.cs b/src/mscorlib/src/System/Globalization/CultureInfo.cs
index 7193b8cfd7..cadd82768f 100644
--- a/src/mscorlib/src/System/Globalization/CultureInfo.cs
+++ b/src/mscorlib/src/System/Globalization/CultureInfo.cs
@@ -42,7 +42,9 @@ namespace System.Globalization {
using System.Diagnostics.Contracts;
using System.Resources;
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
[System.Runtime.InteropServices.ComVisible(true)]
public class CultureInfo : ICloneable, IFormatProvider {
//--------------------------------------------------------------------//
@@ -342,7 +344,7 @@ namespace System.Globalization {
}
-#if FEATURE_USE_LCID
+#if FEATURE_USE_LCID
public CultureInfo(int culture) : this(culture, true) {
}
@@ -407,7 +409,7 @@ namespace System.Globalization {
[OnDeserialized]
private void OnDeserialized(StreamingContext ctx)
{
-#if FEATURE_USE_LCID
+#if FEATURE_USE_LCID
// Whidbey+ should remember our name
// but v1 and v1.1 did not store name -- only lcid
// Whidbey did not store actual alternate sort name in m_name
@@ -428,7 +430,7 @@ namespace System.Globalization {
throw new CultureNotFoundException(
"m_name", m_name, Environment.GetResourceString("Argument_CultureNotSupported"));
-#if FEATURE_USE_LCID
+#if FEATURE_USE_LCID
}
#endif
m_isInherited = (this.GetType() != typeof(System.Globalization.CultureInfo));
@@ -449,7 +451,7 @@ namespace System.Globalization {
}
}
-#if FEATURE_USE_LCID
+#if FEATURE_USE_LCID
// A locale ID is a 32 bit value which is the combination of a
// language ID, a sort ID, and a reserved area. The bits are
// allocated as follows:
@@ -976,7 +978,7 @@ namespace System.Globalization {
// of a customized culture (LCID == LOCALE_CUSTOM_UNSPECIFIED).
//
////////////////////////////////////////////////////////////////////////
-#if FEATURE_USE_LCID
+#if FEATURE_USE_LCID
[System.Runtime.InteropServices.ComVisible(false)]
public virtual int KeyboardLayoutId
{
diff --git a/src/mscorlib/src/System/Globalization/CultureNotFoundException.cs b/src/mscorlib/src/System/Globalization/CultureNotFoundException.cs
index 009866269c..cf919b7db8 100644
--- a/src/mscorlib/src/System/Globalization/CultureNotFoundException.cs
+++ b/src/mscorlib/src/System/Globalization/CultureNotFoundException.cs
@@ -11,7 +11,9 @@ namespace System.Globalization {
using System.Diagnostics.Contracts;
[System.Runtime.InteropServices.ComVisible(true)]
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
public class CultureNotFoundException : ArgumentException, ISerializable
{
private string m_invalidCultureName; // unrecognized culture name
diff --git a/src/mscorlib/src/System/Globalization/DateTimeFormat.cs b/src/mscorlib/src/System/Globalization/DateTimeFormat.cs
index cdb7032a86..cbb4039a0c 100644
--- a/src/mscorlib/src/System/Globalization/DateTimeFormat.cs
+++ b/src/mscorlib/src/System/Globalization/DateTimeFormat.cs
@@ -606,7 +606,7 @@ namespace System {
FormatDigits(result, year % 100, tokenLen);
}
else {
- String fmtPattern = "D" + tokenLen;
+ String fmtPattern = "D" + tokenLen.ToString();
result.Append(year.ToString(fmtPattern, CultureInfo.InvariantCulture));
}
}
diff --git a/src/mscorlib/src/System/Globalization/DateTimeFormatInfo.cs b/src/mscorlib/src/System/Globalization/DateTimeFormatInfo.cs
index d08332f76e..1dd04f8555 100644
--- a/src/mscorlib/src/System/Globalization/DateTimeFormatInfo.cs
+++ b/src/mscorlib/src/System/Globalization/DateTimeFormatInfo.cs
@@ -54,8 +54,10 @@ namespace System.Globalization {
}
+#if FEATURE_SERIALIZATION
[Serializable]
-[System.Runtime.InteropServices.ComVisible(true)]
+#endif
+ [System.Runtime.InteropServices.ComVisible(true)]
public sealed class DateTimeFormatInfo : ICloneable, IFormatProvider
{
//
@@ -384,7 +386,7 @@ namespace System.Globalization {
#endif
}
- #region Serialization
+#region Serialization
// The following fields are defined to keep the serialization compatibility with .NET V1.0/V1.1.
[OptionalField(VersionAdded = 1)]
private int CultureID;
diff --git a/src/mscorlib/src/System/Globalization/GregorianCalendar.cs b/src/mscorlib/src/System/Globalization/GregorianCalendar.cs
index 69b62db225..529f2af8a1 100644
--- a/src/mscorlib/src/System/Globalization/GregorianCalendar.cs
+++ b/src/mscorlib/src/System/Globalization/GregorianCalendar.cs
@@ -22,8 +22,10 @@ namespace System.Globalization {
// 0 CurrentEra (AD)
// 1 BeforeCurrentEra (BC)
-[System.Runtime.InteropServices.ComVisible(true)]
+ [System.Runtime.InteropServices.ComVisible(true)]
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
public class GregorianCalendar : Calendar
{
/*
diff --git a/src/mscorlib/src/System/Globalization/RegionInfo.cs b/src/mscorlib/src/System/Globalization/RegionInfo.cs
index 7b478c6e0d..cb48148590 100644
--- a/src/mscorlib/src/System/Globalization/RegionInfo.cs
+++ b/src/mscorlib/src/System/Globalization/RegionInfo.cs
@@ -21,8 +21,10 @@ namespace System.Globalization {
using System.Runtime.Serialization;
using System.Diagnostics.Contracts;
+#if FEATURE_SERIALIZATION
[Serializable]
-[System.Runtime.InteropServices.ComVisible(true)]
+#endif
+ [System.Runtime.InteropServices.ComVisible(true)]
public class RegionInfo
{
//--------------------------------------------------------------------//
@@ -137,7 +139,7 @@ namespace System.Globalization {
[System.Security.SecurityCritical] // auto-generated
private void SetName(string name)
{
-#if FEATURE_CORECLR
+#if FEATURE_CORECLR
// Use the name of the region we found
this.m_name = this.m_cultureData.SREGIONNAME;
#else
@@ -163,7 +165,7 @@ namespace System.Globalization {
[OptionalField(VersionAdded = 2)]
internal int m_dataItem = 0;
-#if !FEATURE_CORECLR
+#if !FEATURE_CORECLR
static private readonly int[] IdFromEverettRegionInfoDataItem =
{
0x3801, /* 0 */ // AE ar-AE Arabic (U.A.E.)
@@ -306,7 +308,7 @@ namespace System.Globalization {
[OnDeserialized]
private void OnDeserialized(StreamingContext ctx)
{
-#if FEATURE_CORECLR
+#if FEATURE_CORECLR
// This won't happen anyway since CoreCLR doesn't support serialization
this.m_cultureData = CultureData.GetCultureData(m_name, true);
#else
diff --git a/src/mscorlib/src/System/Globalization/SortKey.cs b/src/mscorlib/src/System/Globalization/SortKey.cs
index 707cd9cce1..0069f97368 100644
--- a/src/mscorlib/src/System/Globalization/SortKey.cs
+++ b/src/mscorlib/src/System/Globalization/SortKey.cs
@@ -18,8 +18,11 @@ namespace System.Globalization {
using System.Runtime.Serialization;
using System.Diagnostics.Contracts;
-[System.Runtime.InteropServices.ComVisible(true)]
- [Serializable] public class SortKey
+ [System.Runtime.InteropServices.ComVisible(true)]
+#if FEATURE_SERIALIZATION
+ [Serializable]
+#endif
+ public class SortKey
{
//--------------------------------------------------------------------//
// Internal Information //
diff --git a/src/mscorlib/src/System/Globalization/StringInfo.cs b/src/mscorlib/src/System/Globalization/StringInfo.cs
index 57c58a4148..5ff832bc0b 100644
--- a/src/mscorlib/src/System/Globalization/StringInfo.cs
+++ b/src/mscorlib/src/System/Globalization/StringInfo.cs
@@ -19,9 +19,10 @@ namespace System.Globalization {
using System.Security.Permissions;
using System.Diagnostics.Contracts;
-
+#if FEATURE_SERIALIZATION
[Serializable]
-[System.Runtime.InteropServices.ComVisible(true)]
+#endif
+ [System.Runtime.InteropServices.ComVisible(true)]
public class StringInfo
{
diff --git a/src/mscorlib/src/System/Globalization/TextElementEnumerator.cs b/src/mscorlib/src/System/Globalization/TextElementEnumerator.cs
index aae35e25ae..77120967c3 100644
--- a/src/mscorlib/src/System/Globalization/TextElementEnumerator.cs
+++ b/src/mscorlib/src/System/Globalization/TextElementEnumerator.cs
@@ -21,8 +21,10 @@ namespace System.Globalization {
// This is public because GetTextElement() is public.
//
+#if FEATURE_SERIALIZATION
[Serializable]
-[System.Runtime.InteropServices.ComVisible(true)]
+#endif
+ [System.Runtime.InteropServices.ComVisible(true)]
public class TextElementEnumerator: IEnumerator
{
private String str;
diff --git a/src/mscorlib/src/System/Globalization/TextInfo.cs b/src/mscorlib/src/System/Globalization/TextInfo.cs
index e3d531ee36..cba9556d30 100644
--- a/src/mscorlib/src/System/Globalization/TextInfo.cs
+++ b/src/mscorlib/src/System/Globalization/TextInfo.cs
@@ -27,9 +27,14 @@ namespace System.Globalization {
using System.Diagnostics.Contracts;
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
[System.Runtime.InteropServices.ComVisible(true)]
- public class TextInfo : ICloneable, IDeserializationCallback
+ public class TextInfo : ICloneable
+#if FEATURE_SERIALIZATION
+ , IDeserializationCallback
+#endif
{
//--------------------------------------------------------------------//
// Internal Information //
@@ -169,7 +174,7 @@ namespace System.Globalization {
m_cultureName = CultureInfo.GetCultureInfo(m_win32LangID).m_cultureData.CultureName;
}
}
-#endif
+#endif
}
// Get the text info name belonging to that culture
@@ -375,7 +380,7 @@ namespace System.Globalization {
return (this.m_cultureData.IDEFAULTEBCDICCODEPAGE);
}
}
-#endif
+#endif
////////////////////////////////////////////////////////////////////////
@@ -387,7 +392,7 @@ namespace System.Globalization {
//
////////////////////////////////////////////////////////////////////////
-#if FEATURE_USE_LCID
+#if FEATURE_USE_LCID
[System.Runtime.InteropServices.ComVisible(false)]
public int LCID
{
@@ -431,7 +436,7 @@ namespace System.Globalization {
//
// Clone
//
- // Is the implementation of IColnable.
+ // Is the implementation of ICloneable.
//
////////////////////////////////////////////////////////////////////////
[System.Runtime.InteropServices.ComVisible(false)]
diff --git a/src/mscorlib/src/System/IO/DirectoryNotFoundException.cs b/src/mscorlib/src/System/IO/DirectoryNotFoundException.cs
index 09d7e7d4e7..3fe9eee315 100644
--- a/src/mscorlib/src/System/IO/DirectoryNotFoundException.cs
+++ b/src/mscorlib/src/System/IO/DirectoryNotFoundException.cs
@@ -22,7 +22,9 @@ namespace System.IO {
* the Win32 errorcode-as-HRESULT ERROR_PATH_NOT_FOUND (0x80070003)
* and STG_E_PATHNOTFOUND (0x80030003).
*/
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
[System.Runtime.InteropServices.ComVisible(true)]
public class DirectoryNotFoundException : IOException {
public DirectoryNotFoundException()
diff --git a/src/mscorlib/src/System/IO/DriveInfo.cs b/src/mscorlib/src/System/IO/DriveInfo.cs
index b4af120e80..be75e8979d 100644
--- a/src/mscorlib/src/System/IO/DriveInfo.cs
+++ b/src/mscorlib/src/System/IO/DriveInfo.cs
@@ -40,9 +40,14 @@ namespace System.IO
// Ideally we'll get a better security permission, but possibly
// not for Whidbey.
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
[ComVisible(true)]
- public sealed class DriveInfo : ISerializable
+ public sealed class DriveInfo
+#if FEATURE_SERIALIZATION
+ : ISerializable
+#endif
{
private String _name;
diff --git a/src/mscorlib/src/System/IO/DriveNotFoundException.cs b/src/mscorlib/src/System/IO/DriveNotFoundException.cs
index 0ca2254459..a021313dc6 100644
--- a/src/mscorlib/src/System/IO/DriveNotFoundException.cs
+++ b/src/mscorlib/src/System/IO/DriveNotFoundException.cs
@@ -16,8 +16,10 @@ using System.Runtime.Serialization;
namespace System.IO {
//Thrown when trying to access a drive that is not availabe.
+#if FEATURE_SERIALIZATION
[Serializable]
-[System.Runtime.InteropServices.ComVisible(true)]
+#endif
+ [System.Runtime.InteropServices.ComVisible(true)]
public class DriveNotFoundException : IOException {
public DriveNotFoundException()
: base(Environment.GetResourceString("Arg_DriveNotFoundException")) {
diff --git a/src/mscorlib/src/System/IO/EndOfStreamException.cs b/src/mscorlib/src/System/IO/EndOfStreamException.cs
index c77244dbad..6643917777 100644
--- a/src/mscorlib/src/System/IO/EndOfStreamException.cs
+++ b/src/mscorlib/src/System/IO/EndOfStreamException.cs
@@ -17,8 +17,10 @@ using System;
using System.Runtime.Serialization;
namespace System.IO {
+#if FEATURE_SERIALIZATION
[Serializable]
-[System.Runtime.InteropServices.ComVisible(true)]
+#endif
+ [System.Runtime.InteropServices.ComVisible(true)]
public class EndOfStreamException : IOException
{
public EndOfStreamException()
diff --git a/src/mscorlib/src/System/IO/FileLoadException.cs b/src/mscorlib/src/System/IO/FileLoadException.cs
index 60e5ff0e05..7888bef504 100644
--- a/src/mscorlib/src/System/IO/FileLoadException.cs
+++ b/src/mscorlib/src/System/IO/FileLoadException.cs
@@ -26,8 +26,10 @@ using SecurityException = System.Security.SecurityException;
namespace System.IO {
+#if FEATURE_SERIALIZATION
[Serializable]
-[System.Runtime.InteropServices.ComVisible(true)]
+#endif
+ [System.Runtime.InteropServices.ComVisible(true)]
public class FileLoadException : IOException {
private String _fileName; // the name of the file we could not load.
diff --git a/src/mscorlib/src/System/IO/FileNotFoundException.cs b/src/mscorlib/src/System/IO/FileNotFoundException.cs
index 8e24f2fe12..5d23dab3a8 100644
--- a/src/mscorlib/src/System/IO/FileNotFoundException.cs
+++ b/src/mscorlib/src/System/IO/FileNotFoundException.cs
@@ -22,8 +22,10 @@ using System.Globalization;
namespace System.IO {
// Thrown when trying to access a file that doesn't exist on disk.
+#if FEATURE_SERIALIZATION
[Serializable]
-[System.Runtime.InteropServices.ComVisible(true)]
+#endif
+ [System.Runtime.InteropServices.ComVisible(true)]
public class FileNotFoundException : IOException {
private String _fileName; // The name of the file that isn't found.
diff --git a/src/mscorlib/src/System/IO/FileSystemInfo.cs b/src/mscorlib/src/System/IO/FileSystemInfo.cs
index 80cdf71eb2..7a17a417af 100644
--- a/src/mscorlib/src/System/IO/FileSystemInfo.cs
+++ b/src/mscorlib/src/System/IO/FileSystemInfo.cs
@@ -25,12 +25,14 @@ using System.Runtime.Versioning;
using System.Diagnostics.Contracts;
namespace System.IO {
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
#if !FEATURE_CORECLR
[FileIOPermissionAttribute(SecurityAction.InheritanceDemand,Unrestricted=true)]
#endif
[ComVisible(true)]
-#if FEATURE_REMOTING
+#if FEATURE_REMOTING
public abstract class FileSystemInfo : MarshalByRefObject, ISerializable {
#else // FEATURE_REMOTING
public abstract class FileSystemInfo : ISerializable {
@@ -49,7 +51,7 @@ namespace System.IO {
protected String OriginalPath; // path passed in by the user
private String _displayPath = ""; // path that can be displayed to the user
- #if FEATURE_CORECLR
+#if FEATURE_CORECLR
#if FEATURE_CORESYSTEM
[System.Security.SecurityCritical]
#else
@@ -305,11 +307,11 @@ namespace System.IO {
return (FileAttributes) _data.fileAttributes;
}
- #if FEATURE_CORECLR
+#if FEATURE_CORECLR
[System.Security.SecurityCritical] // auto-generated
- #else
+#else
[System.Security.SecuritySafeCritical]
- #endif
+#endif
set {
#if !FEATURE_CORECLR
new FileIOPermission(FileIOPermissionAccess.Write, FullPath).Demand();
diff --git a/src/mscorlib/src/System/IO/IOException.cs b/src/mscorlib/src/System/IO/IOException.cs
index a5b06c5dbe..3cfe3498d3 100644
--- a/src/mscorlib/src/System/IO/IOException.cs
+++ b/src/mscorlib/src/System/IO/IOException.cs
@@ -18,8 +18,10 @@ using System.Runtime.Serialization;
namespace System.IO {
+#if FEATURE_SERIALIZATION
[Serializable]
-[System.Runtime.InteropServices.ComVisible(true)]
+#endif
+ [System.Runtime.InteropServices.ComVisible(true)]
public class IOException : SystemException
{
// For debugging purposes, store the complete path in the IOException
diff --git a/src/mscorlib/src/System/IO/PathTooLongException.cs b/src/mscorlib/src/System/IO/PathTooLongException.cs
index fde4e94d1e..b49b0c962b 100644
--- a/src/mscorlib/src/System/IO/PathTooLongException.cs
+++ b/src/mscorlib/src/System/IO/PathTooLongException.cs
@@ -19,8 +19,10 @@ using System.Runtime.Serialization;
namespace System.IO {
+#if FEATURE_SERIALIZATION
[Serializable]
-[System.Runtime.InteropServices.ComVisible(true)]
+#endif
+ [System.Runtime.InteropServices.ComVisible(true)]
public class PathTooLongException : IOException
{
public PathTooLongException()
diff --git a/src/mscorlib/src/System/IO/Stream.cs b/src/mscorlib/src/System/IO/Stream.cs
index 618e833ec5..3de9492310 100644
--- a/src/mscorlib/src/System/IO/Stream.cs
+++ b/src/mscorlib/src/System/IO/Stream.cs
@@ -116,7 +116,40 @@ namespace System.IO {
[ComVisible(false)]
public Task CopyToAsync(Stream destination)
{
- return CopyToAsync(destination, _DefaultCopyBufferSize);
+ int bufferSize = _DefaultCopyBufferSize;
+
+#if FEATURE_CORECLR
+ if (CanSeek)
+ {
+ long length = Length;
+ long position = Position;
+ if (length <= position) // Handles negative overflows
+ {
+ // If we go down this branch, it means there are
+ // no bytes left in this stream.
+
+ // Ideally we would just return Task.CompletedTask here,
+ // but CopyToAsync(Stream, int, CancellationToken) was already
+ // virtual at the time this optimization was introduced. So
+ // if it does things like argument validation (checking if destination
+ // is null and throwing an exception), then await fooStream.CopyToAsync(null)
+ // would no longer throw if there were no bytes left. On the other hand,
+ // we also can't roll our own argument validation and return Task.CompletedTask,
+ // because it would be a breaking change if the stream's override didn't throw before,
+ // or in a different order. So for simplicity, we just set the bufferSize to 1
+ // (not 0 since the default implementation throws for 0) and forward to the virtual method.
+ bufferSize = 1;
+ }
+ else
+ {
+ long remaining = length - position;
+ if (remaining > 0) // In the case of a positive overflow, stick to the default size
+ bufferSize = (int)Math.Min(bufferSize, remaining);
+ }
+ }
+#endif // FEATURE_CORECLR
+
+ return CopyToAsync(destination, bufferSize);
}
[HostProtection(ExternalThreading = true)]
@@ -155,7 +188,30 @@ namespace System.IO {
// the current position.
public void CopyTo(Stream destination)
{
- CopyTo(destination, _DefaultCopyBufferSize);
+ int bufferSize = _DefaultCopyBufferSize;
+
+#if FEATURE_CORECLR
+ if (CanSeek)
+ {
+ long length = Length;
+ long position = Position;
+ if (length <= position) // Handles negative overflows
+ {
+ // No bytes left in stream
+ // Call the other overload with a bufferSize of 1,
+ // in case it's made virtual in the future
+ bufferSize = 1;
+ }
+ else
+ {
+ long remaining = length - position;
+ if (remaining > 0) // In the case of a positive overflow, stick to the default size
+ bufferSize = (int)Math.Min(bufferSize, remaining);
+ }
+ }
+#endif // FEATURE_CORECLR
+
+ CopyTo(destination, bufferSize);
}
public void CopyTo(Stream destination, int bufferSize)
diff --git a/src/mscorlib/src/System/IndexOutOfRangeException.cs b/src/mscorlib/src/System/IndexOutOfRangeException.cs
index 5e456f8cc4..b03b360deb 100644
--- a/src/mscorlib/src/System/IndexOutOfRangeException.cs
+++ b/src/mscorlib/src/System/IndexOutOfRangeException.cs
@@ -16,7 +16,9 @@ namespace System {
using System;
using System.Runtime.Serialization;
[System.Runtime.InteropServices.ComVisible(true)]
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
public sealed class IndexOutOfRangeException : SystemException {
public IndexOutOfRangeException()
: base(Environment.GetResourceString("Arg_IndexOutOfRangeException")) {
diff --git a/src/mscorlib/src/System/InsufficientExecutionStackException.cs b/src/mscorlib/src/System/InsufficientExecutionStackException.cs
index 6b02f46f29..55a1ca0c14 100644
--- a/src/mscorlib/src/System/InsufficientExecutionStackException.cs
+++ b/src/mscorlib/src/System/InsufficientExecutionStackException.cs
@@ -17,7 +17,9 @@ namespace System {
using System;
using System.Runtime.Serialization;
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
public sealed class InsufficientExecutionStackException : SystemException
{
public InsufficientExecutionStackException()
diff --git a/src/mscorlib/src/System/InsufficientMemoryException.cs b/src/mscorlib/src/System/InsufficientMemoryException.cs
index 448a061821..4dda82fc47 100644
--- a/src/mscorlib/src/System/InsufficientMemoryException.cs
+++ b/src/mscorlib/src/System/InsufficientMemoryException.cs
@@ -21,7 +21,9 @@ namespace System {
using System;
using System.Runtime.Serialization;
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
public sealed class InsufficientMemoryException : OutOfMemoryException
{
public InsufficientMemoryException()
diff --git a/src/mscorlib/src/System/IntPtr.cs b/src/mscorlib/src/System/IntPtr.cs
index df31f34116..9933ad4fb3 100644
--- a/src/mscorlib/src/System/IntPtr.cs
+++ b/src/mscorlib/src/System/IntPtr.cs
@@ -21,10 +21,15 @@ namespace System {
using System.Runtime.ConstrainedExecution;
using System.Security;
using System.Diagnostics.Contracts;
-
+
+#if FEATURE_SERIALIZATION
[Serializable]
-[System.Runtime.InteropServices.ComVisible(true)]
- public struct IntPtr : ISerializable
+#endif
+ [System.Runtime.InteropServices.ComVisible(true)]
+ public struct IntPtr
+#if FEATURE_SERIALIZATION
+ : ISerializable
+#endif
{
[SecurityCritical]
unsafe private void* m_value; // The compiler treats void* closest to uint hence explicit casts are required to preserve int behavior
@@ -45,11 +50,11 @@ namespace System {
[System.Runtime.Versioning.NonVersionable]
public unsafe IntPtr(int value)
{
- #if BIT64
+#if BIT64
m_value = (void *)(long)value;
- #else // !BIT64 (32)
+#else // !BIT64 (32)
m_value = (void *)value;
- #endif
+#endif
}
[System.Security.SecuritySafeCritical] // auto-generated
@@ -57,11 +62,11 @@ namespace System {
[System.Runtime.Versioning.NonVersionable]
public unsafe IntPtr(long value)
{
- #if BIT64
+#if BIT64
m_value = (void *)value;
- #else // !BIT64 (32)
+#else // !BIT64 (32)
m_value = (void *)checked((int)value);
- #endif
+#endif
}
[System.Security.SecurityCritical]
@@ -91,11 +96,11 @@ namespace System {
throw new ArgumentNullException("info");
}
Contract.EndContractBlock();
- #if BIT64
+#if BIT64
info.AddValue("value", (long)(m_value));
- #else // !BIT64 (32)
+#else // !BIT64 (32)
info.AddValue("value", (long)((int)m_value));
- #endif
+#endif
}
#endif
@@ -110,12 +115,12 @@ namespace System {
[System.Security.SecuritySafeCritical] // auto-generated
public unsafe override int GetHashCode() {
#if FEATURE_CORECLR
- #if BIT64
+#if BIT64
long l = (long)m_value;
return (unchecked((int)l) ^ (int)(l >> 32));
- #else // !BIT64 (32)
+#else // !BIT64 (32)
return unchecked((int)m_value);
- #endif
+#endif
#else
return unchecked((int)((long)m_value));
#endif
@@ -125,32 +130,32 @@ namespace System {
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
[System.Runtime.Versioning.NonVersionable]
public unsafe int ToInt32() {
- #if BIT64
+#if BIT64
long l = (long)m_value;
return checked((int)l);
- #else // !BIT64 (32)
+#else // !BIT64 (32)
return (int)m_value;
- #endif
+#endif
}
[System.Security.SecuritySafeCritical] // auto-generated
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
[System.Runtime.Versioning.NonVersionable]
public unsafe long ToInt64() {
- #if BIT64
+#if BIT64
return (long)m_value;
- #else // !BIT64 (32)
+#else // !BIT64 (32)
return (long)(int)m_value;
- #endif
+#endif
}
[System.Security.SecuritySafeCritical] // auto-generated
public unsafe override String ToString() {
- #if BIT64
+#if BIT64
return ((long)m_value).ToString(CultureInfo.InvariantCulture);
- #else // !BIT64 (32)
+#else // !BIT64 (32)
return ((int)m_value).ToString(CultureInfo.InvariantCulture);
- #endif
+#endif
}
[System.Security.SecuritySafeCritical] // auto-generated
@@ -158,11 +163,11 @@ namespace System {
{
Contract.Ensures(Contract.Result<String>() != null);
- #if BIT64
+#if BIT64
return ((long)m_value).ToString(format, CultureInfo.InvariantCulture);
- #else // !BIT64 (32)
+#else // !BIT64 (32)
return ((int)m_value).ToString(format, CultureInfo.InvariantCulture);
- #endif
+#endif
}
@@ -200,23 +205,23 @@ namespace System {
[System.Runtime.Versioning.NonVersionable]
public unsafe static explicit operator int (IntPtr value)
{
- #if BIT64
+#if BIT64
long l = (long)value.m_value;
return checked((int)l);
- #else // !BIT64 (32)
+#else // !BIT64 (32)
return (int)value.m_value;
- #endif
+#endif
}
[System.Security.SecuritySafeCritical] // auto-generated
[System.Runtime.Versioning.NonVersionable]
public unsafe static explicit operator long (IntPtr value)
{
- #if BIT64
+#if BIT64
return (long)value.m_value;
- #else // !BIT64 (32)
+#else // !BIT64 (32)
return (long)(int)value.m_value;
- #endif
+#endif
}
[System.Security.SecuritySafeCritical] // auto-generated
@@ -246,11 +251,11 @@ namespace System {
[System.Runtime.Versioning.NonVersionable]
public static IntPtr operator +(IntPtr pointer, int offset)
{
- #if BIT64
+#if BIT64
return new IntPtr(pointer.ToInt64() + offset);
- #else // !BIT64 (32)
+#else // !BIT64 (32)
return new IntPtr(pointer.ToInt32() + offset);
- #endif
+#endif
}
[ReliabilityContract(Consistency.MayCorruptInstance, Cer.MayFail)]
@@ -262,11 +267,11 @@ namespace System {
[ReliabilityContract(Consistency.MayCorruptInstance, Cer.MayFail)]
[System.Runtime.Versioning.NonVersionable]
public static IntPtr operator -(IntPtr pointer, int offset) {
- #if BIT64
+#if BIT64
return new IntPtr(pointer.ToInt64() - offset);
- #else // !BIT64 (32)
+#else // !BIT64 (32)
return new IntPtr(pointer.ToInt32() - offset);
- #endif
+#endif
}
public static int Size
@@ -276,11 +281,11 @@ namespace System {
[System.Runtime.Versioning.NonVersionable]
get
{
- #if BIT64
+#if BIT64
return 8;
- #else // !BIT64 (32)
+#else // !BIT64 (32)
return 4;
- #endif
+#endif
}
}
diff --git a/src/mscorlib/src/System/InvalidCastException.cs b/src/mscorlib/src/System/InvalidCastException.cs
index 7003574c68..c2c8ad3fcf 100644
--- a/src/mscorlib/src/System/InvalidCastException.cs
+++ b/src/mscorlib/src/System/InvalidCastException.cs
@@ -15,8 +15,10 @@ namespace System {
using System;
using System.Runtime.Serialization;
-[System.Runtime.InteropServices.ComVisible(true)]
+ [System.Runtime.InteropServices.ComVisible(true)]
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
public class InvalidCastException : SystemException {
public InvalidCastException()
: base(Environment.GetResourceString("Arg_InvalidCastException")) {
diff --git a/src/mscorlib/src/System/InvalidOperationException.cs b/src/mscorlib/src/System/InvalidOperationException.cs
index c0cbb4f517..175d9497f8 100644
--- a/src/mscorlib/src/System/InvalidOperationException.cs
+++ b/src/mscorlib/src/System/InvalidOperationException.cs
@@ -15,8 +15,10 @@ namespace System {
using System;
using System.Runtime.Serialization;
-[System.Runtime.InteropServices.ComVisible(true)]
+ [System.Runtime.InteropServices.ComVisible(true)]
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
public class InvalidOperationException : SystemException
{
public InvalidOperationException()
diff --git a/src/mscorlib/src/System/InvalidProgramException.cs b/src/mscorlib/src/System/InvalidProgramException.cs
index 1ec9acde1e..37444bb3db 100644
--- a/src/mscorlib/src/System/InvalidProgramException.cs
+++ b/src/mscorlib/src/System/InvalidProgramException.cs
@@ -15,8 +15,10 @@ namespace System {
using System;
using System.Runtime.Serialization;
+#if FEATURE_SERIALIZATION
[Serializable]
-[System.Runtime.InteropServices.ComVisible(true)]
+#endif
+ [System.Runtime.InteropServices.ComVisible(true)]
public sealed class InvalidProgramException : SystemException {
public InvalidProgramException()
: base(Environment.GetResourceString("InvalidProgram_Default")) {
diff --git a/src/mscorlib/src/System/InvalidTimeZoneException.cs b/src/mscorlib/src/System/InvalidTimeZoneException.cs
index 48e66d9c11..8d41892c63 100644
--- a/src/mscorlib/src/System/InvalidTimeZoneException.cs
+++ b/src/mscorlib/src/System/InvalidTimeZoneException.cs
@@ -6,7 +6,9 @@ namespace System {
using System.Runtime.Serialization;
using System.Runtime.CompilerServices;
- [Serializable]
+#if FEATURE_SERIALIZATION
+ [Serializable]
+#endif
[System.Security.Permissions.HostProtection(MayLeakOnAbort = true)]
[TypeForwardedFrom("System.Core, Version=3.5.0.0, Culture=Neutral, PublicKeyToken=b77a5c561934e089")]
public class InvalidTimeZoneException : Exception {
diff --git a/src/mscorlib/src/System/Lazy.cs b/src/mscorlib/src/System/Lazy.cs
index 43410176b3..903c19c2ad 100644
--- a/src/mscorlib/src/System/Lazy.cs
+++ b/src/mscorlib/src/System/Lazy.cs
@@ -46,7 +46,9 @@ namespace System
/// using parameters to the type's constructors.
/// </para>
/// </remarks>
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
[ComVisible(false)]
#if !FEATURE_CORECLR
[HostProtection(Synchronization = true, ExternalThreading = true)]
@@ -56,7 +58,7 @@ namespace System
public class Lazy<T>
{
- #region Inner classes
+#region Inner classes
/// <summary>
/// wrapper class to box the initialized value, this is mainly created to avoid boxing/unboxing the value each time the value is called in case T is
/// a value type
@@ -83,7 +85,7 @@ namespace System
m_edi = ExceptionDispatchInfo.Capture(ex);
}
}
- #endregion
+#endregion
// A dummy delegate used as a :
// 1- Flag to avoid recursive call to Value in None and ExecutionAndPublication modes in m_valueFactory
@@ -124,6 +126,19 @@ namespace System
}
/// <summary>
+ /// Initializes a new instance of the <see cref="T:System.Threading.Lazy{T}"/> class that
+ /// uses a pre-initialized specified value.
+ /// </summary>
+ /// <remarks>
+ /// An instance created with this constructor should be usable by multiple threads
+ // concurrently.
+ /// </remarks>
+ public Lazy(T value)
+ {
+ m_boxed = new Boxed(value);
+ }
+
+ /// <summary>
/// Initializes a new instance of the <see cref="T:System.Threading.Lazy{T}"/> class that uses a
/// specified initialization function.
/// </summary>
diff --git a/src/mscorlib/src/System/MemberAccessException.cs b/src/mscorlib/src/System/MemberAccessException.cs
index 0b9fabba0c..d915022fc7 100644
--- a/src/mscorlib/src/System/MemberAccessException.cs
+++ b/src/mscorlib/src/System/MemberAccessException.cs
@@ -15,8 +15,10 @@ namespace System {
// The MemberAccessException is thrown when trying to access a class
// member fails.
//
-[System.Runtime.InteropServices.ComVisible(true)]
+ [System.Runtime.InteropServices.ComVisible(true)]
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
public class MemberAccessException : SystemException {
// Creates a new MemberAccessException with its message string set to
diff --git a/src/mscorlib/src/System/MethodAccessException.cs b/src/mscorlib/src/System/MethodAccessException.cs
index f010236e5d..b178868d9b 100644
--- a/src/mscorlib/src/System/MethodAccessException.cs
+++ b/src/mscorlib/src/System/MethodAccessException.cs
@@ -13,8 +13,11 @@ namespace System {
using System;
using System.Runtime.Serialization;
-[System.Runtime.InteropServices.ComVisible(true)]
- [Serializable] public class MethodAccessException : MemberAccessException {
+ [System.Runtime.InteropServices.ComVisible(true)]
+#if FEATURE_SERIALIZATION
+ [Serializable]
+#endif
+ public class MethodAccessException : MemberAccessException {
public MethodAccessException()
: base(Environment.GetResourceString("Arg_MethodAccessException")) {
SetErrorCode(__HResults.COR_E_METHODACCESS);
diff --git a/src/mscorlib/src/System/MissingFieldException.cs b/src/mscorlib/src/System/MissingFieldException.cs
index de1627edef..75e4485abc 100644
--- a/src/mscorlib/src/System/MissingFieldException.cs
+++ b/src/mscorlib/src/System/MissingFieldException.cs
@@ -16,8 +16,10 @@ namespace System {
using System.Runtime.Serialization;
using System.Runtime.CompilerServices;
using System.Globalization;
-[System.Runtime.InteropServices.ComVisible(true)]
+ [System.Runtime.InteropServices.ComVisible(true)]
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
public class MissingFieldException : MissingMemberException, ISerializable {
public MissingFieldException()
: base(Environment.GetResourceString("Arg_MissingFieldException")) {
diff --git a/src/mscorlib/src/System/MissingMemberException.cs b/src/mscorlib/src/System/MissingMemberException.cs
index 30b9e8a723..c58d74eef9 100644
--- a/src/mscorlib/src/System/MissingMemberException.cs
+++ b/src/mscorlib/src/System/MissingMemberException.cs
@@ -23,7 +23,10 @@ namespace System {
using System.Diagnostics.Contracts;
[System.Runtime.InteropServices.ComVisible(true)]
- [Serializable] public class MissingMemberException : MemberAccessException, ISerializable {
+#if FEATURE_SERIALIZATION
+ [Serializable]
+#endif
+ public class MissingMemberException : MemberAccessException, ISerializable {
public MissingMemberException()
: base(Environment.GetResourceString("Arg_MissingMemberException")) {
SetErrorCode(__HResults.COR_E_MISSINGMEMBER);
diff --git a/src/mscorlib/src/System/MissingMethodException.cs b/src/mscorlib/src/System/MissingMethodException.cs
index 2631d73d8d..02e2e9fb90 100644
--- a/src/mscorlib/src/System/MissingMethodException.cs
+++ b/src/mscorlib/src/System/MissingMethodException.cs
@@ -18,8 +18,10 @@ namespace System {
using System.Runtime.Serialization;
using System.Runtime.CompilerServices;
using System.Globalization;
-[System.Runtime.InteropServices.ComVisible(true)]
+ [System.Runtime.InteropServices.ComVisible(true)]
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
public class MissingMethodException : MissingMemberException, ISerializable {
public MissingMethodException()
: base(Environment.GetResourceString("Arg_MissingMethodException")) {
diff --git a/src/mscorlib/src/System/MulticastDelegate.cs b/src/mscorlib/src/System/MulticastDelegate.cs
index f7d864d691..e93ce3dcf2 100644
--- a/src/mscorlib/src/System/MulticastDelegate.cs
+++ b/src/mscorlib/src/System/MulticastDelegate.cs
@@ -11,8 +11,10 @@ namespace System
using System.Runtime.Serialization;
using System.Diagnostics.Contracts;
using System.Reflection.Emit;
-
+
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
[System.Runtime.InteropServices.ComVisible(true)]
public abstract class MulticastDelegate : Delegate
{
diff --git a/src/mscorlib/src/System/MulticastNotSupportedException.cs b/src/mscorlib/src/System/MulticastNotSupportedException.cs
index 5b58db7a5c..dec0c981c0 100644
--- a/src/mscorlib/src/System/MulticastNotSupportedException.cs
+++ b/src/mscorlib/src/System/MulticastNotSupportedException.cs
@@ -11,8 +11,10 @@ namespace System {
using System;
using System.Runtime.Serialization;
-[System.Runtime.InteropServices.ComVisible(true)]
+ [System.Runtime.InteropServices.ComVisible(true)]
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
public sealed class MulticastNotSupportedException : SystemException {
public MulticastNotSupportedException()
diff --git a/src/mscorlib/src/System/NotFiniteNumberException.cs b/src/mscorlib/src/System/NotFiniteNumberException.cs
index 979090d865..f1b622cbff 100644
--- a/src/mscorlib/src/System/NotFiniteNumberException.cs
+++ b/src/mscorlib/src/System/NotFiniteNumberException.cs
@@ -9,8 +9,10 @@ namespace System {
using System.Security.Permissions;
using System.Diagnostics.Contracts;
-[System.Runtime.InteropServices.ComVisible(true)]
+ [System.Runtime.InteropServices.ComVisible(true)]
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
public class NotFiniteNumberException : ArithmeticException {
private double _offendingNumber;
diff --git a/src/mscorlib/src/System/NotImplementedException.cs b/src/mscorlib/src/System/NotImplementedException.cs
index 12f67d458d..ba7df488f1 100644
--- a/src/mscorlib/src/System/NotImplementedException.cs
+++ b/src/mscorlib/src/System/NotImplementedException.cs
@@ -17,8 +17,10 @@ namespace System {
using System;
using System.Runtime.Serialization;
-[System.Runtime.InteropServices.ComVisible(true)]
+ [System.Runtime.InteropServices.ComVisible(true)]
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
public class NotImplementedException : SystemException
{
public NotImplementedException()
diff --git a/src/mscorlib/src/System/NotSupportedException.cs b/src/mscorlib/src/System/NotSupportedException.cs
index 1c30c322c8..0dd1598aff 100644
--- a/src/mscorlib/src/System/NotSupportedException.cs
+++ b/src/mscorlib/src/System/NotSupportedException.cs
@@ -15,8 +15,10 @@ namespace System {
using System;
using System.Runtime.Serialization;
-[System.Runtime.InteropServices.ComVisible(true)]
+ [System.Runtime.InteropServices.ComVisible(true)]
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
public class NotSupportedException : SystemException
{
public NotSupportedException()
diff --git a/src/mscorlib/src/System/NullReferenceException.cs b/src/mscorlib/src/System/NullReferenceException.cs
index 668f8d4c53..20a6b81a25 100644
--- a/src/mscorlib/src/System/NullReferenceException.cs
+++ b/src/mscorlib/src/System/NullReferenceException.cs
@@ -15,8 +15,10 @@ namespace System {
using System;
using System.Runtime.Serialization;
-[System.Runtime.InteropServices.ComVisible(true)]
+ [System.Runtime.InteropServices.ComVisible(true)]
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
public class NullReferenceException : SystemException {
public NullReferenceException()
: base(Environment.GetResourceString("Arg_NullReferenceException")) {
diff --git a/src/mscorlib/src/System/ObjectDisposedException.cs b/src/mscorlib/src/System/ObjectDisposedException.cs
index fdad0f8d52..b731e33147 100644
--- a/src/mscorlib/src/System/ObjectDisposedException.cs
+++ b/src/mscorlib/src/System/ObjectDisposedException.cs
@@ -12,8 +12,10 @@ namespace System {
/// <para> The exception that is thrown when accessing an object that was
/// disposed.</para>
/// </devdoc>
-[System.Runtime.InteropServices.ComVisible(true)]
+ [System.Runtime.InteropServices.ComVisible(true)]
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
public class ObjectDisposedException : InvalidOperationException {
private String objectName;
diff --git a/src/mscorlib/src/System/OperatingSystem.cs b/src/mscorlib/src/System/OperatingSystem.cs
index 6955310acf..32475b2d11 100644
--- a/src/mscorlib/src/System/OperatingSystem.cs
+++ b/src/mscorlib/src/System/OperatingSystem.cs
@@ -19,7 +19,9 @@ namespace System {
[ComVisible(true)]
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
public sealed class OperatingSystem : ICloneable , ISerializable
{
private Version _version;
diff --git a/src/mscorlib/src/System/OperationCanceledException.cs b/src/mscorlib/src/System/OperationCanceledException.cs
index 14781f5653..63f4ee1510 100644
--- a/src/mscorlib/src/System/OperationCanceledException.cs
+++ b/src/mscorlib/src/System/OperationCanceledException.cs
@@ -17,7 +17,9 @@ using System.Threading;
namespace System {
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
[System.Runtime.InteropServices.ComVisible(true)]
public class OperationCanceledException : SystemException
{
diff --git a/src/mscorlib/src/System/OutOfMemoryException.cs b/src/mscorlib/src/System/OutOfMemoryException.cs
index 9bea0b46d7..5c1b6e90f6 100644
--- a/src/mscorlib/src/System/OutOfMemoryException.cs
+++ b/src/mscorlib/src/System/OutOfMemoryException.cs
@@ -17,7 +17,9 @@ namespace System {
using System.Runtime.Serialization;
[System.Runtime.InteropServices.ComVisible(true)]
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
public class OutOfMemoryException : SystemException {
public OutOfMemoryException()
: base(GetMessageFromNativeResources(ExceptionMessageKind.OutOfMemory)) {
diff --git a/src/mscorlib/src/System/OverflowException.cs b/src/mscorlib/src/System/OverflowException.cs
index 7778800571..ed7ebd5703 100644
--- a/src/mscorlib/src/System/OverflowException.cs
+++ b/src/mscorlib/src/System/OverflowException.cs
@@ -16,8 +16,10 @@ namespace System {
using System;
using System.Runtime.Serialization;
-[System.Runtime.InteropServices.ComVisible(true)]
+ [System.Runtime.InteropServices.ComVisible(true)]
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
public class OverflowException : ArithmeticException {
public OverflowException()
: base(Environment.GetResourceString("Arg_OverflowException")) {
diff --git a/src/mscorlib/src/System/PlatformNotSupportedException.cs b/src/mscorlib/src/System/PlatformNotSupportedException.cs
index f8afb416a1..1ab7f155d1 100644
--- a/src/mscorlib/src/System/PlatformNotSupportedException.cs
+++ b/src/mscorlib/src/System/PlatformNotSupportedException.cs
@@ -16,8 +16,10 @@ namespace System {
using System;
using System.Runtime.Serialization;
-[System.Runtime.InteropServices.ComVisible(true)]
+ [System.Runtime.InteropServices.ComVisible(true)]
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
public class PlatformNotSupportedException : NotSupportedException
{
public PlatformNotSupportedException()
diff --git a/src/mscorlib/src/System/RankException.cs b/src/mscorlib/src/System/RankException.cs
index b37b5d260d..27809b08a7 100644
--- a/src/mscorlib/src/System/RankException.cs
+++ b/src/mscorlib/src/System/RankException.cs
@@ -16,8 +16,10 @@ namespace System {
using System;
using System.Runtime.Serialization;
-[System.Runtime.InteropServices.ComVisible(true)]
+ [System.Runtime.InteropServices.ComVisible(true)]
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
public class RankException : SystemException
{
public RankException()
diff --git a/src/mscorlib/src/System/Reflection/AmbiguousMatchException.cs b/src/mscorlib/src/System/Reflection/AmbiguousMatchException.cs
index 13da58d413..59088a18cd 100644
--- a/src/mscorlib/src/System/Reflection/AmbiguousMatchException.cs
+++ b/src/mscorlib/src/System/Reflection/AmbiguousMatchException.cs
@@ -17,8 +17,10 @@ namespace System.Reflection {
using System;
using SystemException = System.SystemException;
using System.Runtime.Serialization;
+#if FEATURE_SERIALIZATION
[Serializable]
-[System.Runtime.InteropServices.ComVisible(true)]
+#endif
+ [System.Runtime.InteropServices.ComVisible(true)]
public sealed class AmbiguousMatchException : SystemException
{
diff --git a/src/mscorlib/src/System/Reflection/Assembly.cs b/src/mscorlib/src/System/Reflection/Assembly.cs
index 1dfe2f8135..b28f8681fc 100644
--- a/src/mscorlib/src/System/Reflection/Assembly.cs
+++ b/src/mscorlib/src/System/Reflection/Assembly.cs
@@ -42,12 +42,16 @@ namespace System.Reflection
using System.Diagnostics.Contracts;
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
[System.Runtime.InteropServices.ComVisible(true)]
public delegate Module ModuleResolveEventHandler(Object sender, ResolveEventArgs e);
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
[ClassInterface(ClassInterfaceType.None)]
[ComDefaultInterface(typeof(_Assembly))]
[System.Runtime.InteropServices.ComVisible(true)]
@@ -56,11 +60,11 @@ namespace System.Reflection
#pragma warning restore 618
public abstract class Assembly : _Assembly, IEvidenceFactory, ICustomAttributeProvider, ISerializable
{
- #region constructors
+#region constructors
protected Assembly() {}
- #endregion
+#endregion
- #region public static methods
+#region public static methods
public static String CreateQualifiedName(String assemblyName, String typeName)
{
@@ -596,9 +600,9 @@ namespace System.Reflection
return domainManager.EntryAssembly;
}
- #endregion // public static methods
+#endregion // public static methods
- #region public methods
+#region public methods
public virtual event ModuleResolveEventHandler ModuleResolve
{
[System.Security.SecurityCritical] // auto-generated_required
@@ -1069,7 +1073,7 @@ namespace System.Reflection
return false;
}
}
- #endregion // public methods
+#endregion // public methods
}
@@ -1089,7 +1093,7 @@ namespace System.Reflection
#endif
{
#if !FEATURE_CORECLR
- #region ICustomQueryInterface
+#region ICustomQueryInterface
[System.Security.SecurityCritical]
CustomQueryInterfaceResult ICustomQueryInterface.GetInterface([In]ref Guid iid, out IntPtr ppv)
{
@@ -1102,7 +1106,7 @@ namespace System.Reflection
ppv = IntPtr.Zero;
return CustomQueryInterfaceResult.NotHandled;
}
- #endregion
+#endregion
#endif // !FEATURE_CORECLR
#if FEATURE_APPX
@@ -1122,7 +1126,7 @@ namespace System.Reflection
internal RuntimeAssembly() { throw new NotSupportedException(); }
- #region private data members
+#region private data members
[method: System.Security.SecurityCritical]
private event ModuleResolveEventHandler _ModuleResolve;
private string m_fullname;
@@ -1132,7 +1136,7 @@ namespace System.Reflection
#if FEATURE_APPX
private ASSEMBLY_FLAGS m_flags;
#endif
- #endregion
+#endregion
#if FEATURE_APPX
internal int InvocableAttributeCtorToken
diff --git a/src/mscorlib/src/System/Reflection/AssemblyName.cs b/src/mscorlib/src/System/Reflection/AssemblyName.cs
index f1d58ba44a..132db90e3c 100644
--- a/src/mscorlib/src/System/Reflection/AssemblyName.cs
+++ b/src/mscorlib/src/System/Reflection/AssemblyName.cs
@@ -25,11 +25,16 @@ namespace System.Reflection {
using System.Runtime.Versioning;
using System.Diagnostics.Contracts;
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
[ClassInterface(ClassInterfaceType.None)]
[ComDefaultInterface(typeof(_AssemblyName))]
-[System.Runtime.InteropServices.ComVisible(true)]
- public sealed class AssemblyName : _AssemblyName, ICloneable, ISerializable, IDeserializationCallback
+ [System.Runtime.InteropServices.ComVisible(true)]
+ public sealed class AssemblyName : _AssemblyName, ICloneable
+#if FEATURE_SERIALIZATION
+ , ISerializable, IDeserializationCallback
+#endif
{
//
// READ ME
@@ -105,13 +110,13 @@ namespace System.Reflection {
public String CodeBase
{
- #if FEATURE_CORECLR
+#if FEATURE_CORECLR
[System.Security.SecurityCritical] // auto-generated
- #endif
+#endif
get { return _CodeBase; }
- #if FEATURE_CORECLR
+#if FEATURE_CORECLR
[System.Security.SecurityCritical] // auto-generated
- #endif
+#endif
set { _CodeBase = value; }
}
@@ -309,7 +314,7 @@ namespace System.Reflection {
info.AddValue("_Name", _Name);
info.AddValue("_PublicKey", _PublicKey, typeof(byte[]));
info.AddValue("_PublicKeyToken", _PublicKeyToken, typeof(byte[]));
-#if FEATURE_USE_LCID
+#if FEATURE_USE_LCID
info.AddValue("_CultureInfo", (_CultureInfo == null) ? -1 :_CultureInfo.LCID);
#endif
info.AddValue("_CodeBase", _CodeBase);
@@ -335,7 +340,7 @@ namespace System.Reflection {
int lcid = (int)m_siInfo.GetInt32("_CultureInfo");
if (lcid != -1)
_CultureInfo = new CultureInfo(lcid);
-#endif
+#endif
_CodeBase = m_siInfo.GetString("_CodeBase");
_Version = (Version) m_siInfo.GetValue("_Version", typeof(Version));
diff --git a/src/mscorlib/src/System/Reflection/ConstructorInfo.cs b/src/mscorlib/src/System/Reflection/ConstructorInfo.cs
index 4d918ed039..d8082f97ed 100644
--- a/src/mscorlib/src/System/Reflection/ConstructorInfo.cs
+++ b/src/mscorlib/src/System/Reflection/ConstructorInfo.cs
@@ -25,7 +25,9 @@ namespace System.Reflection
using RuntimeTypeCache = System.RuntimeType.RuntimeTypeCache;
using System.Runtime.CompilerServices;
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
[ClassInterface(ClassInterfaceType.None)]
[ComDefaultInterface(typeof(_ConstructorInfo))]
#pragma warning disable 618
@@ -156,7 +158,9 @@ namespace System.Reflection
#endif
}
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
internal sealed class RuntimeConstructorInfo : ConstructorInfo, ISerializable, IRuntimeMethodInfo
{
#region Private Data Members
diff --git a/src/mscorlib/src/System/Reflection/CustomAttributeFormatException.cs b/src/mscorlib/src/System/Reflection/CustomAttributeFormatException.cs
index 07d3b81cc5..88bf49a5a0 100644
--- a/src/mscorlib/src/System/Reflection/CustomAttributeFormatException.cs
+++ b/src/mscorlib/src/System/Reflection/CustomAttributeFormatException.cs
@@ -14,8 +14,10 @@ namespace System.Reflection {
using System;
using ApplicationException = System.ApplicationException;
using System.Runtime.Serialization;
+#if FEATURE_SERIALIZATION
[Serializable]
-[System.Runtime.InteropServices.ComVisible(true)]
+#endif
+ [System.Runtime.InteropServices.ComVisible(true)]
public class CustomAttributeFormatException : FormatException {
public CustomAttributeFormatException()
diff --git a/src/mscorlib/src/System/Reflection/Emit/EnumBuilder.cs b/src/mscorlib/src/System/Reflection/Emit/EnumBuilder.cs
index b4a2018b27..f8e3ab2991 100644
--- a/src/mscorlib/src/System/Reflection/Emit/EnumBuilder.cs
+++ b/src/mscorlib/src/System/Reflection/Emit/EnumBuilder.cs
@@ -362,17 +362,17 @@ namespace System.Reflection.Emit {
public override Type MakePointerType()
{
- return SymbolType.FormCompoundType("*".ToCharArray(), this, 0);
+ return SymbolType.FormCompoundType("*", this, 0);
}
public override Type MakeByRefType()
{
- return SymbolType.FormCompoundType("&".ToCharArray(), this, 0);
+ return SymbolType.FormCompoundType("&", this, 0);
}
public override Type MakeArrayType()
{
- return SymbolType.FormCompoundType("[]".ToCharArray(), this, 0);
+ return SymbolType.FormCompoundType("[]", this, 0);
}
public override Type MakeArrayType(int rank)
@@ -392,7 +392,7 @@ namespace System.Reflection.Emit {
}
string s = String.Format(CultureInfo.InvariantCulture, "[{0}]", szrank); // [,,]
- return SymbolType.FormCompoundType((s).ToCharArray(), this, 0);
+ return SymbolType.FormCompoundType(s, this, 0);
}
diff --git a/src/mscorlib/src/System/Reflection/Emit/GenericTypeParameterBuilder.cs b/src/mscorlib/src/System/Reflection/Emit/GenericTypeParameterBuilder.cs
index 81683c5143..bcf70dbe46 100644
--- a/src/mscorlib/src/System/Reflection/Emit/GenericTypeParameterBuilder.cs
+++ b/src/mscorlib/src/System/Reflection/Emit/GenericTypeParameterBuilder.cs
@@ -65,17 +65,17 @@ namespace System.Reflection.Emit
public override Type MakePointerType()
{
- return SymbolType.FormCompoundType("*".ToCharArray(), this, 0);
+ return SymbolType.FormCompoundType("*", this, 0);
}
public override Type MakeByRefType()
{
- return SymbolType.FormCompoundType("&".ToCharArray(), this, 0);
+ return SymbolType.FormCompoundType("&", this, 0);
}
public override Type MakeArrayType()
{
- return SymbolType.FormCompoundType("[]".ToCharArray(), this, 0);
+ return SymbolType.FormCompoundType("[]", this, 0);
}
public override Type MakeArrayType(int rank)
@@ -96,7 +96,7 @@ namespace System.Reflection.Emit
}
string s = String.Format(CultureInfo.InvariantCulture, "[{0}]", szrank); // [,,]
- SymbolType st = SymbolType.FormCompoundType(s.ToCharArray(), this, 0) as SymbolType;
+ SymbolType st = SymbolType.FormCompoundType(s, this, 0) as SymbolType;
return st;
}
diff --git a/src/mscorlib/src/System/Reflection/Emit/ModuleBuilder.cs b/src/mscorlib/src/System/Reflection/Emit/ModuleBuilder.cs
index 05b1956a9a..ce2a592ae2 100644
--- a/src/mscorlib/src/System/Reflection/Emit/ModuleBuilder.cs
+++ b/src/mscorlib/src/System/Reflection/Emit/ModuleBuilder.cs
@@ -142,8 +142,7 @@ namespace System.Reflection.Emit
}
// convert the format string to byte array and then call FormCompoundType
- char[] bFormat = strFormat.ToCharArray();
- return SymbolType.FormCompoundType(bFormat, baseType, 0);
+ return SymbolType.FormCompoundType(strFormat, baseType, 0);
}
diff --git a/src/mscorlib/src/System/Reflection/Emit/SymbolType.cs b/src/mscorlib/src/System/Reflection/Emit/SymbolType.cs
index 6cc7a470c8..633a2bffb4 100644
--- a/src/mscorlib/src/System/Reflection/Emit/SymbolType.cs
+++ b/src/mscorlib/src/System/Reflection/Emit/SymbolType.cs
@@ -29,7 +29,7 @@ namespace System.Reflection.Emit
}
#region Static Members
- internal static Type FormCompoundType(char[] bFormat, Type baseType, int curIndex)
+ internal static Type FormCompoundType(string format, Type baseType, int curIndex)
{
// This function takes a string to describe the compound type, such as "[,][]", and a baseType.
//
@@ -46,7 +46,7 @@ namespace System.Reflection.Emit
int iLowerBound;
int iUpperBound;
- if (bFormat == null || curIndex == bFormat.Length)
+ if (format == null || curIndex == format.Length)
{
// we have consumed all of the format string
return baseType;
@@ -55,15 +55,15 @@ namespace System.Reflection.Emit
- if (bFormat[curIndex] == '&')
+ if (format[curIndex] == '&')
{
// ByRef case
symbolType = new SymbolType(TypeKind.IsByRef);
- symbolType.SetFormat(bFormat, curIndex, 1);
+ symbolType.SetFormat(format, curIndex, 1);
curIndex++;
- if (curIndex != bFormat.Length)
+ if (curIndex != format.Length)
// ByRef has to be the last char!!
throw new ArgumentException(Environment.GetResourceString("Argument_BadSigFormat"));
@@ -71,7 +71,7 @@ namespace System.Reflection.Emit
return symbolType;
}
- if (bFormat[curIndex] == '[')
+ if (format[curIndex] == '[')
{
// Array type.
symbolType = new SymbolType(TypeKind.IsArray);
@@ -85,28 +85,28 @@ namespace System.Reflection.Emit
// Example: [3, 5, 6] - three dimension array with lower bound 3, 5, 6
// Example: [-3, ] [] - one dimensional array of two dimensional array (with lower bound -3 sepcified)
- while (bFormat[curIndex] != ']')
+ while (format[curIndex] != ']')
{
- if (bFormat[curIndex] == '*')
+ if (format[curIndex] == '*')
{
symbolType.m_isSzArray = false;
curIndex++;
}
// consume, one dimension at a time
- if ((bFormat[curIndex] >= '0' && bFormat[curIndex] <= '9') || bFormat[curIndex] == '-')
+ if ((format[curIndex] >= '0' && format[curIndex] <= '9') || format[curIndex] == '-')
{
bool isNegative = false;
- if (bFormat[curIndex] == '-')
+ if (format[curIndex] == '-')
{
isNegative = true;
curIndex++;
}
// lower bound is specified. Consume the low bound
- while (bFormat[curIndex] >= '0' && bFormat[curIndex] <= '9')
+ while (format[curIndex] >= '0' && format[curIndex] <= '9')
{
iLowerBound = iLowerBound * 10;
- iLowerBound += bFormat[curIndex] - '0';
+ iLowerBound += format[curIndex] - '0';
curIndex++;
}
@@ -119,13 +119,13 @@ namespace System.Reflection.Emit
iUpperBound = iLowerBound - 1;
}
- if (bFormat[curIndex] == '.')
+ if (format[curIndex] == '.')
{
// upper bound is specified
// skip over ".."
curIndex++;
- if (bFormat[curIndex] != '.')
+ if (format[curIndex] != '.')
{
// bad format!! Throw exception
throw new ArgumentException(Environment.GetResourceString("Argument_BadSigFormat"));
@@ -133,21 +133,21 @@ namespace System.Reflection.Emit
curIndex++;
// consume the upper bound
- if ((bFormat[curIndex] >= '0' && bFormat[curIndex] <= '9') || bFormat[curIndex] == '-')
+ if ((format[curIndex] >= '0' && format[curIndex] <= '9') || format[curIndex] == '-')
{
bool isNegative = false;
iUpperBound = 0;
- if (bFormat[curIndex] == '-')
+ if (format[curIndex] == '-')
{
isNegative = true;
curIndex++;
}
// lower bound is specified. Consume the low bound
- while (bFormat[curIndex] >= '0' && bFormat[curIndex] <= '9')
+ while (format[curIndex] >= '0' && format[curIndex] <= '9')
{
iUpperBound = iUpperBound * 10;
- iUpperBound += bFormat[curIndex] - '0';
+ iUpperBound += format[curIndex] - '0';
curIndex++;
}
if (isNegative)
@@ -163,7 +163,7 @@ namespace System.Reflection.Emit
}
}
- if (bFormat[curIndex] == ',')
+ if (format[curIndex] == ',')
{
// We have more dimension to deal with.
// now set the lower bound, the size, and increase the dimension count!
@@ -174,7 +174,7 @@ namespace System.Reflection.Emit
iLowerBound = 0;
iUpperBound = -1;
}
- else if (bFormat[curIndex] != ']')
+ else if (format[curIndex] != ']')
{
throw new ArgumentException(Environment.GetResourceString("Argument_BadSigFormat"));
}
@@ -186,21 +186,21 @@ namespace System.Reflection.Emit
// skip over ']'
curIndex++;
- symbolType.SetFormat(bFormat, startIndex, curIndex - startIndex);
+ symbolType.SetFormat(format, startIndex, curIndex - startIndex);
// set the base type of array
symbolType.SetElementType(baseType);
- return FormCompoundType(bFormat, symbolType, curIndex);
+ return FormCompoundType(format, symbolType, curIndex);
}
- else if (bFormat[curIndex] == '*')
+ else if (format[curIndex] == '*')
{
// pointer type.
symbolType = new SymbolType(TypeKind.IsPointer);
- symbolType.SetFormat(bFormat, curIndex, 1);
+ symbolType.SetFormat(format, curIndex, 1);
curIndex++;
symbolType.SetElementType(baseType);
- return FormCompoundType(bFormat, symbolType, curIndex);
+ return FormCompoundType(format, symbolType, curIndex);
}
return null;
@@ -216,7 +216,7 @@ namespace System.Reflection.Emit
// If UpperBound is less than LowerBound, then the size is not specified.
internal int[] m_iaLowerBound;
internal int[] m_iaUpperBound; // count of dimension
- private char[] m_bFormat; // format string to form the full name.
+ private string m_format; // format string to form the full name.
private bool m_isSzArray = true;
#endregion
@@ -262,13 +262,11 @@ namespace System.Reflection.Emit
m_cRank++;
}
- internal void SetFormat(char[] bFormat, int curIndex, int length)
+ internal void SetFormat(string format, int curIndex, int length)
{
// Cache the text display format for this SymbolType
- char[] bFormatTemp = new char[length];
- Array.Copy(bFormat, curIndex, bFormatTemp, 0, length);
- m_bFormat = bFormatTemp;
+ m_format = format.Substring(curIndex, length);
}
#endregion
@@ -286,17 +284,17 @@ namespace System.Reflection.Emit
public override Type MakePointerType()
{
- return SymbolType.FormCompoundType((new String(m_bFormat) + "*").ToCharArray(), m_baseType, 0);
+ return SymbolType.FormCompoundType(m_format + "*", m_baseType, 0);
}
public override Type MakeByRefType()
{
- return SymbolType.FormCompoundType((new String(m_bFormat) + "&").ToCharArray(), m_baseType, 0);
+ return SymbolType.FormCompoundType(m_format + "&", m_baseType, 0);
}
public override Type MakeArrayType()
{
- return SymbolType.FormCompoundType((new String(m_bFormat) + "[]").ToCharArray(), m_baseType, 0);
+ return SymbolType.FormCompoundType(m_format + "[]", m_baseType, 0);
}
public override Type MakeArrayType(int rank)
@@ -317,7 +315,7 @@ namespace System.Reflection.Emit
}
string s = String.Format(CultureInfo.InvariantCulture, "[{0}]", szrank); // [,,]
- SymbolType st = SymbolType.FormCompoundType((new String(m_bFormat) + s).ToCharArray(), m_baseType, 0) as SymbolType;
+ SymbolType st = SymbolType.FormCompoundType(m_format + s, m_baseType, 0) as SymbolType;
return st;
}
@@ -374,10 +372,10 @@ namespace System.Reflection.Emit
get
{
Type baseType;
- String sFormat = new String(m_bFormat);
+ String sFormat = m_format;
for (baseType = m_baseType; baseType is SymbolType; baseType = ((SymbolType)baseType).m_baseType)
- sFormat = new String(((SymbolType)baseType).m_bFormat) + sFormat;
+ sFormat = ((SymbolType)baseType).m_format + sFormat;
return baseType.Name + sFormat;
}
diff --git a/src/mscorlib/src/System/Reflection/Emit/TypeBuilder.cs b/src/mscorlib/src/System/Reflection/Emit/TypeBuilder.cs
index 9861bcb1d4..6db04717b5 100644
--- a/src/mscorlib/src/System/Reflection/Emit/TypeBuilder.cs
+++ b/src/mscorlib/src/System/Reflection/Emit/TypeBuilder.cs
@@ -852,7 +852,7 @@ namespace System.Reflection.Emit {
ThrowIfCreated();
// form the value class name
- strValueClassName = ModuleBuilderData.MULTI_BYTE_VALUE_CLASS + size;
+ strValueClassName = ModuleBuilderData.MULTI_BYTE_VALUE_CLASS + size.ToString();
// Is this already defined in this module?
Type temp = m_module.FindTypeBuilderWithName(strValueClassName, false);
@@ -1442,17 +1442,17 @@ namespace System.Reflection.Emit {
public override Type MakePointerType()
{
- return SymbolType.FormCompoundType("*".ToCharArray(), this, 0);
+ return SymbolType.FormCompoundType("*", this, 0);
}
public override Type MakeByRefType()
{
- return SymbolType.FormCompoundType("&".ToCharArray(), this, 0);
+ return SymbolType.FormCompoundType("&", this, 0);
}
public override Type MakeArrayType()
{
- return SymbolType.FormCompoundType("[]".ToCharArray(), this, 0);
+ return SymbolType.FormCompoundType("[]", this, 0);
}
public override Type MakeArrayType(int rank)
@@ -1473,7 +1473,7 @@ namespace System.Reflection.Emit {
}
string s = String.Format(CultureInfo.InvariantCulture, "[{0}]", szrank); // [,,]
- return SymbolType.FormCompoundType((s).ToCharArray(), this, 0);
+ return SymbolType.FormCompoundType(s, this, 0);
}
#endregion
diff --git a/src/mscorlib/src/System/Reflection/Emit/TypeBuilderInstantiation.cs b/src/mscorlib/src/System/Reflection/Emit/TypeBuilderInstantiation.cs
index dca04f95ec..13b98b6543 100644
--- a/src/mscorlib/src/System/Reflection/Emit/TypeBuilderInstantiation.cs
+++ b/src/mscorlib/src/System/Reflection/Emit/TypeBuilderInstantiation.cs
@@ -79,15 +79,15 @@ namespace System.Reflection.Emit
#region Type Overrides
public override Type MakePointerType()
{
- return SymbolType.FormCompoundType("*".ToCharArray(), this, 0);
+ return SymbolType.FormCompoundType("*", this, 0);
}
public override Type MakeByRefType()
{
- return SymbolType.FormCompoundType("&".ToCharArray(), this, 0);
+ return SymbolType.FormCompoundType("&", this, 0);
}
public override Type MakeArrayType()
{
- return SymbolType.FormCompoundType("[]".ToCharArray(), this, 0);
+ return SymbolType.FormCompoundType("[]", this, 0);
}
public override Type MakeArrayType(int rank)
{
@@ -100,7 +100,7 @@ namespace System.Reflection.Emit
comma += ",";
string s = String.Format(CultureInfo.InvariantCulture, "[{0}]", comma);
- return SymbolType.FormCompoundType(s.ToCharArray(), this, 0);
+ return SymbolType.FormCompoundType(s, this, 0);
}
public override Guid GUID { get { throw new NotSupportedException(); } }
public override Object InvokeMember(String name, BindingFlags invokeAttr, Binder binder, Object target, Object[] args, ParameterModifier[] modifiers, CultureInfo culture, String[] namedParameters) { throw new NotSupportedException(); }
diff --git a/src/mscorlib/src/System/Reflection/EventInfo.cs b/src/mscorlib/src/System/Reflection/EventInfo.cs
index 9f1f5849ff..27c29c4f4c 100644
--- a/src/mscorlib/src/System/Reflection/EventInfo.cs
+++ b/src/mscorlib/src/System/Reflection/EventInfo.cs
@@ -16,7 +16,9 @@ namespace System.Reflection
using System.Security.Permissions;
using RuntimeTypeCache = System.RuntimeType.RuntimeTypeCache;
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
[ClassInterface(ClassInterfaceType.None)]
[ComDefaultInterface(typeof(_EventInfo))]
#pragma warning disable 618
@@ -223,7 +225,9 @@ namespace System.Reflection
#endif
}
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
internal unsafe sealed class RuntimeEventInfo : EventInfo, ISerializable
{
#region Private Data Members
diff --git a/src/mscorlib/src/System/Reflection/FieldInfo.cs b/src/mscorlib/src/System/Reflection/FieldInfo.cs
index 5247c47aae..9a6aeb3851 100644
--- a/src/mscorlib/src/System/Reflection/FieldInfo.cs
+++ b/src/mscorlib/src/System/Reflection/FieldInfo.cs
@@ -23,7 +23,9 @@ namespace System.Reflection
using System.Threading;
using RuntimeTypeCache = System.RuntimeType.RuntimeTypeCache;
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
[ClassInterface(ClassInterfaceType.None)]
[ComDefaultInterface(typeof(_FieldInfo))]
#pragma warning disable 618
@@ -219,7 +221,9 @@ namespace System.Reflection
#endif
}
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
internal abstract class RuntimeFieldInfo : FieldInfo, ISerializable
{
#region Private Data Members
@@ -820,7 +824,9 @@ namespace System.Reflection
#endregion
}
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
internal sealed unsafe class MdFieldInfo : RuntimeFieldInfo, ISerializable
{
#region Private Data Members
diff --git a/src/mscorlib/src/System/Reflection/InvalidFilterCriteriaException.cs b/src/mscorlib/src/System/Reflection/InvalidFilterCriteriaException.cs
index 8662991082..ce344bffc4 100644
--- a/src/mscorlib/src/System/Reflection/InvalidFilterCriteriaException.cs
+++ b/src/mscorlib/src/System/Reflection/InvalidFilterCriteriaException.cs
@@ -17,8 +17,10 @@ namespace System.Reflection {
using System;
using System.Runtime.Serialization;
using ApplicationException = System.ApplicationException;
+#if FEATURE_SERIALIZATION
[Serializable]
-[System.Runtime.InteropServices.ComVisible(true)]
+#endif
+ [System.Runtime.InteropServices.ComVisible(true)]
#if FEATURE_CORECLR
public class InvalidFilterCriteriaException : Exception {
#else
diff --git a/src/mscorlib/src/System/Reflection/MemberFilter.cs b/src/mscorlib/src/System/Reflection/MemberFilter.cs
index 244bba4461..74010e75c4 100644
--- a/src/mscorlib/src/System/Reflection/MemberFilter.cs
+++ b/src/mscorlib/src/System/Reflection/MemberFilter.cs
@@ -11,9 +11,11 @@
//
//
namespace System.Reflection {
-
+
// Define the delegate
+#if FEATURE_SERIALIZATION
[Serializable]
-[System.Runtime.InteropServices.ComVisible(true)]
+#endif
+ [System.Runtime.InteropServices.ComVisible(true)]
public delegate bool MemberFilter(MemberInfo m, Object filterCriteria);
}
diff --git a/src/mscorlib/src/System/Reflection/MemberInfoSerializationHolder.cs b/src/mscorlib/src/System/Reflection/MemberInfoSerializationHolder.cs
index 65c203c26b..ef34a38196 100644
--- a/src/mscorlib/src/System/Reflection/MemberInfoSerializationHolder.cs
+++ b/src/mscorlib/src/System/Reflection/MemberInfoSerializationHolder.cs
@@ -11,8 +11,10 @@ using System.Globalization;
using System.Diagnostics.Contracts;
namespace System.Reflection
-{
+{
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
internal class MemberInfoSerializationHolder : ISerializable, IObjectReference
{
#region Staitc Public Members
diff --git a/src/mscorlib/src/System/Reflection/MethodInfo.cs b/src/mscorlib/src/System/Reflection/MethodInfo.cs
index b5c022aa17..aa054bd00f 100644
--- a/src/mscorlib/src/System/Reflection/MethodInfo.cs
+++ b/src/mscorlib/src/System/Reflection/MethodInfo.cs
@@ -124,7 +124,9 @@ namespace System.Reflection
#endif
}
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
internal sealed class RuntimeMethodInfo : MethodInfo, ISerializable, IRuntimeMethodInfo
{
#region Private Data Members
diff --git a/src/mscorlib/src/System/Reflection/Missing.cs b/src/mscorlib/src/System/Reflection/Missing.cs
index ca8e00cd14..7b539b3938 100644
--- a/src/mscorlib/src/System/Reflection/Missing.cs
+++ b/src/mscorlib/src/System/Reflection/Missing.cs
@@ -13,9 +13,14 @@ namespace System.Reflection
using System.Diagnostics.Contracts;
// This is not serializable because it is a reflection command.
+#if FEATURE_SERIALIZATION
[Serializable]
-[System.Runtime.InteropServices.ComVisible(true)]
- public sealed class Missing: ISerializable
+#endif
+ [System.Runtime.InteropServices.ComVisible(true)]
+ public sealed class Missing
+#if FEATURE_SERIALIZATION
+ : ISerializable
+#endif
{
public static readonly Missing Value = new Missing();
diff --git a/src/mscorlib/src/System/Reflection/Module.cs b/src/mscorlib/src/System/Reflection/Module.cs
index 54205517b6..11ccfc5d21 100644
--- a/src/mscorlib/src/System/Reflection/Module.cs
+++ b/src/mscorlib/src/System/Reflection/Module.cs
@@ -55,7 +55,9 @@ namespace System.Reflection
ARM = 0x01c4,
}
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
[ClassInterface(ClassInterfaceType.None)]
[ComDefaultInterface(typeof(_Module))]
[System.Runtime.InteropServices.ComVisible(true)]
diff --git a/src/mscorlib/src/System/Reflection/ParameterInfo.cs b/src/mscorlib/src/System/Reflection/ParameterInfo.cs
index 6ab0321f66..9163933b4d 100644
--- a/src/mscorlib/src/System/Reflection/ParameterInfo.cs
+++ b/src/mscorlib/src/System/Reflection/ParameterInfo.cs
@@ -259,7 +259,9 @@ namespace System.Reflection
#endregion
}
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
internal unsafe sealed class RuntimeParameterInfo : ParameterInfo, ISerializable
{
#region Static Members
diff --git a/src/mscorlib/src/System/Reflection/Pointer.cs b/src/mscorlib/src/System/Reflection/Pointer.cs
index d7a7a889b0..dcd1f44d89 100644
--- a/src/mscorlib/src/System/Reflection/Pointer.cs
+++ b/src/mscorlib/src/System/Reflection/Pointer.cs
@@ -18,10 +18,16 @@ namespace System.Reflection {
using System.Diagnostics.Contracts;
[CLSCompliant(false)]
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
[System.Runtime.InteropServices.ComVisible(true)]
- public sealed class Pointer: ISerializable {
- [SecurityCritical]
+ public sealed class Pointer
+#if FEATURE_SERIALIZATION
+ : ISerializable
+#endif
+ {
+ [SecurityCritical]
unsafe private void* _ptr;
private RuntimeType _ptrType;
diff --git a/src/mscorlib/src/System/Reflection/PropertyInfo.cs b/src/mscorlib/src/System/Reflection/PropertyInfo.cs
index 30e375c0d8..50d02a9f01 100644
--- a/src/mscorlib/src/System/Reflection/PropertyInfo.cs
+++ b/src/mscorlib/src/System/Reflection/PropertyInfo.cs
@@ -186,7 +186,9 @@ namespace System.Reflection
#endif
}
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
internal unsafe sealed class RuntimePropertyInfo : PropertyInfo, ISerializable
{
#region Private Data Members
diff --git a/src/mscorlib/src/System/Reflection/ReflectionTypeLoadException.cs b/src/mscorlib/src/System/Reflection/ReflectionTypeLoadException.cs
index 7786a65c72..33abb08161 100644
--- a/src/mscorlib/src/System/Reflection/ReflectionTypeLoadException.cs
+++ b/src/mscorlib/src/System/Reflection/ReflectionTypeLoadException.cs
@@ -21,8 +21,10 @@ namespace System.Reflection {
using System.Runtime.Serialization;
using System.Security.Permissions;
using System.Diagnostics.Contracts;
+#if FEATURE_SERIALIZATION
[Serializable]
-[System.Runtime.InteropServices.ComVisible(true)]
+#endif
+ [System.Runtime.InteropServices.ComVisible(true)]
public sealed class ReflectionTypeLoadException : SystemException, ISerializable {
private Type[] _classes;
private Exception[] _exceptions;
diff --git a/src/mscorlib/src/System/Reflection/StrongNameKeyPair.cs b/src/mscorlib/src/System/Reflection/StrongNameKeyPair.cs
index ad503bc0f8..9f7849bf9a 100644
--- a/src/mscorlib/src/System/Reflection/StrongNameKeyPair.cs
+++ b/src/mscorlib/src/System/Reflection/StrongNameKeyPair.cs
@@ -40,8 +40,10 @@ namespace System.Reflection
}
}
#else
+#if FEATURE_SERIALIZATION
[Serializable]
-[System.Runtime.InteropServices.ComVisible(true)]
+#endif
+ [System.Runtime.InteropServices.ComVisible(true)]
public class StrongNameKeyPair : IDeserializationCallback, ISerializable
{
private bool _keyPairExported;
diff --git a/src/mscorlib/src/System/Reflection/TargetException.cs b/src/mscorlib/src/System/Reflection/TargetException.cs
index 57ce2b077f..32e07b49f1 100644
--- a/src/mscorlib/src/System/Reflection/TargetException.cs
+++ b/src/mscorlib/src/System/Reflection/TargetException.cs
@@ -17,8 +17,10 @@ namespace System.Reflection {
using System;
using System.Runtime.Serialization;
+#if FEATURE_SERIALIZATION
[Serializable]
-[System.Runtime.InteropServices.ComVisible(true)]
+#endif
+ [System.Runtime.InteropServices.ComVisible(true)]
#if FEATURE_CORECLR
public class TargetException : Exception {
#else
diff --git a/src/mscorlib/src/System/Reflection/TargetInvocationException.cs b/src/mscorlib/src/System/Reflection/TargetInvocationException.cs
index 25fe919115..5296420c28 100644
--- a/src/mscorlib/src/System/Reflection/TargetInvocationException.cs
+++ b/src/mscorlib/src/System/Reflection/TargetInvocationException.cs
@@ -17,8 +17,10 @@ namespace System.Reflection {
using System;
using System.Runtime.Serialization;
+#if FEATURE_SERIALIZATION
[Serializable]
-[System.Runtime.InteropServices.ComVisible(true)]
+#endif
+ [System.Runtime.InteropServices.ComVisible(true)]
#if FEATURE_CORECLR
public sealed class TargetInvocationException : Exception {
#else
diff --git a/src/mscorlib/src/System/Reflection/TargetParameterCountException.cs b/src/mscorlib/src/System/Reflection/TargetParameterCountException.cs
index b7719a8428..7b6101739f 100644
--- a/src/mscorlib/src/System/Reflection/TargetParameterCountException.cs
+++ b/src/mscorlib/src/System/Reflection/TargetParameterCountException.cs
@@ -17,8 +17,10 @@ namespace System.Reflection {
using System;
using SystemException = System.SystemException;
using System.Runtime.Serialization;
+#if FEATURE_SERIALIZATION
[Serializable]
-[System.Runtime.InteropServices.ComVisible(true)]
+#endif
+ [System.Runtime.InteropServices.ComVisible(true)]
#if FEATURE_CORECLR
public sealed class TargetParameterCountException : Exception {
#else
diff --git a/src/mscorlib/src/System/Reflection/TypeFilter.cs b/src/mscorlib/src/System/Reflection/TypeFilter.cs
index b6d0729402..753b9a7fc1 100644
--- a/src/mscorlib/src/System/Reflection/TypeFilter.cs
+++ b/src/mscorlib/src/System/Reflection/TypeFilter.cs
@@ -11,9 +11,11 @@
//
//
namespace System.Reflection {
-
+
// Define the delegate
+#if FEATURE_SERIALIZATION
[Serializable]
-[System.Runtime.InteropServices.ComVisible(true)]
+#endif
+ [System.Runtime.InteropServices.ComVisible(true)]
public delegate bool TypeFilter(Type m, Object filterCriteria);
}
diff --git a/src/mscorlib/src/System/Resources/MissingManifestResourceException.cs b/src/mscorlib/src/System/Resources/MissingManifestResourceException.cs
index bb42413c54..30c01f8560 100644
--- a/src/mscorlib/src/System/Resources/MissingManifestResourceException.cs
+++ b/src/mscorlib/src/System/Resources/MissingManifestResourceException.cs
@@ -17,8 +17,10 @@ using System;
using System.Runtime.Serialization;
namespace System.Resources {
+#if FEATURE_SERIALIZATION
[Serializable]
-[System.Runtime.InteropServices.ComVisible(true)]
+#endif
+ [System.Runtime.InteropServices.ComVisible(true)]
public class MissingManifestResourceException : SystemException
{
public MissingManifestResourceException()
diff --git a/src/mscorlib/src/System/Resources/MissingSatelliteAssemblyException.cs b/src/mscorlib/src/System/Resources/MissingSatelliteAssemblyException.cs
index 48827412f0..95f195a02c 100644
--- a/src/mscorlib/src/System/Resources/MissingSatelliteAssemblyException.cs
+++ b/src/mscorlib/src/System/Resources/MissingSatelliteAssemblyException.cs
@@ -19,8 +19,10 @@ using System;
using System.Runtime.Serialization;
namespace System.Resources {
+#if FEATURE_SERIALIZATION
[Serializable]
-[System.Runtime.InteropServices.ComVisible(true)]
+#endif
+ [System.Runtime.InteropServices.ComVisible(true)]
public class MissingSatelliteAssemblyException : SystemException
{
private String _cultureName;
diff --git a/src/mscorlib/src/System/Resources/ResourceManager.cs b/src/mscorlib/src/System/Resources/ResourceManager.cs
index b088e7f492..e60e9cc8c9 100644
--- a/src/mscorlib/src/System/Resources/ResourceManager.cs
+++ b/src/mscorlib/src/System/Resources/ResourceManager.cs
@@ -155,7 +155,9 @@ namespace System.Resources {
// is one such example.
//
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
[System.Runtime.InteropServices.ComVisible(true)]
public class ResourceManager
{
diff --git a/src/mscorlib/src/System/RtType.cs b/src/mscorlib/src/System/RtType.cs
index bc1032244b..b6c52b2d6e 100644
--- a/src/mscorlib/src/System/RtType.cs
+++ b/src/mscorlib/src/System/RtType.cs
@@ -79,7 +79,9 @@ namespace System
FullName,
}
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
internal class RuntimeType :
System.Reflection.TypeInfo, ISerializable, ICloneable
{
@@ -5571,7 +5573,9 @@ namespace System
// method (RuntimeType) and an instance of this type will work around the reason to have this type in the
// first place. However given RuntimeType is not public all its methods are protected and require full trust
// to be accessed
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
internal class ReflectionOnlyType : RuntimeType {
private ReflectionOnlyType() {}
diff --git a/src/mscorlib/src/System/Runtime/InteropServices/COMException.cs b/src/mscorlib/src/System/Runtime/InteropServices/COMException.cs
index 95b925c3f4..35157c64a8 100644
--- a/src/mscorlib/src/System/Runtime/InteropServices/COMException.cs
+++ b/src/mscorlib/src/System/Runtime/InteropServices/COMException.cs
@@ -22,7 +22,9 @@ namespace System.Runtime.InteropServices {
// Exception for COM Interop errors where we don't recognize the HResult.
//
[ComVisible(true)]
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
public class COMException : ExternalException {
public COMException()
: base(Environment.GetResourceString("Arg_COMException"))
diff --git a/src/mscorlib/src/System/Runtime/InteropServices/ExternalException.cs b/src/mscorlib/src/System/Runtime/InteropServices/ExternalException.cs
index 31713f8e7c..6e66bca565 100644
--- a/src/mscorlib/src/System/Runtime/InteropServices/ExternalException.cs
+++ b/src/mscorlib/src/System/Runtime/InteropServices/ExternalException.cs
@@ -20,8 +20,10 @@ namespace System.Runtime.InteropServices {
// Base exception for COM Interop errors &; Structured Exception Handler
// exceptions.
//
-[System.Runtime.InteropServices.ComVisible(true)]
+ [System.Runtime.InteropServices.ComVisible(true)]
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
public class ExternalException : SystemException {
public ExternalException()
: base(Environment.GetResourceString("Arg_ExternalException")) {
diff --git a/src/mscorlib/src/System/Runtime/InteropServices/InvalidComObjectException.cs b/src/mscorlib/src/System/Runtime/InteropServices/InvalidComObjectException.cs
index 8a8da03de7..16f6cc9200 100644
--- a/src/mscorlib/src/System/Runtime/InteropServices/InvalidComObjectException.cs
+++ b/src/mscorlib/src/System/Runtime/InteropServices/InvalidComObjectException.cs
@@ -16,8 +16,10 @@ namespace System.Runtime.InteropServices {
using System;
using System.Runtime.Serialization;
-[System.Runtime.InteropServices.ComVisible(true)]
+ [System.Runtime.InteropServices.ComVisible(true)]
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
public class InvalidComObjectException : SystemException {
public InvalidComObjectException()
: base(Environment.GetResourceString("Arg_InvalidComObjectException")) {
diff --git a/src/mscorlib/src/System/Runtime/InteropServices/InvalidOleVariantTypeException.cs b/src/mscorlib/src/System/Runtime/InteropServices/InvalidOleVariantTypeException.cs
index b69a67b532..92a2026d45 100644
--- a/src/mscorlib/src/System/Runtime/InteropServices/InvalidOleVariantTypeException.cs
+++ b/src/mscorlib/src/System/Runtime/InteropServices/InvalidOleVariantTypeException.cs
@@ -15,8 +15,11 @@ namespace System.Runtime.InteropServices {
using System;
using System.Runtime.Serialization;
-[System.Runtime.InteropServices.ComVisible(true)]
- [Serializable] public class InvalidOleVariantTypeException : SystemException {
+ [System.Runtime.InteropServices.ComVisible(true)]
+#if FEATURE_SERIALIZATION
+ [Serializable]
+#endif
+ public class InvalidOleVariantTypeException : SystemException {
public InvalidOleVariantTypeException()
: base(Environment.GetResourceString("Arg_InvalidOleVariantTypeException")) {
SetErrorCode(__HResults.COR_E_INVALIDOLEVARIANTTYPE);
diff --git a/src/mscorlib/src/System/Runtime/InteropServices/MarshalDirectiveException.cs b/src/mscorlib/src/System/Runtime/InteropServices/MarshalDirectiveException.cs
index 3c2b5ae1a4..a0ddd4c545 100644
--- a/src/mscorlib/src/System/Runtime/InteropServices/MarshalDirectiveException.cs
+++ b/src/mscorlib/src/System/Runtime/InteropServices/MarshalDirectiveException.cs
@@ -16,8 +16,10 @@ namespace System.Runtime.InteropServices {
using System;
using System.Runtime.Serialization;
-[System.Runtime.InteropServices.ComVisible(true)]
+ [System.Runtime.InteropServices.ComVisible(true)]
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
public class MarshalDirectiveException : SystemException {
public MarshalDirectiveException()
: base(Environment.GetResourceString("Arg_MarshalDirectiveException")) {
diff --git a/src/mscorlib/src/System/Runtime/InteropServices/SEHException.cs b/src/mscorlib/src/System/Runtime/InteropServices/SEHException.cs
index bd7bc93c57..28c3522737 100644
--- a/src/mscorlib/src/System/Runtime/InteropServices/SEHException.cs
+++ b/src/mscorlib/src/System/Runtime/InteropServices/SEHException.cs
@@ -17,8 +17,10 @@ namespace System.Runtime.InteropServices {
using System.Runtime.Serialization;
// Exception for Structured Exception Handler exceptions.
//
-[System.Runtime.InteropServices.ComVisible(true)]
+ [System.Runtime.InteropServices.ComVisible(true)]
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
public class SEHException : ExternalException {
public SEHException()
: base() {
diff --git a/src/mscorlib/src/System/Runtime/InteropServices/SafeArrayRankMismatchException.cs b/src/mscorlib/src/System/Runtime/InteropServices/SafeArrayRankMismatchException.cs
index 79d3cbfc8f..90f7639a87 100644
--- a/src/mscorlib/src/System/Runtime/InteropServices/SafeArrayRankMismatchException.cs
+++ b/src/mscorlib/src/System/Runtime/InteropServices/SafeArrayRankMismatchException.cs
@@ -15,8 +15,11 @@ namespace System.Runtime.InteropServices {
using System;
using System.Runtime.Serialization;
-[System.Runtime.InteropServices.ComVisible(true)]
- [Serializable] public class SafeArrayRankMismatchException : SystemException {
+ [System.Runtime.InteropServices.ComVisible(true)]
+#if FEATURE_SERIALIZATION
+ [Serializable]
+#endif
+ public class SafeArrayRankMismatchException : SystemException {
public SafeArrayRankMismatchException()
: base(Environment.GetResourceString("Arg_SafeArrayRankMismatchException")) {
SetErrorCode(__HResults.COR_E_SAFEARRAYRANKMISMATCH);
diff --git a/src/mscorlib/src/System/Runtime/InteropServices/SafeArrayTypeMismatchException.cs b/src/mscorlib/src/System/Runtime/InteropServices/SafeArrayTypeMismatchException.cs
index 7c061b8854..9f9f25559e 100644
--- a/src/mscorlib/src/System/Runtime/InteropServices/SafeArrayTypeMismatchException.cs
+++ b/src/mscorlib/src/System/Runtime/InteropServices/SafeArrayTypeMismatchException.cs
@@ -16,8 +16,11 @@ namespace System.Runtime.InteropServices {
using System;
using System.Runtime.Serialization;
-[System.Runtime.InteropServices.ComVisible(true)]
- [Serializable] public class SafeArrayTypeMismatchException : SystemException {
+ [System.Runtime.InteropServices.ComVisible(true)]
+#if FEATURE_SERIALIZATION
+ [Serializable]
+#endif
+ public class SafeArrayTypeMismatchException : SystemException {
public SafeArrayTypeMismatchException()
: base(Environment.GetResourceString("Arg_SafeArrayTypeMismatchException")) {
SetErrorCode(__HResults.COR_E_SAFEARRAYTYPEMISMATCH);
diff --git a/src/mscorlib/src/System/Runtime/Serialization/IDeserializationCallback.cs b/src/mscorlib/src/System/Runtime/Serialization/IDeserializationCallback.cs
index d13c46f991..e2497e5d34 100644
--- a/src/mscorlib/src/System/Runtime/Serialization/IDeserializationCallback.cs
+++ b/src/mscorlib/src/System/Runtime/Serialization/IDeserializationCallback.cs
@@ -18,9 +18,6 @@ namespace System.Runtime.Serialization {
// Interface does not need to be marked with the serializable attribute
[System.Runtime.InteropServices.ComVisible(true)]
public interface IDeserializationCallback {
-#if FEATURE_SERIALIZATION
void OnDeserialization(Object sender);
-#endif
-
}
}
diff --git a/src/mscorlib/src/System/Runtime/Serialization/ISerializable.cs b/src/mscorlib/src/System/Runtime/Serialization/ISerializable.cs
index 006b7fd501..e59fa65043 100644
--- a/src/mscorlib/src/System/Runtime/Serialization/ISerializable.cs
+++ b/src/mscorlib/src/System/Runtime/Serialization/ISerializable.cs
@@ -22,10 +22,8 @@ namespace System.Runtime.Serialization {
[System.Runtime.InteropServices.ComVisible(true)]
public interface ISerializable {
-#if FEATURE_SERIALIZATION
[System.Security.SecurityCritical] // auto-generated_required
void GetObjectData(SerializationInfo info, StreamingContext context);
-#endif
}
}
diff --git a/src/mscorlib/src/System/Runtime/Serialization/SerializationException.cs b/src/mscorlib/src/System/Runtime/Serialization/SerializationException.cs
index f2341699fc..6bb11b67bf 100644
--- a/src/mscorlib/src/System/Runtime/Serialization/SerializationException.cs
+++ b/src/mscorlib/src/System/Runtime/Serialization/SerializationException.cs
@@ -17,8 +17,11 @@ namespace System.Runtime.Serialization {
using System;
using System.Runtime.Serialization;
-[System.Runtime.InteropServices.ComVisible(true)]
- [Serializable] public class SerializationException : SystemException {
+ [System.Runtime.InteropServices.ComVisible(true)]
+#if FEATURE_SERIALIZATION
+ [Serializable]
+#endif
+ public class SerializationException : SystemException {
private static String _nullMessage = Environment.GetResourceString("Arg_SerializationException");
diff --git a/src/mscorlib/src/System/Runtime/Serialization/SerializationInfo.cs b/src/mscorlib/src/System/Runtime/Serialization/SerializationInfo.cs
index 04c1094fbc..a009033180 100644
--- a/src/mscorlib/src/System/Runtime/Serialization/SerializationInfo.cs
+++ b/src/mscorlib/src/System/Runtime/Serialization/SerializationInfo.cs
@@ -173,10 +173,12 @@ namespace System.Runtime.Serialization
[SecuritySafeCritical]
internal static void DemandForUnsafeAssemblyNameAssignments(string originalAssemblyName, string newAssemblyName)
{
+#if !FEATURE_CORECLR
if (!IsAssemblyNameAssignmentSafe(originalAssemblyName, newAssemblyName))
{
CodeAccessPermission.Demand(PermissionType.SecuritySerialization);
}
+#endif
}
internal static bool IsAssemblyNameAssignmentSafe(string originalAssemblyName, string newAssemblyName)
diff --git a/src/mscorlib/src/System/RuntimeHandles.cs b/src/mscorlib/src/System/RuntimeHandles.cs
index 7d4628ae74..34683be98a 100644
--- a/src/mscorlib/src/System/RuntimeHandles.cs
+++ b/src/mscorlib/src/System/RuntimeHandles.cs
@@ -23,8 +23,10 @@ namespace System
using Microsoft.Win32.SafeHandles;
using System.Diagnostics.Contracts;
using StackCrawlMark = System.Threading.StackCrawlMark;
-
- [Serializable()]
+
+#if FEATURE_SERIALIZATION
+ [Serializable]
+#endif
[System.Runtime.InteropServices.ComVisible(true)]
public unsafe struct RuntimeTypeHandle : ISerializable
{
@@ -690,9 +692,9 @@ namespace System
[SuppressUnmanagedCodeSecurity]
internal extern static bool IsCollectible(RuntimeTypeHandle handle);
- #if FEATURE_CORECLR
+#if FEATURE_CORECLR
[System.Security.SecuritySafeCritical] // auto-generated
- #endif
+#endif
[MethodImplAttribute(MethodImplOptions.InternalCall)]
internal extern static bool HasInstantiation(RuntimeType type);
@@ -916,9 +918,11 @@ namespace System
{
get;
}
- }
+ }
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
[System.Runtime.InteropServices.ComVisible(true)]
public unsafe struct RuntimeMethodHandle : ISerializable
{
@@ -1163,7 +1167,7 @@ namespace System
[MethodImplAttribute(MethodImplOptions.InternalCall)]
internal extern static object InvokeMethod(object target, object[] arguments, Signature sig, bool constructor);
- #region Private Invocation Helpers
+#region Private Invocation Helpers
[System.Security.SecurityCritical] // auto-generated
internal static INVOCATION_FLAGS GetSecurityFlags(IRuntimeMethodInfo handle)
{
@@ -1187,7 +1191,7 @@ namespace System
return;
}
#endif //!FEATURE_CORECLR
- #endregion
+#endregion
[System.Security.SecuritySafeCritical] // auto-generated
[DebuggerStepThroughAttribute]
@@ -1202,11 +1206,11 @@ namespace System
[MethodImplAttribute(MethodImplOptions.InternalCall)]
internal static extern bool _IsTokenSecurityTransparent(RuntimeModule module, int metaDataToken);
- #if FEATURE_CORECLR
+#if FEATURE_CORECLR
[System.Security.SecuritySafeCritical] // auto-generated
- #else
+#else
[System.Security.SecurityCritical]
- #endif
+#endif
internal static bool IsTokenSecurityTransparent(Module module, int metaDataToken)
{
return _IsTokenSecurityTransparent(module.ModuleHandle.GetRuntimeModule(), metaDataToken);
@@ -1466,8 +1470,10 @@ namespace System
}
}
+#if FEATURE_SERIALIZATION
[Serializable]
-[System.Runtime.InteropServices.ComVisible(true)]
+#endif
+ [System.Runtime.InteropServices.ComVisible(true)]
public unsafe struct RuntimeFieldHandle : ISerializable
{
// Returns handle for interop with EE. The handle is guaranteed to be non-null.
@@ -1680,27 +1686,27 @@ namespace System
public unsafe struct ModuleHandle
{
// Returns handle for interop with EE. The handle is guaranteed to be non-null.
- #region Public Static Members
+#region Public Static Members
public static readonly ModuleHandle EmptyHandle = GetEmptyMH();
- #endregion
+#endregion
unsafe static private ModuleHandle GetEmptyMH()
{
return new ModuleHandle();
}
- #region Private Data Members
+#region Private Data Members
private RuntimeModule m_ptr;
- #endregion
+#endregion
- #region Constructor
+#region Constructor
internal ModuleHandle(RuntimeModule module)
{
m_ptr = module;
}
- #endregion
+#endregion
- #region Internal FCalls
+#region Internal FCalls
internal RuntimeModule GetRuntimeModule()
{
@@ -1962,12 +1968,12 @@ namespace System
{
return new MetadataImport(_GetMetadataImport(module.GetNativeHandle()), module);
}
- #endregion
+#endregion
}
internal unsafe class Signature
{
- #region Definitions
+#region Definitions
internal enum MdSigCallingConvention : byte
{
Generics = 0x10,
@@ -1987,18 +1993,18 @@ namespace System
GenericInst = 0x0A,
Max = 0x0B,
}
- #endregion
+#endregion
- #region FCalls
+#region FCalls
[System.Security.SecurityCritical] // auto-generated
[MethodImplAttribute(MethodImplOptions.InternalCall)]
private extern void GetSignature(
void* pCorSig, int cCorSig,
RuntimeFieldHandleInternal fieldHandle, IRuntimeMethodInfo methodHandle, RuntimeType declaringType);
- #endregion
+#endregion
- #region Private Data Members
+#region Private Data Members
//
// Keep the layout in sync with SignatureNative in the VM
//
@@ -2012,9 +2018,9 @@ namespace System
internal int m_nSizeOfArgStack;
internal int m_csig;
internal RuntimeMethodHandleInternal m_pMethod;
- #endregion
+#endregion
- #region Constructors
+#region Constructors
[System.Security.SecuritySafeCritical] // auto-generated
public Signature (
IRuntimeMethodInfo method,
@@ -2048,9 +2054,9 @@ namespace System
{
GetSignature(pCorSig, cCorSig, new RuntimeFieldHandleInternal(), null, declaringType);
}
- #endregion
+#endregion
- #region Internal Members
+#region Internal Members
internal CallingConventions CallingConvention { get { return (CallingConventions)(byte)m_managedCallingConventionAndArgIteratorFlags; } }
internal RuntimeType[] Arguments { get { return m_arguments; } }
internal RuntimeType ReturnType { get { return m_returnTypeORfieldType; } }
@@ -2063,7 +2069,7 @@ namespace System
[System.Security.SecuritySafeCritical]
[MethodImplAttribute(MethodImplOptions.InternalCall)]
internal extern Type[] GetCustomModifiers(int position, bool required);
- #endregion
+#endregion
}
diff --git a/src/mscorlib/src/System/Security/HostProtectionException.cs b/src/mscorlib/src/System/Security/HostProtectionException.cs
index c767411d22..0b69d59f15 100644
--- a/src/mscorlib/src/System/Security/HostProtectionException.cs
+++ b/src/mscorlib/src/System/Security/HostProtectionException.cs
@@ -23,7 +23,10 @@ namespace System.Security
using System.Diagnostics.Contracts;
[System.Runtime.InteropServices.ComVisible(true)]
- [Serializable] public class HostProtectionException : SystemException
+#if FEATURE_SERIALIZATION
+ [Serializable]
+#endif
+ public class HostProtectionException : SystemException
{
private HostProtectionResource m_protected;
private HostProtectionResource m_demanded;
diff --git a/src/mscorlib/src/System/Security/PermissionSet.cs b/src/mscorlib/src/System/Security/PermissionSet.cs
index c16bbc2cd2..e36f0752ad 100644
--- a/src/mscorlib/src/System/Security/PermissionSet.cs
+++ b/src/mscorlib/src/System/Security/PermissionSet.cs
@@ -33,17 +33,22 @@ namespace System.Security {
SkipVerification = 3
}
- [Serializable]
+#if FEATURE_SERIALIZATION
+ [Serializable]
+#endif
#if !FEATURE_CORECLR
[StrongNameIdentityPermissionAttribute(SecurityAction.InheritanceDemand, Name = "mscorlib", PublicKey = "0x" + AssemblyRef.EcmaPublicKeyFull)]
#endif
[System.Runtime.InteropServices.ComVisible(true)]
- public class PermissionSet : ISecurityEncodable, ICollection, IStackWalk, IDeserializationCallback
+ public class PermissionSet : ISecurityEncodable, ICollection, IStackWalk
+#if FEATURE_SERIALIZATION
+ , IDeserializationCallback
+#endif
{
- #if _DEBUG
+#if _DEBUG
internal static readonly bool debug;
- #endif
-
+#endif
+
[System.Diagnostics.Conditional( "_DEBUG" )]
private static void DEBUG_WRITE(String str) {
#if _DEBUG
diff --git a/src/mscorlib/src/System/Security/Permissions/SiteIdentityPermission.cs b/src/mscorlib/src/System/Security/Permissions/SiteIdentityPermission.cs
index ed241ec23d..6050b580df 100644
--- a/src/mscorlib/src/System/Security/Permissions/SiteIdentityPermission.cs
+++ b/src/mscorlib/src/System/Security/Permissions/SiteIdentityPermission.cs
@@ -15,8 +15,10 @@ namespace System.Security.Permissions
using System.Globalization;
using System.Runtime.Serialization;
-[System.Runtime.InteropServices.ComVisible(true)]
+ [System.Runtime.InteropServices.ComVisible(true)]
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
sealed public class SiteIdentityPermission : CodeAccessPermission, IBuiltInPermission
{
//------------------------------------------------------
diff --git a/src/mscorlib/src/System/Security/Permissions/URLIdentityPermission.cs b/src/mscorlib/src/System/Security/Permissions/URLIdentityPermission.cs
index 04528f0e9b..e62449cf3e 100644
--- a/src/mscorlib/src/System/Security/Permissions/URLIdentityPermission.cs
+++ b/src/mscorlib/src/System/Security/Permissions/URLIdentityPermission.cs
@@ -17,8 +17,11 @@ namespace System.Security.Permissions
using System.Runtime.Serialization;
using System.Diagnostics.Contracts;
-[System.Runtime.InteropServices.ComVisible(true)]
- [Serializable] sealed public class UrlIdentityPermission : CodeAccessPermission, IBuiltInPermission
+ [System.Runtime.InteropServices.ComVisible(true)]
+#if FEATURE_SERIALIZATION
+ [Serializable]
+#endif
+ sealed public class UrlIdentityPermission : CodeAccessPermission, IBuiltInPermission
{
//------------------------------------------------------
//
diff --git a/src/mscorlib/src/System/Security/Permissions/ZoneIdentityPermission.cs b/src/mscorlib/src/System/Security/Permissions/ZoneIdentityPermission.cs
index af8eb23ff6..803bd34cf1 100644
--- a/src/mscorlib/src/System/Security/Permissions/ZoneIdentityPermission.cs
+++ b/src/mscorlib/src/System/Security/Permissions/ZoneIdentityPermission.cs
@@ -17,8 +17,10 @@ namespace System.Security.Permissions
using System.Collections.Generic;
using System.Diagnostics.Contracts;
-[System.Runtime.InteropServices.ComVisible(true)]
+ [System.Runtime.InteropServices.ComVisible(true)]
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
sealed public class ZoneIdentityPermission : CodeAccessPermission, IBuiltInPermission
{
//------------------------------------------------------
diff --git a/src/mscorlib/src/System/Security/Policy/Evidence.cs b/src/mscorlib/src/System/Security/Policy/Evidence.cs
index 29d7682ae3..8bf8aa7e92 100644
--- a/src/mscorlib/src/System/Security/Policy/Evidence.cs
+++ b/src/mscorlib/src/System/Security/Policy/Evidence.cs
@@ -43,7 +43,9 @@ namespace System.Security.Policy
/// not contain any evidence data or null. As requests come in for that evidence, we'll populate the
/// EvidenceTypeDescriptor appropriately.
/// </summary>
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
[ComVisible(true)]
public sealed class Evidence
#if FEATURE_CAS_POLICY
diff --git a/src/mscorlib/src/System/Security/SecurityException.cs b/src/mscorlib/src/System/Security/SecurityException.cs
index 407ea0a536..35775391f6 100644
--- a/src/mscorlib/src/System/Security/SecurityException.cs
+++ b/src/mscorlib/src/System/Security/SecurityException.cs
@@ -31,7 +31,10 @@ namespace System.Security
using System.Diagnostics.Contracts;
[System.Runtime.InteropServices.ComVisible(true)]
- [Serializable] public class SecurityException : SystemException
+#if FEATURE_SERIALIZATION
+ [Serializable]
+#endif
+ public class SecurityException : SystemException
{
#if FEATURE_CAS_POLICY
private String m_debugString; // NOTE: If you change the name of this field, you'll have to update SOS as well!
diff --git a/src/mscorlib/src/System/Security/Util/TokenBasedSet.cs b/src/mscorlib/src/System/Security/Util/TokenBasedSet.cs
index 6870567e68..590a909662 100644
--- a/src/mscorlib/src/System/Security/Util/TokenBasedSet.cs
+++ b/src/mscorlib/src/System/Security/Util/TokenBasedSet.cs
@@ -12,7 +12,9 @@ namespace System.Security.Util
using System.Diagnostics.Contracts;
using System.Diagnostics.CodeAnalysis;
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
internal class TokenBasedSet
{
diff --git a/src/mscorlib/src/System/Security/Util/URLString.cs b/src/mscorlib/src/System/Security/Util/URLString.cs
index 8ac00caf66..51ae24cf4a 100644
--- a/src/mscorlib/src/System/Security/Util/URLString.cs
+++ b/src/mscorlib/src/System/Security/Util/URLString.cs
@@ -21,8 +21,10 @@ namespace System.Security.Util {
using System.Text;
using System.IO;
using System.Diagnostics.Contracts;
-
+
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
internal sealed class URLString : SiteString
{
private String m_protocol;
diff --git a/src/mscorlib/src/System/Security/VerificationException.cs b/src/mscorlib/src/System/Security/VerificationException.cs
index c740c1b87f..339bd22373 100644
--- a/src/mscorlib/src/System/Security/VerificationException.cs
+++ b/src/mscorlib/src/System/Security/VerificationException.cs
@@ -10,7 +10,10 @@ namespace System.Security {
using System.Runtime.Serialization;
[System.Runtime.InteropServices.ComVisible(true)]
- [Serializable] public class VerificationException : SystemException {
+#if FEATURE_SERIALIZATION
+ [Serializable]
+#endif
+ public class VerificationException : SystemException {
public VerificationException()
: base(Environment.GetResourceString("Verification_Exception")) {
SetErrorCode(__HResults.COR_E_VERIFICATION);
diff --git a/src/mscorlib/src/System/StackOverflowException.cs b/src/mscorlib/src/System/StackOverflowException.cs
index a04f5b72f5..c4b367d708 100644
--- a/src/mscorlib/src/System/StackOverflowException.cs
+++ b/src/mscorlib/src/System/StackOverflowException.cs
@@ -15,8 +15,10 @@ namespace System {
using System;
using System.Runtime.Serialization;
-[System.Runtime.InteropServices.ComVisible(true)]
+ [System.Runtime.InteropServices.ComVisible(true)]
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
public sealed class StackOverflowException : SystemException {
public StackOverflowException()
: base(Environment.GetResourceString("Arg_StackOverflowException")) {
diff --git a/src/mscorlib/src/System/String.cs b/src/mscorlib/src/System/String.cs
index d769147359..067f88a605 100644
--- a/src/mscorlib/src/System/String.cs
+++ b/src/mscorlib/src/System/String.cs
@@ -34,15 +34,9 @@ namespace System {
// instance and return the result as a new String. All comparison methods are
// implemented as a part of String. As with arrays, character positions
// (indices) are zero-based.
- //
- // When passing a null string into a constructor in VJ and VC, the null should be
- // explicitly type cast to a String.
- // For Example:
- // String s = new String((String)null);
- // Console.WriteLine(s);
- //
+
[ComVisible(true)]
- [Serializable]
+ [Serializable]
public sealed class String : IComparable, ICloneable, IConvertible, IEnumerable
, IComparable<String>, IEnumerable<char>, IEquatable<String>
{
@@ -51,13 +45,12 @@ namespace System {
//NOTE NOTE NOTE NOTE
//These fields map directly onto the fields in an EE StringObject. See object.h for the layout.
//
- [NonSerialized]private int m_stringLength;
+ [NonSerialized] private int m_stringLength;
- [NonSerialized]private char m_firstChar;
+ // For empty strings, this will be '\0' since
+ // strings are both null-terminated and length prefixed
+ [NonSerialized] private char m_firstChar;
- //private static readonly char FmtMsgMarkerChar='%';
- //private static readonly char FmtMsgFmtCodeChar='!';
- //These are defined in Com99/src/vm/COMStringCommon.h and must be kept in sync.
private const int TrimHead = 0;
private const int TrimTail = 1;
private const int TrimBoth = 2;
@@ -468,85 +461,118 @@ namespace System {
Contract.Requires(strA != null);
Contract.Requires(strB != null);
+ // NOTE: This may be subject to change if eliminating the check
+ // in the callers makes them small enough to be inlined by the JIT
+ Contract.Assert(strA.m_firstChar == strB.m_firstChar,
+ "For performance reasons, callers of this method should " +
+ "check/short-circuit beforehand if the first char is the same.");
+
int length = Math.Min(strA.Length, strB.Length);
- int diffOffset = -1;
fixed (char* ap = &strA.m_firstChar) fixed (char* bp = &strB.m_firstChar)
{
char* a = ap;
char* b = bp;
+ // Check if the second chars are different here
+ // The reason we check if m_firstChar is different is because
+ // it's the most common case and allows us to avoid a method call
+ // to here.
+ // The reason we check if the second char is different is because
+ // if the first two chars the same we can increment by 4 bytes,
+ // leaving us word-aligned on both 32-bit (12 bytes into the string)
+ // and 64-bit (16 bytes) platforms.
+
+ // For empty strings, the second char will be null due to padding.
+ // The start of the string (not including sync block pointer)
+ // is the method table pointer + string length, which takes up
+ // 8 bytes on 32-bit, 12 on x64. For empty strings the null
+ // terminator immediately follows, leaving us with an object
+ // 10/14 bytes in size. Since everything needs to be a multiple
+ // of 4/8, this will get padded and zeroed out.
+
+ // For one-char strings the second char will be the null terminator.
+
+ // NOTE: If in the future there is a way to read the second char
+ // without pinning the string (e.g. System.Runtime.CompilerServices.Unsafe
+ // is exposed to mscorlib, or a future version of C# allows inline IL),
+ // then do that and short-circuit before the fixed.
+
+ if (*(a + 1) != *(b + 1)) goto DiffOffset1;
+
+ // Since we know that the first two chars are the same,
+ // we can increment by 2 here and skip 4 bytes.
+ // This leaves us 8-byte aligned, which results
+ // on better perf for 64-bit platforms.
+ length -= 2; a += 2; b += 2;
+
// unroll the loop
- while (length >= 10)
+#if BIT64
+ while (length >= 12)
{
- if (*(int*)a != *(int*)b) {
- diffOffset = 0;
- break;
- }
-
- if (*(int*)(a+2) != *(int*)(b+2)) {
- diffOffset = 2;
- break;
- }
-
- if (*(int*)(a+4) != *(int*)(b+4)) {
- diffOffset = 4;
- break;
- }
-
- if (*(int*)(a+6) != *(int*)(b+6)) {
- diffOffset = 6;
- break;
- }
-
- if (*(int*)(a+8) != *(int*)(b+8)) {
- diffOffset = 8;
- break;
- }
- length -= 10;
- a += 10;
- b += 10;
+ if (*(long*)a != *(long*)b) goto DiffOffset0;
+ if (*(long*)(a + 4) != *(long*)(b + 4)) goto DiffOffset4;
+ if (*(long*)(a + 8) != *(long*)(b + 8)) goto DiffOffset8;
+ length -= 12; a += 12; b += 12;
}
-
- if( diffOffset != -1) {
- // we already see a difference in the unrolled loop above
- a += diffOffset;
- b += diffOffset;
- int order;
- if ( (order = (int)*a - (int)*b) != 0) {
- return order;
- }
- Contract.Assert( *(a+1) != *(b+1), "This byte must be different if we reach here!");
- return ((int)*(a+1) - (int)*(b+1));
+#else // BIT64
+ while (length >= 10)
+ {
+ if (*(int*)a != *(int*)b) goto DiffOffset0;
+ if (*(int*)(a + 2) != *(int*)(b + 2)) goto DiffOffset2;
+ if (*(int*)(a + 4) != *(int*)(b + 4)) goto DiffOffset4;
+ if (*(int*)(a + 6) != *(int*)(b + 6)) goto DiffOffset6;
+ if (*(int*)(a + 8) != *(int*)(b + 8)) goto DiffOffset8;
+ length -= 10; a += 10; b += 10;
}
+#endif // BIT64
- // now go back to slower code path and do comparison on 4 bytes at a time.
+ // Fallback loop:
+ // go back to slower code path and do comparison on 4 bytes at a time.
// This depends on the fact that the String objects are
// always zero terminated and that the terminating zero is not included
// in the length. For odd string sizes, the last compare will include
// the zero terminator.
- while (length > 0) {
- if (*(int*)a != *(int*)b) {
- break;
- }
+ while (length > 0)
+ {
+ if (*(int*)a != *(int*)b) goto DiffNextInt;
length -= 2;
a += 2;
b += 2;
}
- if( length > 0) {
- int c;
- // found a different int on above loop
- if ( (c = (int)*a - (int)*b) != 0) {
- return c;
- }
- Contract.Assert( *(a+1) != *(b+1), "This byte must be different if we reach here!");
- return ((int)*(a+1) - (int)*(b+1));
- }
-
// At this point, we have compared all the characters in at least one string.
// The longer string will be larger.
return strA.Length - strB.Length;
+
+#if BIT64
+ DiffOffset8: a += 4; b += 4;
+ DiffOffset4: a += 4; b += 4;
+#else // BIT64
+ // Use jumps instead of falling through, since
+ // otherwise going to DiffOffset8 will involve
+ // 8 add instructions before getting to DiffNextInt
+ DiffOffset8: a += 8; b += 8; goto DiffOffset0;
+ DiffOffset6: a += 6; b += 6; goto DiffOffset0;
+ DiffOffset4: a += 2; b += 2;
+ DiffOffset2: a += 2; b += 2;
+#endif // BIT64
+
+ DiffOffset0:
+ // If we reached here, we already see a difference in the unrolled loop above
+#if BIT64
+ if (*(int*)a == *(int*)b)
+ {
+ a += 2; b += 2;
+ }
+#endif // BIT64
+
+ DiffNextInt:
+ if (*a != *b) return *a - *b;
+
+ DiffOffset1:
+ Contract.Assert(*(a + 1) != *(b + 1), "This char must be different if we reach here!");
+ return *(a + 1) - *(b + 1);
}
}
@@ -854,64 +880,16 @@ namespace System {
// they will return the same hash code.
[System.Security.SecuritySafeCritical] // auto-generated
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
- public override int GetHashCode() {
-
+ public override int GetHashCode()
+ {
#if FEATURE_RANDOMIZED_STRING_HASHING
- if(HashHelpers.s_UseRandomizedStringHashing)
+ if (HashHelpers.s_UseRandomizedStringHashing)
{
return InternalMarvin32HashString(this, this.Length, 0);
}
#endif // FEATURE_RANDOMIZED_STRING_HASHING
- unsafe {
- fixed (char* src = &m_firstChar) {
- Contract.Assert(src[this.Length] == '\0', "src[this.Length] == '\\0'");
- Contract.Assert( ((int)src)%4 == 0, "Managed string should start at 4 bytes boundary");
-
-#if BIT64
- int hash1 = 5381;
-#else // !BIT64 (32)
- int hash1 = (5381<<16) + 5381;
-#endif
- int hash2 = hash1;
-#if BIT64
- int c;
- char *s = src;
- while ((c = s[0]) != 0) {
- hash1 = ((hash1 << 5) + hash1) ^ c;
- c = s[1];
- if (c == 0)
- break;
- hash2 = ((hash2 << 5) + hash2) ^ c;
- s += 2;
- }
-#else // !BIT64 (32)
- // 32 bit machines.
- int* pint = (int *)src;
- int len = this.Length;
- while (len > 2)
- {
- hash1 = ((hash1 << 5) + hash1 + (hash1 >> 27)) ^ pint[0];
- hash2 = ((hash2 << 5) + hash2 + (hash2 >> 27)) ^ pint[1];
- pint += 2;
- len -= 4;
- }
-
- if (len > 0)
- {
- hash1 = ((hash1 << 5) + hash1 + (hash1 >> 27)) ^ pint[0];
- }
-#endif
-#if DEBUG
- // We want to ensure we can change our hash function daily.
- // This is perfectly fine as long as you don't persist the
- // value from GetHashCode to disk or count on String A
- // hashing before string B. Those are bugs in your code.
- hash1 ^= ThisAssembly.DailyBuildNumber;
-#endif
- return hash1 + (hash2 * 1566083941);
- }
- }
+ return GetLegacyNonRandomizedHashCode();
}
// Use this if and only if you need the hashcode to not change across app domains (e.g. you have an app domain agile
@@ -1695,29 +1673,91 @@ namespace System {
private static unsafe int wcslen(char *ptr)
{
char *end = ptr;
+
+ // First make sure our pointer is aligned on a word boundary
+ int alignment = IntPtr.Size - 1;
+ // If ptr is at an odd address (e.g. 0x5), this loop will simply iterate all the way
+ while (((uint)end & (uint)alignment) != 0)
+ {
+ if (*end == 0) goto FoundZero;
+ end++;
+ }
+
+#if !BIT64
// The following code is (somewhat surprisingly!) significantly faster than a naive loop,
// at least on x86 and the current jit.
- // First make sure our pointer is aligned on a dword boundary
- while (((uint)end & 3) != 0 && *end != 0)
- end++;
- if (*end != 0) {
- // The loop condition below works because if "end[0] & end[1]" is non-zero, that means
- // neither operand can have been zero. If is zero, we have to look at the operands individually,
- // but we hope this going to fairly rare.
+ // The loop condition below works because if "end[0] & end[1]" is non-zero, that means
+ // neither operand can have been zero. If is zero, we have to look at the operands individually,
+ // but we hope this going to fairly rare.
+
+ // In general, it would be incorrect to access end[1] if we haven't made sure
+ // end[0] is non-zero. However, we know the ptr has been aligned by the loop above
+ // so end[0] and end[1] must be in the same word (and therefore page), so they're either both accessible, or both not.
- // In general, it would be incorrect to access end[1] if we haven't made sure
- // end[0] is non-zero. However, we know the ptr has been aligned by the loop above
- // so end[0] and end[1] must be in the same page, so they're either both accessible, or both not.
+ while ((end[0] & end[1]) != 0 || (end[0] != 0 && end[1] != 0)) {
+ end += 2;
+ }
+
+ Contract.Assert(end[0] == 0 || end[1] == 0);
+ if (end[0] != 0) end++;
+#else // !BIT64
+ // Based on https://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord
+
+ // 64-bit implementation: process 1 ulong (word) at a time
+
+ // What we do here is add 0x7fff from each of the
+ // 4 individual chars within the ulong, using MagicMask.
+ // If the char > 0 and < 0x8001, it will have its high bit set.
+ // We then OR with MagicMask, to set all the other bits.
+ // This will result in all bits set (ulong.MaxValue) for any
+ // char that fits the above criteria, and something else otherwise.
- while ((end[0] & end[1]) != 0 || (end[0] != 0 && end[1] != 0)) {
- end += 2;
+ // Note that for any char > 0x8000, this will be a false
+ // positive and we will fallback to the slow path and
+ // check each char individually. This is OK though, since
+ // we optimize for the common case (ASCII chars, which are < 0x80).
+
+ // NOTE: We can access a ulong a time since the ptr is aligned,
+ // and therefore we're only accessing the same word/page. (See notes
+ // for the 32-bit version above.)
+
+ const ulong MagicMask = 0x7fff7fff7fff7fff;
+
+ while (true)
+ {
+ ulong word = *(ulong*)end;
+ word += MagicMask; // cause high bit to be set if not zero, and <= 0x8000
+ word |= MagicMask; // set everything besides the high bits
+
+ if (word == ulong.MaxValue) // 0xffff...
+ {
+ // all of the chars have their bits set (and therefore none can be 0)
+ end += 4;
+ continue;
}
+
+ // at least one of them didn't have their high bit set!
+ // go through each char and check for 0.
+
+ if (end[0] == 0) goto EndAt0;
+ if (end[1] == 0) goto EndAt1;
+ if (end[2] == 0) goto EndAt2;
+ if (end[3] == 0) goto EndAt3;
+
+ // if we reached here, it was a false positive-- just continue
+ end += 4;
}
- // finish up with the naive loop
- for ( ; *end != 0; end++)
- ;
+
+ EndAt3: end++;
+ EndAt2: end++;
+ EndAt1: end++;
+ EndAt0:
+#endif // !BIT64
+
+ FoundZero:
+ Contract.Assert(*end == 0);
int count = (int)(end - ptr);
@@ -1862,7 +1902,8 @@ namespace System {
case StringComparison.Ordinal:
// Most common case: first character is different.
- if ((strA.m_firstChar - strB.m_firstChar) != 0)
+ // Returns false for empty strings.
+ if (strA.m_firstChar != strB.m_firstChar)
{
return strA.m_firstChar - strB.m_firstChar;
}
@@ -2174,7 +2215,8 @@ namespace System {
}
// Most common case, first character is different.
- if ((strA.m_firstChar - strB.m_firstChar) != 0)
+ // This will return false for empty strings.
+ if (strA.m_firstChar != strB.m_firstChar)
{
return strA.m_firstChar - strB.m_firstChar;
}
diff --git a/src/mscorlib/src/System/SystemException.cs b/src/mscorlib/src/System/SystemException.cs
index 42a2586f14..c477efdc2a 100644
--- a/src/mscorlib/src/System/SystemException.cs
+++ b/src/mscorlib/src/System/SystemException.cs
@@ -6,8 +6,10 @@ namespace System {
using System;
using System.Runtime.Serialization;
+#if FEATURE_SERIALIZATION
[Serializable]
-[System.Runtime.InteropServices.ComVisible(true)]
+#endif
+ [System.Runtime.InteropServices.ComVisible(true)]
public class SystemException : Exception
{
public SystemException()
diff --git a/src/mscorlib/src/System/Text/ASCIIEncoding.cs b/src/mscorlib/src/System/Text/ASCIIEncoding.cs
index 178ade5515..ab5fa77145 100644
--- a/src/mscorlib/src/System/Text/ASCIIEncoding.cs
+++ b/src/mscorlib/src/System/Text/ASCIIEncoding.cs
@@ -36,127 +36,49 @@ namespace System.Text
this.decoderFallback = DecoderFallback.ReplacementFallback;
}
- //
// WARNING: GetByteCount(string chars), GetBytes(string chars,...), and GetString(byte[] byteIndex...)
// WARNING: have different variable names than EncodingNLS.cs, so this can't just be cut & pasted,
// WARNING: or it'll break VB's way of calling these.
- //
- // The following methods are copied from EncodingNLS.cs.
- // Unfortunately EncodingNLS.cs is internal and we're public, so we have to reimpliment them here.
- // These should be kept in sync for the following classes:
- // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
- //
+ // NOTE: Many methods in this class forward to EncodingForwarder for
+ // validating arguments/wrapping the unsafe methods in this class
+ // which do the actual work. That class contains
+ // shared logic for doing this which is used by
+ // ASCIIEncoding, EncodingNLS, UnicodeEncoding, UTF32Encoding,
+ // UTF7Encoding, and UTF8Encoding.
+ // The reason the code is separated out into a static class, rather
+ // than a base class which overrides all of these methods for us
+ // (which is what EncodingNLS is for internal Encodings) is because
+ // that's really more of an implementation detail so it's internal.
+ // At the same time, C# doesn't allow a public class subclassing an
+ // internal/private one, so we end up having to re-override these
+ // methods in all of the public Encodings + EncodingNLS.
+
// Returns the number of bytes required to encode a range of characters in
// a character array.
- //
- // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
- // So if you fix this, fix the others. Currently those include:
- // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
- // parent method is safe
-
- [System.Security.SecuritySafeCritical] // auto-generated
- public override unsafe int GetByteCount(char[] chars, int index, int count)
- {
- // Validate input parameters
- if (chars == null)
- throw new ArgumentNullException("chars",
- Environment.GetResourceString("ArgumentNull_Array"));
-
- if (index < 0 || count < 0)
- throw new ArgumentOutOfRangeException((index<0 ? "index" : "count"),
- Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
-
- if (chars.Length - index < count)
- throw new ArgumentOutOfRangeException("chars",
- Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer"));
- Contract.EndContractBlock();
-
- // If no input, return 0, avoid fixed empty array problem
- if (count == 0)
- return 0;
- // Just call the pointer version
- fixed (char* pChars = chars)
- return GetByteCount(pChars + index, count, null);
+ public override int GetByteCount(char[] chars, int index, int count)
+ {
+ return EncodingForwarder.GetByteCount(this, chars, index, count);
}
- // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
- // So if you fix this, fix the others. Currently those include:
- // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
- // parent method is safe
-
- [System.Security.SecuritySafeCritical] // auto-generated
- public override unsafe int GetByteCount(String chars)
+ public override int GetByteCount(String chars)
{
- // Validate input
- if (chars==null)
- throw new ArgumentNullException("chars");
- Contract.EndContractBlock();
-
- fixed (char* pChars = chars)
- return GetByteCount(pChars, chars.Length, null);
+ return EncodingForwarder.GetByteCount(this, chars);
}
- // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
- // So if you fix this, fix the others. Currently those include:
- // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
-
[System.Security.SecurityCritical] // auto-generated
[CLSCompliant(false)]
[System.Runtime.InteropServices.ComVisible(false)]
public override unsafe int GetByteCount(char* chars, int count)
{
- // Validate Parameters
- if (chars == null)
- throw new ArgumentNullException("chars",
- Environment.GetResourceString("ArgumentNull_Array"));
-
- if (count < 0)
- throw new ArgumentOutOfRangeException("count",
- Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
- Contract.EndContractBlock();
-
- // Call it with empty encoder
- return GetByteCount(chars, count, null);
+ return EncodingForwarder.GetByteCount(this, chars, count);
}
- // Parent method is safe.
- // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
- // So if you fix this, fix the others. Currently those include:
- // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
-
- [System.Security.SecuritySafeCritical] // auto-generated
- public override unsafe int GetBytes(String chars, int charIndex, int charCount,
+ public override int GetBytes(String chars, int charIndex, int charCount,
byte[] bytes, int byteIndex)
{
- if (chars == null || bytes == null)
- throw new ArgumentNullException((chars == null ? "chars" : "bytes"),
- Environment.GetResourceString("ArgumentNull_Array"));
-
- if (charIndex < 0 || charCount < 0)
- throw new ArgumentOutOfRangeException((charIndex<0 ? "charIndex" : "charCount"),
- Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
-
- if (chars.Length - charIndex < charCount)
- throw new ArgumentOutOfRangeException("chars",
- Environment.GetResourceString("ArgumentOutOfRange_IndexCount"));
-
- if (byteIndex < 0 || byteIndex > bytes.Length)
- throw new ArgumentOutOfRangeException("byteIndex",
- Environment.GetResourceString("ArgumentOutOfRange_Index"));
- Contract.EndContractBlock();
-
- int byteCount = bytes.Length - byteIndex;
-
- // Fixed doesn't like empty byte arrays
- if (bytes.Length == 0)
- bytes = new byte[1];
-
- fixed (char* pChars = chars)
- fixed ( byte* pBytes = bytes)
- return GetBytes(pChars + charIndex, charCount,
- pBytes + byteIndex, byteCount, null);
+ return EncodingForwarder.GetBytes(this, chars, charIndex, charCount, bytes, byteIndex);
}
// Encodes a range of characters in a character array into a range of bytes
@@ -167,234 +89,60 @@ namespace System.Text
// Alternatively, the GetMaxByteCount method can be used to
// determine the maximum number of bytes that will be produced for a given
// number of characters, regardless of the actual character values.
- //
- // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
- // So if you fix this, fix the others. Currently those include:
- // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
- // parent method is safe
-
- [System.Security.SecuritySafeCritical] // auto-generated
- public override unsafe int GetBytes(char[] chars, int charIndex, int charCount,
+
+ public override int GetBytes(char[] chars, int charIndex, int charCount,
byte[] bytes, int byteIndex)
{
- // Validate parameters
- if (chars == null || bytes == null)
- throw new ArgumentNullException((chars == null ? "chars" : "bytes"),
- Environment.GetResourceString("ArgumentNull_Array"));
-
- if (charIndex < 0 || charCount < 0)
- throw new ArgumentOutOfRangeException((charIndex<0 ? "charIndex" : "charCount"),
- Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
-
- if (chars.Length - charIndex < charCount)
- throw new ArgumentOutOfRangeException("chars",
- Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer"));
-
- if (byteIndex < 0 || byteIndex > bytes.Length)
- throw new ArgumentOutOfRangeException("byteIndex",
- Environment.GetResourceString("ArgumentOutOfRange_Index"));
- Contract.EndContractBlock();
-
- // If nothing to encode return 0, avoid fixed problem
- if (charCount == 0)
- return 0;
-
- // Just call pointer version
- int byteCount = bytes.Length - byteIndex;
-
- // Fixed doesn't like empty byte arrays
- if (bytes.Length == 0)
- bytes = new byte[1];
-
- fixed (char* pChars = chars)
- fixed (byte* pBytes = bytes)
- // Remember that byteCount is # to decode, not size of array.
- return GetBytes(pChars + charIndex, charCount,
- pBytes + byteIndex, byteCount, null);
+ return EncodingForwarder.GetBytes(this, chars, charIndex, charCount, bytes, byteIndex);
}
- // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
- // So if you fix this, fix the others. Currently those include:
- // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
-
[System.Security.SecurityCritical] // auto-generated
[CLSCompliant(false)]
[System.Runtime.InteropServices.ComVisible(false)]
public override unsafe int GetBytes(char* chars, int charCount, byte* bytes, int byteCount)
{
- // Validate Parameters
- if (bytes == null || chars == null)
- throw new ArgumentNullException(bytes == null ? "bytes" : "chars",
- Environment.GetResourceString("ArgumentNull_Array"));
-
- if (charCount < 0 || byteCount < 0)
- throw new ArgumentOutOfRangeException((charCount<0 ? "charCount" : "byteCount"),
- Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
- Contract.EndContractBlock();
-
- return GetBytes(chars, charCount, bytes, byteCount, null);
+ return EncodingForwarder.GetBytes(this, chars, charCount, bytes, byteCount);
}
// Returns the number of characters produced by decoding a range of bytes
// in a byte array.
- //
- // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
- // So if you fix this, fix the others. Currently those include:
- // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
- // parent method is safe
-
- [System.Security.SecuritySafeCritical] // auto-generated
- public override unsafe int GetCharCount(byte[] bytes, int index, int count)
- {
- // Validate Parameters
- if (bytes == null)
- throw new ArgumentNullException("bytes",
- Environment.GetResourceString("ArgumentNull_Array"));
-
- if (index < 0 || count < 0)
- throw new ArgumentOutOfRangeException((index<0 ? "index" : "count"),
- Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
- if (bytes.Length - index < count)
- throw new ArgumentOutOfRangeException("bytes",
- Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer"));
- Contract.EndContractBlock();
-
- // If no input just return 0, fixed doesn't like 0 length arrays
- if (count == 0)
- return 0;
-
- // Just call pointer version
- fixed (byte* pBytes = bytes)
- return GetCharCount(pBytes + index, count, null);
+ public override int GetCharCount(byte[] bytes, int index, int count)
+ {
+ return EncodingForwarder.GetCharCount(this, bytes, index, count);
}
- // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
- // So if you fix this, fix the others. Currently those include:
- // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
-
[System.Security.SecurityCritical] // auto-generated
[CLSCompliant(false)]
[System.Runtime.InteropServices.ComVisible(false)]
public override unsafe int GetCharCount(byte* bytes, int count)
{
- // Validate Parameters
- if (bytes == null)
- throw new ArgumentNullException("bytes",
- Environment.GetResourceString("ArgumentNull_Array"));
-
- if (count < 0)
- throw new ArgumentOutOfRangeException("count",
- Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
- Contract.EndContractBlock();
-
- return GetCharCount(bytes, count, null);
+ return EncodingForwarder.GetCharCount(this, bytes, count);
}
- // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
- // So if you fix this, fix the others. Currently those include:
- // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
- // parent method is safe
-
- [System.Security.SecuritySafeCritical] // auto-generated
- public override unsafe int GetChars(byte[] bytes, int byteIndex, int byteCount,
+ public override int GetChars(byte[] bytes, int byteIndex, int byteCount,
char[] chars, int charIndex)
{
- // Validate Parameters
- if (bytes == null || chars == null)
- throw new ArgumentNullException(bytes == null ? "bytes" : "chars",
- Environment.GetResourceString("ArgumentNull_Array"));
-
- if (byteIndex < 0 || byteCount < 0)
- throw new ArgumentOutOfRangeException((byteIndex<0 ? "byteIndex" : "byteCount"),
- Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
-
- if ( bytes.Length - byteIndex < byteCount)
- throw new ArgumentOutOfRangeException("bytes",
- Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer"));
-
- if (charIndex < 0 || charIndex > chars.Length)
- throw new ArgumentOutOfRangeException("charIndex",
- Environment.GetResourceString("ArgumentOutOfRange_Index"));
- Contract.EndContractBlock();
-
- // If no input, return 0 & avoid fixed problem
- if (byteCount == 0)
- return 0;
-
- // Just call pointer version
- int charCount = chars.Length - charIndex;
-
- // Fixed doesn't like empty char arrays
- if (chars.Length == 0)
- chars = new char[1];
-
- fixed (byte* pBytes = bytes)
- fixed (char* pChars = chars)
- // Remember that charCount is # to decode, not size of array
- return GetChars(pBytes + byteIndex, byteCount,
- pChars + charIndex, charCount, null);
+ return EncodingForwarder.GetChars(this, bytes, byteIndex, byteCount, chars, charIndex);
}
- // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
- // So if you fix this, fix the others. Currently those include:
- // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
-
[System.Security.SecurityCritical] // auto-generated
[CLSCompliant(false)]
[System.Runtime.InteropServices.ComVisible(false)]
public unsafe override int GetChars(byte* bytes, int byteCount, char* chars, int charCount)
{
- // Validate Parameters
- if (bytes == null || chars == null)
- throw new ArgumentNullException(bytes == null ? "bytes" : "chars",
- Environment.GetResourceString("ArgumentNull_Array"));
-
- if (charCount < 0 || byteCount < 0)
- throw new ArgumentOutOfRangeException((charCount<0 ? "charCount" : "byteCount"),
- Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
- Contract.EndContractBlock();
-
- return GetChars(bytes, byteCount, chars, charCount, null);
+ return EncodingForwarder.GetChars(this, bytes, byteCount, chars, charCount);
}
// Returns a string containing the decoded representation of a range of
// bytes in a byte array.
- //
- // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
- // So if you fix this, fix the others. Currently those include:
- // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
- // parent method is safe
-
- [System.Security.SecuritySafeCritical] // auto-generated
- public override unsafe String GetString(byte[] bytes, int byteIndex, int byteCount)
- {
- // Validate Parameters
- if (bytes == null)
- throw new ArgumentNullException("bytes",
- Environment.GetResourceString("ArgumentNull_Array"));
- if (byteIndex < 0 || byteCount < 0)
- throw new ArgumentOutOfRangeException((byteIndex < 0 ? "byteIndex" : "byteCount"),
- Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
-
-
- if (bytes.Length - byteIndex < byteCount)
- throw new ArgumentOutOfRangeException("bytes",
- Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer"));
- Contract.EndContractBlock();
-
- // Avoid problems with empty input buffer
- if (byteCount == 0) return String.Empty;
-
- fixed (byte* pBytes = bytes)
- return String.CreateStringFromEncoding(
- pBytes + byteIndex, byteCount, this);
+ public override String GetString(byte[] bytes, int byteIndex, int byteCount)
+ {
+ return EncodingForwarder.GetString(this, bytes, byteIndex, byteCount);
}
-
- //
- // End of standard methods copied from EncodingNLS.cs
- //
+
+ // End of overridden methods which use EncodingForwarder
// GetByteCount
// Note: We start by assuming that the output will be the same as count. Having
diff --git a/src/mscorlib/src/System/Text/BaseCodePageEncoding.cs b/src/mscorlib/src/System/Text/BaseCodePageEncoding.cs
index 2de3d484dc..4da0b8158e 100644
--- a/src/mscorlib/src/System/Text/BaseCodePageEncoding.cs
+++ b/src/mscorlib/src/System/Text/BaseCodePageEncoding.cs
@@ -48,7 +48,9 @@ namespace System.Text
// BYTE[] data; // data section
// }
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
internal abstract class BaseCodePageEncoding : EncodingNLS, ISerializable
{
// Static & Const stuff
diff --git a/src/mscorlib/src/System/Text/CodePageEncoding.cs b/src/mscorlib/src/System/Text/CodePageEncoding.cs
index 35925fe9d9..e04ed49fcf 100644
--- a/src/mscorlib/src/System/Text/CodePageEncoding.cs
+++ b/src/mscorlib/src/System/Text/CodePageEncoding.cs
@@ -20,8 +20,13 @@ namespace System.Text
** to Everett compatibility as well.
==============================================================================*/
+#if FEATURE_SERIALIZATION
[Serializable]
- internal sealed class CodePageEncoding : ISerializable, IObjectReference
+#endif
+ internal sealed class CodePageEncoding : IObjectReference
+#if FEATURE_SERIALIZATION
+ , ISerializable
+#endif
{
// Temp stuff
[NonSerialized]
@@ -104,8 +109,13 @@ namespace System.Text
#endif
// Same problem with the Decoder, this only happens with Everett Decoders
+#if FEATURE_SERIALIZATION
[Serializable]
- internal sealed class Decoder : ISerializable, IObjectReference
+#endif
+ internal sealed class Decoder : IObjectReference
+#if FEATURE_SERIALIZATION
+ , ISerializable
+#endif
{
// Might need this when GetRealObjecting
[NonSerialized]
diff --git a/src/mscorlib/src/System/Text/DBCSCodePageEncoding.cs b/src/mscorlib/src/System/Text/DBCSCodePageEncoding.cs
index c103d7898f..d2ec430e01 100644
--- a/src/mscorlib/src/System/Text/DBCSCodePageEncoding.cs
+++ b/src/mscorlib/src/System/Text/DBCSCodePageEncoding.cs
@@ -15,7 +15,9 @@ namespace System.Text
// DBCSCodePageEncoding
//
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
internal class DBCSCodePageEncoding : BaseCodePageEncoding, ISerializable
{
// Pointers to our memory section parts
diff --git a/src/mscorlib/src/System/Text/DecoderExceptionFallback.cs b/src/mscorlib/src/System/Text/DecoderExceptionFallback.cs
index 7a0478de20..b0cb05f564 100644
--- a/src/mscorlib/src/System/Text/DecoderExceptionFallback.cs
+++ b/src/mscorlib/src/System/Text/DecoderExceptionFallback.cs
@@ -101,7 +101,9 @@ namespace System.Text
}
// Exception for decoding unknown byte sequences.
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
public sealed class DecoderFallbackException : ArgumentException
{
byte[] bytesUnknown = null;
diff --git a/src/mscorlib/src/System/Text/DecoderNLS.cs b/src/mscorlib/src/System/Text/DecoderNLS.cs
index 5c12afa919..ad87f9ed26 100644
--- a/src/mscorlib/src/System/Text/DecoderNLS.cs
+++ b/src/mscorlib/src/System/Text/DecoderNLS.cs
@@ -21,8 +21,13 @@ namespace System.Text
// of Encoding objects.
//
+#if FEATURE_SERIALIZATION
[Serializable]
- internal class DecoderNLS : Decoder, ISerializable
+#endif
+ internal class DecoderNLS : Decoder
+#if FEATURE_SERIALIZATION
+ , ISerializable
+#endif
{
// Remember our encoding
protected Encoding m_encoding;
diff --git a/src/mscorlib/src/System/Text/EncoderExceptionFallback.cs b/src/mscorlib/src/System/Text/EncoderExceptionFallback.cs
index 5ab51cb6dd..23e381f769 100644
--- a/src/mscorlib/src/System/Text/EncoderExceptionFallback.cs
+++ b/src/mscorlib/src/System/Text/EncoderExceptionFallback.cs
@@ -103,7 +103,9 @@ namespace System.Text
}
}
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
public sealed class EncoderFallbackException : ArgumentException
{
char charUnknown;
diff --git a/src/mscorlib/src/System/Text/EncoderNLS.cs b/src/mscorlib/src/System/Text/EncoderNLS.cs
index 1d1ff59264..6eefaacd70 100644
--- a/src/mscorlib/src/System/Text/EncoderNLS.cs
+++ b/src/mscorlib/src/System/Text/EncoderNLS.cs
@@ -21,8 +21,13 @@ namespace System.Text
// of Encoding objects.
//
+#if FEATURE_SERIALIZATION
[Serializable]
- internal class EncoderNLS : Encoder, ISerializable
+#endif
+ internal class EncoderNLS : Encoder
+#if FEATURE_SERIALIZATION
+ , ISerializable
+#endif
{
// Need a place for the last left over character, most of our encodings use this
internal char charLeftOver;
diff --git a/src/mscorlib/src/System/Text/Encoding.cs b/src/mscorlib/src/System/Text/Encoding.cs
index 5a0ce140b3..e0fe883440 100644
--- a/src/mscorlib/src/System/Text/Encoding.cs
+++ b/src/mscorlib/src/System/Text/Encoding.cs
@@ -82,8 +82,10 @@ namespace System.Text
// generally executes faster.
//
-[System.Runtime.InteropServices.ComVisible(true)]
+ [System.Runtime.InteropServices.ComVisible(true)]
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
public abstract class Encoding : ICloneable
{
private static volatile Encoding defaultEncoding;
@@ -722,7 +724,7 @@ namespace System.Text
{
get
{
- return (Environment.GetResourceString("Globalization.cp_" + m_codePage));
+ return Environment.GetResourceString("Globalization.cp_" + m_codePage.ToString());
}
}
@@ -1610,8 +1612,13 @@ namespace System.Text
decoder.ClearMustFlush();
}
+#if FEATURE_SERIALIZATION
[Serializable]
- internal class DefaultEncoder : Encoder, ISerializable, IObjectReference
+#endif
+ internal class DefaultEncoder : Encoder, IObjectReference
+#if FEATURE_SERIALIZATION
+ , ISerializable
+#endif
{
private Encoding m_encoding;
[NonSerialized] private bool m_hasInitializedEncoding;
@@ -1738,8 +1745,13 @@ namespace System.Text
}
}
+#if FEATURE_SERIALIZATION
[Serializable]
- internal class DefaultDecoder : Decoder, ISerializable, IObjectReference
+#endif
+ internal class DefaultDecoder : Decoder, IObjectReference
+#if FEATURE_SERIALIZATION
+ , ISerializable
+#endif
{
private Encoding m_encoding;
[NonSerialized]
diff --git a/src/mscorlib/src/System/Text/EncodingForwarder.cs b/src/mscorlib/src/System/Text/EncodingForwarder.cs
new file mode 100644
index 0000000000..d4bcf800e3
--- /dev/null
+++ b/src/mscorlib/src/System/Text/EncodingForwarder.cs
@@ -0,0 +1,339 @@
+// 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.Diagnostics.Contracts;
+using System.Security;
+
+namespace System.Text
+{
+ // Shared implementations for commonly overriden Encoding methods
+
+ internal static class EncodingForwarder
+ {
+ // We normally have to duplicate a lot of code between UTF8Encoding,
+ // UTF7Encoding, EncodingNLS, etc. because we want to override many
+ // of the methods in all of those classes to just forward to the unsafe
+ // version. (e.g. GetBytes(char[]))
+ // Ideally, everything would just derive from EncodingNLS, but that's
+ // not exposed in the public API, and C# prohibits a public class from
+ // inheriting from an internal one. So, we have to override each of the
+ // methods in question and repeat the argument validation/logic.
+
+ // These set of methods exist so instead of duplicating code, we can
+ // simply have those overriden methods call here to do the actual work.
+
+ // NOTE: This class should ONLY be called from Encodings that override
+ // the internal methods which accept an Encoder/DecoderNLS. The reason
+ // for this is that by default, those methods just call the same overload
+ // except without the encoder/decoder parameter. If an overriden method
+ // without that parameter calls this class, which calls the overload with
+ // the parameter, it will call the same method again, which will eventually
+ // lead to a StackOverflowException.
+
+ [SecuritySafeCritical]
+ public unsafe static int GetByteCount(Encoding encoding, char[] chars, int index, int count)
+ {
+ // Validate parameters
+
+ Contract.Assert(encoding != null); // this parameter should only be affected internally, so just do a debug check here
+ if (chars == null)
+ {
+ throw new ArgumentNullException("chars", Environment.GetResourceString("ArgumentNull_Array"));
+ }
+ if (index < 0 || count < 0)
+ {
+ throw new ArgumentOutOfRangeException(index < 0 ? "index" : "count", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
+ }
+ if (chars.Length - index < count)
+ {
+ throw new ArgumentOutOfRangeException("chars", Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer"));
+ }
+ Contract.EndContractBlock();
+
+ // If no input, return 0, avoid fixed empty array problem
+ if (count == 0)
+ return 0;
+
+ // Just call the (internal) pointer version
+ fixed (char* pChars = chars)
+ return encoding.GetByteCount(pChars + index, count, encoder: null);
+ }
+
+ [SecuritySafeCritical]
+ public unsafe static int GetByteCount(Encoding encoding, string s)
+ {
+ Contract.Assert(encoding != null);
+ if (s == null)
+ {
+ string paramName = encoding is ASCIIEncoding ? "chars" : "s"; // ASCIIEncoding calls the string chars
+ // UTF8Encoding does this as well, but it originally threw an ArgumentNull for "s" so don't check for that
+ throw new ArgumentNullException(paramName);
+ }
+ Contract.EndContractBlock();
+
+ // NOTE: The behavior of fixed *is* defined by
+ // the spec for empty strings, although not for
+ // null strings/empty char arrays. See
+ // http://stackoverflow.com/q/37757751/4077294
+ // Regardless, we may still want to check
+ // for if (s.Length == 0) in the future
+ // and short-circuit as an optimization (TODO).
+
+ fixed (char* pChars = s)
+ return encoding.GetByteCount(pChars, s.Length, encoder: null);
+ }
+
+ [SecurityCritical]
+ public unsafe static int GetByteCount(Encoding encoding, char* chars, int count)
+ {
+ Contract.Assert(encoding != null);
+ if (chars == null)
+ {
+ throw new ArgumentNullException("chars", Environment.GetResourceString("ArgumentNull_Array"));
+ }
+ if (count < 0)
+ {
+ throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
+ }
+ Contract.EndContractBlock();
+
+ // Call the internal version, with an empty encoder
+ return encoding.GetByteCount(chars, count, encoder: null);
+ }
+
+ [SecuritySafeCritical]
+ public unsafe static int GetBytes(Encoding encoding, string s, int charIndex, int charCount, byte[] bytes, int byteIndex)
+ {
+ Contract.Assert(encoding != null);
+ if (s == null || bytes == null)
+ {
+ string stringName = encoding is ASCIIEncoding ? "chars" : "s"; // ASCIIEncoding calls the first parameter chars
+ throw new ArgumentNullException(s == null ? stringName : "bytes", Environment.GetResourceString("ArgumentNull_Array"));
+ }
+ if (charIndex < 0 || charCount < 0)
+ {
+ throw new ArgumentOutOfRangeException(charIndex < 0 ? "charIndex" : "charCount", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
+ }
+ if (s.Length - charIndex < charCount)
+ {
+ string stringName = encoding is ASCIIEncoding ? "chars" : "s"; // ASCIIEncoding calls the first parameter chars
+ // Duplicate the above check since we don't want the overhead of a type check on the general path
+ throw new ArgumentOutOfRangeException(stringName, Environment.GetResourceString("ArgumentOutOfRange_IndexCount"));
+ }
+ if (byteIndex < 0 || byteIndex > bytes.Length)
+ {
+ throw new ArgumentOutOfRangeException("byteIndex", Environment.GetResourceString("ArgumentOutOfRange_Index"));
+ }
+ Contract.EndContractBlock();
+
+ int byteCount = bytes.Length - byteIndex;
+
+ // Fixed doesn't like empty arrays
+ if (bytes.Length == 0)
+ bytes = new byte[1];
+
+ fixed (char* pChars = s) fixed (byte* pBytes = bytes)
+ {
+ return encoding.GetBytes(pChars + charIndex, charCount, pBytes + byteIndex, byteCount, encoder: null);
+ }
+ }
+
+ [SecuritySafeCritical]
+ public unsafe static int GetBytes(Encoding encoding, char[] chars, int charIndex, int charCount, byte[] bytes, int byteIndex)
+ {
+ Contract.Assert(encoding != null);
+ if (chars == null || bytes == null)
+ {
+ throw new ArgumentNullException(chars == null ? "chars" : "bytes", Environment.GetResourceString("ArgumentNull_Array"));
+ }
+ if (charIndex < 0 || charCount < 0)
+ {
+ throw new ArgumentOutOfRangeException(charIndex < 0 ? "charIndex" : "charCount", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
+ }
+ if (chars.Length - charIndex < charCount)
+ {
+ throw new ArgumentOutOfRangeException("chars", Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer"));
+ }
+ if (byteIndex < 0 || byteIndex > bytes.Length)
+ {
+ throw new ArgumentOutOfRangeException("byteIndex", Environment.GetResourceString("ArgumentOutOfRange_Index"));
+ }
+ Contract.EndContractBlock();
+
+ // If nothing to encode return 0, avoid fixed problem
+ if (charCount == 0)
+ return 0;
+
+ // Note that this is the # of bytes to decode,
+ // not the size of the array
+ int byteCount = bytes.Length - byteIndex;
+
+ // Fixed doesn't like 0 length arrays.
+ if (bytes.Length == 0)
+ bytes = new byte[1];
+
+ // Just call the (internal) pointer version
+ fixed (char* pChars = chars) fixed (byte* pBytes = bytes)
+ {
+ return encoding.GetBytes(pChars + charIndex, charCount, pBytes + byteIndex, byteCount, encoder: null);
+ }
+ }
+
+ [SecurityCritical]
+ public unsafe static int GetBytes(Encoding encoding, char* chars, int charCount, byte* bytes, int byteCount)
+ {
+ Contract.Assert(encoding != null);
+ if (bytes == null || chars == null)
+ {
+ throw new ArgumentNullException(bytes == null ? "bytes" : "chars", Environment.GetResourceString("ArgumentNull_Array"));
+ }
+ if (charCount < 0 || byteCount < 0)
+ {
+ throw new ArgumentOutOfRangeException(charCount < 0 ? "charCount" : "byteCount", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
+ }
+ Contract.EndContractBlock();
+
+ return encoding.GetBytes(chars, charCount, bytes, byteCount, encoder: null);
+ }
+
+ [SecuritySafeCritical]
+ public unsafe static int GetCharCount(Encoding encoding, byte[] bytes, int index, int count)
+ {
+ Contract.Assert(encoding != null);
+ if (bytes == null)
+ {
+ throw new ArgumentNullException("bytes", Environment.GetResourceString("ArgumentNull_Array"));
+ }
+ if (index < 0 || count < 0)
+ {
+ throw new ArgumentOutOfRangeException(index < 0 ? "index" : "count", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
+ }
+ if (bytes.Length - index < count)
+ {
+ throw new ArgumentOutOfRangeException("bytes", Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer"));
+ }
+ Contract.EndContractBlock();
+
+ // If no input just return 0, fixed doesn't like 0 length arrays.
+ if (count == 0)
+ return 0;
+
+ // Just call pointer version
+ fixed (byte* pBytes = bytes)
+ return encoding.GetCharCount(pBytes + index, count, decoder: null);
+ }
+
+ [SecurityCritical]
+ public unsafe static int GetCharCount(Encoding encoding, byte* bytes, int count)
+ {
+ Contract.Assert(encoding != null);
+ if (bytes == null)
+ {
+ throw new ArgumentNullException("bytes", Environment.GetResourceString("ArgumentNull_Array"));
+ }
+ if (count < 0)
+ {
+ throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
+ }
+ Contract.EndContractBlock();
+
+ return encoding.GetCharCount(bytes, count, decoder: null);
+ }
+
+ [SecuritySafeCritical]
+ public unsafe static int GetChars(Encoding encoding, byte[] bytes, int byteIndex, int byteCount, char[] chars, int charIndex)
+ {
+ Contract.Assert(encoding != null);
+ if (bytes == null || chars == null)
+ {
+ throw new ArgumentNullException(bytes == null ? "bytes" : "chars", Environment.GetResourceString("ArgumentNull_Array"));
+ }
+ if (byteIndex < 0 || byteCount < 0)
+ {
+ throw new ArgumentOutOfRangeException(byteIndex < 0 ? "byteIndex" : "byteCount", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
+ }
+ if (bytes.Length - byteIndex < byteCount)
+ {
+ throw new ArgumentOutOfRangeException("bytes", Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer"));
+ }
+ if (charIndex < 0 || charIndex > chars.Length)
+ {
+ throw new ArgumentOutOfRangeException("charIndex", Environment.GetResourceString("ArgumentOutOfRange_Index"));
+ }
+ Contract.EndContractBlock();
+
+ if (byteCount == 0)
+ return 0;
+
+ // NOTE: This is the # of chars we can decode,
+ // not the size of the array
+ int charCount = chars.Length - charIndex;
+
+ // Fixed doesn't like 0 length arrays.
+ if (chars.Length == 0)
+ chars = new char[1];
+
+ fixed (byte* pBytes = bytes) fixed (char* pChars = chars)
+ {
+ return encoding.GetChars(pBytes + byteIndex, byteCount, pChars + charIndex, charCount, decoder: null);
+ }
+ }
+
+ [SecurityCritical]
+ public unsafe static int GetChars(Encoding encoding, byte* bytes, int byteCount, char* chars, int charCount)
+ {
+ Contract.Assert(encoding != null);
+ if (bytes == null || chars == null)
+ {
+ throw new ArgumentNullException(bytes == null ? "bytes" : "chars", Environment.GetResourceString("ArgumentNull_Array"));
+ }
+ if (charCount < 0 || byteCount < 0)
+ {
+ throw new ArgumentOutOfRangeException(charCount < 0 ? "charCount" : "byteCount", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
+ }
+ Contract.EndContractBlock();
+
+ return encoding.GetChars(bytes, byteCount, chars, charCount, decoder: null);
+ }
+
+ [SecuritySafeCritical]
+ public unsafe static string GetString(Encoding encoding, byte[] bytes, int index, int count)
+ {
+ Contract.Assert(encoding != null);
+ if (bytes == null)
+ {
+ throw new ArgumentNullException("bytes", Environment.GetResourceString("ArgumentNull_Array"));
+ }
+ if (index < 0 || count < 0)
+ {
+ // ASCIIEncoding has different names for its parameters here (byteIndex, byteCount)
+ bool ascii = encoding is ASCIIEncoding;
+ string indexName = ascii ? "byteIndex" : "index";
+ string countName = ascii ? "byteCount" : "count";
+ throw new ArgumentOutOfRangeException(index < 0 ? indexName : countName, Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
+ }
+ if (bytes.Length - index < count)
+ {
+ throw new ArgumentOutOfRangeException("bytes", Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer"));
+ }
+ Contract.EndContractBlock();
+
+ // Avoid problems with empty input buffer
+ if (count == 0)
+ return string.Empty;
+
+ // Call string.CreateStringFromEncoding here, which
+ // allocates a string and lets the Encoding modify
+ // it in place. This way, we don't have to allocate
+ // an intermediary char[] to decode into and then
+ // call the string constructor; instead we decode
+ // directly into the string.
+
+ fixed (byte* pBytes = bytes)
+ {
+ return string.CreateStringFromEncoding(pBytes + index, count, encoding);
+ }
+ }
+ }
+}
diff --git a/src/mscorlib/src/System/Text/EncodingNLS.cs b/src/mscorlib/src/System/Text/EncodingNLS.cs
index 73aba3df95..d670d6daa7 100644
--- a/src/mscorlib/src/System/Text/EncodingNLS.cs
+++ b/src/mscorlib/src/System/Text/EncodingNLS.cs
@@ -14,18 +14,7 @@ namespace System.Text
using Win32Native = Microsoft.Win32.Win32Native;
// This class overrides Encoding with the things we need for our NLS Encodings
- //
- // All of the GetBytes/Chars GetByte/CharCount methods are just wrappers for the pointer
- // plus decoder/encoder method that is our real workhorse. Note that this is an internal
- // class, so our public classes cannot derive from this class. Because of this, all of the
- // GetBytes/Chars GetByte/CharCount wrapper methods are duplicated in all of our public
- // encodings, which currently include:
- //
- // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, & UnicodeEncoding
- //
- // So if you change the wrappers in this class, you must change the wrappers in the other classes
- // as well because they should have the same behavior.
- //
+
[System.Runtime.InteropServices.ComVisible(true)]
[Serializable]
internal abstract class EncodingNLS : Encoding
@@ -34,110 +23,43 @@ namespace System.Text
{
}
+ // NOTE: Many methods in this class forward to EncodingForwarder for
+ // validating arguments/wrapping the unsafe methods in this class
+ // which do the actual work. That class contains
+ // shared logic for doing this which is used by
+ // ASCIIEncoding, EncodingNLS, UnicodeEncoding, UTF32Encoding,
+ // UTF7Encoding, and UTF8Encoding.
+ // The reason the code is separated out into a static class, rather
+ // than a base class which overrides all of these methods for us
+ // (which is what EncodingNLS is for internal Encodings) is because
+ // that's really more of an implementation detail so it's internal.
+ // At the same time, C# doesn't allow a public class subclassing an
+ // internal/private one, so we end up having to re-override these
+ // methods in all of the public Encodings + EncodingNLS.
+
// Returns the number of bytes required to encode a range of characters in
// a character array.
- //
- // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
- // So if you fix this, fix the others. Currently those include:
- // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
- // parent method is safe
- [System.Security.SecuritySafeCritical] // overrides public transparent member
- public override unsafe int GetByteCount(char[] chars, int index, int count)
- {
- // Validate input parameters
- if (chars == null)
- throw new ArgumentNullException("chars",
- Environment.GetResourceString("ArgumentNull_Array"));
-
- if (index < 0 || count < 0)
- throw new ArgumentOutOfRangeException((index<0 ? "index" : "count"),
- Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
-
- if (chars.Length - index < count)
- throw new ArgumentOutOfRangeException("chars",
- Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer"));
- Contract.EndContractBlock();
-
- // If no input, return 0, avoid fixed empty array problem
- if (count == 0)
- return 0;
- // Just call the pointer version
- fixed (char* pChars = chars)
- return GetByteCount(pChars + index, count, null);
+ public override int GetByteCount(char[] chars, int index, int count)
+ {
+ return EncodingForwarder.GetByteCount(this, chars, index, count);
}
-
- // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
- // So if you fix this, fix the others. Currently those include:
- // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
- // parent method is safe
- [System.Security.SecuritySafeCritical] // overrides public transparent member
- public override unsafe int GetByteCount(String s)
+
+ public override int GetByteCount(String s)
{
- // Validate input
- if (s==null)
- throw new ArgumentNullException("s");
- Contract.EndContractBlock();
-
- fixed (char* pChars = s)
- return GetByteCount(pChars, s.Length, null);
- }
+ return EncodingForwarder.GetByteCount(this, s);
+ }
- // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
- // So if you fix this, fix the others. Currently those include:
- // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
[System.Security.SecurityCritical] // auto-generated
public override unsafe int GetByteCount(char* chars, int count)
{
- // Validate Parameters
- if (chars == null)
- throw new ArgumentNullException("chars",
- Environment.GetResourceString("ArgumentNull_Array"));
-
- if (count < 0)
- throw new ArgumentOutOfRangeException("count",
- Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
- Contract.EndContractBlock();
-
- // Call it with empty encoder
- return GetByteCount(chars, count, null);
+ return EncodingForwarder.GetByteCount(this, chars, count);
}
- // Parent method is safe.
- // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
- // So if you fix this, fix the others. Currently those include:
- // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
- [System.Security.SecuritySafeCritical] // overrides public transparent member
- public override unsafe int GetBytes(String s, int charIndex, int charCount,
+ public override int GetBytes(String s, int charIndex, int charCount,
byte[] bytes, int byteIndex)
{
- if (s == null || bytes == null)
- throw new ArgumentNullException((s == null ? "s" : "bytes"),
- Environment.GetResourceString("ArgumentNull_Array"));
-
- if (charIndex < 0 || charCount < 0)
- throw new ArgumentOutOfRangeException((charIndex<0 ? "charIndex" : "charCount"),
- Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
-
- if (s.Length - charIndex < charCount)
- throw new ArgumentOutOfRangeException("s",
- Environment.GetResourceString("ArgumentOutOfRange_IndexCount"));
-
- if (byteIndex < 0 || byteIndex > bytes.Length)
- throw new ArgumentOutOfRangeException("byteIndex",
- Environment.GetResourceString("ArgumentOutOfRange_Index"));
- Contract.EndContractBlock();
-
- int byteCount = bytes.Length - byteIndex;
-
- // Fixed doesn't like empty arrays
- if (bytes.Length == 0)
- bytes = new byte[1];
-
- fixed (char* pChars = s)
- fixed ( byte* pBytes = bytes)
- return GetBytes(pChars + charIndex, charCount,
- pBytes + byteIndex, byteCount, null);
+ return EncodingForwarder.GetBytes(this, s, charIndex, charCount, bytes, byteIndex);
}
// Encodes a range of characters in a character array into a range of bytes
@@ -148,215 +70,51 @@ namespace System.Text
// Alternatively, the GetMaxByteCount method can be used to
// determine the maximum number of bytes that will be produced for a given
// number of characters, regardless of the actual character values.
- //
- // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
- // So if you fix this, fix the others. Currently those include:
- // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
- // parent method is safe
- [System.Security.SecuritySafeCritical] // overrides public transparent member
- public override unsafe int GetBytes(char[] chars, int charIndex, int charCount,
+
+ public override int GetBytes(char[] chars, int charIndex, int charCount,
byte[] bytes, int byteIndex)
{
- // Validate parameters
- if (chars == null || bytes == null)
- throw new ArgumentNullException((chars == null ? "chars" : "bytes"),
- Environment.GetResourceString("ArgumentNull_Array"));
-
- if (charIndex < 0 || charCount < 0)
- throw new ArgumentOutOfRangeException((charIndex<0 ? "charIndex" : "charCount"),
- Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
-
- if (chars.Length - charIndex < charCount)
- throw new ArgumentOutOfRangeException("chars",
- Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer"));
-
- if (byteIndex < 0 || byteIndex > bytes.Length)
- throw new ArgumentOutOfRangeException("byteIndex",
- Environment.GetResourceString("ArgumentOutOfRange_Index"));
- Contract.EndContractBlock();
-
- // If nothing to encode return 0, avoid fixed problem
- if (charCount == 0)
- return 0;
-
- // Just call pointer version
- int byteCount = bytes.Length - byteIndex;
-
- // Fixed doesn't like empty arrays
- if (bytes.Length == 0)
- bytes = new byte[1];
-
- fixed (char* pChars = chars)
- fixed (byte* pBytes = bytes)
- // Remember that byteCount is # to decode, not size of array.
- return GetBytes(pChars + charIndex, charCount,
- pBytes + byteIndex, byteCount, null);
+ return EncodingForwarder.GetBytes(this, chars, charIndex, charCount, bytes, byteIndex);
}
- // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
- // So if you fix this, fix the others. Currently those include:
- // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
[System.Security.SecurityCritical] // auto-generated
public override unsafe int GetBytes(char* chars, int charCount, byte* bytes, int byteCount)
{
- // Validate Parameters
- if (bytes == null || chars == null)
- throw new ArgumentNullException(bytes == null ? "bytes" : "chars",
- Environment.GetResourceString("ArgumentNull_Array"));
-
- if (charCount < 0 || byteCount < 0)
- throw new ArgumentOutOfRangeException((charCount<0 ? "charCount" : "byteCount"),
- Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
- Contract.EndContractBlock();
-
- return GetBytes(chars, charCount, bytes, byteCount, null);
+ return EncodingForwarder.GetBytes(this, chars, charCount, bytes, byteCount);
}
// Returns the number of characters produced by decoding a range of bytes
// in a byte array.
- //
- // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
- // So if you fix this, fix the others. Currently those include:
- // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
- // parent method is safe
- [System.Security.SecuritySafeCritical] // overrides public transparent member
- public override unsafe int GetCharCount(byte[] bytes, int index, int count)
+
+ public override int GetCharCount(byte[] bytes, int index, int count)
{
- // Validate Parameters
- if (bytes == null)
- throw new ArgumentNullException("bytes",
- Environment.GetResourceString("ArgumentNull_Array"));
-
- if (index < 0 || count < 0)
- throw new ArgumentOutOfRangeException((index<0 ? "index" : "count"),
- Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
-
- if (bytes.Length - index < count)
- throw new ArgumentOutOfRangeException("bytes",
- Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer"));
- Contract.EndContractBlock();
-
- // If no input just return 0, fixed doesn't like 0 length arrays
- if (count == 0)
- return 0;
-
- // Just call pointer version
- fixed (byte* pBytes = bytes)
- return GetCharCount(pBytes + index, count, null);
+ return EncodingForwarder.GetCharCount(this, bytes, index, count);
}
- // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
- // So if you fix this, fix the others. Currently those include:
- // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
[System.Security.SecurityCritical] // auto-generated
public override unsafe int GetCharCount(byte* bytes, int count)
{
- // Validate Parameters
- if (bytes == null)
- throw new ArgumentNullException("bytes",
- Environment.GetResourceString("ArgumentNull_Array"));
-
- if (count < 0)
- throw new ArgumentOutOfRangeException("count",
- Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
- Contract.EndContractBlock();
-
- return GetCharCount(bytes, count, null);
+ return EncodingForwarder.GetCharCount(this, bytes, count);
}
- // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
- // So if you fix this, fix the others. Currently those include:
- // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
- // parent method is safe
- [System.Security.SecuritySafeCritical] // overrides public transparent member
- public override unsafe int GetChars(byte[] bytes, int byteIndex, int byteCount,
+ public override int GetChars(byte[] bytes, int byteIndex, int byteCount,
char[] chars, int charIndex)
{
- // Validate Parameters
- if (bytes == null || chars == null)
- throw new ArgumentNullException(bytes == null ? "bytes" : "chars",
- Environment.GetResourceString("ArgumentNull_Array"));
-
- if (byteIndex < 0 || byteCount < 0)
- throw new ArgumentOutOfRangeException((byteIndex<0 ? "byteIndex" : "byteCount"),
- Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
-
- if ( bytes.Length - byteIndex < byteCount)
- throw new ArgumentOutOfRangeException("bytes",
- Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer"));
-
- if (charIndex < 0 || charIndex > chars.Length)
- throw new ArgumentOutOfRangeException("charIndex",
- Environment.GetResourceString("ArgumentOutOfRange_Index"));
- Contract.EndContractBlock();
-
- // If no input, return 0 & avoid fixed problem
- if (byteCount == 0)
- return 0;
-
- // Just call pointer version
- int charCount = chars.Length - charIndex;
-
- // Fixed doesn't like empty arrays
- if (chars.Length == 0)
- chars = new char[1];
-
- fixed (byte* pBytes = bytes)
- fixed (char* pChars = chars)
- // Remember that charCount is # to decode, not size of array
- return GetChars(pBytes + byteIndex, byteCount,
- pChars + charIndex, charCount, null);
+ return EncodingForwarder.GetChars(this, bytes, byteIndex, byteCount, chars, charIndex);
}
- // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
- // So if you fix this, fix the others. Currently those include:
- // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
[System.Security.SecurityCritical] // auto-generated
public unsafe override int GetChars(byte* bytes, int byteCount, char* chars, int charCount)
{
- // Validate Parameters
- if (bytes == null || chars == null)
- throw new ArgumentNullException(bytes == null ? "bytes" : "chars",
- Environment.GetResourceString("ArgumentNull_Array"));
-
- if (charCount < 0 || byteCount < 0)
- throw new ArgumentOutOfRangeException((charCount<0 ? "charCount" : "byteCount"),
- Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
- Contract.EndContractBlock();
-
- return GetChars(bytes, byteCount, chars, charCount, null);
+ return EncodingForwarder.GetChars(this, bytes, byteCount, chars, charCount);
}
// Returns a string containing the decoded representation of a range of
// bytes in a byte array.
- //
- // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
- // So if you fix this, fix the others. Currently those include:
- // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
- // parent method is safe
- [System.Security.SecuritySafeCritical] // overrides public transparent member
- public override unsafe String GetString(byte[] bytes, int index, int count)
+
+ public override String GetString(byte[] bytes, int index, int count)
{
- // Validate Parameters
- if (bytes == null)
- throw new ArgumentNullException("bytes",
- Environment.GetResourceString("ArgumentNull_Array"));
-
- if (index < 0 || count < 0)
- throw new ArgumentOutOfRangeException((index < 0 ? "index" : "count"),
- Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
-
- if (bytes.Length - index < count)
- throw new ArgumentOutOfRangeException("bytes",
- Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer"));
- Contract.EndContractBlock();
-
- // Avoid problems with empty input buffer
- if (count == 0) return String.Empty;
-
- fixed (byte* pBytes = bytes)
- return String.CreateStringFromEncoding(
- pBytes + index, count, this);
+ return EncodingForwarder.GetString(this, bytes, index, count);
}
public override Decoder GetDecoder()
diff --git a/src/mscorlib/src/System/Text/GB18030Encoding.cs b/src/mscorlib/src/System/Text/GB18030Encoding.cs
index 55cabe5574..b774058d77 100644
--- a/src/mscorlib/src/System/Text/GB18030Encoding.cs
+++ b/src/mscorlib/src/System/Text/GB18030Encoding.cs
@@ -101,7 +101,9 @@ namespace System.Text
**
==============================================================================*/
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
internal sealed class GB18030Encoding : DBCSCodePageEncoding, ISerializable
{
// This is the table of 4 byte conversions.
@@ -840,7 +842,9 @@ namespace System.Text
return new GB18030Decoder(this);
}
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
internal sealed class GB18030Decoder : System.Text.DecoderNLS, ISerializable
{
internal short bLeftOver1 = -1;
diff --git a/src/mscorlib/src/System/Text/ISCIIEncoding.cs b/src/mscorlib/src/System/Text/ISCIIEncoding.cs
index 5cf228252d..7e73bb70b9 100644
--- a/src/mscorlib/src/System/Text/ISCIIEncoding.cs
+++ b/src/mscorlib/src/System/Text/ISCIIEncoding.cs
@@ -28,8 +28,13 @@ namespace System.Text
// Form IDNA has the above problems plus case mapping, so false (like most encodings)
//
+#if FEATURE_SERIALIZATION
[Serializable]
- internal class ISCIIEncoding : EncodingNLS, ISerializable
+#endif
+ internal class ISCIIEncoding : EncodingNLS
+#if FEATURE_SERIALIZATION
+ , ISerializable
+#endif
{
// Constants
private const int CodeDefault = 0; // 0x40 Default
diff --git a/src/mscorlib/src/System/Text/Latin1Encoding.cs b/src/mscorlib/src/System/Text/Latin1Encoding.cs
index f65c0ec402..a623630ef1 100644
--- a/src/mscorlib/src/System/Text/Latin1Encoding.cs
+++ b/src/mscorlib/src/System/Text/Latin1Encoding.cs
@@ -19,8 +19,13 @@ namespace System.Text
// Latin1Encoding is a simple override to optimize the GetString version of Latin1Encoding.
// because of the best fit cases we can't do this when encoding the string, only when decoding
//
+#if FEATURE_SERIALIZATION
[Serializable]
- internal class Latin1Encoding : EncodingNLS, ISerializable
+#endif
+ internal class Latin1Encoding : EncodingNLS
+#if FEATURE_SERIALIZATION
+ , ISerializable
+#endif
{
// We only use the best-fit table, of which ASCII is a superset for us.
public Latin1Encoding() : base(Encoding.ISO_8859_1)
@@ -490,7 +495,7 @@ namespace System.Text
}
}
-#if !FEATURE_NORM_IDNA_ONLY
+#if !FEATURE_NORM_IDNA_ONLY
public override bool IsAlwaysNormalized(NormalizationForm form)
{
// Latin-1 contains precomposed characters, so normal for Form C.
diff --git a/src/mscorlib/src/System/Text/MLangCodePageEncoding.cs b/src/mscorlib/src/System/Text/MLangCodePageEncoding.cs
index 0ef1bd3e4d..747e1084ac 100644
--- a/src/mscorlib/src/System/Text/MLangCodePageEncoding.cs
+++ b/src/mscorlib/src/System/Text/MLangCodePageEncoding.cs
@@ -22,8 +22,13 @@ namespace System.Text
** to Everett compatibility as well.
==============================================================================*/
+#if FEATURE_SERIALIZATION
[Serializable]
- internal sealed class MLangCodePageEncoding : ISerializable, IObjectReference
+#endif
+ internal sealed class MLangCodePageEncoding : IObjectReference
+#if FEATURE_SERIALIZATION
+ , ISerializable
+#endif
{
// Temp stuff
[NonSerialized]
@@ -105,9 +110,14 @@ namespace System.Text
}
#endif
- // Same problem with the Encoder, this only happens with Everett Encoders
+// Same problem with the Encoder, this only happens with Everett Encoders
+#if FEATURE_SERIALIZATION
[Serializable]
- internal sealed class MLangEncoder : ISerializable, IObjectReference
+#endif
+ internal sealed class MLangEncoder : IObjectReference
+#if FEATURE_SERIALIZATION
+ , ISerializable
+#endif
{
// Might need this when GetRealObjecting
[NonSerialized]
@@ -144,8 +154,13 @@ namespace System.Text
// Same problem with the Decoder, this only happens with Everett Decoders
+#if FEATURE_SERIALIZATION
[Serializable]
- internal sealed class MLangDecoder : ISerializable, IObjectReference
+#endif
+ internal sealed class MLangDecoder : IObjectReference
+#if FEATURE_SERIALIZATION
+ , ISerializable
+#endif
{
// Might need this when GetRealObjecting
[NonSerialized]
diff --git a/src/mscorlib/src/System/Text/SBCSCodePageEncoding.cs b/src/mscorlib/src/System/Text/SBCSCodePageEncoding.cs
index ce611d8b1f..06f09ad425 100644
--- a/src/mscorlib/src/System/Text/SBCSCodePageEncoding.cs
+++ b/src/mscorlib/src/System/Text/SBCSCodePageEncoding.cs
@@ -15,7 +15,9 @@ namespace System.Text
using System.Security.Permissions;
// SBCSCodePageEncoding
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
internal class SBCSCodePageEncoding : BaseCodePageEncoding, ISerializable
{
// Pointers to our memory section parts
diff --git a/src/mscorlib/src/System/Text/StringBuilder.cs b/src/mscorlib/src/System/Text/StringBuilder.cs
index 0c0d1201d3..c519f1c0b2 100644
--- a/src/mscorlib/src/System/Text/StringBuilder.cs
+++ b/src/mscorlib/src/System/Text/StringBuilder.cs
@@ -40,8 +40,14 @@ namespace System.Text {
// Console.WriteLine(sb2);
//
[System.Runtime.InteropServices.ComVisible(true)]
+#if FEATURE_SERIALIZATION
[Serializable]
- public sealed class StringBuilder : ISerializable {
+#endif
+ public sealed class StringBuilder
+#if FEATURE_SERIALIZATION
+ : ISerializable
+#endif
+ {
// A StringBuilder is internally represented as a linked list of blocks each of which holds
// a chunk of the string. It turns out string as a whole can also be represented as just a chunk,
// so that is what we do.
diff --git a/src/mscorlib/src/System/Text/SurrogateEncoder.cs b/src/mscorlib/src/System/Text/SurrogateEncoder.cs
index e88aa597c6..f1115c5537 100644
--- a/src/mscorlib/src/System/Text/SurrogateEncoder.cs
+++ b/src/mscorlib/src/System/Text/SurrogateEncoder.cs
@@ -19,8 +19,13 @@ namespace System.Text
** Appropriate Whidbey (V2.0) objects.
==============================================================================*/
+#if FEATURE_SERIALIZATION
[Serializable]
- internal sealed class SurrogateEncoder : ISerializable, IObjectReference
+#endif
+ internal sealed class SurrogateEncoder : IObjectReference
+#if FEATURE_SERIALIZATION
+ , ISerializable
+#endif
{
// Might need this when GetRealObjecting
[NonSerialized]
diff --git a/src/mscorlib/src/System/Text/UTF32Encoding.cs b/src/mscorlib/src/System/Text/UTF32Encoding.cs
index 02a3232809..cd7d0a9088 100644
--- a/src/mscorlib/src/System/Text/UTF32Encoding.cs
+++ b/src/mscorlib/src/System/Text/UTF32Encoding.cs
@@ -78,123 +78,44 @@ namespace System.Text
}
}
-
- //
- // The following methods are copied from EncodingNLS.cs.
- // Unfortunately EncodingNLS.cs is internal and we're public, so we have to reimpliment them here.
- // These should be kept in sync for the following classes:
- // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
- //
+ // NOTE: Many methods in this class forward to EncodingForwarder for
+ // validating arguments/wrapping the unsafe methods in this class
+ // which do the actual work. That class contains
+ // shared logic for doing this which is used by
+ // ASCIIEncoding, EncodingNLS, UnicodeEncoding, UTF32Encoding,
+ // UTF7Encoding, and UTF8Encoding.
+ // The reason the code is separated out into a static class, rather
+ // than a base class which overrides all of these methods for us
+ // (which is what EncodingNLS is for internal Encodings) is because
+ // that's really more of an implementation detail so it's internal.
+ // At the same time, C# doesn't allow a public class subclassing an
+ // internal/private one, so we end up having to re-override these
+ // methods in all of the public Encodings + EncodingNLS.
// Returns the number of bytes required to encode a range of characters in
// a character array.
- //
- // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
- // So if you fix this, fix the others. Currently those include:
- // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
- // parent method is safe
- [System.Security.SecuritySafeCritical] // auto-generated
- public override unsafe int GetByteCount(char[] chars, int index, int count)
+ public override int GetByteCount(char[] chars, int index, int count)
{
- // Validate input parameters
- if (chars == null)
- throw new ArgumentNullException("chars",
- Environment.GetResourceString("ArgumentNull_Array"));
-
- if (index < 0 || count < 0)
- throw new ArgumentOutOfRangeException((index<0 ? "index" : "count"),
- Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
-
- if (chars.Length - index < count)
- throw new ArgumentOutOfRangeException("chars",
- Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer"));
- Contract.EndContractBlock();
-
- // If no input, return 0, avoid fixed empty array problem
- if (count == 0)
- return 0;
-
- // Just call the pointer version
- fixed (char* pChars = chars)
- return GetByteCount(pChars + index, count, null);
+ return EncodingForwarder.GetByteCount(this, chars, index, count);
}
- // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
- // So if you fix this, fix the others. Currently those include:
- // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
- // parent method is safe
-
- [System.Security.SecuritySafeCritical] // auto-generated
- public override unsafe int GetByteCount(String s)
+ public override int GetByteCount(String s)
{
- // Validate input
- if (s==null)
- throw new ArgumentNullException("s");
- Contract.EndContractBlock();
-
- fixed (char* pChars = s)
- return GetByteCount(pChars, s.Length, null);
+ return EncodingForwarder.GetByteCount(this, s);
}
- // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
- // So if you fix this, fix the others. Currently those include:
- // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
-
[System.Security.SecurityCritical] // auto-generated
[CLSCompliant(false)]
public override unsafe int GetByteCount(char* chars, int count)
{
- // Validate Parameters
- if (chars == null)
- throw new ArgumentNullException("chars",
- Environment.GetResourceString("ArgumentNull_Array"));
-
- if (count < 0)
- throw new ArgumentOutOfRangeException("count",
- Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
- Contract.EndContractBlock();
-
- // Call it with empty encoder
- return GetByteCount(chars, count, null);
+ return EncodingForwarder.GetByteCount(this, chars, count);
}
- // Parent method is safe.
- // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
- // So if you fix this, fix the others. Currently those include:
- // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
-
- [System.Security.SecuritySafeCritical] // auto-generated
- public override unsafe int GetBytes(String s, int charIndex, int charCount,
+ public override int GetBytes(String s, int charIndex, int charCount,
byte[] bytes, int byteIndex)
{
- if (s == null || bytes == null)
- throw new ArgumentNullException((s == null ? "s" : "bytes"),
- Environment.GetResourceString("ArgumentNull_Array"));
-
- if (charIndex < 0 || charCount < 0)
- throw new ArgumentOutOfRangeException((charIndex<0 ? "charIndex" : "charCount"),
- Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
-
- if (s.Length - charIndex < charCount)
- throw new ArgumentOutOfRangeException("s",
- Environment.GetResourceString("ArgumentOutOfRange_IndexCount"));
-
- if (byteIndex < 0 || byteIndex > bytes.Length)
- throw new ArgumentOutOfRangeException("byteIndex",
- Environment.GetResourceString("ArgumentOutOfRange_Index"));
- Contract.EndContractBlock();
-
- int byteCount = bytes.Length - byteIndex;
-
- // Fix our input array if 0 length because fixed doesn't like 0 length arrays
- if (bytes.Length == 0)
- bytes = new byte[1];
-
- fixed (char* pChars = s)
- fixed ( byte* pBytes = bytes)
- return GetBytes(pChars + charIndex, charCount,
- pBytes + byteIndex, byteCount, null);
+ return EncodingForwarder.GetBytes(this, s, charIndex, charCount, bytes, byteIndex);
}
// Encodes a range of characters in a character array into a range of bytes
@@ -205,230 +126,57 @@ namespace System.Text
// Alternatively, the GetMaxByteCount method can be used to
// determine the maximum number of bytes that will be produced for a given
// number of characters, regardless of the actual character values.
- //
- // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
- // So if you fix this, fix the others. Currently those include:
- // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
- // parent method is safe
- [System.Security.SecuritySafeCritical] // auto-generated
- public override unsafe int GetBytes(char[] chars, int charIndex, int charCount,
+ public override int GetBytes(char[] chars, int charIndex, int charCount,
byte[] bytes, int byteIndex)
{
- // Validate parameters
- if (chars == null || bytes == null)
- throw new ArgumentNullException((chars == null ? "chars" : "bytes"),
- Environment.GetResourceString("ArgumentNull_Array"));
-
- if (charIndex < 0 || charCount < 0)
- throw new ArgumentOutOfRangeException((charIndex<0 ? "charIndex" : "charCount"),
- Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
-
- if (chars.Length - charIndex < charCount)
- throw new ArgumentOutOfRangeException("chars",
- Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer"));
-
- if (byteIndex < 0 || byteIndex > bytes.Length)
- throw new ArgumentOutOfRangeException("byteIndex",
- Environment.GetResourceString("ArgumentOutOfRange_Index"));
- Contract.EndContractBlock();
-
- // If nothing to encode return 0, avoid fixed problem
- if (charCount == 0)
- return 0;
-
- // Just call pointer version
- int byteCount = bytes.Length - byteIndex;
-
- // Fix our input array if 0 length because fixed doesn't like 0 length arrays
- if (bytes.Length == 0)
- bytes = new byte[1];
-
- fixed (char* pChars = chars)
- fixed (byte* pBytes = bytes)
- // Remember that byteCount is # to decode, not size of array.
- return GetBytes(pChars + charIndex, charCount,
- pBytes + byteIndex, byteCount, null);
+ return EncodingForwarder.GetBytes(this, chars, charIndex, charCount, bytes, byteIndex);
}
- // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
- // So if you fix this, fix the others. Currently those include:
- // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
-
[System.Security.SecurityCritical] // auto-generated
[CLSCompliant(false)]
public override unsafe int GetBytes(char* chars, int charCount, byte* bytes, int byteCount)
{
- // Validate Parameters
- if (bytes == null || chars == null)
- throw new ArgumentNullException(bytes == null ? "bytes" : "chars",
- Environment.GetResourceString("ArgumentNull_Array"));
-
- if (charCount < 0 || byteCount < 0)
- throw new ArgumentOutOfRangeException((charCount<0 ? "charCount" : "byteCount"),
- Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
- Contract.EndContractBlock();
-
- return GetBytes(chars, charCount, bytes, byteCount, null);
+ return EncodingForwarder.GetBytes(this, chars, charCount, bytes, byteCount);
}
// Returns the number of characters produced by decoding a range of bytes
// in a byte array.
- //
- // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
- // So if you fix this, fix the others. Currently those include:
- // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
- // parent method is safe
- [System.Security.SecuritySafeCritical] // auto-generated
- public override unsafe int GetCharCount(byte[] bytes, int index, int count)
+ public override int GetCharCount(byte[] bytes, int index, int count)
{
- // Validate Parameters
- if (bytes == null)
- throw new ArgumentNullException("bytes",
- Environment.GetResourceString("ArgumentNull_Array"));
-
- if (index < 0 || count < 0)
- throw new ArgumentOutOfRangeException((index<0 ? "index" : "count"),
- Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
-
- if (bytes.Length - index < count)
- throw new ArgumentOutOfRangeException("bytes",
- Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer"));
- Contract.EndContractBlock();
-
- // If no input just return 0, fixed doesn't like 0 length arrays.
- if (count == 0)
- return 0;
-
- // Just call pointer version
- fixed (byte* pBytes = bytes)
- return GetCharCount(pBytes + index, count, null);
+ return EncodingForwarder.GetCharCount(this, bytes, index, count);
}
- // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
- // So if you fix this, fix the others. Currently those include:
- // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
-
[System.Security.SecurityCritical] // auto-generated
[CLSCompliant(false)]
public override unsafe int GetCharCount(byte* bytes, int count)
{
- // Validate Parameters
- if (bytes == null)
- throw new ArgumentNullException("bytes",
- Environment.GetResourceString("ArgumentNull_Array"));
-
- if (count < 0)
- throw new ArgumentOutOfRangeException("count",
- Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
- Contract.EndContractBlock();
-
- return GetCharCount(bytes, count, null);
+ return EncodingForwarder.GetCharCount(this, bytes, count);
}
- // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
- // So if you fix this, fix the others. Currently those include:
- // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
- // parent method is safe
-
- [System.Security.SecuritySafeCritical] // auto-generated
- public override unsafe int GetChars(byte[] bytes, int byteIndex, int byteCount,
+ public override int GetChars(byte[] bytes, int byteIndex, int byteCount,
char[] chars, int charIndex)
{
- // Validate Parameters
- if (bytes == null || chars == null)
- throw new ArgumentNullException(bytes == null ? "bytes" : "chars",
- Environment.GetResourceString("ArgumentNull_Array"));
-
- if (byteIndex < 0 || byteCount < 0)
- throw new ArgumentOutOfRangeException((byteIndex<0 ? "byteIndex" : "byteCount"),
- Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
-
- if ( bytes.Length - byteIndex < byteCount)
- throw new ArgumentOutOfRangeException("bytes",
- Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer"));
-
- if (charIndex < 0 || charIndex > chars.Length)
- throw new ArgumentOutOfRangeException("charIndex",
- Environment.GetResourceString("ArgumentOutOfRange_Index"));
- Contract.EndContractBlock();
-
- // If no input, return 0 & avoid fixed problem
- if (byteCount == 0)
- return 0;
-
- // Just call pointer version
- int charCount = chars.Length - charIndex;
-
- // Fix our input array if 0 length because fixed doesn't like 0 length arrays
- if (chars.Length == 0)
- chars = new char[1];
-
- fixed (byte* pBytes = bytes)
- fixed (char* pChars = chars)
- // Remember that charCount is # to decode, not size of array
- return GetChars(pBytes + byteIndex, byteCount,
- pChars + charIndex, charCount, null);
+ return EncodingForwarder.GetChars(this, bytes, byteIndex, byteCount, chars, charIndex);
}
- // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
- // So if you fix this, fix the others. Currently those include:
- // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
-
[System.Security.SecurityCritical] // auto-generated
[CLSCompliant(false)]
public unsafe override int GetChars(byte* bytes, int byteCount, char* chars, int charCount)
{
- // Validate Parameters
- if (bytes == null || chars == null)
- throw new ArgumentNullException(bytes == null ? "bytes" : "chars",
- Environment.GetResourceString("ArgumentNull_Array"));
-
- if (charCount < 0 || byteCount < 0)
- throw new ArgumentOutOfRangeException((charCount<0 ? "charCount" : "byteCount"),
- Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
- Contract.EndContractBlock();
-
- return GetChars(bytes, byteCount, chars, charCount, null);
+ return EncodingForwarder.GetChars(this, bytes, byteCount, chars, charCount);
}
// Returns a string containing the decoded representation of a range of
// bytes in a byte array.
- //
- // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
- // So if you fix this, fix the others. Currently those include:
- // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
- // parent method is safe
- [System.Security.SecuritySafeCritical] // auto-generated
- public override unsafe String GetString(byte[] bytes, int index, int count)
+ public override String GetString(byte[] bytes, int index, int count)
{
- // Validate Parameters
- if (bytes == null)
- throw new ArgumentNullException("bytes",
- Environment.GetResourceString("ArgumentNull_Array"));
-
- if (index < 0 || count < 0)
- throw new ArgumentOutOfRangeException((index < 0 ? "index" : "count"),
- Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
-
- if (bytes.Length - index < count)
- throw new ArgumentOutOfRangeException("bytes",
- Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer"));
- Contract.EndContractBlock();
-
- // Avoid problems with empty input buffer
- if (count == 0) return String.Empty;
-
- fixed (byte* pBytes = bytes)
- return String.CreateStringFromEncoding(
- pBytes + index, count, this);
+ return EncodingForwarder.GetString(this, bytes, index, count);
}
-
- //
- // End of standard methods copied from EncodingNLS.cs
- //
+
+ // End of overridden methods which use EncodingForwarder
[System.Security.SecurityCritical] // auto-generated
internal override unsafe int GetByteCount(char *chars, int count, EncoderNLS encoder)
diff --git a/src/mscorlib/src/System/Text/UTF7Encoding.cs b/src/mscorlib/src/System/Text/UTF7Encoding.cs
index 727a43bc33..8e0c07cdc1 100644
--- a/src/mscorlib/src/System/Text/UTF7Encoding.cs
+++ b/src/mscorlib/src/System/Text/UTF7Encoding.cs
@@ -14,8 +14,10 @@ namespace System.Text
using System.Diagnostics.Contracts;
+#if FEATURE_SERIALIZATION
[Serializable]
-[System.Runtime.InteropServices.ComVisible(true)]
+#endif
+ [System.Runtime.InteropServices.ComVisible(true)]
public class UTF7Encoding : Encoding
{
private const String base64Chars =
@@ -145,125 +147,47 @@ namespace System.Text
return this.CodePage + this.EncoderFallback.GetHashCode() + this.DecoderFallback.GetHashCode();
}
- //
- // The following methods are copied from EncodingNLS.cs.
- // Unfortunately EncodingNLS.cs is internal and we're public, so we have to reimpliment them here.
- // These should be kept in sync for the following classes:
- // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
- //
+ // NOTE: Many methods in this class forward to EncodingForwarder for
+ // validating arguments/wrapping the unsafe methods in this class
+ // which do the actual work. That class contains
+ // shared logic for doing this which is used by
+ // ASCIIEncoding, EncodingNLS, UnicodeEncoding, UTF32Encoding,
+ // UTF7Encoding, and UTF8Encoding.
+ // The reason the code is separated out into a static class, rather
+ // than a base class which overrides all of these methods for us
+ // (which is what EncodingNLS is for internal Encodings) is because
+ // that's really more of an implementation detail so it's internal.
+ // At the same time, C# doesn't allow a public class subclassing an
+ // internal/private one, so we end up having to re-override these
+ // methods in all of the public Encodings + EncodingNLS.
// Returns the number of bytes required to encode a range of characters in
// a character array.
- //
- // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
- // So if you fix this, fix the others. Currently those include:
- // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
- // parent method is safe
-
- [System.Security.SecuritySafeCritical] // auto-generated
- public override unsafe int GetByteCount(char[] chars, int index, int count)
- {
- // Validate input parameters
- if (chars == null)
- throw new ArgumentNullException("chars",
- Environment.GetResourceString("ArgumentNull_Array"));
-
- if (index < 0 || count < 0)
- throw new ArgumentOutOfRangeException((index<0 ? "index" : "count"),
- Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
-
- if (chars.Length - index < count)
- throw new ArgumentOutOfRangeException("chars",
- Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer"));
- Contract.EndContractBlock();
-
- // If no input, return 0, avoid fixed empty array problem
- if (count == 0)
- return 0;
- // Just call the pointer version
- fixed (char* pChars = chars)
- return GetByteCount(pChars + index, count, null);
+ public override int GetByteCount(char[] chars, int index, int count)
+ {
+ return EncodingForwarder.GetByteCount(this, chars, index, count);
}
- // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
- // So if you fix this, fix the others. Currently those include:
- // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
- // parent method is safe
-
- [System.Security.SecuritySafeCritical] // auto-generated
[System.Runtime.InteropServices.ComVisible(false)]
- public override unsafe int GetByteCount(String s)
+ public override int GetByteCount(String s)
{
- // Validate input
- if (s==null)
- throw new ArgumentNullException("s");
- Contract.EndContractBlock();
-
- fixed (char* pChars = s)
- return GetByteCount(pChars, s.Length, null);
+ return EncodingForwarder.GetByteCount(this, s);
}
- // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
- // So if you fix this, fix the others. Currently those include:
- // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
-
[System.Security.SecurityCritical] // auto-generated
[CLSCompliant(false)]
[System.Runtime.InteropServices.ComVisible(false)]
public override unsafe int GetByteCount(char* chars, int count)
{
- // Validate Parameters
- if (chars == null)
- throw new ArgumentNullException("chars",
- Environment.GetResourceString("ArgumentNull_Array"));
-
- if (count < 0)
- throw new ArgumentOutOfRangeException("count",
- Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
- Contract.EndContractBlock();
-
- // Call it with empty encoder
- return GetByteCount(chars, count, null);
+ return EncodingForwarder.GetByteCount(this, chars, count);
}
- // Parent method is safe.
- // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
- // So if you fix this, fix the others. Currently those include:
- // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
-
- [System.Security.SecuritySafeCritical] // auto-generated
[System.Runtime.InteropServices.ComVisible(false)]
- public override unsafe int GetBytes(String s, int charIndex, int charCount,
+ public override int GetBytes(String s, int charIndex, int charCount,
byte[] bytes, int byteIndex)
{
- if (s == null || bytes == null)
- throw new ArgumentNullException((s == null ? "s" : "bytes"),
- Environment.GetResourceString("ArgumentNull_Array"));
-
- if (charIndex < 0 || charCount < 0)
- throw new ArgumentOutOfRangeException((charIndex<0 ? "charIndex" : "charCount"),
- Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
-
- if (s.Length - charIndex < charCount)
- throw new ArgumentOutOfRangeException("s",
- Environment.GetResourceString("ArgumentOutOfRange_IndexCount"));
-
- if (byteIndex < 0 || byteIndex > bytes.Length)
- throw new ArgumentOutOfRangeException("byteIndex",
- Environment.GetResourceString("ArgumentOutOfRange_Index"));
- Contract.EndContractBlock();
-
- int byteCount = bytes.Length - byteIndex;
-
- // Fixed doesn't like empty arrays
- if (bytes.Length == 0)
- bytes = new byte[1];
-
- fixed (char* pChars = s)
- fixed ( byte* pBytes = bytes)
- return GetBytes(pChars + charIndex, charCount,
- pBytes + byteIndex, byteCount, null);
+ return EncodingForwarder.GetBytes(this, s, charIndex, charCount, bytes, byteIndex);
}
// Encodes a range of characters in a character array into a range of bytes
@@ -274,234 +198,61 @@ namespace System.Text
// Alternatively, the GetMaxByteCount method can be used to
// determine the maximum number of bytes that will be produced for a given
// number of characters, regardless of the actual character values.
- //
- // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
- // So if you fix this, fix the others. Currently those include:
- // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
- // parent method is safe
-
- [System.Security.SecuritySafeCritical] // auto-generated
- public override unsafe int GetBytes(char[] chars, int charIndex, int charCount,
+
+ public override int GetBytes(char[] chars, int charIndex, int charCount,
byte[] bytes, int byteIndex)
{
- // Validate parameters
- if (chars == null || bytes == null)
- throw new ArgumentNullException((chars == null ? "chars" : "bytes"),
- Environment.GetResourceString("ArgumentNull_Array"));
-
- if (charIndex < 0 || charCount < 0)
- throw new ArgumentOutOfRangeException((charIndex<0 ? "charIndex" : "charCount"),
- Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
-
- if (chars.Length - charIndex < charCount)
- throw new ArgumentOutOfRangeException("chars",
- Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer"));
-
- if (byteIndex < 0 || byteIndex > bytes.Length)
- throw new ArgumentOutOfRangeException("byteIndex",
- Environment.GetResourceString("ArgumentOutOfRange_Index"));
- Contract.EndContractBlock();
-
- // If nothing to encode return 0, avoid fixed problem
- if (charCount == 0)
- return 0;
-
- // Just call pointer version
- int byteCount = bytes.Length - byteIndex;
-
- // Fixed doesn't like empty arrays
- if (bytes.Length == 0)
- bytes = new byte[1];
-
- fixed (char* pChars = chars)
- fixed (byte* pBytes = bytes)
- // Remember that byteCount is # to decode, not size of array.
- return GetBytes(pChars + charIndex, charCount,
- pBytes + byteIndex, byteCount, null);
+ return EncodingForwarder.GetBytes(this, chars, charIndex, charCount, bytes, byteIndex);
}
- // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
- // So if you fix this, fix the others. Currently those include:
- // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
-
[System.Security.SecurityCritical] // auto-generated
[CLSCompliant(false)]
[System.Runtime.InteropServices.ComVisible(false)]
public override unsafe int GetBytes(char* chars, int charCount, byte* bytes, int byteCount)
{
- // Validate Parameters
- if (bytes == null || chars == null)
- throw new ArgumentNullException(bytes == null ? "bytes" : "chars",
- Environment.GetResourceString("ArgumentNull_Array"));
-
- if (charCount < 0 || byteCount < 0)
- throw new ArgumentOutOfRangeException((charCount<0 ? "charCount" : "byteCount"),
- Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
- Contract.EndContractBlock();
-
- return GetBytes(chars, charCount, bytes, byteCount, null);
+ return EncodingForwarder.GetBytes(this, chars, charCount, bytes, byteCount);
}
// Returns the number of characters produced by decoding a range of bytes
// in a byte array.
- //
- // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
- // So if you fix this, fix the others. Currently those include:
- // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
- // parent method is safe
-
- [System.Security.SecuritySafeCritical] // auto-generated
- public override unsafe int GetCharCount(byte[] bytes, int index, int count)
- {
- // Validate Parameters
- if (bytes == null)
- throw new ArgumentNullException("bytes",
- Environment.GetResourceString("ArgumentNull_Array"));
-
- if (index < 0 || count < 0)
- throw new ArgumentOutOfRangeException((index<0 ? "index" : "count"),
- Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
-
- if (bytes.Length - index < count)
- throw new ArgumentOutOfRangeException("bytes",
- Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer"));
- Contract.EndContractBlock();
- // If no input just return 0, fixed doesn't like 0 length arrays.
- if (count == 0)
- return 0;
-
- // Just call pointer version
- fixed (byte* pBytes = bytes)
- return GetCharCount(pBytes + index, count, null);
+ public override int GetCharCount(byte[] bytes, int index, int count)
+ {
+ return EncodingForwarder.GetCharCount(this, bytes, index, count);
}
- // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
- // So if you fix this, fix the others. Currently those include:
- // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
-
[System.Security.SecurityCritical] // auto-generated
[CLSCompliant(false)]
[System.Runtime.InteropServices.ComVisible(false)]
public override unsafe int GetCharCount(byte* bytes, int count)
{
- // Validate Parameters
- if (bytes == null)
- throw new ArgumentNullException("bytes",
- Environment.GetResourceString("ArgumentNull_Array"));
-
- if (count < 0)
- throw new ArgumentOutOfRangeException("count",
- Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
- Contract.EndContractBlock();
-
- return GetCharCount(bytes, count, null);
+ return EncodingForwarder.GetCharCount(this, bytes, count);
}
- // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
- // So if you fix this, fix the others. Currently those include:
- // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
- // parent method is safe
-
- [System.Security.SecuritySafeCritical] // auto-generated
- public override unsafe int GetChars(byte[] bytes, int byteIndex, int byteCount,
+ public override int GetChars(byte[] bytes, int byteIndex, int byteCount,
char[] chars, int charIndex)
{
- // Validate Parameters
- if (bytes == null || chars == null)
- throw new ArgumentNullException(bytes == null ? "bytes" : "chars",
- Environment.GetResourceString("ArgumentNull_Array"));
-
- if (byteIndex < 0 || byteCount < 0)
- throw new ArgumentOutOfRangeException((byteIndex<0 ? "byteIndex" : "byteCount"),
- Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
-
- if ( bytes.Length - byteIndex < byteCount)
- throw new ArgumentOutOfRangeException("bytes",
- Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer"));
-
- if (charIndex < 0 || charIndex > chars.Length)
- throw new ArgumentOutOfRangeException("charIndex",
- Environment.GetResourceString("ArgumentOutOfRange_Index"));
- Contract.EndContractBlock();
-
- // If no input, return 0 & avoid fixed problem
- if (byteCount == 0)
- return 0;
-
- // Just call pointer version
- int charCount = chars.Length - charIndex;
-
- // Fixed doesn't like empty arrays
- if (chars.Length == 0)
- chars = new char[1];
-
- fixed (byte* pBytes = bytes)
- fixed (char* pChars = chars)
- // Remember that charCount is # to decode, not size of array
- return GetChars(pBytes + byteIndex, byteCount,
- pChars + charIndex, charCount, null);
+ return EncodingForwarder.GetChars(this, bytes, byteIndex, byteCount, chars, charIndex);
}
- // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
- // So if you fix this, fix the others. Currently those include:
- // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
-
[System.Security.SecurityCritical] // auto-generated
[CLSCompliant(false)]
[System.Runtime.InteropServices.ComVisible(false)]
public unsafe override int GetChars(byte* bytes, int byteCount, char* chars, int charCount)
{
- // Validate Parameters
- if (bytes == null || chars == null)
- throw new ArgumentNullException(bytes == null ? "bytes" : "chars",
- Environment.GetResourceString("ArgumentNull_Array"));
-
- if (charCount < 0 || byteCount < 0)
- throw new ArgumentOutOfRangeException((charCount<0 ? "charCount" : "byteCount"),
- Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
- Contract.EndContractBlock();
-
- return GetChars(bytes, byteCount, chars, charCount, null);
+ return EncodingForwarder.GetChars(this, bytes, byteCount, chars, charCount);
}
// Returns a string containing the decoded representation of a range of
// bytes in a byte array.
- //
- // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
- // So if you fix this, fix the others. Currently those include:
- // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
- // parent method is safe
- [System.Security.SecuritySafeCritical] // auto-generated
[System.Runtime.InteropServices.ComVisible(false)]
- public override unsafe String GetString(byte[] bytes, int index, int count)
+ public override String GetString(byte[] bytes, int index, int count)
{
- // Validate Parameters
- if (bytes == null)
- throw new ArgumentNullException("bytes",
- Environment.GetResourceString("ArgumentNull_Array"));
-
- if (index < 0 || count < 0)
- throw new ArgumentOutOfRangeException((index < 0 ? "index" : "count"),
- Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
-
- if (bytes.Length - index < count)
- throw new ArgumentOutOfRangeException("bytes",
- Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer"));
- Contract.EndContractBlock();
-
- // Avoid problems with empty input buffer
- if (count == 0) return String.Empty;
-
- fixed (byte* pBytes = bytes)
- return String.CreateStringFromEncoding(
- pBytes + index, count, this);
+ return EncodingForwarder.GetString(this, bytes, index, count);
}
-
- //
- // End of standard methods copied from EncodingNLS.cs
- //
+
+ // End of overridden methods which use EncodingForwarder
[System.Security.SecurityCritical] // auto-generated
internal override unsafe int GetByteCount(char* chars, int count, EncoderNLS baseEncoder)
@@ -893,12 +644,18 @@ namespace System.Text
return charCount;
}
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
// Of all the amazing things... This MUST be Decoder so that our com name
// for System.Text.Decoder doesn't change
- private class Decoder : DecoderNLS, ISerializable
+ private class Decoder : DecoderNLS
+#if FEATURE_SERIALIZATION
+ , ISerializable
+#endif
{
- /*private*/ internal int bits;
+ /*private*/
+ internal int bits;
/*private*/ internal int bitCount;
/*private*/ internal bool firstByte;
@@ -959,12 +716,18 @@ namespace System.Text
}
}
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
// Of all the amazing things... This MUST be Encoder so that our com name
// for System.Text.Encoder doesn't change
- private class Encoder : EncoderNLS, ISerializable
+ private class Encoder : EncoderNLS
+#if FEATURE_SERIALIZATION
+ , ISerializable
+#endif
{
- /*private*/ internal int bits;
+ /*private*/
+ internal int bits;
/*private*/ internal int bitCount;
public Encoder(UTF7Encoding encoding) : base(encoding)
diff --git a/src/mscorlib/src/System/Text/UTF8Encoding.cs b/src/mscorlib/src/System/Text/UTF8Encoding.cs
index 874f7f3b56..559e445223 100644
--- a/src/mscorlib/src/System/Text/UTF8Encoding.cs
+++ b/src/mscorlib/src/System/Text/UTF8Encoding.cs
@@ -98,128 +98,45 @@ namespace System.Text
}
}
-
- //
- // WARNING: GetByteCount(string chars)
- // WARNING: has different variable names than EncodingNLS.cs, so this can't just be cut & pasted,
- // WARNING: otherwise it'll break VB's way of declaring these.
- //
- // The following methods are copied from EncodingNLS.cs.
- // Unfortunately EncodingNLS.cs is internal and we're public, so we have to reimpliment them here.
- // These should be kept in sync for the following classes:
- // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
- //
+ // NOTE: Many methods in this class forward to EncodingForwarder for
+ // validating arguments/wrapping the unsafe methods in this class
+ // which do the actual work. That class contains
+ // shared logic for doing this which is used by
+ // ASCIIEncoding, EncodingNLS, UnicodeEncoding, UTF32Encoding,
+ // UTF7Encoding, and UTF8Encoding.
+ // The reason the code is separated out into a static class, rather
+ // than a base class which overrides all of these methods for us
+ // (which is what EncodingNLS is for internal Encodings) is because
+ // that's really more of an implementation detail so it's internal.
+ // At the same time, C# doesn't allow a public class subclassing an
+ // internal/private one, so we end up having to re-override these
+ // methods in all of the public Encodings + EncodingNLS.
// Returns the number of bytes required to encode a range of characters in
// a character array.
- //
- // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
- // So if you fix this, fix the others. Currently those include:
- // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
- // parent method is safe
- [System.Security.SecuritySafeCritical] // auto-generated
- public override unsafe int GetByteCount(char[] chars, int index, int count)
+ public override int GetByteCount(char[] chars, int index, int count)
{
- // Validate input parameters
- if (chars == null)
- throw new ArgumentNullException("chars",
- Environment.GetResourceString("ArgumentNull_Array"));
-
- if (index < 0 || count < 0)
- throw new ArgumentOutOfRangeException((index<0 ? "index" : "count"),
- Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
-
- if (chars.Length - index < count)
- throw new ArgumentOutOfRangeException("chars",
- Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer"));
- Contract.EndContractBlock();
-
- // If no input, return 0, avoid fixed empty array problem
- if (count == 0)
- return 0;
-
- // Just call the pointer version
- fixed (char* pChars = chars)
- return GetByteCount(pChars + index, count, null);
+ return EncodingForwarder.GetByteCount(this, chars, index, count);
}
- // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
- // So if you fix this, fix the others. Currently those include:
- // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
- // parent method is safe
-
- [System.Security.SecuritySafeCritical] // auto-generated
- public override unsafe int GetByteCount(String chars)
+ public override int GetByteCount(String chars)
{
- // Validate input
- if (chars==null)
- throw new ArgumentNullException("s");
- Contract.EndContractBlock();
-
- fixed (char* pChars = chars)
- return GetByteCount(pChars, chars.Length, null);
+ return EncodingForwarder.GetByteCount(this, chars);
}
- // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
- // So if you fix this, fix the others. Currently those include:
- // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
-
[System.Security.SecurityCritical] // auto-generated
[CLSCompliant(false)]
[System.Runtime.InteropServices.ComVisible(false)]
public override unsafe int GetByteCount(char* chars, int count)
{
- // Validate Parameters
- if (chars == null)
- throw new ArgumentNullException("chars",
- Environment.GetResourceString("ArgumentNull_Array"));
-
- if (count < 0)
- throw new ArgumentOutOfRangeException("count",
- Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
- Contract.EndContractBlock();
-
- // Call it with empty encoder
- return GetByteCount(chars, count, null);
+ return EncodingForwarder.GetByteCount(this, chars, count);
}
- // Parent method is safe.
- // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
- // So if you fix this, fix the others. Currently those include:
- // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
-
- [System.Security.SecuritySafeCritical] // auto-generated
- public override unsafe int GetBytes(String s, int charIndex, int charCount,
+ public override int GetBytes(String s, int charIndex, int charCount,
byte[] bytes, int byteIndex)
{
- if (s == null || bytes == null)
- throw new ArgumentNullException((s == null ? "s" : "bytes"),
- Environment.GetResourceString("ArgumentNull_Array"));
-
- if (charIndex < 0 || charCount < 0)
- throw new ArgumentOutOfRangeException((charIndex<0 ? "charIndex" : "charCount"),
- Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
-
- if (s.Length - charIndex < charCount)
- throw new ArgumentOutOfRangeException("s",
- Environment.GetResourceString("ArgumentOutOfRange_IndexCount"));
-
- if (byteIndex < 0 || byteIndex > bytes.Length)
- throw new ArgumentOutOfRangeException("byteIndex",
- Environment.GetResourceString("ArgumentOutOfRange_Index"));
- Contract.EndContractBlock();
-
- int byteCount = bytes.Length - byteIndex;
-
- // Fixed doesn't like 0 length arrays.
- if (bytes.Length == 0)
- bytes = new byte[1];
-
- fixed (char* pChars = s)
- fixed ( byte* pBytes = bytes)
- return GetBytes(pChars + charIndex, charCount,
- pBytes + byteIndex, byteCount, null);
+ return EncodingForwarder.GetBytes(this, s, charIndex, charCount, bytes, byteIndex);
}
// Encodes a range of characters in a character array into a range of bytes
@@ -230,234 +147,61 @@ namespace System.Text
// Alternatively, the GetMaxByteCount method can be used to
// determine the maximum number of bytes that will be produced for a given
// number of characters, regardless of the actual character values.
- //
- // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
- // So if you fix this, fix the others. Currently those include:
- // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
- // parent method is safe
- [System.Security.SecuritySafeCritical] // auto-generated
- public override unsafe int GetBytes(char[] chars, int charIndex, int charCount,
+ public override int GetBytes(char[] chars, int charIndex, int charCount,
byte[] bytes, int byteIndex)
{
- // Validate parameters
- if (chars == null || bytes == null)
- throw new ArgumentNullException((chars == null ? "chars" : "bytes"),
- Environment.GetResourceString("ArgumentNull_Array"));
-
- if (charIndex < 0 || charCount < 0)
- throw new ArgumentOutOfRangeException((charIndex<0 ? "charIndex" : "charCount"),
- Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
-
- if (chars.Length - charIndex < charCount)
- throw new ArgumentOutOfRangeException("chars",
- Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer"));
-
- if (byteIndex < 0 || byteIndex > bytes.Length)
- throw new ArgumentOutOfRangeException("byteIndex",
- Environment.GetResourceString("ArgumentOutOfRange_Index"));
- Contract.EndContractBlock();
-
- // If nothing to encode return 0, avoid fixed problem
- if (charCount == 0)
- return 0;
-
- // Just call pointer version
- int byteCount = bytes.Length - byteIndex;
-
- // Fixed doesn't like 0 length arrays.
- if (bytes.Length == 0)
- bytes = new byte[1];
-
- fixed (char* pChars = chars)
- fixed (byte* pBytes = bytes)
- // Remember that byteCount is # to decode, not size of array.
- return GetBytes(pChars + charIndex, charCount,
- pBytes + byteIndex, byteCount, null);
+ return EncodingForwarder.GetBytes(this, chars, charIndex, charCount, bytes, byteIndex);
}
- // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
- // So if you fix this, fix the others. Currently those include:
- // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
-
[System.Security.SecurityCritical] // auto-generated
[CLSCompliant(false)]
[System.Runtime.InteropServices.ComVisible(false)]
public override unsafe int GetBytes(char* chars, int charCount, byte* bytes, int byteCount)
{
- // Validate Parameters
- if (bytes == null || chars == null)
- throw new ArgumentNullException(bytes == null ? "bytes" : "chars",
- Environment.GetResourceString("ArgumentNull_Array"));
-
- if (charCount < 0 || byteCount < 0)
- throw new ArgumentOutOfRangeException((charCount<0 ? "charCount" : "byteCount"),
- Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
- Contract.EndContractBlock();
-
- return GetBytes(chars, charCount, bytes, byteCount, null);
+ return EncodingForwarder.GetBytes(this, chars, charCount, bytes, byteCount);
}
// Returns the number of characters produced by decoding a range of bytes
// in a byte array.
- //
- // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
- // So if you fix this, fix the others. Currently those include:
- // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
- // parent method is safe
- [System.Security.SecuritySafeCritical] // auto-generated
- public override unsafe int GetCharCount(byte[] bytes, int index, int count)
+ public override int GetCharCount(byte[] bytes, int index, int count)
{
- // Validate Parameters
- if (bytes == null)
- throw new ArgumentNullException("bytes",
- Environment.GetResourceString("ArgumentNull_Array"));
-
- if (index < 0 || count < 0)
- throw new ArgumentOutOfRangeException((index<0 ? "index" : "count"),
- Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
-
- if (bytes.Length - index < count)
- throw new ArgumentOutOfRangeException("bytes",
- Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer"));
- Contract.EndContractBlock();
-
- // If no input just return 0, fixed doesn't like 0 length arrays.
- if (count == 0)
- return 0;
-
- // Just call pointer version
- fixed (byte* pBytes = bytes)
- return GetCharCount(pBytes + index, count, null);
+ return EncodingForwarder.GetCharCount(this, bytes, index, count);
}
- // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
- // So if you fix this, fix the others. Currently those include:
- // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
-
[System.Security.SecurityCritical] // auto-generated
[CLSCompliant(false)]
[System.Runtime.InteropServices.ComVisible(false)]
public override unsafe int GetCharCount(byte* bytes, int count)
{
- // Validate Parameters
- if (bytes == null)
- throw new ArgumentNullException("bytes",
- Environment.GetResourceString("ArgumentNull_Array"));
-
- if (count < 0)
- throw new ArgumentOutOfRangeException("count",
- Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
- Contract.EndContractBlock();
-
- return GetCharCount(bytes, count, null);
+ return EncodingForwarder.GetCharCount(this, bytes, count);
}
- // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
- // So if you fix this, fix the others. Currently those include:
- // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
- // parent method is safe
-
- [System.Security.SecuritySafeCritical] // auto-generated
- public override unsafe int GetChars(byte[] bytes, int byteIndex, int byteCount,
+ public override int GetChars(byte[] bytes, int byteIndex, int byteCount,
char[] chars, int charIndex)
{
- // Validate Parameters
- if (bytes == null || chars == null)
- throw new ArgumentNullException(bytes == null ? "bytes" : "chars",
- Environment.GetResourceString("ArgumentNull_Array"));
-
- if (byteIndex < 0 || byteCount < 0)
- throw new ArgumentOutOfRangeException((byteIndex<0 ? "byteIndex" : "byteCount"),
- Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
-
- if ( bytes.Length - byteIndex < byteCount)
- throw new ArgumentOutOfRangeException("bytes",
- Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer"));
-
- if (charIndex < 0 || charIndex > chars.Length)
- throw new ArgumentOutOfRangeException("charIndex",
- Environment.GetResourceString("ArgumentOutOfRange_Index"));
- Contract.EndContractBlock();
-
- // If no input, return 0 & avoid fixed problem
- if (byteCount == 0)
- return 0;
-
- // Just call pointer version
- int charCount = chars.Length - charIndex;
-
- // Fixed doesn't like 0 length arrays.
- if (chars.Length == 0)
- chars = new char[1];
-
- fixed (byte* pBytes = bytes)
- fixed (char* pChars = chars)
- // Remember that charCount is # to decode, not size of array
- return GetChars(pBytes + byteIndex, byteCount,
- pChars + charIndex, charCount, null);
+ return EncodingForwarder.GetChars(this, bytes, byteIndex, byteCount, chars, charIndex);
}
- // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
- // So if you fix this, fix the others. Currently those include:
- // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
-
[System.Security.SecurityCritical] // auto-generated
[CLSCompliant(false)]
[System.Runtime.InteropServices.ComVisible(false)]
public unsafe override int GetChars(byte* bytes, int byteCount, char* chars, int charCount)
{
- // Validate Parameters
- if (bytes == null || chars == null)
- throw new ArgumentNullException(bytes == null ? "bytes" : "chars",
- Environment.GetResourceString("ArgumentNull_Array"));
-
- if (charCount < 0 || byteCount < 0)
- throw new ArgumentOutOfRangeException((charCount<0 ? "charCount" : "byteCount"),
- Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
- Contract.EndContractBlock();
-
- return GetChars(bytes, byteCount, chars, charCount, null);
+ return EncodingForwarder.GetChars(this, bytes, byteCount, chars, charCount);
}
// Returns a string containing the decoded representation of a range of
// bytes in a byte array.
- //
- // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
- // So if you fix this, fix the others. Currently those include:
- // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
- // parent method is safe
- [System.Security.SecuritySafeCritical] // auto-generated
[System.Runtime.InteropServices.ComVisible(false)]
- public override unsafe String GetString(byte[] bytes, int index, int count)
+ public override String GetString(byte[] bytes, int index, int count)
{
- // Validate Parameters
- if (bytes == null)
- throw new ArgumentNullException("bytes",
- Environment.GetResourceString("ArgumentNull_Array"));
-
- if (index < 0 || count < 0)
- throw new ArgumentOutOfRangeException((index < 0 ? "index" : "count"),
- Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
-
- if (bytes.Length - index < count)
- throw new ArgumentOutOfRangeException("bytes",
- Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer"));
- Contract.EndContractBlock();
-
- // Avoid problems with empty input buffer
- if (count == 0) return String.Empty;
-
- fixed (byte* pBytes = bytes)
- return String.CreateStringFromEncoding(
- pBytes + index, count, this);
+ return EncodingForwarder.GetString(this, bytes, index, count);
}
-
- //
- // End of standard methods copied from EncodingNLS.cs
- //
+
+ // End of overridden methods which use EncodingForwarder
// To simplify maintenance, the structure of GetByteCount and GetBytes should be
// kept the same as much as possible
@@ -2410,8 +2154,13 @@ namespace System.Text
UTF8_CODEPAGE + (emitUTF8Identifier?1:0);
}
+#if FEATURE_SERIALIZATION
[Serializable]
- internal class UTF8Encoder : EncoderNLS, ISerializable
+#endif
+ internal class UTF8Encoder : EncoderNLS
+#if FEATURE_SERIALIZATION
+ , ISerializable
+#endif
{
// We must save a high surrogate value until the next call, looking
// for a low surrogate value.
@@ -2485,8 +2234,13 @@ namespace System.Text
}
}
+#if FEATURE_SERIALIZATION
[Serializable]
- internal class UTF8Decoder : DecoderNLS, ISerializable
+#endif
+ internal class UTF8Decoder : DecoderNLS
+#if FEATURE_SERIALIZATION
+ , ISerializable
+#endif
{
// We'll need to remember the previous information. See the comments around definition
// of FinalByte for details.
diff --git a/src/mscorlib/src/System/Text/UnicodeEncoding.cs b/src/mscorlib/src/System/Text/UnicodeEncoding.cs
index 6f0b6efc58..8cc1fcb864 100644
--- a/src/mscorlib/src/System/Text/UnicodeEncoding.cs
+++ b/src/mscorlib/src/System/Text/UnicodeEncoding.cs
@@ -15,7 +15,9 @@ namespace System.Text
using System.Diagnostics.Contracts;
- [Serializable]
+#if FEATURE_SERIALIZATION
+ [Serializable]
+#endif
[System.Runtime.InteropServices.ComVisible(true)]
public class UnicodeEncoding : Encoding
{
@@ -77,123 +79,45 @@ namespace System.Text
}
}
- //
- // The following methods are copied from EncodingNLS.cs.
- // Unfortunately EncodingNLS.cs is internal and we're public, so we have to reimpliment them here.
- // These should be kept in sync for the following classes:
- // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
- //
+ // NOTE: Many methods in this class forward to EncodingForwarder for
+ // validating arguments/wrapping the unsafe methods in this class
+ // which do the actual work. That class contains
+ // shared logic for doing this which is used by
+ // ASCIIEncoding, EncodingNLS, UnicodeEncoding, UTF32Encoding,
+ // UTF7Encoding, and UTF8Encoding.
+ // The reason the code is separated out into a static class, rather
+ // than a base class which overrides all of these methods for us
+ // (which is what EncodingNLS is for internal Encodings) is because
+ // that's really more of an implementation detail so it's internal.
+ // At the same time, C# doesn't allow a public class subclassing an
+ // internal/private one, so we end up having to re-override these
+ // methods in all of the public Encodings + EncodingNLS.
// Returns the number of bytes required to encode a range of characters in
// a character array.
- //
- // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
- // So if you fix this, fix the others. Currently those include:
- // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
- // parent method is safe
-
- [System.Security.SecuritySafeCritical] // auto-generated
- public override unsafe int GetByteCount(char[] chars, int index, int count)
- {
- // Validate input parameters
- if (chars == null)
- throw new ArgumentNullException("chars",
- Environment.GetResourceString("ArgumentNull_Array"));
-
- if (index < 0 || count < 0)
- throw new ArgumentOutOfRangeException((index<0 ? "index" : "count"),
- Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
-
- if (chars.Length - index < count)
- throw new ArgumentOutOfRangeException("chars",
- Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer"));
- Contract.EndContractBlock();
-
- // If no input, return 0, avoid fixed empty array problem
- if (count == 0)
- return 0;
- // Just call the pointer version
- fixed (char* pChars = chars)
- return GetByteCount(pChars + index, count, null);
+ public override int GetByteCount(char[] chars, int index, int count)
+ {
+ return EncodingForwarder.GetByteCount(this, chars, index, count);
}
- // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
- // So if you fix this, fix the others. Currently those include:
- // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
- // parent method is safe
-
- [System.Security.SecuritySafeCritical] // auto-generated
- public override unsafe int GetByteCount(String s)
+ public override int GetByteCount(String s)
{
- // Validate input
- if (s==null)
- throw new ArgumentNullException("s");
- Contract.EndContractBlock();
-
- fixed (char* pChars = s)
- return GetByteCount(pChars, s.Length, null);
+ return EncodingForwarder.GetByteCount(this, s);
}
- // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
- // So if you fix this, fix the others. Currently those include:
- // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
-
[System.Security.SecurityCritical] // auto-generated
[CLSCompliant(false)]
[System.Runtime.InteropServices.ComVisible(false)]
public override unsafe int GetByteCount(char* chars, int count)
{
- // Validate Parameters
- if (chars == null)
- throw new ArgumentNullException("chars",
- Environment.GetResourceString("ArgumentNull_Array"));
-
- if (count < 0)
- throw new ArgumentOutOfRangeException("count",
- Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
- Contract.EndContractBlock();
-
- // Call it with empty encoder
- return GetByteCount(chars, count, null);
+ return EncodingForwarder.GetByteCount(this, chars, count);
}
- // Parent method is safe.
- // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
- // So if you fix this, fix the others. Currently those include:
- // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
-
- [System.Security.SecuritySafeCritical] // auto-generated
- public override unsafe int GetBytes(String s, int charIndex, int charCount,
+ public override int GetBytes(String s, int charIndex, int charCount,
byte[] bytes, int byteIndex)
{
- if (s == null || bytes == null)
- throw new ArgumentNullException((s == null ? "s" : "bytes"),
- Environment.GetResourceString("ArgumentNull_Array"));
-
- if (charIndex < 0 || charCount < 0)
- throw new ArgumentOutOfRangeException((charIndex<0 ? "charIndex" : "charCount"),
- Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
-
- if (s.Length - charIndex < charCount)
- throw new ArgumentOutOfRangeException("s",
- Environment.GetResourceString("ArgumentOutOfRange_IndexCount"));
-
- if (byteIndex < 0 || byteIndex > bytes.Length)
- throw new ArgumentOutOfRangeException("byteIndex",
- Environment.GetResourceString("ArgumentOutOfRange_Index"));
- Contract.EndContractBlock();
-
- int byteCount = bytes.Length - byteIndex;
-
- // Fixed doesn't like 0 length arrays.
- if (bytes.Length == 0)
- bytes = new byte[1];
-
- fixed (char* pChars = s)
- fixed ( byte* pBytes = bytes)
- return GetBytes(pChars + charIndex, charCount,
- pBytes + byteIndex, byteCount, null);
+ return EncodingForwarder.GetBytes(this, s, charIndex, charCount, bytes, byteIndex);
}
// Encodes a range of characters in a character array into a range of bytes
@@ -204,234 +128,61 @@ namespace System.Text
// Alternatively, the GetMaxByteCount method can be used to
// determine the maximum number of bytes that will be produced for a given
// number of characters, regardless of the actual character values.
- //
- // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
- // So if you fix this, fix the others. Currently those include:
- // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
- // parent method is safe
-
- [System.Security.SecuritySafeCritical] // auto-generated
- public override unsafe int GetBytes(char[] chars, int charIndex, int charCount,
+
+ public override int GetBytes(char[] chars, int charIndex, int charCount,
byte[] bytes, int byteIndex)
{
- // Validate parameters
- if (chars == null || bytes == null)
- throw new ArgumentNullException((chars == null ? "chars" : "bytes"),
- Environment.GetResourceString("ArgumentNull_Array"));
-
- if (charIndex < 0 || charCount < 0)
- throw new ArgumentOutOfRangeException((charIndex<0 ? "charIndex" : "charCount"),
- Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
-
- if (chars.Length - charIndex < charCount)
- throw new ArgumentOutOfRangeException("chars",
- Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer"));
-
- if (byteIndex < 0 || byteIndex > bytes.Length)
- throw new ArgumentOutOfRangeException("byteIndex",
- Environment.GetResourceString("ArgumentOutOfRange_Index"));
- Contract.EndContractBlock();
-
- // If nothing to encode return 0, avoid fixed problem
- if (charCount == 0)
- return 0;
-
- // Just call pointer version
- int byteCount = bytes.Length - byteIndex;
-
- // Fixed doesn't like 0 length arrays.
- if (bytes.Length == 0)
- bytes = new byte[1];
-
- fixed (char* pChars = chars)
- fixed (byte* pBytes = bytes)
- // Remember that byteCount is # to decode, not size of array.
- return GetBytes(pChars + charIndex, charCount,
- pBytes + byteIndex, byteCount, null);
+ return EncodingForwarder.GetBytes(this, chars, charIndex, charCount, bytes, byteIndex);
}
- // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
- // So if you fix this, fix the others. Currently those include:
- // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
-
[System.Security.SecurityCritical] // auto-generated
[CLSCompliant(false)]
[System.Runtime.InteropServices.ComVisible(false)]
public override unsafe int GetBytes(char* chars, int charCount, byte* bytes, int byteCount)
{
- // Validate Parameters
- if (bytes == null || chars == null)
- throw new ArgumentNullException(bytes == null ? "bytes" : "chars",
- Environment.GetResourceString("ArgumentNull_Array"));
-
- if (charCount < 0 || byteCount < 0)
- throw new ArgumentOutOfRangeException((charCount<0 ? "charCount" : "byteCount"),
- Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
- Contract.EndContractBlock();
-
- return GetBytes(chars, charCount, bytes, byteCount, null);
+ return EncodingForwarder.GetBytes(this, chars, charCount, bytes, byteCount);
}
// Returns the number of characters produced by decoding a range of bytes
// in a byte array.
- //
- // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
- // So if you fix this, fix the others. Currently those include:
- // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
- // parent method is safe
-
- [System.Security.SecuritySafeCritical] // auto-generated
- public override unsafe int GetCharCount(byte[] bytes, int index, int count)
- {
- // Validate Parameters
- if (bytes == null)
- throw new ArgumentNullException("bytes",
- Environment.GetResourceString("ArgumentNull_Array"));
-
- if (index < 0 || count < 0)
- throw new ArgumentOutOfRangeException((index<0 ? "index" : "count"),
- Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
- if (bytes.Length - index < count)
- throw new ArgumentOutOfRangeException("bytes",
- Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer"));
- Contract.EndContractBlock();
-
- // If no input just return 0, fixed doesn't like 0 length arrays
- if (count == 0)
- return 0;
-
- // Just call pointer version
- fixed (byte* pBytes = bytes)
- return GetCharCount(pBytes + index, count, null);
+ public override int GetCharCount(byte[] bytes, int index, int count)
+ {
+ return EncodingForwarder.GetCharCount(this, bytes, index, count);
}
- // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
- // So if you fix this, fix the others. Currently those include:
- // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
-
[System.Security.SecurityCritical] // auto-generated
[CLSCompliant(false)]
[System.Runtime.InteropServices.ComVisible(false)]
public override unsafe int GetCharCount(byte* bytes, int count)
{
- // Validate Parameters
- if (bytes == null)
- throw new ArgumentNullException("bytes",
- Environment.GetResourceString("ArgumentNull_Array"));
-
- if (count < 0)
- throw new ArgumentOutOfRangeException("count",
- Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
- Contract.EndContractBlock();
-
- return GetCharCount(bytes, count, null);
+ return EncodingForwarder.GetCharCount(this, bytes, count);
}
- // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
- // So if you fix this, fix the others. Currently those include:
- // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
- // parent method is safe
-
- [System.Security.SecuritySafeCritical] // auto-generated
- public override unsafe int GetChars(byte[] bytes, int byteIndex, int byteCount,
+ public override int GetChars(byte[] bytes, int byteIndex, int byteCount,
char[] chars, int charIndex)
{
- // Validate Parameters
- if (bytes == null || chars == null)
- throw new ArgumentNullException(bytes == null ? "bytes" : "chars",
- Environment.GetResourceString("ArgumentNull_Array"));
-
- if (byteIndex < 0 || byteCount < 0)
- throw new ArgumentOutOfRangeException((byteIndex<0 ? "byteIndex" : "byteCount"),
- Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
-
- if ( bytes.Length - byteIndex < byteCount)
- throw new ArgumentOutOfRangeException("bytes",
- Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer"));
-
- if (charIndex < 0 || charIndex > chars.Length)
- throw new ArgumentOutOfRangeException("charIndex",
- Environment.GetResourceString("ArgumentOutOfRange_Index"));
- Contract.EndContractBlock();
-
- // If no input, return 0 & avoid fixed problem
- if (byteCount == 0)
- return 0;
-
- // Just call pointer version
- int charCount = chars.Length - charIndex;
-
- // Fixed doesn't like 0 length arrays.
- if (chars.Length == 0)
- chars = new char[1];
-
- fixed (byte* pBytes = bytes)
- fixed (char* pChars = chars)
- // Remember that charCount is # to decode, not size of array
- return GetChars(pBytes + byteIndex, byteCount,
- pChars + charIndex, charCount, null);
+ return EncodingForwarder.GetChars(this, bytes, byteIndex, byteCount, chars, charIndex);
}
- // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
- // So if you fix this, fix the others. Currently those include:
- // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
-
[System.Security.SecurityCritical] // auto-generated
[CLSCompliant(false)]
[System.Runtime.InteropServices.ComVisible(false)]
public unsafe override int GetChars(byte* bytes, int byteCount, char* chars, int charCount)
{
- // Validate Parameters
- if (bytes == null || chars == null)
- throw new ArgumentNullException(bytes == null ? "bytes" : "chars",
- Environment.GetResourceString("ArgumentNull_Array"));
-
- if (charCount < 0 || byteCount < 0)
- throw new ArgumentOutOfRangeException((charCount<0 ? "charCount" : "byteCount"),
- Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
- Contract.EndContractBlock();
-
- return GetChars(bytes, byteCount, chars, charCount, null);
+ return EncodingForwarder.GetChars(this, bytes, byteCount, chars, charCount);
}
// Returns a string containing the decoded representation of a range of
// bytes in a byte array.
- //
- // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
- // So if you fix this, fix the others. Currently those include:
- // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
- // parent method is safe
- [System.Security.SecuritySafeCritical] // auto-generated
[System.Runtime.InteropServices.ComVisible(false)]
- public override unsafe String GetString(byte[] bytes, int index, int count)
+ public override String GetString(byte[] bytes, int index, int count)
{
- // Validate Parameters
- if (bytes == null)
- throw new ArgumentNullException("bytes",
- Environment.GetResourceString("ArgumentNull_Array"));
-
- if (index < 0 || count < 0)
- throw new ArgumentOutOfRangeException((index < 0 ? "index" : "count"),
- Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
-
- if (bytes.Length - index < count)
- throw new ArgumentOutOfRangeException("bytes",
- Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer"));
- Contract.EndContractBlock();
-
- // Avoid problems with empty input buffer
- if (count == 0) return String.Empty;
-
- fixed (byte* pBytes = bytes)
- return String.CreateStringFromEncoding(
- pBytes + index, count, this);
+ return EncodingForwarder.GetString(this, bytes, index, count);
}
-
- //
- // End of standard methods copied from EncodingNLS.cs
- //
+
+ // End of overridden methods which use EncodingForwarder
[System.Security.SecurityCritical] // auto-generated
internal override unsafe int GetByteCount(char* chars, int count, EncoderNLS encoder)
@@ -2012,8 +1763,13 @@ namespace System.Text
(byteOrderMark?4:0) + (bigEndian?8:0);
}
+#if FEATURE_SERIALIZATION
[Serializable]
- private class Decoder : System.Text.DecoderNLS, ISerializable
+#endif
+ private class Decoder : System.Text.DecoderNLS
+#if FEATURE_SERIALIZATION
+ , ISerializable
+#endif
{
internal int lastByte = -1;
internal char lastChar = '\0';
diff --git a/src/mscorlib/src/System/Threading/AbandonedMutexException.cs b/src/mscorlib/src/System/Threading/AbandonedMutexException.cs
index c6dd96bf2c..b581e561cc 100644
--- a/src/mscorlib/src/System/Threading/AbandonedMutexException.cs
+++ b/src/mscorlib/src/System/Threading/AbandonedMutexException.cs
@@ -15,8 +15,10 @@ namespace System.Threading {
using System.Runtime.Serialization;
using System.Threading;
using System.Runtime.InteropServices;
-
+
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
[ComVisibleAttribute(false)]
public class AbandonedMutexException : SystemException {
diff --git a/src/mscorlib/src/System/Threading/ExecutionContext.cs b/src/mscorlib/src/System/Threading/ExecutionContext.cs
index b4213d24cb..0440368608 100644
--- a/src/mscorlib/src/System/Threading/ExecutionContext.cs
+++ b/src/mscorlib/src/System/Threading/ExecutionContext.cs
@@ -515,7 +515,9 @@ namespace System.Threading
}
- [Serializable]
+#if FEATURE_SERIALIZATION
+ [Serializable]
+#endif
public sealed class ExecutionContext : IDisposable, ISerializable
{
/*=========================================================================
diff --git a/src/mscorlib/src/System/Threading/LockRecursionException.cs b/src/mscorlib/src/System/Threading/LockRecursionException.cs
index 117b32ba92..5071f3217f 100644
--- a/src/mscorlib/src/System/Threading/LockRecursionException.cs
+++ b/src/mscorlib/src/System/Threading/LockRecursionException.cs
@@ -18,7 +18,9 @@ namespace System.Threading
using System.Runtime.Serialization;
using System.Runtime.CompilerServices;
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
[System.Security.Permissions.HostProtection(MayLeakOnAbort = true)]
[TypeForwardedFrom("System.Core, Version=3.5.0.0, Culture=Neutral, PublicKeyToken=b77a5c561934e089")]
public class LockRecursionException : System.Exception
diff --git a/src/mscorlib/src/System/Threading/SemaphoreFullException.cs b/src/mscorlib/src/System/Threading/SemaphoreFullException.cs
index 615ba7f78d..2ff84cedfd 100644
--- a/src/mscorlib/src/System/Threading/SemaphoreFullException.cs
+++ b/src/mscorlib/src/System/Threading/SemaphoreFullException.cs
@@ -7,7 +7,9 @@ namespace System.Threading {
using System.Runtime.Serialization;
using System.Runtime.InteropServices;
- [Serializable()]
+#if FEATURE_SERIALIZATION
+ [Serializable]
+#endif
[ComVisibleAttribute(false)]
[System.Runtime.CompilerServices.TypeForwardedFrom("System, Version=2.0.0.0, Culture=Neutral, PublicKeyToken=b77a5c561934e089")]
public class SemaphoreFullException : SystemException {
diff --git a/src/mscorlib/src/System/Threading/SynchronizationLockException.cs b/src/mscorlib/src/System/Threading/SynchronizationLockException.cs
index dc66751901..0cc595cd99 100644
--- a/src/mscorlib/src/System/Threading/SynchronizationLockException.cs
+++ b/src/mscorlib/src/System/Threading/SynchronizationLockException.cs
@@ -17,8 +17,10 @@ namespace System.Threading {
using System;
using System.Runtime.Serialization;
-[System.Runtime.InteropServices.ComVisible(true)]
+ [System.Runtime.InteropServices.ComVisible(true)]
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
public class SynchronizationLockException : SystemException {
public SynchronizationLockException()
: base(Environment.GetResourceString("Arg_SynchronizationLockException")) {
diff --git a/src/mscorlib/src/System/Threading/Tasks/TaskCanceledException.cs b/src/mscorlib/src/System/Threading/Tasks/TaskCanceledException.cs
index f15e3e783a..037341e860 100644
--- a/src/mscorlib/src/System/Threading/Tasks/TaskCanceledException.cs
+++ b/src/mscorlib/src/System/Threading/Tasks/TaskCanceledException.cs
@@ -20,7 +20,9 @@ namespace System.Threading.Tasks
/// <summary>
/// Represents an exception used to communicate task cancellation.
/// </summary>
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
public class TaskCanceledException : OperationCanceledException
{
diff --git a/src/mscorlib/src/System/Threading/Tasks/TaskSchedulerException.cs b/src/mscorlib/src/System/Threading/Tasks/TaskSchedulerException.cs
index 1d85e49342..94a733cf73 100644
--- a/src/mscorlib/src/System/Threading/Tasks/TaskSchedulerException.cs
+++ b/src/mscorlib/src/System/Threading/Tasks/TaskSchedulerException.cs
@@ -21,7 +21,9 @@ namespace System.Threading.Tasks
/// Represents an exception used to communicate an invalid operation by a
/// <see cref="T:System.Threading.Tasks.TaskScheduler"/>.
/// </summary>
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
public class TaskSchedulerException : Exception
{
/// <summary>
diff --git a/src/mscorlib/src/System/Threading/ThreadAbortException.cs b/src/mscorlib/src/System/Threading/ThreadAbortException.cs
index 11c8744c72..8f1fb5c5f9 100644
--- a/src/mscorlib/src/System/Threading/ThreadAbortException.cs
+++ b/src/mscorlib/src/System/Threading/ThreadAbortException.cs
@@ -22,7 +22,9 @@ namespace System.Threading
using System.Runtime.CompilerServices;
[System.Runtime.InteropServices.ComVisible(true)]
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
public sealed class ThreadAbortException : SystemException
{
private ThreadAbortException()
diff --git a/src/mscorlib/src/System/Threading/ThreadInterruptedException.cs b/src/mscorlib/src/System/Threading/ThreadInterruptedException.cs
index 0056611955..c86bf71c48 100644
--- a/src/mscorlib/src/System/Threading/ThreadInterruptedException.cs
+++ b/src/mscorlib/src/System/Threading/ThreadInterruptedException.cs
@@ -18,7 +18,9 @@ namespace System.Threading {
using System.Runtime.Serialization;
[System.Runtime.InteropServices.ComVisible(true)]
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
public class ThreadInterruptedException : SystemException {
public ThreadInterruptedException()
: base(GetMessageFromNativeResources(ExceptionMessageKind.ThreadInterrupted)) {
diff --git a/src/mscorlib/src/System/Threading/ThreadStartException.cs b/src/mscorlib/src/System/Threading/ThreadStartException.cs
index 33fb460b3d..7b90ad6f25 100644
--- a/src/mscorlib/src/System/Threading/ThreadStartException.cs
+++ b/src/mscorlib/src/System/Threading/ThreadStartException.cs
@@ -10,7 +10,9 @@ namespace System.Threading
using System.Runtime.Serialization;
using System.Runtime.InteropServices;
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
public sealed class ThreadStartException : SystemException
{
private ThreadStartException()
diff --git a/src/mscorlib/src/System/Threading/ThreadStateException.cs b/src/mscorlib/src/System/Threading/ThreadStateException.cs
index c3d5d1ed1c..ac98ac177e 100644
--- a/src/mscorlib/src/System/Threading/ThreadStateException.cs
+++ b/src/mscorlib/src/System/Threading/ThreadStateException.cs
@@ -16,8 +16,10 @@
namespace System.Threading {
using System;
using System.Runtime.Serialization;
-[System.Runtime.InteropServices.ComVisible(true)]
+ [System.Runtime.InteropServices.ComVisible(true)]
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
public class ThreadStateException : SystemException {
public ThreadStateException()
: base(Environment.GetResourceString("Arg_ThreadStateException")) {
diff --git a/src/mscorlib/src/System/Threading/WaitHandleCannotBeOpenedException.cs b/src/mscorlib/src/System/Threading/WaitHandleCannotBeOpenedException.cs
index f873057992..bac48b4084 100644
--- a/src/mscorlib/src/System/Threading/WaitHandleCannotBeOpenedException.cs
+++ b/src/mscorlib/src/System/Threading/WaitHandleCannotBeOpenedException.cs
@@ -9,7 +9,9 @@ namespace System.Threading
using System.Runtime.Serialization;
using System.Runtime.InteropServices;
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
[ComVisibleAttribute(false)]
#if FEATURE_CORECLR
diff --git a/src/mscorlib/src/System/TimeZoneInfo.cs b/src/mscorlib/src/System/TimeZoneInfo.cs
index 08ddc3e4ae..e84a5fff8a 100644
--- a/src/mscorlib/src/System/TimeZoneInfo.cs
+++ b/src/mscorlib/src/System/TimeZoneInfo.cs
@@ -50,11 +50,16 @@ namespace System {
};
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
[System.Security.Permissions.HostProtection(MayLeakOnAbort = true)]
[TypeForwardedFrom("System.Core, Version=3.5.0.0, Culture=Neutral, PublicKeyToken=b77a5c561934e089")]
- sealed public class TimeZoneInfo : IEquatable<TimeZoneInfo>, ISerializable, IDeserializationCallback {
-
+ sealed public class TimeZoneInfo : IEquatable<TimeZoneInfo>
+#if FEATURE_SERIALIZATION
+ , ISerializable, IDeserializationCallback
+#endif
+ {
// ---- SECTION: members supporting exposed properties -------------*
private String m_id;
private String m_displayName;
@@ -1127,7 +1132,7 @@ namespace System {
//
// private ctor
//
-#if FEATURE_WIN32_REGISTRY
+#if FEATURE_WIN32_REGISTRY
[System.Security.SecurityCritical] // auto-generated
private TimeZoneInfo(Win32Native.TimeZoneInformation zone, Boolean dstDisabled) {
@@ -4452,10 +4457,16 @@ namespace System {
**
**
============================================================*/
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
[System.Security.Permissions.HostProtection(MayLeakOnAbort = true)]
[TypeForwardedFrom("System.Core, Version=3.5.0.0, Culture=Neutral, PublicKeyToken=b77a5c561934e089")]
- sealed public class AdjustmentRule : IEquatable<AdjustmentRule>, ISerializable, IDeserializationCallback {
+ sealed public class AdjustmentRule : IEquatable<AdjustmentRule>
+#if FEATURE_SERIALIZATION
+ , ISerializable, IDeserializationCallback
+#endif
+ {
// ---- SECTION: members supporting exposed properties -------------*
private DateTime m_dateStart;
@@ -4761,11 +4772,16 @@ namespace System {
**
**
============================================================*/
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
[System.Security.Permissions.HostProtection(MayLeakOnAbort = true)]
[TypeForwardedFrom("System.Core, Version=3.5.0.0, Culture=Neutral, PublicKeyToken=b77a5c561934e089")]
- public struct TransitionTime : IEquatable<TransitionTime>, ISerializable, IDeserializationCallback {
-
+ public struct TransitionTime : IEquatable<TransitionTime>
+#if FEATURE_SERIALIZATION
+ , ISerializable, IDeserializationCallback
+#endif
+ {
// ---- SECTION: members supporting exposed properties -------------*
private DateTime m_timeOfDay;
private byte m_month;
diff --git a/src/mscorlib/src/System/TimeZoneNotFoundException.cs b/src/mscorlib/src/System/TimeZoneNotFoundException.cs
index d0e9ea4047..6abc3ee5e5 100644
--- a/src/mscorlib/src/System/TimeZoneNotFoundException.cs
+++ b/src/mscorlib/src/System/TimeZoneNotFoundException.cs
@@ -6,7 +6,9 @@ namespace System {
using System.Runtime.Serialization;
using System.Runtime.CompilerServices;
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
[TypeForwardedFrom("System.Core, Version=3.5.0.0, Culture=Neutral, PublicKeyToken=b77a5c561934e089")]
[System.Security.Permissions.HostProtection(MayLeakOnAbort = true)]
public class TimeZoneNotFoundException : Exception {
diff --git a/src/mscorlib/src/System/TimeoutException.cs b/src/mscorlib/src/System/TimeoutException.cs
index ed19f1f373..691682efe3 100644
--- a/src/mscorlib/src/System/TimeoutException.cs
+++ b/src/mscorlib/src/System/TimeoutException.cs
@@ -15,8 +15,10 @@ namespace System
{
using System.Runtime.Serialization;
+#if FEATURE_SERIALIZATION
[Serializable]
-[System.Runtime.InteropServices.ComVisible(true)]
+#endif
+ [System.Runtime.InteropServices.ComVisible(true)]
public class TimeoutException : SystemException {
public TimeoutException()
diff --git a/src/mscorlib/src/System/TypeAccessException.cs b/src/mscorlib/src/System/TypeAccessException.cs
index 5ddc9a7538..1bf5149d0d 100644
--- a/src/mscorlib/src/System/TypeAccessException.cs
+++ b/src/mscorlib/src/System/TypeAccessException.cs
@@ -10,7 +10,9 @@ namespace System
{
// TypeAccessException derives from TypeLoadException rather than MemberAccessException because in
// pre-v4 releases of the runtime TypeLoadException was used in lieu of a TypeAccessException.
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
public class TypeAccessException : TypeLoadException
{
public TypeAccessException()
diff --git a/src/mscorlib/src/System/TypeInitializationException.cs b/src/mscorlib/src/System/TypeInitializationException.cs
index 59defe6b31..9da2854435 100644
--- a/src/mscorlib/src/System/TypeInitializationException.cs
+++ b/src/mscorlib/src/System/TypeInitializationException.cs
@@ -19,8 +19,10 @@ using System.Globalization;
using System.Security.Permissions;
namespace System {
+#if FEATURE_SERIALIZATION
[Serializable]
-[System.Runtime.InteropServices.ComVisible(true)]
+#endif
+ [System.Runtime.InteropServices.ComVisible(true)]
public sealed class TypeInitializationException : SystemException {
private String _typeName;
diff --git a/src/mscorlib/src/System/TypeLoadException.cs b/src/mscorlib/src/System/TypeLoadException.cs
index fe8d2c94f6..4fa692918b 100644
--- a/src/mscorlib/src/System/TypeLoadException.cs
+++ b/src/mscorlib/src/System/TypeLoadException.cs
@@ -23,8 +23,10 @@ namespace System {
using System.Security.Permissions;
using System.Diagnostics.Contracts;
+#if FEATURE_SERIALIZATION
[Serializable]
-[System.Runtime.InteropServices.ComVisible(true)]
+#endif
+ [System.Runtime.InteropServices.ComVisible(true)]
public class TypeLoadException : SystemException, ISerializable {
public TypeLoadException()
diff --git a/src/mscorlib/src/System/TypeUnloadedException.cs b/src/mscorlib/src/System/TypeUnloadedException.cs
index 4f28cac964..f350976a05 100644
--- a/src/mscorlib/src/System/TypeUnloadedException.cs
+++ b/src/mscorlib/src/System/TypeUnloadedException.cs
@@ -15,8 +15,10 @@ namespace System {
using System.Runtime.Serialization;
-[System.Runtime.InteropServices.ComVisible(true)]
+ [System.Runtime.InteropServices.ComVisible(true)]
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
public class TypeUnloadedException : SystemException {
public TypeUnloadedException()
: base(Environment.GetResourceString("Arg_TypeUnloadedException")) {
diff --git a/src/mscorlib/src/System/UIntPtr.cs b/src/mscorlib/src/System/UIntPtr.cs
index c08d193bda..fdeff3d6f0 100644
--- a/src/mscorlib/src/System/UIntPtr.cs
+++ b/src/mscorlib/src/System/UIntPtr.cs
@@ -18,11 +18,16 @@ namespace System {
using System.Runtime.Serialization;
using System.Security;
using System.Diagnostics.Contracts;
-
+
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
[CLSCompliant(false)]
[System.Runtime.InteropServices.ComVisible(true)]
- public struct UIntPtr : ISerializable
+ public struct UIntPtr
+#if FEATURE_SERIALIZATION
+ : ISerializable
+#endif
{
[SecurityCritical]
unsafe private void* m_value;
@@ -90,12 +95,12 @@ namespace System {
[System.Security.SecuritySafeCritical] // auto-generated
public unsafe override int GetHashCode() {
#if FEATURE_CORECLR
- #if BIT64
+#if BIT64
ulong l = (ulong)m_value;
return (unchecked((int)l) ^ (int)(l >> 32));
- #else // 32
+#else // 32
return unchecked((int)m_value);
- #endif
+#endif
#else
return unchecked((int)((long)m_value)) & 0x7fffffff;
#endif
@@ -197,11 +202,11 @@ namespace System {
[System.Runtime.Versioning.NonVersionable]
public static UIntPtr operator +(UIntPtr pointer, int offset) {
- #if BIT64
+#if BIT64
return new UIntPtr(pointer.ToUInt64() + (ulong)offset);
- #else // 32
+#else // 32
return new UIntPtr(pointer.ToUInt32() + (uint)offset);
- #endif
+#endif
}
[System.Runtime.Versioning.NonVersionable]
@@ -211,11 +216,11 @@ namespace System {
[System.Runtime.Versioning.NonVersionable]
public static UIntPtr operator -(UIntPtr pointer, int offset) {
- #if BIT64
+#if BIT64
return new UIntPtr(pointer.ToUInt64() - (ulong)offset);
- #else // 32
+#else // 32
return new UIntPtr(pointer.ToUInt32() - (uint)offset);
- #endif
+#endif
}
public static int Size
diff --git a/src/mscorlib/src/System/UnauthorizedAccessException.cs b/src/mscorlib/src/System/UnauthorizedAccessException.cs
index 53dbecf1c5..55dad34078 100644
--- a/src/mscorlib/src/System/UnauthorizedAccessException.cs
+++ b/src/mscorlib/src/System/UnauthorizedAccessException.cs
@@ -19,8 +19,10 @@ using System.Runtime.Serialization;
namespace System {
// The UnauthorizedAccessException is thrown when access errors
// occur from IO or other OS methods.
+#if FEATURE_SERIALIZATION
[Serializable]
-[System.Runtime.InteropServices.ComVisible(true)]
+#endif
+ [System.Runtime.InteropServices.ComVisible(true)]
public class UnauthorizedAccessException : SystemException {
public UnauthorizedAccessException()
: base(Environment.GetResourceString("Arg_UnauthorizedAccessException")) {
diff --git a/src/mscorlib/src/System/UnhandledExceptionEventHandler.cs b/src/mscorlib/src/System/UnhandledExceptionEventHandler.cs
index 516c32e602..feedfed3c6 100644
--- a/src/mscorlib/src/System/UnhandledExceptionEventHandler.cs
+++ b/src/mscorlib/src/System/UnhandledExceptionEventHandler.cs
@@ -5,10 +5,12 @@
namespace System {
using System;
- #if FEATURE_CORECLR
+#if FEATURE_CORECLR
[System.Security.SecurityCritical] // auto-generated
- #endif
- [Serializable]
-[System.Runtime.InteropServices.ComVisible(true)]
+#endif
+#if FEATURE_SERIALIZATION
+ [Serializable]
+#endif
+ [System.Runtime.InteropServices.ComVisible(true)]
public delegate void UnhandledExceptionEventHandler(Object sender, UnhandledExceptionEventArgs e);
}
diff --git a/src/mscorlib/src/System/UnitySerializationHolder.cs b/src/mscorlib/src/System/UnitySerializationHolder.cs
index ec32fce348..b2e004530e 100644
--- a/src/mscorlib/src/System/UnitySerializationHolder.cs
+++ b/src/mscorlib/src/System/UnitySerializationHolder.cs
@@ -13,7 +13,9 @@ using System.Diagnostics.Contracts;
namespace System {
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
// Holds classes (Empty, Null, Missing) for which we guarantee that there is only ever one instance of.
internal class UnitySerializationHolder : ISerializable, IObjectReference
{
diff --git a/src/mscorlib/src/System/WeakReference.cs b/src/mscorlib/src/System/WeakReference.cs
index 9952bc002e..1ccfc3081e 100644
--- a/src/mscorlib/src/System/WeakReference.cs
+++ b/src/mscorlib/src/System/WeakReference.cs
@@ -21,8 +21,14 @@ namespace System {
#if !FEATURE_CORECLR
[SecurityPermissionAttribute(SecurityAction.InheritanceDemand, Flags=SecurityPermissionFlag.UnmanagedCode)] // Don't call Object::MemberwiseClone.
#endif
+#if FEATURE_SERIALIZATION
[Serializable]
- public class WeakReference : ISerializable {
+#endif
+ public class WeakReference
+#if FEATURE_SERIALIZATION
+ : ISerializable
+#endif
+ {
// If you fix bugs here, please fix them in WeakReference<T> at the same time.
// This field is not a regular GC handle. It can have a special values that are used to prevent a race condition between setting the target and finalization.
diff --git a/src/mscorlib/src/System/WeakReferenceOfT.cs b/src/mscorlib/src/System/WeakReferenceOfT.cs
index 6afa33c134..9cf192efee 100644
--- a/src/mscorlib/src/System/WeakReferenceOfT.cs
+++ b/src/mscorlib/src/System/WeakReferenceOfT.cs
@@ -18,9 +18,15 @@ namespace System
using System.Runtime.Versioning;
using System.Diagnostics.Contracts;
+#if FEATURE_SERIALIZATION
[Serializable]
+#endif
// This class is sealed to mitigate security issues caused by Object::MemberwiseClone.
- public sealed class WeakReference<T> : ISerializable where T : class
+ public sealed class WeakReference<T>
+#if FEATURE_SERIALIZATION
+ : ISerializable
+#endif
+ where T : class
{
// If you fix bugs here, please fix them in WeakReference at the same time.
diff --git a/src/pal/inc/pal.h b/src/pal/inc/pal.h
index 5b44661d87..fe29112b07 100644
--- a/src/pal/inc/pal.h
+++ b/src/pal/inc/pal.h
@@ -6442,6 +6442,13 @@ public:
#include "pal_unwind.h"
+PALIMPORT
+VOID
+PALAPI
+PAL_FreeExceptionRecords(
+ IN EXCEPTION_RECORD *exceptionRecord,
+ IN CONTEXT *contextRecord);
+
#define EXCEPTION_CONTINUE_SEARCH 0
#define EXCEPTION_EXECUTE_HANDLER 1
#define EXCEPTION_CONTINUE_EXECUTION -1
@@ -6450,58 +6457,95 @@ struct PAL_SEHException
{
private:
static const SIZE_T NoTargetFrameSp = SIZE_MAX;
+
+ void Move(PAL_SEHException& ex)
+ {
+ ExceptionPointers.ExceptionRecord = ex.ExceptionPointers.ExceptionRecord;
+ ExceptionPointers.ContextRecord = ex.ExceptionPointers.ContextRecord;
+ TargetFrameSp = ex.TargetFrameSp;
+
+ ex.Clear();
+ }
+
+ void FreeRecords()
+ {
+ if (ExceptionPointers.ExceptionRecord != NULL)
+ {
+ PAL_FreeExceptionRecords(ExceptionPointers.ExceptionRecord, ExceptionPointers.ContextRecord);
+ ExceptionPointers.ExceptionRecord = NULL;
+ ExceptionPointers.ContextRecord = NULL;
+ }
+ }
+
public:
- // Note that the following two are actually embedded in this heap-allocated
- // instance - in contrast to Win32, where the exception record would usually
- // be allocated on the stack. This is needed because foreign cleanup handlers
- // partially unwind the stack on the second pass.
EXCEPTION_POINTERS ExceptionPointers;
- EXCEPTION_RECORD ExceptionRecord;
- CONTEXT ContextRecord;
// Target frame stack pointer set before the 2nd pass.
SIZE_T TargetFrameSp;
PAL_SEHException(EXCEPTION_RECORD *pExceptionRecord, CONTEXT *pContextRecord)
{
- ExceptionPointers.ExceptionRecord = &ExceptionRecord;
- ExceptionPointers.ContextRecord = &ContextRecord;
- ExceptionRecord = *pExceptionRecord;
- ContextRecord = *pContextRecord;
+ ExceptionPointers.ExceptionRecord = pExceptionRecord;
+ ExceptionPointers.ContextRecord = pContextRecord;
TargetFrameSp = NoTargetFrameSp;
}
PAL_SEHException()
{
+ Clear();
}
- PAL_SEHException(const PAL_SEHException& ex)
+ // The copy constructor and copy assignment operators are deleted so that the PAL_SEHException
+ // can never be copied, only moved. This enables simple lifetime management of the exception and
+ // context records, since there is always just one PAL_SEHException instance referring to the same records.
+ PAL_SEHException(const PAL_SEHException& ex) = delete;
+ PAL_SEHException& operator=(const PAL_SEHException& ex) = delete;
+
+ PAL_SEHException(PAL_SEHException&& ex)
{
- *this = ex;
+ Move(ex);
}
- bool IsFirstPass()
+ PAL_SEHException& operator=(PAL_SEHException&& ex)
{
- return (TargetFrameSp == NoTargetFrameSp);
+ FreeRecords();
+ Move(ex);
+ return *this;
}
- void SecondPassDone()
+ ~PAL_SEHException()
{
+ FreeRecords();
+ }
+
+ void Clear()
+ {
+ ExceptionPointers.ExceptionRecord = NULL;
+ ExceptionPointers.ContextRecord = NULL;
TargetFrameSp = NoTargetFrameSp;
}
- PAL_SEHException& operator=(const PAL_SEHException& ex)
+ CONTEXT* GetContextRecord()
{
- ExceptionPointers.ExceptionRecord = &ExceptionRecord;
- ExceptionPointers.ContextRecord = &ContextRecord;
- ExceptionRecord = ex.ExceptionRecord;
- ContextRecord = ex.ContextRecord;
- TargetFrameSp = ex.TargetFrameSp;
+ return ExceptionPointers.ContextRecord;
+ }
- return *this;
+ EXCEPTION_RECORD* GetExceptionRecord()
+ {
+ return ExceptionPointers.ExceptionRecord;
+ }
+
+ bool IsFirstPass()
+ {
+ return (TargetFrameSp == NoTargetFrameSp);
+ }
+
+ void SecondPassDone()
+ {
+ TargetFrameSp = NoTargetFrameSp;
}
};
-typedef VOID (PALAPI *PHARDWARE_EXCEPTION_HANDLER)(PAL_SEHException* ex);
+typedef BOOL (PALAPI *PHARDWARE_EXCEPTION_HANDLER)(PAL_SEHException* ex);
typedef BOOL (PALAPI *PHARDWARE_EXCEPTION_SAFETY_CHECK_FUNCTION)(PCONTEXT contextRecord, PEXCEPTION_RECORD exceptionRecord);
typedef VOID (PALAPI *PTERMINATION_REQUEST_HANDLER)();
typedef DWORD (PALAPI *PGET_GCMARKER_EXCEPTION_CODE)(LPVOID ip);
diff --git a/src/pal/src/config.h.in b/src/pal/src/config.h.in
index 7997a6fb55..7a53c8cb5d 100644
--- a/src/pal/src/config.h.in
+++ b/src/pal/src/config.h.in
@@ -97,7 +97,6 @@
#cmakedefine01 STATVFS64_PROTOTYPE_BROKEN
#cmakedefine01 HAVE_MMAP_DEV_ZERO
#cmakedefine01 MMAP_ANON_IGNORES_PROTECTION
-#cmakedefine01 MMAP_DOESNOT_ALLOW_REMAP
#cmakedefine01 ONE_SHARED_MAPPING_PER_FILEREGION_PER_PROCESS
#cmakedefine01 PTHREAD_CREATE_MODIFIES_ERRNO
#cmakedefine01 SEM_INIT_MODIFIES_ERRNO
diff --git a/src/pal/src/configure.cmake b/src/pal/src/configure.cmake
index d8eadac401..cc38bc8541 100644
--- a/src/pal/src/configure.cmake
+++ b/src/pal/src/configure.cmake
@@ -483,34 +483,6 @@ int main(void) {
exit(0);
}" MMAP_ANON_IGNORES_PROTECTION)
check_cxx_source_runs("
-#include <stdlib.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/mman.h>
-
-#ifndef MAP_ANON
-#define MAP_ANON MAP_ANONYMOUS
-#endif
-
-int main()
-{
- int iRet = 1;
- void * pAddr = MAP_FAILED;
- int MemSize = 1024;
-
- MemSize = getpagesize();
- pAddr = mmap(0x0, MemSize, PROT_NONE, MAP_PRIVATE | MAP_ANON, -1, 0);
- if (pAddr == MAP_FAILED)
- exit(0);
-
- pAddr = mmap(pAddr, MemSize, PROT_WRITE | PROT_READ, MAP_FIXED | MAP_PRIVATE | MAP_ANON, -1, 0);
- if (pAddr == MAP_FAILED)
- iRet = 0;
-
- munmap(pAddr, MemSize); // don't care of this
- exit (iRet);
-}" MMAP_DOESNOT_ALLOW_REMAP)
-check_cxx_source_runs("
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
diff --git a/src/pal/src/exception/machexception.cpp b/src/pal/src/exception/machexception.cpp
index 508a967ef2..a483509f07 100644
--- a/src/pal/src/exception/machexception.cpp
+++ b/src/pal/src/exception/machexception.cpp
@@ -459,12 +459,37 @@ void PAL_DispatchException(DWORD64 dwRDI, DWORD64 dwRSI, DWORD64 dwRDX, DWORD64
}
#endif // FEATURE_PAL_SXS
- EXCEPTION_POINTERS pointers;
- pointers.ExceptionRecord = pExRecord;
- pointers.ContextRecord = pContext;
+ CONTEXT *contextRecord;
+ EXCEPTION_RECORD *exceptionRecord;
+ AllocateExceptionRecords(&exceptionRecord, &contextRecord);
- TRACE("PAL_DispatchException(EC %08x EA %p)\n", pExRecord->ExceptionCode, pExRecord->ExceptionAddress);
- SEHProcessException(&pointers);
+ *contextRecord = *pContext;
+ *exceptionRecord = *pExRecord;
+
+ contextRecord->ContextFlags |= CONTEXT_EXCEPTION_ACTIVE;
+ bool continueExecution;
+
+ {
+ // The exception object takes ownership of the exceptionRecord and contextRecord
+ PAL_SEHException exception(exceptionRecord, contextRecord);
+
+ TRACE("PAL_DispatchException(EC %08x EA %p)\n", pExRecord->ExceptionCode, pExRecord->ExceptionAddress);
+
+ continueExecution = SEHProcessException(&exception);
+ if (continueExecution)
+ {
+ // Make a copy of the exception records so that we can free them before restoring the context
+ *pContext = *contextRecord;
+ *pExRecord = *exceptionRecord;
+ }
+
+ // The exception records are destroyed by the PAL_SEHException destructor now.
+ }
+
+ if (continueExecution)
+ {
+ RtlRestoreContext(pContext, pExRecord);
+ }
// Send the forward request to the exception thread to process
MachMessage sSendMessage;
diff --git a/src/pal/src/exception/seh-unwind.cpp b/src/pal/src/exception/seh-unwind.cpp
index 763306b15d..24eebbbf94 100644
--- a/src/pal/src/exception/seh-unwind.cpp
+++ b/src/pal/src/exception/seh-unwind.cpp
@@ -26,8 +26,7 @@ Abstract:
#include "pal/context.h"
#include "pal.h"
#include <dlfcn.h>
-#include <exception>
-
+
#if HAVE_LIBUNWIND_H
#ifndef __linux__
#define UNW_LOCAL_ONLY
@@ -289,10 +288,16 @@ BOOL PAL_VirtualUnwind(CONTEXT *context, KNONVOLATILE_CONTEXT_POINTERS *contextP
if (unw_is_signal_frame(&cursor) > 0)
{
context->ContextFlags |= CONTEXT_EXCEPTION_ACTIVE;
+#if defined(_ARM_) || defined(_ARM64_)
+ context->ContextFlags &= ~CONTEXT_UNWOUND_TO_CALL;
+#endif // _ARM_ || _ARM64_
}
else
{
context->ContextFlags &= ~CONTEXT_EXCEPTION_ACTIVE;
+#if defined(_ARM_) || defined(_ARM64_)
+ context->ContextFlags |= CONTEXT_UNWOUND_TO_CALL;
+#endif // _ARM_ || _ARM64_
}
// Update the passed in windows context to reflect the unwind
@@ -558,6 +563,85 @@ BOOL PAL_VirtualUnwindOutOfProc(CONTEXT *context,
#endif // !HAVE_UNW_GET_ACCESSORS
#endif // _AMD64_
+struct ExceptionRecords
+{
+ CONTEXT ContextRecord;
+ EXCEPTION_RECORD ExceptionRecord;
+};
+
+// Max number of fallback contexts that are used when malloc fails to allocate ExceptionRecords structure
+static const int MaxFallbackContexts = sizeof(size_t) * 8;
+// Array of fallback contexts
+static ExceptionRecords s_fallbackContexts[MaxFallbackContexts];
+// Bitmap used for allocating fallback contexts - bits set to 1 represent already allocated context.
+static volatile size_t s_allocatedContextsBitmap = 0;
+
+/*++
+Function:
+ AllocateExceptionRecords
+
+ Allocate EXCEPTION_RECORD and CONTEXT structures for an exception.
+Parameters:
+ exceptionRecord - output pointer to the allocated exception record
+ contextRecord - output pointer to the allocated context record
+--*/
+VOID
+AllocateExceptionRecords(EXCEPTION_RECORD** exceptionRecord, CONTEXT** contextRecord)
+{
+ ExceptionRecords* records;
+ if (posix_memalign((void**)&records, alignof(ExceptionRecords), sizeof(ExceptionRecords)) != 0)
+ {
+ size_t bitmap;
+ size_t newBitmap;
+ int index;
+
+ do
+ {
+ bitmap = s_allocatedContextsBitmap;
+ index = __builtin_ffsl(~bitmap) - 1;
+ if (index < 0)
+ {
+ PROCAbort();
+ }
+
+ newBitmap = bitmap | ((size_t)1 << index);
+ }
+ while (__sync_val_compare_and_swap(&s_allocatedContextsBitmap, bitmap, newBitmap) != bitmap);
+
+ records = &s_fallbackContexts[index];
+ }
+
+ *contextRecord = &records->ContextRecord;
+ *exceptionRecord = &records->ExceptionRecord;
+}
+
+/*++
+Function:
+ PAL_FreeExceptionRecords
+
+ Free EXCEPTION_RECORD and CONTEXT structures of an exception that were allocated by the
+ AllocateExceptionRecords.
+Parameters:
+ exceptionRecord - exception record
+ contextRecord - context record
+--*/
+VOID
+PALAPI
+PAL_FreeExceptionRecords(IN EXCEPTION_RECORD *exceptionRecord, IN CONTEXT *contextRecord)
+{
+ // Both records are allocated at once and the allocated memory starts at the contextRecord
+ ExceptionRecords* records = (ExceptionRecords*)contextRecord;
+ if ((records >= &s_fallbackContexts[0]) && (records < &s_fallbackContexts[MaxFallbackContexts]))
+ {
+ int index = records - &s_fallbackContexts[0];
+ __sync_fetch_and_and(&s_allocatedContextsBitmap, ~((size_t)1 << index));
+ }
+ else
+ {
+ free(contextRecord);
+ }
+}
+
/*++
Function:
RtlpRaiseException
@@ -568,7 +652,7 @@ Parameters:
Note:
The name of this function and the name of the ExceptionRecord
parameter is used in the sos lldb plugin code to read the exception
- record. See coreclr\src\ToolBox\SOS\lldbplugin\debugclient.cpp.
+ record. See coreclr\src\ToolBox\SOS\lldbplugin\services.cpp.
This function must not be inlined or optimized so the below PAL_VirtualUnwind
calls end up with RaiseException caller's context and so the above debugger
@@ -578,32 +662,9 @@ PAL_NORETURN
__attribute__((noinline))
__attribute__((optnone))
static void
-RtlpRaiseException(EXCEPTION_RECORD *ExceptionRecord)
+RtlpRaiseException(EXCEPTION_RECORD *ExceptionRecord, CONTEXT *ContextRecord)
{
- // Capture the context of RtlpRaiseException.
- CONTEXT ContextRecord;
- ZeroMemory(&ContextRecord, sizeof(CONTEXT));
- ContextRecord.ContextFlags = CONTEXT_FULL;
- CONTEXT_CaptureContext(&ContextRecord);
-
- // Find the caller of RtlpRaiseException.
- PAL_VirtualUnwind(&ContextRecord, NULL);
-
- // The frame we're looking at now is RaiseException. We have to unwind one
- // level further to get the actual context user code could be resumed at.
- PAL_VirtualUnwind(&ContextRecord, NULL);
-
-#if defined(_X86_)
- ExceptionRecord->ExceptionAddress = (void *) ContextRecord.Eip;
-#elif defined(_AMD64_)
- ExceptionRecord->ExceptionAddress = (void *) ContextRecord.Rip;
-#elif defined(_ARM_) || defined(_ARM64_)
- ExceptionRecord->ExceptionAddress = (void *) ContextRecord.Pc;
-#else
-#error unsupported architecture
-#endif
-
- throw PAL_SEHException(ExceptionRecord, &ContextRecord);
+ throw PAL_SEHException(ExceptionRecord, ContextRecord);
}
/*++
@@ -613,6 +674,7 @@ Function:
See MSDN doc.
--*/
// no PAL_NORETURN, as callers must assume this can return for continuable exceptions.
+__attribute__((noinline))
VOID
PALAPI
RaiseException(IN DWORD dwExceptionCode,
@@ -642,20 +704,34 @@ RaiseException(IN DWORD dwExceptionCode,
nNumberOfArguments = EXCEPTION_MAXIMUM_PARAMETERS;
}
- EXCEPTION_RECORD exceptionRecord;
- ZeroMemory(&exceptionRecord, sizeof(EXCEPTION_RECORD));
+ CONTEXT *contextRecord;
+ EXCEPTION_RECORD *exceptionRecord;
+ AllocateExceptionRecords(&exceptionRecord, &contextRecord);
- exceptionRecord.ExceptionCode = dwExceptionCode;
- exceptionRecord.ExceptionFlags = dwExceptionFlags;
- exceptionRecord.ExceptionRecord = NULL;
- exceptionRecord.ExceptionAddress = NULL; // will be set by RtlpRaiseException
- exceptionRecord.NumberParameters = nNumberOfArguments;
+ ZeroMemory(exceptionRecord, sizeof(EXCEPTION_RECORD));
+
+ exceptionRecord->ExceptionCode = dwExceptionCode;
+ exceptionRecord->ExceptionFlags = dwExceptionFlags;
+ exceptionRecord->ExceptionRecord = NULL;
+ exceptionRecord->ExceptionAddress = NULL; // will be set by RtlpRaiseException
+ exceptionRecord->NumberParameters = nNumberOfArguments;
if (nNumberOfArguments)
{
- CopyMemory(exceptionRecord.ExceptionInformation, lpArguments,
+ CopyMemory(exceptionRecord->ExceptionInformation, lpArguments,
nNumberOfArguments * sizeof(ULONG_PTR));
}
- RtlpRaiseException(&exceptionRecord);
+
+ // Capture the context of RaiseException.
+ ZeroMemory(contextRecord, sizeof(CONTEXT));
+ contextRecord->ContextFlags = CONTEXT_FULL;
+ CONTEXT_CaptureContext(contextRecord);
+
+ // We have to unwind one level to get the actual context user code could be resumed at.
+ PAL_VirtualUnwind(contextRecord, NULL);
+
+ exceptionRecord->ExceptionAddress = (void *)CONTEXTGetPC(contextRecord);
+
+ RtlpRaiseException(exceptionRecord, contextRecord);
LOGEXIT("RaiseException returns\n");
}
diff --git a/src/pal/src/exception/seh.cpp b/src/pal/src/exception/seh.cpp
index 346e94e80e..5320ecd087 100644
--- a/src/pal/src/exception/seh.cpp
+++ b/src/pal/src/exception/seh.cpp
@@ -40,6 +40,37 @@ Abstract:
#include <pthread.h>
#include <stdlib.h>
+// Define the std::move so that we don't have to include the <utility> header
+// which on some platforms pulls in STL stuff that collides with PAL stuff.
+// The std::move is needed to enable using move constructor and assignment operator
+// for PAL_SEHException.
+namespace std
+{
+ template<typename T>
+ struct remove_reference
+ {
+ typedef T type;
+ };
+
+ template<typename T>
+ struct remove_reference<T&>
+ {
+ typedef T type;
+ };
+
+ template<typename T>
+ struct remove_reference<T&&>
+ {
+ typedef T type;
+ };
+
+ template<class T> inline
+ typename remove_reference<T>::type&& move(T&& arg)
+ { // forward arg as movable
+ return ((typename remove_reference<T>::type&&)arg);
+ }
+}
+
using namespace CorUnix;
SET_DEFAULT_DEBUG_CHANNEL(EXCEPT);
@@ -177,7 +208,7 @@ PAL_ThrowExceptionFromContext(CONTEXT* context, PAL_SEHException* ex)
// frames that will become obsolete by the ThrowExceptionFromContextInternal and the ThrowExceptionHelper
// could overwrite the "ex" object by stack e.g. when allocating the low level exception object for "throw".
static __thread BYTE threadLocalExceptionStorage[sizeof(PAL_SEHException)];
- ThrowExceptionFromContextInternal(context, new (threadLocalExceptionStorage) PAL_SEHException(*ex));
+ ThrowExceptionFromContextInternal(context, new (threadLocalExceptionStorage) PAL_SEHException(std::move(*ex)));
}
/*++
@@ -193,44 +224,46 @@ Parameters:
extern "C"
void ThrowExceptionHelper(PAL_SEHException* ex)
{
- throw *ex;
+ throw std::move(*ex);
}
/*++
Function:
SEHProcessException
- Build the PAL exception and sent it to any handler registered.
+ Send the PAL exception to any handler registered.
Parameters:
- PEXCEPTION_POINTERS pointers
+ PAL_SEHException* exception
Return value:
- Returns only if the exception is unhandled
+ Returns TRUE if the exception happened in managed code and the execution should
+ continue (with possibly modified context).
+ Returns FALSE if the exception happened in managed code and it was not handled.
+ In case the exception was handled by calling a catch handler, it doesn't return at all.
--*/
-VOID
-SEHProcessException(PEXCEPTION_POINTERS pointers)
+BOOL
+SEHProcessException(PAL_SEHException* exception)
{
- pointers->ContextRecord->ContextFlags |= CONTEXT_EXCEPTION_ACTIVE;
+ CONTEXT* contextRecord = exception->GetContextRecord();
+ EXCEPTION_RECORD* exceptionRecord = exception->GetExceptionRecord();
- if (!IsInDebugBreak(pointers->ExceptionRecord->ExceptionAddress))
+ if (!IsInDebugBreak(exceptionRecord->ExceptionAddress))
{
- PAL_SEHException exception(pointers->ExceptionRecord, pointers->ContextRecord);
-
if (g_hardwareExceptionHandler != NULL)
{
_ASSERTE(g_safeExceptionCheckFunction != NULL);
// Check if it is safe to handle the hardware exception (the exception happened in managed code
// or in a jitter helper or it is a debugger breakpoint)
- if (g_safeExceptionCheckFunction(pointers->ContextRecord, pointers->ExceptionRecord))
+ if (g_safeExceptionCheckFunction(contextRecord, exceptionRecord))
{
- if (pointers->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION)
+ if (exceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION)
{
// Check if the failed access has hit a stack guard page. In such case, it
// was a stack probe that detected that there is not enough stack left.
void* stackLimit = CPalThread::GetStackLimit();
void* stackGuard = (void*)((size_t)stackLimit - getpagesize());
- void* violationAddr = (void*)pointers->ExceptionRecord->ExceptionInformation[1];
+ void* violationAddr = (void*)exceptionRecord->ExceptionInformation[1];
if ((violationAddr >= stackGuard) && (violationAddr < stackLimit))
{
// The exception happened in the page right below the stack limit,
@@ -240,19 +273,24 @@ SEHProcessException(PEXCEPTION_POINTERS pointers)
}
}
- // The following callback returns only in case the exception was a single step or
- // a breakpoint and it was not handled by the debugger.
- g_hardwareExceptionHandler(&exception);
+ if (g_hardwareExceptionHandler(exception))
+ {
+ // The exception happened in managed code and the execution should continue.
+ return TRUE;
+ }
+
+ // The exception was a single step or a breakpoint and it was not handled by the debugger.
}
}
if (CatchHardwareExceptionHolder::IsEnabled())
{
- PAL_ThrowExceptionFromContext(&exception.ContextRecord, &exception);
+ PAL_ThrowExceptionFromContext(exception->GetContextRecord(), exception);
}
}
- // Unhandled hardware exception pointers->ExceptionRecord->ExceptionCode at pointers->ExceptionRecord->ExceptionAddress
+ // Unhandled hardware exception pointers->ExceptionRecord->ExceptionCode at pointers->ExceptionRecord->ExceptionAddress
+ return FALSE;
}
/*++
diff --git a/src/pal/src/exception/signal.cpp b/src/pal/src/exception/signal.cpp
index adeada1860..8dd75ac185 100644
--- a/src/pal/src/exception/signal.cpp
+++ b/src/pal/src/exception/signal.cpp
@@ -74,7 +74,7 @@ static void sigint_handler(int code, siginfo_t *siginfo, void *context);
static void sigquit_handler(int code, siginfo_t *siginfo, void *context);
static void sigterm_handler(int code, siginfo_t *siginfo, void *context);
-static void common_signal_handler(int code, siginfo_t *siginfo, void *sigcontext, int numParams, ...);
+static bool common_signal_handler(int code, siginfo_t *siginfo, void *sigcontext, int numParams, ...);
#ifdef INJECT_ACTIVATION_SIGNAL
static void inject_activation_handler(int code, siginfo_t *siginfo, void *context);
@@ -217,7 +217,10 @@ static void sigill_handler(int code, siginfo_t *siginfo, void *context)
{
if (PALIsInitialized())
{
- common_signal_handler(code, siginfo, context, 0);
+ if (common_signal_handler(code, siginfo, context, 0))
+ {
+ return;
+ }
}
if (g_previous_sigill.sa_sigaction != NULL)
@@ -248,7 +251,10 @@ static void sigfpe_handler(int code, siginfo_t *siginfo, void *context)
{
if (PALIsInitialized())
{
- common_signal_handler(code, siginfo, context, 0);
+ if (common_signal_handler(code, siginfo, context, 0))
+ {
+ return;
+ }
}
if (g_previous_sigfpe.sa_sigaction != NULL)
@@ -282,7 +288,10 @@ static void sigsegv_handler(int code, siginfo_t *siginfo, void *context)
// TODO: First variable parameter says whether a read (0) or write (non-0) caused the
// fault. We must disassemble the instruction at record.ExceptionAddress
// to correctly fill in this value.
- common_signal_handler(code, siginfo, context, 2, (size_t)0, (size_t)siginfo->si_addr);
+ if (common_signal_handler(code, siginfo, context, 2, (size_t)0, (size_t)siginfo->si_addr))
+ {
+ return;
+ }
}
if (g_previous_sigsegv.sa_sigaction != NULL)
@@ -313,7 +322,10 @@ static void sigtrap_handler(int code, siginfo_t *siginfo, void *context)
{
if (PALIsInitialized())
{
- common_signal_handler(code, siginfo, context, 0);
+ if (common_signal_handler(code, siginfo, context, 0))
+ {
+ return;
+ }
}
if (g_previous_sigtrap.sa_sigaction != NULL)
@@ -348,7 +360,10 @@ static void sigbus_handler(int code, siginfo_t *siginfo, void *context)
// TODO: First variable parameter says whether a read (0) or write (non-0) caused the
// fault. We must disassemble the instruction at record.ExceptionAddress
// to correctly fill in this value.
- common_signal_handler(code, siginfo, context, 2, (size_t)0, (size_t)siginfo->si_addr);
+ if (common_signal_handler(code, siginfo, context, 2, (size_t)0, (size_t)siginfo->si_addr))
+ {
+ return;
+ }
}
if (g_previous_sigbus.sa_sigaction != NULL)
@@ -562,47 +577,44 @@ Parameters :
int numParams : number of variable parameters of the exception
... : variable parameters of the exception (each of size_t type)
- (no return value)
+ Returns true if the execution should continue or false if the exception was unhandled
Note:
the "pointers" parameter should contain a valid exception record pointer,
but the ContextRecord pointer will be overwritten.
--*/
-static void common_signal_handler(int code, siginfo_t *siginfo, void *sigcontext, int numParams, ...)
+static bool common_signal_handler(int code, siginfo_t *siginfo, void *sigcontext, int numParams, ...)
{
sigset_t signal_set;
- CONTEXT context;
- EXCEPTION_RECORD record;
- EXCEPTION_POINTERS pointers;
+ CONTEXT *contextRecord;
+ EXCEPTION_RECORD *exceptionRecord;
native_context_t *ucontext;
ucontext = (native_context_t *)sigcontext;
- record.ExceptionCode = CONTEXTGetExceptionCodeForSignal(siginfo, ucontext);
- record.ExceptionFlags = EXCEPTION_IS_SIGNAL;
- record.ExceptionRecord = NULL;
- record.ExceptionAddress = GetNativeContextPC(ucontext);
- record.NumberParameters = numParams;
+ AllocateExceptionRecords(&exceptionRecord, &contextRecord);
+
+ exceptionRecord->ExceptionCode = CONTEXTGetExceptionCodeForSignal(siginfo, ucontext);
+ exceptionRecord->ExceptionFlags = EXCEPTION_IS_SIGNAL;
+ exceptionRecord->ExceptionRecord = NULL;
+ exceptionRecord->ExceptionAddress = GetNativeContextPC(ucontext);
+ exceptionRecord->NumberParameters = numParams;
va_list params;
va_start(params, numParams);
for (int i = 0; i < numParams; i++)
{
- record.ExceptionInformation[i] = va_arg(params, size_t);
+ exceptionRecord->ExceptionInformation[i] = va_arg(params, size_t);
}
- pointers.ExceptionRecord = &record;
-
// Pre-populate context with data from current frame, because ucontext doesn't have some data (e.g. SS register)
// which is required for restoring context
- RtlCaptureContext(&context);
+ RtlCaptureContext(contextRecord);
// Fill context record with required information. from pal.h:
// On non-Win32 platforms, the CONTEXT pointer in the
// PEXCEPTION_POINTERS will contain at least the CONTEXT_CONTROL registers.
- CONTEXTFromNativeContext(ucontext, &context, CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT);
-
- pointers.ContextRecord = &context;
+ CONTEXTFromNativeContext(ucontext, contextRecord, CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT);
/* Unmask signal so we can receive it again */
sigemptyset(&signal_set);
@@ -613,7 +625,18 @@ static void common_signal_handler(int code, siginfo_t *siginfo, void *sigcontext
ASSERT("pthread_sigmask failed; error number is %d\n", sigmaskRet);
}
- SEHProcessException(&pointers);
+ contextRecord->ContextFlags |= CONTEXT_EXCEPTION_ACTIVE;
+ // The exception object takes ownership of the exceptionRecord and contextRecord
+ PAL_SEHException exception(exceptionRecord, contextRecord);
+
+ if (SEHProcessException(&exception))
+ {
+ // Exception handling may have modified the context, so update it.
+ CONTEXTToNativeContext(contextRecord, ucontext);
+ return true;
+ }
+
+ return false;
}
/*++
diff --git a/src/pal/src/include/pal/seh.hpp b/src/pal/src/include/pal/seh.hpp
index 4fa38359fe..3ac93d655a 100644
--- a/src/pal/src/include/pal/seh.hpp
+++ b/src/pal/src/include/pal/seh.hpp
@@ -63,16 +63,30 @@ SEHCleanup();
Function:
SEHProcessException
- Build the PAL exception and sent it to any handler registered.
+ Send the PAL exception to any handler registered.
Parameters:
- None
+ PAL_SEHException* exception
Return value:
- Does not return
+ Returns TRUE if the exception happened in managed code and the execution should
+ continue (with possibly modified context).
+ Returns FALSE if the exception happened in managed code and it was not handled.
+ In case the exception was handled by calling a catch handler, it doesn't return at all.
--*/
-VOID
-SEHProcessException(PEXCEPTION_POINTERS pointers);
+BOOL
+SEHProcessException(PAL_SEHException* exception);
+
+/*++
+Function:
+ AllocateExceptionRecords
+
+Parameters:
+ exceptionRecord - output pointer to the allocated Windows exception record
+ contextRecord - output pointer to the allocated Windows context record
+--*/
+VOID
+AllocateExceptionRecords(EXCEPTION_RECORD** exceptionRecord, CONTEXT** contextRecord);
#if !HAVE_MACH_EXCEPTIONS
// TODO: Implement for Mach exceptions. Not in CoreCLR surface area.
diff --git a/src/pal/src/include/pal/virtual.h b/src/pal/src/include/pal/virtual.h
index ec8244e8db..028d83f0f1 100644
--- a/src/pal/src/include/pal/virtual.h
+++ b/src/pal/src/include/pal/virtual.h
@@ -26,7 +26,7 @@ extern "C"
#endif // __cplusplus
typedef struct _CMI {
-
+
struct _CMI * pNext; /* Link to the next entry. */
struct _CMI * pLast; /* Link to the previous entry. */
@@ -41,11 +41,8 @@ typedef struct _CMI {
BYTE * pProtectionState; /* Individual allocation type tracking for each */
/* page in the region. */
-#if MMAP_DOESNOT_ALLOW_REMAP
- BYTE * pDirtyPages; /* Pages that need to be cleared if re-committed */
-#endif // MMAP_DOESNOT_ALLOW_REMAP
-}CMI, * PCMI;
+} CMI, * PCMI;
enum VIRTUAL_CONSTANTS
{
diff --git a/src/pal/src/loader/module.cpp b/src/pal/src/loader/module.cpp
index 1c06371d56..321a744345 100644
--- a/src/pal/src/loader/module.cpp
+++ b/src/pal/src/loader/module.cpp
@@ -1607,15 +1607,19 @@ static HMODULE LOADLoadLibrary(LPCSTR shortAsciiName, BOOL fDynamic)
HMODULE module = nullptr;
void *dl_handle = nullptr;
- // Check whether we have been requested to load 'libc'. If that's the case then use the
- // full name of the library that is defined in <gnu/lib-names.h> by the LIBC_SO constant.
- // The problem is that calling dlopen("libc.so") will fail for libc even thought it works
- // for other libraries. The reason is that libc.so is just linker script (i.e. a test file).
- // As a result, we have to use the full name (i.e. lib.so.6) that is defined by LIBC_SO.
+ // Check whether we have been requested to load 'libc'. If that's the case, then:
+ // * For Linux, use the full name of the library that is defined in <gnu/lib-names.h> by the
+ // LIBC_SO constant. The problem is that calling dlopen("libc.so") will fail for libc even
+ // though it works for other libraries. The reason is that libc.so is just linker script
+ // (i.e. a test file).
+ // As a result, we have to use the full name (i.e. lib.so.6) that is defined by LIBC_SO.
+ // * For macOS, use constant value absolute path "/usr/lib/libc.dylib".
+ // * For FreeBSD, use constant value "libc.so.7".
+ // * For rest of Unices, use constant value "libc.so".
if (strcmp(shortAsciiName, LIBC_NAME_WITHOUT_EXTENSION) == 0)
{
#if defined(__APPLE__)
- shortAsciiName = "libc.dylib";
+ shortAsciiName = "/usr/lib/libc.dylib";
#elif defined(__FreeBSD__)
shortAsciiName = "libc.so.7";
#elif defined(LIBC_SO)
diff --git a/src/pal/src/map/virtual.cpp b/src/pal/src/map/virtual.cpp
index 04167c3830..c3891494fd 100644
--- a/src/pal/src/map/virtual.cpp
+++ b/src/pal/src/map/virtual.cpp
@@ -125,9 +125,6 @@ void VIRTUALCleanup()
pEntry->startBoundary );
InternalFree(pEntry->pAllocState);
InternalFree(pEntry->pProtectionState );
-#if MMAP_DOESNOT_ALLOW_REMAP
- InternalFree(pEntry->pDirtyPages );
-#endif
pTempEntry = pEntry;
pEntry = pEntry->pNext;
InternalFree(pTempEntry );
@@ -196,45 +193,6 @@ static BOOL VIRTUALIsPageCommitted( SIZE_T nBitToRetrieve, CONST PCMI pInformati
}
}
-#if MMAP_DOESNOT_ALLOW_REMAP
-/****
- *
- * VIRTUALIsPageDirty
- *
- * SIZE_T nBitToRetrieve - Which page to check.
- *
- * Returns TRUE if the page needs to be cleared if re-committed,
- * FALSE otherwise.
- *
- */
-static BOOL VIRTUALIsPageDirty( SIZE_T nBitToRetrieve, CONST PCMI pInformation )
-{
- SIZE_T nByteOffset = 0;
- UINT nBitOffset = 0;
- UINT byteMask = 0;
-
- if ( !pInformation )
- {
- ERROR( "pInformation was NULL!\n" );
- return FALSE;
- }
-
- nByteOffset = nBitToRetrieve / CHAR_BIT;
- nBitOffset = nBitToRetrieve % CHAR_BIT;
-
- byteMask = 1 << nBitOffset;
-
- if ( pInformation->pDirtyPages[ nByteOffset ] & byteMask )
- {
- return TRUE;
- }
- else
- {
- return FALSE;
- }
-}
-#endif // MMAP_DOESNOT_ALLOW_REMAP
-
/*********
*
* VIRTUALGetAllocationType
@@ -428,40 +386,6 @@ static BOOL VIRTUALSetAllocState( UINT nAction, SIZE_T nStartingBit,
nNumberOfBits, pInformation->pAllocState);
}
-#if MMAP_DOESNOT_ALLOW_REMAP
-/****
- *
- * VIRTUALSetDirtyPages
- *
- * IN UINT nStatus - 0: memory clean, any other value: memory is dirty
- * IN SIZE_T nStartingBit - The bit to set.
- *
- * IN SIZE_T nNumberOfBits - The range of bits to set.
- * IN PCMI pStateArray - A pointer the array to be manipulated.
- *
- * Returns TRUE on success, FALSE otherwise.
- * Turns bit(s) on/off bit to indicate dirty page(s)
- *
- */
-static BOOL VIRTUALSetDirtyPages( UINT nStatus, SIZE_T nStartingBit,
- SIZE_T nNumberOfBits, CONST PCMI pInformation )
-{
- TRACE( "VIRTUALSetDirtyPages( nStatus = %d, nStartingBit = %d, "
- "nNumberOfBits = %d, pStateArray = 0x%p )\n",
- nStatus, nStartingBit, nNumberOfBits, pInformation );
-
- if ( !pInformation )
- {
- ERROR( "pInformation was invalid!\n" );
- return FALSE;
- }
-
- return VIRTUALSetPageBits(nStatus, nStartingBit,
- nNumberOfBits, pInformation->pDirtyPages);
-}
-#endif // MMAP_DOESNOT_ALLOW_REMAP
-
-
/****
*
* VIRTUALFindRegionInformation( )
@@ -540,15 +464,10 @@ static BOOL VIRTUALReleaseMemory( PCMI pMemoryToBeReleased )
InternalFree( pMemoryToBeReleased->pAllocState );
pMemoryToBeReleased->pAllocState = NULL;
-
+
InternalFree( pMemoryToBeReleased->pProtectionState );
pMemoryToBeReleased->pProtectionState = NULL;
-#if MMAP_DOESNOT_ALLOW_REMAP
- InternalFree( pMemoryToBeReleased->pDirtyPages );
- pMemoryToBeReleased->pDirtyPages = NULL;
-#endif // MMAP_DOESNOT_ALLOW_REMAP
-
InternalFree( pMemoryToBeReleased );
pMemoryToBeReleased = NULL;
@@ -729,20 +648,10 @@ static BOOL VIRTUALStoreAllocationInfo(
pNewEntry->pAllocState = (BYTE*)InternalMalloc( nBufferSize );
pNewEntry->pProtectionState = (BYTE*)InternalMalloc( (memSize / VIRTUAL_PAGE_SIZE) );
-#if MMAP_DOESNOT_ALLOW_REMAP
- pNewEntry->pDirtyPages = (BYTE*)InternalMalloc( nBufferSize );
-#endif //
- if ( pNewEntry->pAllocState && pNewEntry->pProtectionState
-#if MMAP_DOESNOT_ALLOW_REMAP
- && pNewEntry->pDirtyPages
-#endif // MMAP_DOESNOT_ALLOW_REMAP
- )
+ if (pNewEntry->pAllocState && pNewEntry->pProtectionState)
{
/* Set the intial allocation state, and initial allocation protection. */
-#if MMAP_DOESNOT_ALLOW_REMAP
- memset (pNewEntry->pDirtyPages, 0, nBufferSize);
-#endif // MMAP_DOESNOT_ALLOW_REMAP
VIRTUALSetAllocState( MEM_RESERVE, 0, nBufferSize * CHAR_BIT, pNewEntry );
memset( pNewEntry->pProtectionState,
VIRTUALConvertWinFlags( flProtection ),
@@ -753,14 +662,9 @@ static BOOL VIRTUALStoreAllocationInfo(
ERROR( "Unable to allocate memory for the structure.\n");
bRetVal = FALSE;
-#if MMAP_DOESNOT_ALLOW_REMAP
- if (pNewEntry->pDirtyPages) InternalFree( pNewEntry->pDirtyPages );
- pNewEntry->pDirtyPages = NULL;
-#endif //
-
if (pNewEntry->pProtectionState) InternalFree( pNewEntry->pProtectionState );
pNewEntry->pProtectionState = NULL;
-
+
if (pNewEntry->pAllocState) InternalFree( pNewEntry->pAllocState );
pNewEntry->pAllocState = NULL;
@@ -889,75 +793,72 @@ static LPVOID ReserveVirtualMemory(
IN LPVOID lpAddress, /* Region to reserve or commit */
IN SIZE_T dwSize) /* Size of Region */
{
- LPVOID pRetVal = NULL;
UINT_PTR StartBoundary = (UINT_PTR)lpAddress;
SIZE_T MemSize = dwSize;
-#if HAVE_VM_ALLOCATE
- int result;
-#endif // HAVE_VM_ALLOCATE
- TRACE( "Reserving the memory now..\n");
+ TRACE( "Reserving the memory now.\n");
- // Most platforms will only commit the memory if it is dirtied,
+ // Most platforms will only commit memory if it is dirtied,
// so this should not consume too much swap space.
int mmapFlags = 0;
- int mmapFile = -1;
- off_t mmapOffset = 0;
#if HAVE_VM_ALLOCATE
// Allocate with vm_allocate first, then map at the fixed address.
- result = vm_allocate(mach_task_self(), &StartBoundary, MemSize,
- ((LPVOID) StartBoundary != NULL) ? FALSE : TRUE);
- if (result != KERN_SUCCESS) {
+ int result = vm_allocate(mach_task_self(),
+ &StartBoundary,
+ MemSize,
+ ((LPVOID) StartBoundary != nullptr) ? FALSE : TRUE);
+
+ if (result != KERN_SUCCESS)
+ {
ERROR("vm_allocate failed to allocated the requested region!\n");
pthrCurrent->SetLastError(ERROR_INVALID_ADDRESS);
- pRetVal = NULL;
- goto done;
+ return nullptr;
}
+
mmapFlags |= MAP_FIXED;
#endif // HAVE_VM_ALLOCATE
mmapFlags |= MAP_ANON | MAP_PRIVATE;
- pRetVal = mmap((LPVOID) StartBoundary, MemSize, PROT_NONE,
- mmapFlags, mmapFile, mmapOffset);
+ LPVOID pRetVal = mmap((LPVOID) StartBoundary,
+ MemSize,
+ PROT_NONE,
+ mmapFlags,
+ -1 /* fd */,
+ 0 /* offset */);
+
+ if (pRetVal == MAP_FAILED)
+ {
+ ERROR( "Failed due to insufficient memory.\n" );
+
+#if HAVE_VM_ALLOCATE
+ vm_deallocate(mach_task_self(), StartBoundary, MemSize);
+#endif // HAVE_VM_ALLOCATE
+
+ pthrCurrent->SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ return nullptr;
+ }
/* Check to see if the region is what we asked for. */
- if (pRetVal != MAP_FAILED && lpAddress != NULL &&
- StartBoundary != (UINT_PTR) pRetVal)
+ if (lpAddress != nullptr && StartBoundary != (UINT_PTR)pRetVal)
{
- ERROR("We did not get the region we asked for!\n");
+ ERROR("We did not get the region we asked for from mmap!\n");
pthrCurrent->SetLastError(ERROR_INVALID_ADDRESS);
munmap(pRetVal, MemSize);
- pRetVal = NULL;
- goto done;
+ return nullptr;
}
- if ( pRetVal != MAP_FAILED)
- {
#if MMAP_ANON_IGNORES_PROTECTION
- if (mprotect(pRetVal, MemSize, PROT_NONE) != 0)
- {
- ERROR("mprotect failed to protect the region!\n");
- pthrCurrent->SetLastError(ERROR_INVALID_ADDRESS);
- munmap(pRetVal, MemSize);
- pRetVal = NULL;
- goto done;
- }
-#endif // MMAP_ANON_IGNORES_PROTECTION
- }
- else
+ if (mprotect(pRetVal, MemSize, PROT_NONE) != 0)
{
- ERROR( "Failed due to insufficient memory.\n" );
-#if HAVE_VM_ALLOCATE
- vm_deallocate(mach_task_self(), StartBoundary, MemSize);
-#endif // HAVE_VM_ALLOCATE
- pthrCurrent->SetLastError( ERROR_NOT_ENOUGH_MEMORY );
- pRetVal = NULL;
- goto done;
+ ERROR("mprotect failed to protect the region!\n");
+ pthrCurrent->SetLastError(ERROR_INVALID_ADDRESS);
+ munmap(pRetVal, MemSize);
+ return nullptr;
}
+#endif // MMAP_ANON_IGNORES_PROTECTION
-done:
return pRetVal;
}
@@ -969,7 +870,8 @@ done:
* exists, and that would be very complicated to work around.
*
*/
-static LPVOID VIRTUALCommitMemory(
+static LPVOID
+VIRTUALCommitMemory(
IN CPalThread *pthrCurrent, /* Currently executing thread */
IN LPVOID lpAddress, /* Region to reserve or commit */
IN SIZE_T dwSize, /* Size of Region */
@@ -1092,37 +994,17 @@ static LPVOID VIRTUALCommitMemory(
StartBoundary = pInformation->startBoundary + runStart * VIRTUAL_PAGE_SIZE;
MemSize = runLength * VIRTUAL_PAGE_SIZE;
+
if (allocationType != MEM_COMMIT)
{
// Commit the pages
- if (mprotect((void *) StartBoundary, MemSize, PROT_WRITE | PROT_READ) == 0)
- {
-#if MMAP_DOESNOT_ALLOW_REMAP
- SIZE_T i;
- char *temp = (char *) StartBoundary;
- for(i = 0; i < runLength; i++)
- {
-
- if (VIRTUALIsPageDirty(runStart + i, pInformation))
- {
- // This page is being recommitted after being decommitted,
- // therefore the memory needs to be cleared
- memset (temp, 0, VIRTUAL_PAGE_SIZE);
- }
-
- temp += VIRTUAL_PAGE_SIZE;
- }
-#endif // MMAP_DOESNOT_ALLOW_REMAP
- }
- else
+ if (mprotect((void *) StartBoundary, MemSize, PROT_WRITE | PROT_READ) != 0)
{
ERROR("mprotect() failed! Error(%d)=%s\n", errno, strerror(errno));
goto error;
}
+
VIRTUALSetAllocState(MEM_COMMIT, runStart, runLength, pInformation);
-#if MMAP_DOESNOT_ALLOW_REMAP
- VIRTUALSetDirtyPages (0, runStart, runLength, pInformation);
-#endif // MMAP_DOESNOT_ALLOW_REMAP
if (nProtect == (PROT_WRITE | PROT_READ))
{
@@ -1131,8 +1013,10 @@ static LPVOID VIRTUALCommitMemory(
memset(pInformation->pProtectionState + runStart,
vProtect, runLength);
}
+
protectionState = VIRTUAL_READWRITE;
}
+
if (protectionState != vProtect)
{
// Change permissions.
@@ -1148,14 +1032,14 @@ static LPVOID VIRTUALCommitMemory(
goto error;
}
}
-
+
runStart = index;
runLength = 1;
allocationType = curAllocationType;
protectionState = curProtectionState;
}
- pRetVal = (void *) (pInformation->startBoundary +
- initialRunStart * VIRTUAL_PAGE_SIZE);
+
+ pRetVal = (void *) (pInformation->startBoundary + initialRunStart * VIRTUAL_PAGE_SIZE);
goto done;
error:
@@ -1174,7 +1058,6 @@ error:
}
done:
-
return pRetVal;
}
@@ -1359,19 +1242,13 @@ VirtualFree(
TRACE( "Un-committing the following page(s) %d to %d.\n",
StartBoundary, MemSize );
-#if MMAP_DOESNOT_ALLOW_REMAP
- // if no double mapping is supported,
- // just mprotect the memory with no access
- if (mprotect((LPVOID)StartBoundary, MemSize, PROT_NONE) == 0)
-#else // MMAP_DOESNOT_ALLOW_REMAP
// Explicitly calling mmap instead of mprotect here makes it
// that much more clear to the operating system that we no
// longer need these pages.
if ( mmap( (LPVOID)StartBoundary, MemSize, PROT_NONE,
MAP_FIXED | MAP_ANON | MAP_PRIVATE, -1, 0 ) != MAP_FAILED )
-#endif // MMAP_DOESNOT_ALLOW_REMAP
{
-#if (MMAP_ANON_IGNORES_PROTECTION && !MMAP_DOESNOT_ALLOW_REMAP)
+#if (MMAP_ANON_IGNORES_PROTECTION)
if (mprotect((LPVOID) StartBoundary, MemSize, PROT_NONE) != 0)
{
ASSERT("mprotect failed to protect the region!\n");
@@ -1380,7 +1257,7 @@ VirtualFree(
bRetVal = FALSE;
goto VirtualFreeExit;
}
-#endif // MMAP_ANON_IGNORES_PROTECTION && !MMAP_DOESNOT_ALLOW_REMAP
+#endif // MMAP_ANON_IGNORES_PROTECTION
SIZE_T index = 0;
SIZE_T nNumOfPagesToChange = 0;
@@ -1390,13 +1267,9 @@ VirtualFree(
nNumOfPagesToChange = MemSize / VIRTUAL_PAGE_SIZE;
VIRTUALSetAllocState( MEM_RESERVE, index,
- nNumOfPagesToChange, pUnCommittedMem );
-#if MMAP_DOESNOT_ALLOW_REMAP
- VIRTUALSetDirtyPages( 1, index,
- nNumOfPagesToChange, pUnCommittedMem );
-#endif // MMAP_DOESNOT_ALLOW_REMAP
+ nNumOfPagesToChange, pUnCommittedMem );
- goto VirtualFreeExit;
+ goto VirtualFreeExit;
}
else
{
@@ -1517,10 +1390,9 @@ VirtualProtect(
Index = OffSet = StartBoundary - pEntry->startBoundary == 0 ?
0 : ( StartBoundary - pEntry->startBoundary ) / VIRTUAL_PAGE_SIZE;
NumberOfPagesToChange = MemSize / VIRTUAL_PAGE_SIZE;
-
- TRACE( "Number of pages to check %d, starting page %d \n",
- NumberOfPagesToChange, Index );
-
+
+ TRACE( "Number of pages to check %d, starting page %d \n", NumberOfPagesToChange, Index );
+
for ( ; Index < NumberOfPagesToChange; Index++ )
{
if ( !VIRTUALIsPageCommitted( Index, pEntry ) )
diff --git a/src/pal/tests/palsuite/exception_handling/pal_sxs/test1/dlltest1.cpp b/src/pal/tests/palsuite/exception_handling/pal_sxs/test1/dlltest1.cpp
index 8aa7a0f0a5..614690897a 100644
--- a/src/pal/tests/palsuite/exception_handling/pal_sxs/test1/dlltest1.cpp
+++ b/src/pal/tests/palsuite/exception_handling/pal_sxs/test1/dlltest1.cpp
@@ -45,7 +45,7 @@ int DllTest1()
}
// Validate that the faulting address is correct; the contents of "p" (0x11).
- if (ex.ExceptionRecord.ExceptionInformation[1] != 0x11)
+ if (ex.GetExceptionRecord()->ExceptionInformation[1] != 0x11)
{
Fail("ERROR: PAL_EXCEPT ExceptionInformation[1] != 0x11\n");
}
diff --git a/src/pal/tests/palsuite/exception_handling/pal_sxs/test1/dlltest2.cpp b/src/pal/tests/palsuite/exception_handling/pal_sxs/test1/dlltest2.cpp
index fe5c8e01d4..1e85821422 100644
--- a/src/pal/tests/palsuite/exception_handling/pal_sxs/test1/dlltest2.cpp
+++ b/src/pal/tests/palsuite/exception_handling/pal_sxs/test1/dlltest2.cpp
@@ -45,7 +45,7 @@ int DllTest2()
}
// Validate that the faulting address is correct; the contents of "p" (0x22).
- if (ex.ExceptionRecord.ExceptionInformation[1] != 0x22)
+ if (ex.GetExceptionRecord()->ExceptionInformation[1] != 0x22)
{
Fail("ERROR: PAL_EXCEPT ExceptionInformation[1] != 0x22\n");
}
diff --git a/src/sign.builds b/src/sign.builds
index aae3dc4d69..a8652b3ff4 100644
--- a/src/sign.builds
+++ b/src/sign.builds
@@ -15,10 +15,6 @@
<OutDir>$(BinDir)</OutDir>
</PropertyGroup>
- <PropertyGroup>
- <SkipFileSigning Condition="'$(SkipFileSigning)' == '' and '$(BuildArch)' == 'arm64'">true</SkipFileSigning>
- </PropertyGroup>
-
<UsingTask AssemblyFile="$(BuildToolsTaskDir)Microsoft.DotNet.Build.Tasks.dll" TaskName="ReadSigningRequired" />
<!-- apply the default signing certificates (defined in sign.targets) -->
@@ -30,7 +26,7 @@
</ItemDefinitionGroup>
<!-- gather the list of binaries to sign with the default certificates -->
- <ItemGroup Condition="'$(SkipFileSigning)' != 'true'">
+ <ItemGroup>
<FilesToSign Include="$(BinDir)*.dll" Exclude="$(BinDir)*.ni.dll" />
<FilesToSign Include="$(BinDir)*.exe" />
</ItemGroup>
@@ -39,14 +35,14 @@
for some reason the signing task incorrectly attemps to strong-name sign
native images which causes the signing step to fail for obvious reasons.
-->
- <ItemGroup Condition="'$(SkipFileSigning)' != 'true'">
+ <ItemGroup>
<FilesToSign Include="$(BinDir)*.ni.dll">
<StrongName>None</StrongName>
</FilesToSign>
</ItemGroup>
<!-- populates item group FilesToSign with the list of files to sign -->
- <Target Name="GetFilesToSignItems" BeforeTargets="SignFiles" Condition="'$(SkipFileSigning)' != 'true'">
+ <Target Name="GetFilesToSignItems" BeforeTargets="SignFiles">
<!-- read all of the marker files and populate the FilesToSign item group -->
<ItemGroup>
<SignMarkerFile Include="$(OutDir)**\*.requires_signing" />
@@ -57,9 +53,9 @@
</Target>
<!-- now that signing is done clean up any marker files -->
- <Target Name="CleanUpMarkerFiles" AfterTargets="SignFiles" Condition="'$(SkipFileSigning)' != 'true'">
+ <Target Name="CleanUpMarkerFiles" AfterTargets="SignFiles">
<!-- now that the files have been signed delete the marker files -->
<Delete Files="@(SignMarkerFile)" />
</Target>
-</Project>
+</Project> \ No newline at end of file
diff --git a/src/vm/CMakeLists.txt b/src/vm/CMakeLists.txt
index b24a1509e6..89a6437da1 100644
--- a/src/vm/CMakeLists.txt
+++ b/src/vm/CMakeLists.txt
@@ -151,7 +151,6 @@ set(VM_SOURCES_WKS
coverage.cpp
customattribute.cpp
custommarshalerinfo.cpp
- dbggcinfodecoder.cpp
dllimportcallback.cpp
eeconfig.cpp
eecontract.cpp
@@ -430,7 +429,6 @@ endif(CLR_CMAKE_PLATFORM_UNIX)
set(VM_SOURCES_DAC_ARCH
gcinfodecoder.cpp
- dbggcinfodecoder.cpp
exceptionhandling.cpp
)
diff --git a/src/vm/assemblyspec.cpp b/src/vm/assemblyspec.cpp
index b3707d70c1..5baf588cb2 100644
--- a/src/vm/assemblyspec.cpp
+++ b/src/vm/assemblyspec.cpp
@@ -1850,29 +1850,6 @@ AssemblySpecBindingCache::AssemblyBinding* AssemblySpecBindingCache::GetAssembly
}
pEntry = (AssemblyBinding *) m_map.LookupValue(lookupKey, pSpec);
- if (pEntry == (AssemblyBinding *) INVALIDENTRY)
- {
- // We didnt find the AssemblyBinding entry against the binder of the parent assembly.
- // It is possible that the AssemblySpec corresponds to a TPA assembly, so try the lookup
- // against the TPABinder context.
- ICLRPrivBinder* pTPABinderContext = pSpecDomain->GetTPABinderContext();
- if ((pTPABinderContext != NULL) && !AreSameBinderInstance(pTPABinderContext, pBinderContextForLookup))
- {
- UINT_PTR tpaBinderID = 0;
- HRESULT hr = pTPABinderContext->GetBinderID(&tpaBinderID);
- _ASSERTE(SUCCEEDED(hr));
- lookupKey = key^tpaBinderID;
-
- // Set the binding context in AssemblySpec to be TPABinder
- // as that will be used in the Lookup operation below.
- if (fGetBindingContextFromParent)
- {
- pSpec->SetBindingContext(pTPABinderContext);
- }
-
- pEntry = (AssemblyBinding *) m_map.LookupValue(lookupKey, pSpec);
- }
- }
// Reset the binding context if one was originally never present in the AssemblySpec and we didnt find any entry
// in the cache.
diff --git a/src/vm/codeman.cpp b/src/vm/codeman.cpp
index 7eea254646..8e1800d24f 100644
--- a/src/vm/codeman.cpp
+++ b/src/vm/codeman.cpp
@@ -858,39 +858,34 @@ BOOL IsFunctionFragment(TADDR baseAddress, PTR_RUNTIME_FUNCTION pFunctionEntry)
// 1. Prolog only: The host record. Epilog Count and E bit are all 0.
// 2. Prolog and some epilogs: The host record with acompannying epilog-only records
// 3. Epilogs only: First unwind code is Phantom prolog (Starting with an end_c, indicating an empty prolog)
- // 4. No prologs or epilogs: Epilog Count = 1 and Epilog Start Index points end_c. (as if it's case #2 with empty epilog codes)
+ // 4. No prologs or epilogs: First unwind code is Phantom prolog (Starting with an end_c, indicating an empty prolog)
//
int EpilogCount = (int)(unwindHeader >> 22) & 0x1F;
int CodeWords = unwindHeader >> 27;
PTR_DWORD pUnwindCodes = (PTR_DWORD)(baseAddress + pFunctionEntry->UnwindData);
+ // Skip header.
+ pUnwindCodes++;
+
+ // Skip extended header.
if ((CodeWords == 0) && (EpilogCount == 0))
- pUnwindCodes++;
- BOOL Ebit = (unwindHeader >> 21) & 0x1;
- if (Ebit)
{
- // EpilogCount is the index of the first unwind code that describes the one and only epilog
- // The unwind codes immediatelly follow the unwindHeader
+ EpilogCount = (*pUnwindCodes) & 0xFFFF;
pUnwindCodes++;
}
- else if (EpilogCount != 0)
+
+ // Skip epilog scopes.
+ BOOL Ebit = (unwindHeader >> 21) & 0x1;
+ if (!Ebit && (EpilogCount != 0))
{
// EpilogCount is the number of exception scopes defined right after the unwindHeader
- pUnwindCodes += EpilogCount+1;
- }
- else
- {
- return FALSE;
+ pUnwindCodes += EpilogCount;
}
- if ((*pUnwindCodes & 0xFF) == 0xE5) // Phantom prolog
- return TRUE;
-
-
+ return ((*pUnwindCodes & 0xFF) == 0xE5);
#else
PORTABILITY_ASSERT("IsFunctionFragnent - NYI on this platform");
#endif
- return FALSE;
}
#endif // EXCEPTION_DATA_SUPPORTS_FUNCTION_FRAGMENTS
@@ -3015,7 +3010,7 @@ void * EEJitManager::allocCodeFragmentBlock(size_t blockSize, unsigned alignment
#endif // !DACCESS_COMPILE
-PTR_VOID EEJitManager::GetGCInfo(const METHODTOKEN& MethodToken)
+GCInfoToken EEJitManager::GetGCInfoToken(const METHODTOKEN& MethodToken)
{
CONTRACTL {
NOTHROW;
@@ -3024,7 +3019,8 @@ PTR_VOID EEJitManager::GetGCInfo(const METHODTOKEN& MethodToken)
SUPPORTS_DAC;
} CONTRACTL_END;
- return GetCodeHeader(MethodToken)->GetGCInfo();
+ // The JIT-ed code always has the current version of GCInfo
+ return{ GetCodeHeader(MethodToken)->GetGCInfo(), GCINFO_VERSION };
}
// creates an enumeration and returns the number of EH clauses
@@ -5035,7 +5031,7 @@ NativeImageJitManager::NativeImageJitManager()
#endif // #ifndef DACCESS_COMPILE
-PTR_VOID NativeImageJitManager::GetGCInfo(const METHODTOKEN& MethodToken)
+GCInfoToken NativeImageJitManager::GetGCInfoToken(const METHODTOKEN& MethodToken)
{
CONTRACTL {
NOTHROW;
@@ -5060,7 +5056,8 @@ PTR_VOID NativeImageJitManager::GetGCInfo(const METHODTOKEN& MethodToken)
PTR_VOID pUnwindData = GetUnwindDataBlob(baseAddress, pRuntimeFunction, &nUnwindDataSize);
// GCInfo immediatelly follows unwind data
- return dac_cast<PTR_BYTE>(pUnwindData) + nUnwindDataSize;
+ // GCInfo from an NGEN-ed image is always the current version
+ return{ dac_cast<PTR_BYTE>(pUnwindData) + nUnwindDataSize, GCINFO_VERSION };
}
unsigned NativeImageJitManager::InitializeEHEnumeration(const METHODTOKEN& MethodToken, EH_CLAUSE_ENUMERATOR* pEnumState)
@@ -5681,7 +5678,7 @@ void NativeImageJitManager::JitTokenToMethodRegionInfo(const METHODTOKEN& Method
//
methodRegionInfo->hotStartAddress = JitTokenToStartAddress(MethodToken);
- methodRegionInfo->hotSize = GetCodeManager()->GetFunctionSize(GetGCInfo(MethodToken));
+ methodRegionInfo->hotSize = GetCodeManager()->GetFunctionSize(GetGCInfoToken(MethodToken));
methodRegionInfo->coldStartAddress = 0;
methodRegionInfo->coldSize = 0;
@@ -6274,14 +6271,17 @@ PTR_MethodDesc MethodIterator::GetMethodDesc()
return NativeUnwindInfoLookupTable::GetMethodDesc(m_pNgenLayout, GetRuntimeFunction(), m_ModuleBase);
}
-PTR_VOID MethodIterator::GetGCInfo()
+GCInfoToken MethodIterator::GetGCInfoToken()
{
LIMITED_METHOD_CONTRACT;
// get the gc info from the RT function
SIZE_T size;
PTR_VOID pUnwindData = GetUnwindDataBlob(m_ModuleBase, GetRuntimeFunction(), &size);
- return (PTR_VOID)((PTR_BYTE)pUnwindData + size);
+ PTR_VOID gcInfo = (PTR_VOID)((PTR_BYTE)pUnwindData + size);
+ // MethodIterator is used to iterate over methods of an NgenImage.
+ // So, GcInfo version is always current
+ return{ gcInfo, GCINFO_VERSION };
}
TADDR MethodIterator::GetMethodStartAddress()
@@ -6359,8 +6359,8 @@ void MethodIterator::GetMethodRegionInfo(IJitManager::MethodRegionInfo *methodRe
methodRegionInfo->hotStartAddress = GetMethodStartAddress();
methodRegionInfo->coldStartAddress = GetMethodColdStartAddress();
-
- methodRegionInfo->hotSize = ExecutionManager::GetNativeImageJitManager()->GetCodeManager()->GetFunctionSize(GetGCInfo());
+ GCInfoToken gcInfoToken = GetGCInfoToken();
+ methodRegionInfo->hotSize = ExecutionManager::GetNativeImageJitManager()->GetCodeManager()->GetFunctionSize(gcInfoToken);
methodRegionInfo->coldSize = 0;
if (methodRegionInfo->coldStartAddress != NULL)
@@ -6408,6 +6408,24 @@ ReadyToRunInfo * ReadyToRunJitManager::JitTokenToReadyToRunInfo(const METHODTOKE
return dac_cast<PTR_Module>(MethodToken.m_pRangeSection->pHeapListOrZapModule)->GetReadyToRunInfo();
}
+UINT32 ReadyToRunJitManager::JitTokenToGCInfoVersion(const METHODTOKEN& MethodToken)
+{
+ CONTRACTL{
+ NOTHROW;
+ GC_NOTRIGGER;
+ HOST_NOCALLS;
+ SUPPORTS_DAC;
+ } CONTRACTL_END;
+
+ READYTORUN_HEADER * header = JitTokenToReadyToRunInfo(MethodToken)->GetImage()->GetReadyToRunHeader();
+ UINT32 gcInfoVersion = header->MajorVersion;
+
+ // Currently there's only one version of GCInfo.
+ _ASSERTE(gcInfoVersion == GCINFO_VERSION);
+
+ return gcInfoVersion;
+}
+
PTR_RUNTIME_FUNCTION ReadyToRunJitManager::JitTokenToRuntimeFunction(const METHODTOKEN& MethodToken)
{
CONTRACTL {
@@ -6433,7 +6451,7 @@ TADDR ReadyToRunJitManager::JitTokenToStartAddress(const METHODTOKEN& MethodToke
RUNTIME_FUNCTION__BeginAddress(dac_cast<PTR_RUNTIME_FUNCTION>(MethodToken.m_pCodeHeader));
}
-PTR_VOID ReadyToRunJitManager::GetGCInfo(const METHODTOKEN& MethodToken)
+GCInfoToken ReadyToRunJitManager::GetGCInfoToken(const METHODTOKEN& MethodToken)
{
CONTRACTL {
NOTHROW;
@@ -6458,7 +6476,10 @@ PTR_VOID ReadyToRunJitManager::GetGCInfo(const METHODTOKEN& MethodToken)
PTR_VOID pUnwindData = GetUnwindDataBlob(baseAddress, pRuntimeFunction, &nUnwindDataSize);
// GCInfo immediatelly follows unwind data
- return dac_cast<PTR_BYTE>(pUnwindData) + nUnwindDataSize;
+ PTR_BYTE gcInfo = dac_cast<PTR_BYTE>(pUnwindData) + nUnwindDataSize;
+ UINT32 gcInfoVersion = JitTokenToGCInfoVersion(MethodToken);
+
+ return{ gcInfo, gcInfoVersion };
}
unsigned ReadyToRunJitManager::InitializeEHEnumeration(const METHODTOKEN& MethodToken, EH_CLAUSE_ENUMERATOR* pEnumState)
@@ -6863,7 +6884,7 @@ void ReadyToRunJitManager::JitTokenToMethodRegionInfo(const METHODTOKEN& MethodT
// READYTORUN: FUTURE: Hot-cold spliting
methodRegionInfo->hotStartAddress = JitTokenToStartAddress(MethodToken);
- methodRegionInfo->hotSize = GetCodeManager()->GetFunctionSize(GetGCInfo(MethodToken));
+ methodRegionInfo->hotSize = GetCodeManager()->GetFunctionSize(GetGCInfoToken(MethodToken));
methodRegionInfo->coldStartAddress = 0;
methodRegionInfo->coldSize = 0;
}
diff --git a/src/vm/codeman.h b/src/vm/codeman.h
index 855c15125a..f143dd642c 100644
--- a/src/vm/codeman.h
+++ b/src/vm/codeman.h
@@ -24,9 +24,10 @@ Abstract:
An IJitManager knows about which method bodies live in each RangeSection.
It can handle methods of one given CodeType. It can map a method body to
a MethodDesc. It knows where the GCInfo about the method lives.
- Today, we have 2 IJitManagers viz.
+ Today, we have three IJitManagers viz.
1. EEJitManager for JITcompiled code generated by clrjit.dll
2. NativeImageJitManager for ngenned code.
+ 3. ReadyToRunJitManager for version resiliant ReadyToRun code
An ICodeManager knows how to crack a specific format of GCInfo. There is
a default format (handled by ExecutionManager::GetDefaultCodeManager())
@@ -66,6 +67,7 @@ Abstract:
#include "debuginfostore.h"
#include "shash.h"
#include "pedecoder.h"
+#include "gcinfo.h"
class MethodDesc;
class ICorJitCompiler;
@@ -113,6 +115,7 @@ enum StubCodeBlockKind : int
// Method header which exists just before the code.
// Every IJitManager could have its own format for the header.
// Today CodeHeader is used by the EEJitManager.
+// The GCInfo version is always current GCINFO_VERSION in this header.
#ifdef USE_INDIRECT_CODEHEADER
typedef DPTR(struct _hpRealCodeHdr) PTR_RealCodeHeader;
@@ -735,7 +738,11 @@ public:
CrawlFrame *pCf)=0;
#endif // #ifndef DACCESS_COMPILE
- virtual PTR_VOID GetGCInfo(const METHODTOKEN& MethodToken)=0;
+ virtual GCInfoToken GetGCInfoToken(const METHODTOKEN& MethodToken)=0;
+ PTR_VOID GetGCInfo(const METHODTOKEN& MethodToken)
+ {
+ return GetGCInfoToken(MethodToken).Info;
+ }
TADDR JitTokenToModuleBase(const METHODTOKEN& MethodToken);
@@ -965,7 +972,7 @@ public:
virtual TypeHandle ResolveEHClause(EE_ILEXCEPTION_CLAUSE* pEHClause,
CrawlFrame *pCf);
#endif // !DACCESS_COMPILE
- PTR_VOID GetGCInfo(const METHODTOKEN& MethodToken);
+ GCInfoToken GetGCInfoToken(const METHODTOKEN& MethodToken);
#endif // !CROSSGEN_COMPILE
#if !defined DACCESS_COMPILE && !defined CROSSGEN_COMPILE
void RemoveJitData(CodeHeader * pCHdr, size_t GCinfo_len, size_t EHinfo_len);
@@ -1486,7 +1493,7 @@ inline void EEJitManager::JitTokenToMethodRegionInfo(const METHODTOKEN& MethodTo
} CONTRACTL_END;
methodRegionInfo->hotStartAddress = JitTokenToStartAddress(MethodToken);
- methodRegionInfo->hotSize = GetCodeManager()->GetFunctionSize(GetGCInfo(MethodToken));
+ methodRegionInfo->hotSize = GetCodeManager()->GetFunctionSize(GetGCInfoToken(MethodToken));
methodRegionInfo->coldStartAddress = 0;
methodRegionInfo->coldSize = 0;
}
@@ -1543,7 +1550,7 @@ public:
CrawlFrame *pCf);
#endif // #ifndef DACCESS_COMPILE
- virtual PTR_VOID GetGCInfo(const METHODTOKEN& MethodToken);
+ virtual GCInfoToken GetGCInfoToken(const METHODTOKEN& MethodToken);
#if defined(WIN64EXCEPTIONS)
virtual PTR_RUNTIME_FUNCTION LazyGetFunctionEntry(EECodeInfo * pCodeInfo);
@@ -1638,6 +1645,8 @@ public:
virtual PCODE GetCodeAddressForRelOffset(const METHODTOKEN& MethodToken, DWORD relOffset);
static ReadyToRunInfo * JitTokenToReadyToRunInfo(const METHODTOKEN& MethodToken);
+ static UINT32 JitTokenToGCInfoVersion(const METHODTOKEN& MethodToken);
+
static PTR_RUNTIME_FUNCTION JitTokenToRuntimeFunction(const METHODTOKEN& MethodToken);
virtual TADDR JitTokenToStartAddress(const METHODTOKEN& MethodToken);
@@ -1653,7 +1662,7 @@ public:
CrawlFrame *pCf);
#endif // #ifndef DACCESS_COMPILE
- virtual PTR_VOID GetGCInfo(const METHODTOKEN& MethodToken);
+ virtual GCInfoToken GetGCInfoToken(const METHODTOKEN& MethodToken);
#if defined(WIN64EXCEPTIONS)
virtual PTR_RUNTIME_FUNCTION LazyGetFunctionEntry(EECodeInfo * pCodeInfo);
@@ -1754,10 +1763,16 @@ public:
return m_relOffset;
}
- PTR_VOID GetGCInfo()
+ GCInfoToken GetGCInfoToken()
{
WRAPPER_NO_CONTRACT;
- return GetJitManager()->GetGCInfo(GetMethodToken());
+ return GetJitManager()->GetGCInfoToken(GetMethodToken());
+ }
+
+ PTR_VOID GetGCInfo()
+ {
+ WRAPPER_NO_CONTRACT;
+ return GetGCInfoToken().Info;
}
void GetMethodRegionInfo(IJitManager::MethodRegionInfo *methodRegionInfo)
@@ -1824,7 +1839,7 @@ class MethodSectionIterator;
//
// MethodIterator class is used to iterate all the methods in an ngen image.
// It will match and report hot (and cold, if any) sections of a method at the same time.
-//
+// GcInfo version is always current
class MethodIterator
{
public:
@@ -1852,7 +1867,7 @@ private:
BOOL Next();
PTR_MethodDesc GetMethodDesc();
- PTR_VOID GetGCInfo();
+ GCInfoToken GetGCInfoToken();
TADDR GetMethodStartAddress();
TADDR GetMethodColdStartAddress();
ULONG GetHotCodeSize();
diff --git a/src/vm/coreassemblyspec.cpp b/src/vm/coreassemblyspec.cpp
index caa9f17365..310c663392 100644
--- a/src/vm/coreassemblyspec.cpp
+++ b/src/vm/coreassemblyspec.cpp
@@ -183,9 +183,16 @@ VOID AssemblySpec::Bind(AppDomain *pAppDomain,
&pPrivAsm);
}
+ bool fBoundUsingTPABinder = false;
if(SUCCEEDED(hr))
{
_ASSERTE(pPrivAsm != nullptr);
+
+ if (AreSameBinderInstance(pTPABinder, reinterpret_cast<ICLRPrivBinder *>(pPrivAsm.Extract())))
+ {
+ fBoundUsingTPABinder = true;
+ }
+
result = BINDER_SPACE::GetAssemblyFromPrivAssemblyFast(pPrivAsm.Extract());
_ASSERTE(result != nullptr);
}
@@ -193,13 +200,20 @@ VOID AssemblySpec::Bind(AppDomain *pAppDomain,
pResult->SetHRBindResult(hr);
if (SUCCEEDED(hr))
{
- BOOL fIsInGAC = pAppDomain->IsImageFromTrustedPath(result->GetNativeOrILPEImage());
+ BOOL fIsInGAC = FALSE;
BOOL fIsOnTpaList = FALSE;
- const SString &sImagePath = result->GetNativeOrILPEImage()->GetPath();
- if (pTPABinder->IsInTpaList(sImagePath))
+
+ // Only initialize TPA/GAC status if we bound using DefaultContext
+ if (fBoundUsingTPABinder == true)
{
- fIsOnTpaList = TRUE;
+ fIsInGAC = pAppDomain->IsImageFromTrustedPath(result->GetNativeOrILPEImage());
+ const SString &sImagePath = result->GetNativeOrILPEImage()->GetPath();
+ if (pTPABinder->IsInTpaList(sImagePath))
+ {
+ fIsOnTpaList = TRUE;
+ }
}
+
pResult->Init(result,fIsInGAC, fIsOnTpaList);
}
else if (FAILED(hr) && (fThrowOnFileNotFound || (!Assembly::FileNotFound(hr))))
diff --git a/src/vm/crossgen/CMakeLists.txt b/src/vm/crossgen/CMakeLists.txt
index 3a20675ef1..c2392a2d9a 100644
--- a/src/vm/crossgen/CMakeLists.txt
+++ b/src/vm/crossgen/CMakeLists.txt
@@ -92,7 +92,6 @@ set(VM_CROSSGEN_SOURCES
../vars.cpp
../versionresilienthashcode.cpp
../zapsig.cpp
- ../dbggcinfodecoder.cpp
../gcinfodecoder.cpp
../sha1.cpp
../crossgencompile.cpp
diff --git a/src/vm/crossgen/wks_crossgen.nativeproj b/src/vm/crossgen/wks_crossgen.nativeproj
index 31404a3d66..803a3cb705 100644
--- a/src/vm/crossgen/wks_crossgen.nativeproj
+++ b/src/vm/crossgen/wks_crossgen.nativeproj
@@ -130,7 +130,6 @@
<!-- SOURCES_NONPAL -->
<ItemGroup>
- <CppCompile Include="$(VmSourcesDir)\DbgGcInfoDecoder.cpp" />
<CppCompile Include="$(VmSourcesDir)\GcInfoDecoder.cpp" />
<CppCompile Include="$(VmSourcesDir)\Crypto\SHA1.cpp" Condition="'$(FeatureCoreclr)' != 'true'"/>
<CppCompile Include="$(VmSourcesDir)\SHA1.cpp" Condition="'$(FeatureCoreclr)' == 'true'"/>
diff --git a/src/vm/dac/dacwks.targets b/src/vm/dac/dacwks.targets
index 121b14ec90..82ab5439d5 100644
--- a/src/vm/dac/dacwks.targets
+++ b/src/vm/dac/dacwks.targets
@@ -127,7 +127,6 @@
<ItemGroup Condition="'$(TargetArch)' == 'amd64'" >
<CppCompile Include="$(ClrSrcDirectory)\vm\GcInfoDecoder.cpp" />
- <CppCompile Include="$(ClrSrcDirectory)\vm\DbgGcInfoDecoder.cpp" />
<CppCompile Include="$(ClrSrcDirectory)\vm\amd64\cGenAMD64.cpp" />
<CppCompile Include="$(ClrSrcDirectory)\vm\amd64\ExcepAMD64.cpp" />
<CppCompile Include="$(ClrSrcDirectory)\vm\amd64\gmsAMD64.cpp" />
diff --git a/src/vm/dbggcinfodecoder.cpp b/src/vm/dbggcinfodecoder.cpp
deleted file mode 100644
index c921256ef9..0000000000
--- a/src/vm/dbggcinfodecoder.cpp
+++ /dev/null
@@ -1,932 +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.
-
-
-
-
-#include "common.h"
-#include "gcinfodecoder.h"
-
-#ifdef VERIFY_GCINFO
-#ifdef USE_GC_INFO_DECODER
-
-#include "dbggcinfodecoder.h"
-
-#ifndef GCINFODECODER_CONTRACT
-#define GCINFODECODER_CONTRACT(contract) contract
-#endif // !GCINFODECODER_CONTRACT
-
-#ifndef GET_CALLER_SP
-#define GET_CALLER_SP(pREGDISPLAY) EECodeManager::GetCallerSp(pREGDISPLAY)
-#endif // !GET_CALLER_SP
-
-#ifndef VALIDATE_OBJECTREF
-#ifdef DACCESS_COMPILE
-#define VALIDATE_OBJECTREF(objref, fDeep)
-#else // DACCESS_COMPILE
-#define VALIDATE_OBJECTREF(objref, fDeep) OBJECTREFToObject(objref)->Validate(fDeep)
-#endif // DACCESS_COMPILE
-#endif // !VALIDATE_OBJECTREF
-
-#ifndef VALIDATE_ROOT
-#define VALIDATE_ROOT(isInterior, hCallBack, pObjRef) \
- do { \
- /* Only call Object::Validate() with bDeep == TRUE if we are in the promote phase. */ \
- /* We should call Validate() with bDeep == FALSE if we are in the relocation phase. */ \
- \
- GCCONTEXT* pGCCtx = (GCCONTEXT*)(hCallBack); \
- \
- if (!(isInterior) && !(m_Flags & DECODE_NO_VALIDATION)) \
- VALIDATE_OBJECTREF(*(pObjRef), pGCCtx->sc->promotion == TRUE); \
- } while (0)
-#endif // !VALIDATE_ROOT
-
-
-
-namespace DbgGcInfo {
-
-
-//static
-bool GcInfoDecoder::SetIsInterruptibleCB (UINT32 startOffset, UINT32 stopOffset, LPVOID hCallback)
-{
- GcInfoDecoder *pThis = (GcInfoDecoder*)hCallback;
-
- bool fStop = pThis->m_InstructionOffset >= startOffset && pThis->m_InstructionOffset < stopOffset;
-
- if (fStop)
- pThis->m_IsInterruptible = true;
-
- return fStop;
-}
-
-
-GcInfoDecoder::GcInfoDecoder(
- const BYTE* gcInfoAddr,
- GcInfoDecoderFlags flags,
- UINT32 breakOffset
- )
- : m_Reader( gcInfoAddr )
- , m_InstructionOffset( breakOffset )
- , m_IsInterruptible( false )
- , m_pLiveRegisters( NULL )
- , m_pLiveStackSlots( NULL )
- , m_NumLiveRegisters(0)
- , m_NumLiveStackSlots(0)
-#ifdef _DEBUG
- , m_Flags( flags )
-#endif
-{
-#ifdef _TARGET_ARM_
- _ASSERTE(!"JIT32 is not generating GCInfo in the correct format yet!");
-#endif
-
- _ASSERTE( (flags & (DECODE_INTERRUPTIBILITY | DECODE_GC_LIFETIMES)) || (0 == breakOffset) );
-
- // The current implementation doesn't support the two flags together
- _ASSERTE(
- ((flags & (DECODE_INTERRUPTIBILITY | DECODE_GC_LIFETIMES)) != (DECODE_INTERRUPTIBILITY | DECODE_GC_LIFETIMES))
- );
-
-
- //--------------------------------------------
- // Pre-decode information
- //--------------------------------------------
-
- m_IsVarArg = (m_Reader.Read(1)) ? true : false;
-
- size_t hasSecurityObject = m_Reader.Read(1);
- if(hasSecurityObject)
- m_SecurityObjectStackSlot = (INT32) DENORMALIZE_STACK_SLOT(m_Reader.DecodeVarLengthSigned(SECURITY_OBJECT_STACK_SLOT_ENCBASE));
- else
- m_SecurityObjectStackSlot = NO_SECURITY_OBJECT;
-
- size_t hasPSPSym = m_Reader.Read(1);
- if(hasPSPSym)
- {
- m_PSPSymStackSlot = (INT32) DENORMALIZE_STACK_SLOT(m_Reader.DecodeVarLengthSigned(PSP_SYM_STACK_SLOT_ENCBASE));
- }
- else
- {
- m_PSPSymStackSlot = NO_PSP_SYM;
- }
-
- size_t hasGenericsInstContext = m_Reader.Read(1);
- if(hasGenericsInstContext)
- {
- m_GenericsInstContextStackSlot = (INT32) DENORMALIZE_STACK_SLOT(m_Reader.DecodeVarLengthSigned(GENERICS_INST_CONTEXT_STACK_SLOT_ENCBASE));
- }
- else
- {
- m_GenericsInstContextStackSlot = NO_GENERICS_INST_CONTEXT;
- }
-
- m_CodeLength = (UINT32) DENORMALIZE_CODE_LENGTH(m_Reader.DecodeVarLengthUnsigned(CODE_LENGTH_ENCBASE));
-
- size_t hasStackBaseRegister = m_Reader.Read(1);
- if(hasStackBaseRegister)
- m_StackBaseRegister = (UINT32) DENORMALIZE_STACK_BASE_REGISTER(m_Reader.DecodeVarLengthUnsigned(STACK_BASE_REGISTER_ENCBASE));
- else
- m_StackBaseRegister = NO_STACK_BASE_REGISTER;
-
- size_t hasSizeOfEditAndContinuePreservedArea = m_Reader.Read(1);
- if(hasSizeOfEditAndContinuePreservedArea)
- m_SizeOfEditAndContinuePreservedArea = (UINT32) m_Reader.DecodeVarLengthUnsigned(SIZE_OF_EDIT_AND_CONTINUE_PRESERVED_AREA_ENCBASE);
- else
- m_SizeOfEditAndContinuePreservedArea = NO_SIZE_OF_EDIT_AND_CONTINUE_PRESERVED_AREA;
-
-#ifdef FIXED_STACK_PARAMETER_SCRATCH_AREA
- m_SizeOfStackOutgoingAndScratchArea = (UINT32)DENORMALIZE_SIZE_OF_STACK_AREA(m_Reader.DecodeVarLengthUnsigned(SIZE_OF_STACK_AREA_ENCBASE));
-#endif // FIXED_STACK_PARAMETER_SCRATCH_AREA
-
- m_NumInterruptibleRanges = (UINT32) DENORMALIZE_NUM_INTERRUPTIBLE_RANGES(m_Reader.DecodeVarLengthUnsigned(NUM_INTERRUPTIBLE_RANGES_ENCBASE));
-
- if( flags & DECODE_INTERRUPTIBILITY )
- {
- EnumerateInterruptibleRanges(&SetIsInterruptibleCB, this);
- }
-}
-
-
-bool GcInfoDecoder::IsInterruptible()
-{
- _ASSERTE( m_Flags & DECODE_INTERRUPTIBILITY );
- return m_IsInterruptible;
-}
-
-
-void GcInfoDecoder::EnumerateInterruptibleRanges (
- EnumerateInterruptibleRangesCallback *pCallback,
- LPVOID hCallback)
-{
-#if 0
-#ifdef PARTIALLY_INTERRUPTIBLE_GC_SUPPORTED
-
- //------------------------------------------------------------------------------
- // Try partially interruptible first
- //------------------------------------------------------------------------------
-
- UINT32 numCallSites = (UINT32)m_Reader.Read( sizeof( numCallSites ) * 8 );
- UINT32 callSiteIdx = 0;
-
- if( numCallSites > 0 )
- {
- UINT32 numSlotMappings = (UINT32)m_Reader.Read( sizeof( numSlotMappings ) * 8 );
-
- // Align the reader to the next byte to continue decoding
- m_Reader.Skip( ( 8 - ( m_Reader.GetCurrentPos() % 8 ) ) % 8 );
-
- for( callSiteIdx=0; callSiteIdx<numCallSites; callSiteIdx++ )
- {
- UINT32 instructionOffset = (UINT32)m_Reader.Read( 32 );
-
- bool fStop = pCallback(instructionOffset, instructionOffset+1, hCallback);
- if (fStop)
- return;
-
- m_Reader.Skip( numSlotMappings );
- }
-
- // Call site not found. Skip the slot mapping table in preparation for reading the fully-interruptible information
- m_Reader.Skip( numSlotMappings * sizeof( GcSlotDesc ) * 8 );
- }
-
-#endif // PARTIALLY_INTERRUPTIBLE_GC_SUPPORTED
-#endif
-
-
- // If no info is found for the call site, we default to fully-interruptbile
- LOG((LF_GCROOTS, LL_INFO1000000, "No GC info found for call site at offset %x. Defaulting to fully-interruptible information.\n", (int) m_InstructionOffset));
-
- // Align the reader to the next byte to continue decoding
- m_Reader.Skip( ( 8 - ( m_Reader.GetCurrentPos() % 8 ) ) % 8 );
-
- UINT32 lastInterruptibleRangeStopOffsetNormalized = 0;
-
- for(UINT32 i=0; i<m_NumInterruptibleRanges; i++)
- {
- UINT32 normStartDelta = (UINT32) m_Reader.DecodeVarLengthUnsigned( INTERRUPTIBLE_RANGE_DELTA_ENCBASE );
- UINT32 normStopDelta = (UINT32) m_Reader.DecodeVarLengthUnsigned( INTERRUPTIBLE_RANGE_DELTA_ENCBASE ) + 1;
-
- UINT32 rangeStartOffsetNormalized = lastInterruptibleRangeStopOffsetNormalized + normStartDelta;
- UINT32 rangeStopOffsetNormalized = rangeStartOffsetNormalized + normStopDelta;
-
- UINT32 rangeStartOffset = DENORMALIZE_CODE_OFFSET(rangeStartOffsetNormalized);
- UINT32 rangeStopOffset = DENORMALIZE_CODE_OFFSET(rangeStopOffsetNormalized);
-
- bool fStop = pCallback(rangeStartOffset, rangeStopOffset, hCallback);
- if (fStop)
- return;
-
- lastInterruptibleRangeStopOffsetNormalized = rangeStopOffsetNormalized;
- }
-}
-
-
-INT32 GcInfoDecoder::GetSecurityObjectStackSlot()
-{
- _ASSERTE( m_Flags & DECODE_SECURITY_OBJECT );
- return m_SecurityObjectStackSlot;
-}
-
-INT32 GcInfoDecoder::GetGenericsInstContextStackSlot()
-{
- _ASSERTE( m_Flags & DECODE_GENERICS_INST_CONTEXT );
- return m_GenericsInstContextStackSlot;
-}
-
-INT32 GcInfoDecoder::GetPSPSymStackSlot()
-{
- _ASSERTE( m_Flags & DECODE_PSP_SYM);
- return m_PSPSymStackSlot;
-}
-
-bool GcInfoDecoder::GetIsVarArg()
-{
- _ASSERTE( m_Flags & DECODE_VARARG );
- return m_IsVarArg;
-}
-
-UINT32 GcInfoDecoder::GetCodeLength()
-{
- _ASSERTE( m_Flags & DECODE_CODE_LENGTH );
- return m_CodeLength;
-}
-
-UINT32 GcInfoDecoder::GetStackBaseRegister()
-{
- return m_StackBaseRegister;
-}
-
-UINT32 GcInfoDecoder::GetSizeOfEditAndContinuePreservedArea()
-{
- _ASSERTE( m_Flags & DECODE_EDIT_AND_CONTINUE );
- return m_SizeOfEditAndContinuePreservedArea;
-}
-
-
-#ifdef FIXED_STACK_PARAMETER_SCRATCH_AREA
-
-UINT32 GcInfoDecoder::GetSizeOfStackParameterArea()
-{
- return m_SizeOfStackOutgoingAndScratchArea;
-}
-
-#endif // FIXED_STACK_PARAMETER_SCRATCH_AREA
-
-
-bool GcInfoDecoder::EnumerateLiveSlots(
- PREGDISPLAY pRD,
- bool reportScratchSlots,
- unsigned flags,
- GCEnumCallback pCallBack,
- LPVOID hCallBack
- )
-{
- _ASSERTE( m_Flags & DECODE_GC_LIFETIMES );
-
-#if 0
-#ifdef PARTIALLY_INTERRUPTIBLE_GC_SUPPORTED
-
- //------------------------------------------------------------------------------
- // Try partially interruptible first
- //------------------------------------------------------------------------------
-
- UINT32 numCallSites = (UINT32)m_Reader.Read( sizeof( numCallSites ) * 8 );
- UINT32 callSiteIdx = 0;
-
- if( numCallSites > 0 )
- {
- UINT32 numSlotMappings = (UINT32)m_Reader.Read( sizeof( numSlotMappings ) * 8 );
-
- // Align the reader to the next byte to continue decoding
- m_Reader.Skip( ( 8 - ( m_Reader.GetCurrentPos() % 8 ) ) % 8 );
-
- for( callSiteIdx=0; callSiteIdx<numCallSites; callSiteIdx++ )
- {
- UINT32 instructionOffset = (UINT32)m_Reader.Read( 32 );
- if( instructionOffset == m_InstructionOffset )
- {
- m_IsInterruptible = true;
-
- BYTE* callSiteLiveSet = (BYTE*) _alloca( ( numSlotMappings + 7 ) / 8 );
-
- UINT32 i;
- for( i=0; i<numSlotMappings/8; i++ )
- callSiteLiveSet[ i ] = (BYTE)m_Reader.Read( 8 );
-
- callSiteLiveSet[ i ] = (BYTE)m_Reader.Read( numSlotMappings % 8 );
-
- m_Reader.Skip( ( numCallSites - callSiteIdx - 1 ) * ( 32 + numSlotMappings ) );
-
- //---------------------------------------------------------------------------
- // Read slot mappings
- //---------------------------------------------------------------------------
-
- GcSlotDesc* slotMappings = (GcSlotDesc*) _alloca( numSlotMappings * sizeof( GcSlotDesc ) );
- // Assert that we can read a GcSlotDesc with a single call to m_Reader.Read()
- _ASSERTE( sizeof( GcSlotDesc ) <= sizeof ( size_t ) );
- for( UINT32 i=0; i<numSlotMappings; i++ )
- {
- size_t data = m_Reader.Read( sizeof( GcSlotDesc ) * 8 );
- slotMappings[ i ] = *( (GcSlotDesc*) &data );
- }
-
- //---------------------------------------------------------------------------
- // Report live slots
- //---------------------------------------------------------------------------
-
- for( UINT32 i=0; i<numSlotMappings; i++ )
- {
- BYTE isLive = callSiteLiveSet[ i / 8 ] & ( 1 << ( i % 8 ) );
- if( isLive )
- {
- GcSlotDesc slotDesc = slotMappings[ i ];
- if( slotDesc.IsRegister )
- {
- if( reportScratchSlots || !IsScratchRegister( slotDesc.Slot.RegisterNumber, pRD ) )
- {
- ReportRegisterToGC(
- slotDesc.Slot.RegisterNumber,
- slotDesc.IsInterior,
- slotDesc.IsPinned,
- pRD,
- flags,
- pCallBack,
- hCallBack
- );
- }
- else
- {
- LOG((LF_GCROOTS, LL_INFO1000, "\"Live\" scratch register " FMT_REG " not reported\n", slotDesc.Slot.RegisterNumber));
- }
- }
- else
- {
- GcStackSlotBase spBase = (GcStackSlotBase) (slotDesc.Slot.SpOffset & 0x3);
- INT32 realSpOffset = slotDesc.Slot.SpOffset ^ (int) spBase;
-
- if( reportScratchSlots || !IsScratchStackSlot(realSpOffset, spBase, pRD) )
- {
- ReportStackSlotToGC(
- realSpOffset,
- spBase,
- slotDesc.IsInterior,
- slotDesc.IsPinned,
- pRD,
- flags,
- pCallBack,
- hCallBack
- );
- }
- else
- {
- LOG((LF_GCROOTS, LL_INFO1000, "\"Live\" scratch stack slot " FMT_STK " not reported\n", DBG_STK(realSpOffset)));
- }
- }
- }
- }
-
- return true;
- }
-
- m_Reader.Skip( numSlotMappings );
- }
-
- // Call site not found. Skip the slot mapping table in preparation for reading the fully-interruptible information
- m_Reader.Skip( numSlotMappings * sizeof( GcSlotDesc ) * 8 );
- }
-
-#endif // PARTIALLY_INTERRUPTIBLE_GC_SUPPORTED
-#endif
-
-
- // If no info is found for the call site, we default to fully-interruptbile
- LOG((LF_GCROOTS, LL_INFO1000000, "No GC info found for call site at offset %x. Defaulting to fully-interruptible information.\n", (int) m_InstructionOffset));
-
- // Align the reader to the next byte to continue decoding
- m_Reader.Skip( ( 8 - ( m_Reader.GetCurrentPos() % 8 ) ) % 8 );
-
- // Skip interruptibility information
- for(UINT32 i=0; i<m_NumInterruptibleRanges; i++)
- {
- m_Reader.DecodeVarLengthUnsigned( INTERRUPTIBLE_RANGE_DELTA_ENCBASE );
- m_Reader.DecodeVarLengthUnsigned( INTERRUPTIBLE_RANGE_DELTA_ENCBASE );
- }
-
- //
- // If this is a non-leaf frame and we are executing a call, the unwinder has given us the PC
- // of the call instruction. We should adjust it to the PC of the instruction after the call in order to
- // obtain transition information for scratch slots. However, we always assume scratch slots to be
- // dead for non-leaf frames (except for ResumableFrames), so we don't need to adjust the PC.
- // If this is a non-leaf frame and we are not executing a call (i.e.: a fault occurred in the function),
- // then it would be incorrect to ajust the PC
- //
-
- int lifetimeTransitionsCount = 0;
-
- //--------------------------------------------------------------------
- // Decode registers
- //--------------------------------------------------------------------
-
- size_t numRegisters = m_Reader.DecodeVarLengthUnsigned(NUM_REGISTERS_ENCBASE);
-
- {
-#ifdef ENABLE_CONTRACTS_IMPL
- CONTRACT_VIOLATION(FaultViolation | FaultNotFatal);
-#endif
- m_pLiveRegisters = (GcSlotDesc*) qbSlots1.AllocNoThrow(sizeof(GcSlotDesc)*numRegisters);
- }
- if (m_pLiveRegisters == NULL)
- {
- return false;
- }
-
-
- _ASSERTE(m_pLiveRegisters);
-
- int lastNormRegNum = 0;
-
- for(int i=0; i<numRegisters; i++)
- {
- if( i==0 )
- {
- lastNormRegNum = (int) m_Reader.DecodeVarLengthUnsigned(REGISTER_ENCBASE);
- }
- else
- {
- int normRegDelta = (int) m_Reader.DecodeVarLengthUnsigned(REGISTER_DELTA_ENCBASE) + 1;
- lastNormRegNum += normRegDelta;
- }
- int regNum = DENORMALIZE_REGISTER(lastNormRegNum);
-
- BOOL isInterior = FALSE;
- BOOL isPinned = FALSE;
- BOOL isLive = FALSE;
-
- size_t normCodeOffset = (size_t)(SSIZE_T)(-1);
- BOOL becomesLive = TRUE;
- for(;;)
- {
- size_t normCodeOffsetDelta = m_Reader.DecodeVarLengthUnsigned(NORM_CODE_OFFSET_DELTA_ENCBASE);
- if(normCodeOffsetDelta == 0) // terminator
- break;
-
- if(normCodeOffset != (size_t)(SSIZE_T)(-1))
- becomesLive = (BOOL) m_Reader.Read(1);
-
- normCodeOffset += normCodeOffsetDelta;
-
- UINT32 instructionOffset = DENORMALIZE_CODE_OFFSET((UINT32)normCodeOffset);
-
- BOOL becomesInterior = FALSE;
- BOOL becomesPinned = FALSE;
-
- if(becomesLive)
- {
- if(m_Reader.Read(1))
- {
- size_t flagEnc = m_Reader.Read( 2 );
- becomesInterior = (BOOL)(flagEnc & 0x1);
- becomesPinned = (BOOL)(flagEnc & 0x2);
- }
- }
-
- lifetimeTransitionsCount++;
-
- LOG((LF_GCROOTS, LL_INFO1000000,
- "Transition " FMT_PIPTR "in " FMT_REG "going %s at offset %04x.\n",
- DBG_PIN_NAME(becomesPinned), DBG_IPTR_NAME(becomesInterior), regNum,
- becomesLive ? "live" : "dead",
- (int) instructionOffset ));
-
- if( instructionOffset > m_InstructionOffset )
- continue;
-
- isLive = becomesLive;
- isInterior = becomesInterior;
- isPinned = becomesPinned;
- }
-
- if( isLive )
- {
- if( reportScratchSlots || !IsScratchRegister( regNum, pRD ) )
- {
- m_pLiveRegisters[m_NumLiveRegisters].Slot.RegisterNumber = regNum;
- GcSlotFlags flags = GC_SLOT_BASE;
- if(isInterior)
- flags = (GcSlotFlags) (flags | GC_SLOT_INTERIOR);
- if(isPinned)
- flags = (GcSlotFlags) (flags | GC_SLOT_PINNED);
-
- m_pLiveRegisters[m_NumLiveRegisters].Flags = flags;
- m_NumLiveRegisters++;
- }
- else
- {
- LOG((LF_GCROOTS, LL_INFO1000, "\"Live\" scratch register " FMT_REG " not reported\n", regNum));
- }
- }
- }
-
- //--------------------------------------------------------------------
- // Decode stack slots
- //--------------------------------------------------------------------
-
- size_t numStackSlots = m_Reader.DecodeVarLengthUnsigned(NUM_STACK_SLOTS_ENCBASE);
- {
-#ifdef ENABLE_CONTRACTS_IMPL
- CONTRACT_VIOLATION(FaultViolation | FaultNotFatal);
-#endif
- m_pLiveStackSlots = (GcSlotDesc*) qbSlots2.AllocNoThrow(sizeof(GcSlotDesc)*numStackSlots);
- }
- if (m_pLiveStackSlots == NULL)
- {
- return false;
- }
- _ASSERTE(m_pLiveStackSlots);
-
- INT32 lastNormStackSlot = 0;
-
- for(int i=0; i<numStackSlots; i++)
- {
- if( i==0 )
- {
- lastNormStackSlot = (INT32) m_Reader.DecodeVarLengthSigned(STACK_SLOT_ENCBASE);
- }
- else
- {
- INT32 normStackSlotDelta = (INT32) m_Reader.DecodeVarLengthUnsigned(STACK_SLOT_DELTA_ENCBASE);
- lastNormStackSlot += normStackSlotDelta;
- }
- INT32 spOffset = DENORMALIZE_STACK_SLOT(lastNormStackSlot);
- GcStackSlotBase spBase = (GcStackSlotBase) m_Reader.Read(2);
-
- BOOL isInterior = FALSE;
- BOOL isPinned = FALSE;
- BOOL isLive = FALSE;
-
- size_t normCodeOffset = (size_t)(SSIZE_T)(-1);
- BOOL becomesLive = TRUE;
- for(;;)
- {
- size_t normCodeOffsetDelta = m_Reader.DecodeVarLengthUnsigned(NORM_CODE_OFFSET_DELTA_ENCBASE);
- if(normCodeOffsetDelta == 0) // terminator
- break;
-
- if(normCodeOffset != (size_t)(SSIZE_T)(-1))
- becomesLive = (BOOL) m_Reader.Read(1);
-
- normCodeOffset += normCodeOffsetDelta;
-
- UINT32 instructionOffset = DENORMALIZE_CODE_OFFSET((UINT32)normCodeOffset);
-
- BOOL becomesInterior = FALSE;
- BOOL becomesPinned = FALSE;
-
- if(becomesLive)
- {
- if(m_Reader.Read(1))
- {
- size_t flagEnc = m_Reader.Read( 2 );
- becomesInterior = (BOOL)(flagEnc & 0x1);
- becomesPinned = (BOOL)(flagEnc & 0x2);
- }
- }
-
- lifetimeTransitionsCount++;
-
- LOG((LF_GCROOTS, LL_INFO1000000,
- "Transition " FMT_PIPTR "in " FMT_STK "going %s at offset %04x.\n",
- DBG_PIN_NAME(becomesPinned), DBG_IPTR_NAME(becomesInterior), DBG_STK(spOffset),
- becomesLive ? "live" : "dead",
- (int) instructionOffset ));
-
- if( instructionOffset > m_InstructionOffset )
- continue;
-
- isLive = becomesLive;
- isInterior = becomesInterior;
- isPinned = becomesPinned;
- }
-
- if( isLive )
- {
- if( reportScratchSlots || !IsScratchStackSlot(spOffset, spBase, pRD) )
- {
- m_pLiveStackSlots[m_NumLiveStackSlots].Slot.Stack.SpOffset = spOffset;
- m_pLiveStackSlots[m_NumLiveStackSlots].Slot.Stack.Base = spBase;
- GcSlotFlags flags = GC_SLOT_BASE;
- if(isInterior)
- flags = (GcSlotFlags) (flags | GC_SLOT_INTERIOR);
- if(isPinned)
- flags = (GcSlotFlags) (flags | GC_SLOT_PINNED);
-
- m_pLiveStackSlots[m_NumLiveStackSlots].Flags = flags;
- m_NumLiveStackSlots++;
- }
- else
- {
- LOG((LF_GCROOTS, LL_INFO1000, "\"Live\" scratch stack slot " FMT_STK " not reported\n", DBG_STK(spOffset)));
- }
- }
- }
-
-
- LOG((LF_GCROOTS, LL_INFO1000000, "Decoded %d lifetime transitions.\n", (int) lifetimeTransitionsCount ));
-
- return true;
-}
-
-void GcInfoDecoder::VerifyLiveRegister(
- UINT32 regNum,
- GcSlotFlags flags
- )
-{
- _ASSERTE(m_pLiveRegisters);
-
- // If this assert fails, the slot being passed was not found to be live in this decoder
- _ASSERTE(m_NumLiveRegisters > 0);
-
- int pos;
- for(pos = 0; pos < m_NumLiveRegisters; pos++)
- {
- if(regNum == m_pLiveRegisters[pos].Slot.RegisterNumber &&
- flags == m_pLiveRegisters[pos].Flags)
- {
- break;
- }
- }
-
- // If this assert fails, the slot being passed was not found to be live in this decoder
- _ASSERTE(pos < m_NumLiveRegisters);
-
- m_pLiveRegisters[pos] = m_pLiveRegisters[--m_NumLiveRegisters];
-}
-
-void GcInfoDecoder::VerifyLiveStackSlot(
- INT32 spOffset,
- GcStackSlotBase spBase,
- GcSlotFlags flags
- )
-{
- _ASSERTE(m_pLiveStackSlots);
-
- // If this assert fails, the slot being passed was not found to be live in this decoder
- _ASSERTE(m_NumLiveStackSlots > 0);
-
- int pos;
- for(pos = 0; pos < m_NumLiveStackSlots; pos++)
- {
- if(spOffset == m_pLiveStackSlots[pos].Slot.Stack.SpOffset &&
- spBase == m_pLiveStackSlots[pos].Slot.Stack.Base &&
- flags == m_pLiveStackSlots[pos].Flags)
- {
- break;
- }
- }
-
- // If this assert fails, the slot being passed was not found to be live in this decoder
- _ASSERTE(pos < m_NumLiveStackSlots);
-
- m_pLiveStackSlots[pos] = m_pLiveStackSlots[--m_NumLiveStackSlots];
-}
-
-void GcInfoDecoder::DoFinalVerification()
-{
- // If this assert fails, the m_NumLiveRegisters slots remaining in m_pLiveRegisters
- // were not reported by the calling decoder
- _ASSERTE(m_NumLiveRegisters == 0);
-
- // If this assert fails, the m_NumLiveStackSlots slots remaining in m_pLiveStackSlots
- // were not reported by the calling decoder
- _ASSERTE(m_NumLiveStackSlots == 0);
-
-}
-
-//-----------------------------------------------------------------------------
-// Platform-specific methods
-//-----------------------------------------------------------------------------
-
-#if defined(_TARGET_AMD64_)
-
-
-OBJECTREF* GcInfoDecoder::GetRegisterSlot(
- int regNum,
- PREGDISPLAY pRD
- )
-{
- _ASSERTE(regNum >= 0 && regNum <= 16);
- _ASSERTE(regNum != 4); // rsp
-
- // The fields of KNONVOLATILE_CONTEXT_POINTERS are in the same order as
- // the processor encoding numbers.
-
- ULONGLONG **ppRax;
-#ifdef _NTAMD64_
- ppRax = &pRD->pCurrentContextPointers->Rax;
-#else
- ppRax = &pRD->pCurrentContextPointers->Integer.Register.Rax;
-#endif
-
- return (OBJECTREF*)*(ppRax + regNum);
-}
-
-
-bool GcInfoDecoder::IsScratchRegister(int regNum, PREGDISPLAY pRD)
-{
- _ASSERTE(regNum >= 0 && regNum <= 16);
- _ASSERTE(regNum != 4); // rsp
-
- UINT16 PreservedRegMask =
- (1 << 3) // rbx
- | (1 << 5) // rbp
- | (1 << 6) // rsi
- | (1 << 7) // rdi
- | (1 << 12) // r12
- | (1 << 13) // r13
- | (1 << 14) // r14
- | (1 << 15); // r15
-
- return !(PreservedRegMask & (1 << regNum));
-}
-
-
-bool GcInfoDecoder::IsScratchStackSlot(INT32 spOffset, GcStackSlotBase spBase, PREGDISPLAY pRD)
-{
-#ifdef FIXED_STACK_PARAMETER_SCRATCH_AREA
- _ASSERTE( m_Flags & DECODE_GC_LIFETIMES );
-
- ULONGLONG pSlot = (ULONGLONG) GetStackSlot(spOffset, spBase, pRD);
- _ASSERTE(pSlot >= pRD->SP);
-
- return (pSlot < pRD->SP + m_SizeOfStackOutgoingAndScratchArea);
-#else
- return FALSE;
-#endif
-}
-
-
-void GcInfoDecoder::ReportRegisterToGC( // AMD64
- int regNum,
- BOOL isInterior,
- BOOL isPinned,
- PREGDISPLAY pRD,
- unsigned flags,
- GCEnumCallback pCallBack,
- LPVOID hCallBack)
-{
- GCINFODECODER_CONTRACT(CONTRACTL {
- NOTHROW;
- GC_NOTRIGGER;
- } CONTRACTL_END);
-
- _ASSERTE(regNum >= 0 && regNum <= 16);
- _ASSERTE(regNum != 4); // rsp
-
- LOG((LF_GCROOTS, LL_INFO1000, "Reporting " FMT_REG, regNum ));
-
- OBJECTREF* pObjRef = GetRegisterSlot( regNum, pRD );
-
-#ifdef _DEBUG
- if(IsScratchRegister(regNum, pRD))
- {
- // Scratch registers cannot be reported for non-leaf frames
- _ASSERTE(flags & ActiveStackFrame);
- }
-
- LOG((LF_GCROOTS, LL_INFO1000, /* Part Two */
- "at" FMT_ADDR "as ", DBG_ADDR(pObjRef) ));
-
- VALIDATE_ROOT(isInterior, hCallBack, pObjRef);
-
- LOG((LF_GCROOTS, LL_INFO1000, /* Part Three */
- LOG_PIPTR_OBJECT_CLASS(OBJECTREF_TO_UNCHECKED_OBJECTREF(*pObjRef), isPinned, isInterior)));
-#endif //_DEBUG
-
- DWORD gcFlags = CHECK_APP_DOMAIN;
-
- if (isInterior)
- gcFlags |= GC_CALL_INTERIOR;
-
- if (isPinned)
- gcFlags |= GC_CALL_PINNED;
-
- pCallBack(hCallBack, pObjRef, gcFlags);
-}
-
-#else // Unknown platform
-
-OBJECTREF* GcInfoDecoder::GetRegisterSlot(
- int regNum,
- PREGDISPLAY pRD
- )
-{
- PORTABILITY_ASSERT("GcInfoDecoder::GetRegisterSlot");
- return NULL;
-}
-
-bool GcInfoDecoder::IsScratchRegister(int regNum, PREGDISPLAY pRD)
-{
- PORTABILITY_ASSERT("GcInfoDecoder::IsScratchRegister");
- return false;
-}
-
-bool GcInfoDecoder::IsScratchStackSlot(INT32 spOffset, GcStackSlotBase spBase, PREGDISPLAY pRD)
-{
- _ASSERTE( !"NYI" );
- return false;
-}
-
-void GcInfoDecoder::ReportRegisterToGC(
- int regNum,
- BOOL isInterior,
- BOOL isPinned,
- PREGDISPLAY pRD,
- unsigned flags,
- GCEnumCallback pCallBack,
- LPVOID hCallBack)
-{
- _ASSERTE( !"NYI" );
-}
-
-#endif // Unknown platform
-
-
-OBJECTREF* GcInfoDecoder::GetStackSlot(
- INT32 spOffset,
- GcStackSlotBase spBase,
- PREGDISPLAY pRD
- )
-{
- OBJECTREF* pObjRef;
-
- if( GC_SP_REL == spBase )
- {
- pObjRef = (OBJECTREF*) ((SIZE_T)GetRegdisplaySP(pRD) + spOffset);
- }
- else if( GC_CALLER_SP_REL == spBase )
- {
- pObjRef = (OBJECTREF*) (GET_CALLER_SP(pRD) + spOffset);
- }
- else
- {
- _ASSERTE( GC_FRAMEREG_REL == spBase );
- _ASSERTE( NO_STACK_BASE_REGISTER != m_StackBaseRegister );
-
- pObjRef = (OBJECTREF*)((*((INT64*)(GetRegisterSlot( m_StackBaseRegister, pRD )))) + spOffset);
- }
-
- return pObjRef;
-}
-
-void GcInfoDecoder::ReportStackSlotToGC(
- INT32 spOffset,
- GcStackSlotBase spBase,
- BOOL isInterior,
- BOOL isPinned,
- PREGDISPLAY pRD,
- unsigned flags,
- GCEnumCallback pCallBack,
- LPVOID hCallBack)
-{
- GCINFODECODER_CONTRACT(CONTRACTL {
- NOTHROW;
- GC_NOTRIGGER;
- } CONTRACTL_END);
-
- OBJECTREF* pObjRef = GetStackSlot(spOffset, spBase, pRD);
- _ASSERTE( IS_ALIGNED( pObjRef, sizeof( Object* ) ) );
-
-#ifdef _DEBUG
- LOG((LF_GCROOTS, LL_INFO1000, /* Part One */
- "Reporting %s" FMT_STK,
- ( (GC_SP_REL == spBase) ? "" :
- ((GC_CALLER_SP_REL == spBase) ? "caller's " :
- ((GC_FRAMEREG_REL == spBase) ? "frame " : "<unrecognized GcStackSlotBase> "))),
- DBG_STK(spOffset) ));
-
- LOG((LF_GCROOTS, LL_INFO1000, /* Part Two */
- "at" FMT_ADDR "as ", DBG_ADDR(pObjRef) ));
-
- VALIDATE_ROOT(isInterior, hCallBack, pObjRef);
-
- LOG((LF_GCROOTS, LL_INFO1000, /* Part Three */
- LOG_PIPTR_OBJECT_CLASS(OBJECTREF_TO_UNCHECKED_OBJECTREF(*pObjRef), isPinned, isInterior)));
-#endif
-
- DWORD gcFlags = CHECK_APP_DOMAIN;
-
- if (isInterior)
- gcFlags |= GC_CALL_INTERIOR;
-
- if (isPinned)
- gcFlags |= GC_CALL_PINNED;
-
- pCallBack(hCallBack, pObjRef, gcFlags);
-}
-
-}
-
-#endif // USE_GC_INFO_DECODER
-#endif // VERIFY_GCINFO
diff --git a/src/vm/debughelp.cpp b/src/vm/debughelp.cpp
index 7e4455a7ff..df769455aa 100644
--- a/src/vm/debughelp.cpp
+++ b/src/vm/debughelp.cpp
@@ -1198,24 +1198,24 @@ void DumpGCInfo(MethodDesc* method)
_ASSERTE(codeInfo.GetRelOffset() == 0);
ICodeManager* codeMan = codeInfo.GetCodeManager();
- BYTE* table = (BYTE*) codeInfo.GetGCInfo();
+ GCInfoToken table = codeInfo.GetGCInfoToken();
unsigned methodSize = (unsigned)codeMan->GetFunctionSize(table);
- GCDump gcDump;
+ GCDump gcDump(table.Version);
+ PTR_CBYTE gcInfo = PTR_CBYTE(table.Info);
gcDump.gcPrintf = printfToDbgOut;
InfoHdr header;
printfToDbgOut ("Method info block:\n");
-
- table += gcDump.DumpInfoHdr(table, &header, &methodSize, 0);
+ gcInfo += gcDump.DumpInfoHdr(gcInfo, &header, &methodSize, 0);
printfToDbgOut ("\n");
printfToDbgOut ("Pointer table:\n");
- table += gcDump.DumpGCTable(table, header, methodSize, 0);
+ gcInfo += gcDump.DumpGCTable(gcInfo, header, methodSize, 0);
}
void DumpGCInfoMD(size_t method)
diff --git a/src/vm/ecalllist.h b/src/vm/ecalllist.h
index 8675ddd44c..2228c05e73 100644
--- a/src/vm/ecalllist.h
+++ b/src/vm/ecalllist.h
@@ -218,9 +218,7 @@ FCFuncStart(gStringFuncs)
FCDynamicSig(COR_CTOR_METHOD_NAME, &gsig_IM_Char_Int_RetVoid, CORINFO_INTRINSIC_Illegal, ECall::CtorCharCountManaged)
FCFuncElementSig(COR_CTOR_METHOD_NAME, &gsig_IM_PtrSByt_RetVoid, COMString::StringInitCharPtr)
FCFuncElementSig(COR_CTOR_METHOD_NAME, &gsig_IM_PtrSByt_Int_Int_RetVoid, COMString::StringInitCharPtrPartial)
-#ifndef FEATURE_CORECLR
FCFuncElementSig(COR_CTOR_METHOD_NAME, &gsig_IM_PtrSByt_Int_Int_Encoding_RetVoid, COMString::StringInitSBytPtrPartialEx)
-#endif // FEATURE_CORECLR
FCFuncElement("IsFastSort", COMString::IsFastSort)
FCFuncElement("nativeCompareOrdinalIgnoreCaseWC", COMString::FCCompareOrdinalIgnoreCaseWC)
FCIntrinsic("get_Length", COMString::Length, CORINFO_INTRINSIC_StringLength)
@@ -340,8 +338,8 @@ FCFuncEnd()
FCFuncStart(gExceptionFuncs)
FCFuncElement("IsImmutableAgileException", ExceptionNative::IsImmutableAgileException)
FCFuncElement("nIsTransient", ExceptionNative::IsTransient)
-#ifndef FEATURE_CORECLR
FCFuncElement("GetMethodFromStackTrace", SystemNative::GetMethodFromStackTrace)
+#ifndef FEATURE_CORECLR
FCFuncElement("StripFileInfo", ExceptionNative::StripFileInfo)
#endif
QCFuncElement("GetMessageFromNativeResources", ExceptionNative::GetMessageFromNativeResources)
@@ -1519,9 +1517,7 @@ FCFuncStart(gArrayFuncs)
FCFuncElement("GetUpperBound", ArrayNative::GetUpperBound)
FCIntrinsicSig("GetLength", &gsig_IM_Int_RetInt, ArrayNative::GetLength, CORINFO_INTRINSIC_Array_GetDimLength)
FCFuncElement("get_Length", ArrayNative::GetLengthNoRank)
-#ifndef FEATURE_CORECLR
FCFuncElement("get_LongLength", ArrayNative::GetLongLengthNoRank)
-#endif
FCFuncElement("GetDataPtrOffsetInternal", ArrayNative::GetDataPtrOffsetInternal)
FCFuncElement("Initialize", ArrayNative::Initialize)
FCFuncElement("Copy", ArrayNative::ArrayCopy)
@@ -1550,8 +1546,8 @@ FCFuncStart(gBufferFuncs)
FCFuncEnd()
FCFuncStart(gGCInterfaceFuncs)
-#ifndef FEATURE_CORECLR
FCFuncElement("GetGenerationWR", GCInterface::GetGenerationWR)
+#ifndef FEATURE_CORECLR
FCFuncElement("_RegisterForFullGCNotification", GCInterface::RegisterForFullGCNotification)
FCFuncElement("_CancelFullGCNotification", GCInterface::CancelFullGCNotification)
FCFuncElement("_WaitForFullGCApproach", GCInterface::WaitForFullGCApproach)
diff --git a/src/vm/eedbginterfaceimpl.cpp b/src/vm/eedbginterfaceimpl.cpp
index 53cb288319..93decc9b0d 100644
--- a/src/vm/eedbginterfaceimpl.cpp
+++ b/src/vm/eedbginterfaceimpl.cpp
@@ -665,10 +665,8 @@ size_t EEDbgInterfaceImpl::GetFunctionSize(MethodDesc *pFD)
return 0;
EECodeInfo codeInfo(methodStart);
-
- PTR_VOID methodInfo = codeInfo.GetGCInfo();
-
- return codeInfo.GetCodeManager()->GetFunctionSize(methodInfo);
+ GCInfoToken gcInfoToken = codeInfo.GetGCInfoToken();
+ return codeInfo.GetCodeManager()->GetFunctionSize(gcInfoToken);
}
#endif //!DACCESS_COMPILE
diff --git a/src/vm/eetwain.cpp b/src/vm/eetwain.cpp
index 69eb177542..82b76f69e0 100644
--- a/src/vm/eetwain.cpp
+++ b/src/vm/eetwain.cpp
@@ -11,8 +11,6 @@
#define RETURN_ADDR_OFFS 1 // in DWORDS
-#include "gcinfo.h"
-
#ifdef USE_GC_INFO_DECODER
#include "gcinfodecoder.h"
#endif
@@ -942,14 +940,14 @@ HRESULT EECodeManager::FixContextForEnC(PCONTEXT pCtx,
// GCInfo for old method
GcInfoDecoder oldGcDecoder(
- dac_cast<PTR_CBYTE>(pOldCodeInfo->GetGCInfo()),
+ pOldCodeInfo->GetGCInfoToken(),
GcInfoDecoderFlags(DECODE_SECURITY_OBJECT | DECODE_PSP_SYM | DECODE_EDIT_AND_CONTINUE),
0 // Instruction offset (not needed)
);
// GCInfo for new method
GcInfoDecoder newGcDecoder(
- dac_cast<PTR_CBYTE>(pNewCodeInfo->GetGCInfo()),
+ pNewCodeInfo->GetGCInfoToken(),
GcInfoDecoderFlags(DECODE_SECURITY_OBJECT | DECODE_PSP_SYM | DECODE_EDIT_AND_CONTINUE),
0 // Instruction offset (not needed)
);
@@ -1437,8 +1435,10 @@ bool EECodeManager::IsGcSafe( EECodeInfo *pCodeInfo,
GC_NOTRIGGER;
} CONTRACTL_END;
+ GCInfoToken gcInfoToken = pCodeInfo->GetGCInfoToken();
+
GcInfoDecoder gcInfoDecoder(
- dac_cast<PTR_CBYTE>(pCodeInfo->GetGCInfo()),
+ gcInfoToken,
DECODE_INTERRUPTIBILITY,
dwRelOffset
);
@@ -1502,13 +1502,11 @@ bool FindEndOfLastInterruptibleRegionCB (
*/
unsigned EECodeManager::FindEndOfLastInterruptibleRegion(unsigned curOffset,
unsigned endOffset,
- PTR_VOID methodInfoPtr)
+ GCInfoToken gcInfoToken)
{
#ifndef DACCESS_COMPILE
- BYTE* gcInfoAddr = (BYTE*) methodInfoPtr;
-
GcInfoDecoder gcInfoDecoder(
- gcInfoAddr,
+ gcInfoToken,
DECODE_FOR_RANGES_CALLBACK,
0);
@@ -4758,7 +4756,7 @@ bool EECodeManager::EnumGcRefs( PREGDISPLAY pRD,
methodName, curOffs));
#endif
- PTR_BYTE gcInfoAddr = dac_cast<PTR_BYTE>(pCodeInfo->GetGCInfo());
+ GCInfoToken gcInfoToken = pCodeInfo->GetGCInfoToken();
#if defined(STRESS_HEAP) && defined(PARTIALLY_INTERRUPTIBLE_GC_SUPPORTED)
#ifdef USE_GC_INFO_DECODER
@@ -4770,7 +4768,7 @@ bool EECodeManager::EnumGcRefs( PREGDISPLAY pRD,
if (flags & ActiveStackFrame)
{
GcInfoDecoder _gcInfoDecoder(
- gcInfoAddr,
+ gcInfoToken,
DECODE_INTERRUPTIBILITY,
curOffs
);
@@ -4778,7 +4776,7 @@ bool EECodeManager::EnumGcRefs( PREGDISPLAY pRD,
{
// This must be the offset after a call
#ifdef _DEBUG
- GcInfoDecoder _safePointDecoder(gcInfoAddr, (GcInfoDecoderFlags)0, 0);
+ GcInfoDecoder _safePointDecoder(gcInfoToken, (GcInfoDecoderFlags)0, 0);
_ASSERTE(_safePointDecoder.IsSafePoint(curOffs));
#endif
flags &= ~((unsigned)ActiveStackFrame);
@@ -4791,7 +4789,7 @@ bool EECodeManager::EnumGcRefs( PREGDISPLAY pRD,
if (flags & ActiveStackFrame)
{
GcInfoDecoder _gcInfoDecoder(
- gcInfoAddr,
+ gcInfoToken,
DECODE_INTERRUPTIBILITY,
curOffs
);
@@ -4839,7 +4837,7 @@ bool EECodeManager::EnumGcRefs( PREGDISPLAY pRD,
// We've been given an override offset for GC Info
#ifdef _DEBUG
GcInfoDecoder _gcInfoDecoder(
- gcInfoAddr,
+ gcInfoToken,
DECODE_CODE_LENGTH,
0
);
@@ -4884,7 +4882,7 @@ bool EECodeManager::EnumGcRefs( PREGDISPLAY pRD,
GcInfoDecoder gcInfoDecoder(
- gcInfoAddr,
+ gcInfoToken,
GcInfoDecoderFlags (DECODE_GC_LIFETIMES | DECODE_SECURITY_OBJECT | DECODE_VARARG),
curOffs
);
@@ -5027,7 +5025,7 @@ OBJECTREF* EECodeManager::GetAddrOfSecurityObject(CrawlFrame *pCF)
unsigned relOffset = pCF->GetRelOffset();
CodeManState* pState = pCF->GetCodeManState();
- PTR_VOID methodInfoPtr = pJitMan->GetGCInfo(methodToken);
+ GCInfoToken gcInfoToken = pJitMan->GetGCInfoToken(methodToken);
_ASSERTE(sizeof(CodeManStateBuf) <= sizeof(pState->stateBuf));
@@ -5035,7 +5033,7 @@ OBJECTREF* EECodeManager::GetAddrOfSecurityObject(CrawlFrame *pCF)
CodeManStateBuf * stateBuf = (CodeManStateBuf*)pState->stateBuf;
/* Extract the necessary information from the info block header */
- stateBuf->hdrInfoSize = (DWORD)crackMethodInfoHdr(methodInfoPtr, // <TODO>truncation</TODO>
+ stateBuf->hdrInfoSize = (DWORD)crackMethodInfoHdr(gcInfoToken.Info, // <TODO>truncation</TODO>
relOffset,
&stateBuf->hdrInfoBody);
@@ -5051,10 +5049,8 @@ OBJECTREF* EECodeManager::GetAddrOfSecurityObject(CrawlFrame *pCF)
}
#elif defined(USE_GC_INFO_DECODER) && !defined(CROSSGEN_COMPILE)
- BYTE* gcInfoAddr = (BYTE*) methodInfoPtr;
-
GcInfoDecoder gcInfoDecoder(
- gcInfoAddr,
+ gcInfoToken,
DECODE_SECURITY_OBJECT,
0
);
@@ -5270,11 +5266,10 @@ GenericParamContextType EECodeManager::GetParamContextType(PREGDISPLAY pCont
}
// On x86 the generic param context parameter is never this.
#elif defined(USE_GC_INFO_DECODER)
- PTR_VOID methodInfoPtr = pCodeInfo->GetGCInfo();
- PTR_CBYTE gcInfoAddr = PTR_CBYTE(methodInfoPtr);
+ GCInfoToken gcInfoToken = pCodeInfo->GetGCInfoToken();
GcInfoDecoder gcInfoDecoder(
- gcInfoAddr,
+ gcInfoToken,
GcInfoDecoderFlags (DECODE_GENERICS_INST_CONTEXT),
0
);
@@ -5363,11 +5358,10 @@ PTR_VOID EECodeManager::GetExactGenericsToken(SIZE_T baseStackSlot,
WRAPPER_NO_CONTRACT;
SUPPORTS_DAC;
- PTR_VOID methodInfoPtr = pCodeInfo->GetGCInfo();
- PTR_CBYTE gcInfoAddr = PTR_CBYTE(methodInfoPtr);
+ GCInfoToken gcInfoToken = pCodeInfo->GetGCInfoToken();
GcInfoDecoder gcInfoDecoder(
- gcInfoAddr,
+ gcInfoToken,
GcInfoDecoderFlags (DECODE_PSP_SYM | DECODE_GENERICS_INST_CONTEXT),
0
);
@@ -5432,7 +5426,7 @@ void * EECodeManager::GetGSCookieAddr(PREGDISPLAY pContext,
_ASSERTE(sizeof(CodeManStateBuf) <= sizeof(pState->stateBuf));
- PTR_VOID methodInfoPtr = pCodeInfo->GetGCInfo();
+ GCInfoToken gcInfoToken = pCodeInfo->GetGCInfoToken();
unsigned relOffset = pCodeInfo->GetRelOffset();
#if defined(_TARGET_X86_)
@@ -5440,7 +5434,7 @@ void * EECodeManager::GetGSCookieAddr(PREGDISPLAY pContext,
/* Extract the necessary information from the info block header */
hdrInfo * info = &stateBuf->hdrInfoBody;
- stateBuf->hdrInfoSize = (DWORD)crackMethodInfoHdr(methodInfoPtr, // <TODO>truncation</TODO>
+ stateBuf->hdrInfoSize = (DWORD)crackMethodInfoHdr(gcInfoToken.Info, // <TODO>truncation</TODO>
relOffset,
info);
@@ -5459,22 +5453,20 @@ void * EECodeManager::GetGSCookieAddr(PREGDISPLAY pContext,
}
else
{
- PTR_CBYTE table = PTR_CBYTE(methodInfoPtr) + stateBuf->hdrInfoSize;
+ PTR_CBYTE table = PTR_CBYTE(gcInfoToken.Info) + stateBuf->hdrInfoSize;
unsigned argSize = GetPushedArgSize(info, table, relOffset);
return PVOID(SIZE_T(pContext->Esp + argSize + info->gsCookieOffset));
}
#elif defined(USE_GC_INFO_DECODER) && !defined(CROSSGEN_COMPILE)
- PTR_CBYTE gcInfoAddr = PTR_CBYTE(methodInfoPtr);
-
if (pCodeInfo->IsFunclet())
{
return NULL;
}
GcInfoDecoder gcInfoDecoder(
- gcInfoAddr,
+ gcInfoToken,
DECODE_GS_COOKIE,
0
);
@@ -5567,7 +5559,7 @@ bool EECodeManager::IsInSynchronizedRegion(
*
* Returns the size of a given function.
*/
-size_t EECodeManager::GetFunctionSize(PTR_VOID methodInfoPtr)
+size_t EECodeManager::GetFunctionSize(GCInfoToken gcInfoToken)
{
CONTRACTL {
NOTHROW;
@@ -5577,16 +5569,15 @@ size_t EECodeManager::GetFunctionSize(PTR_VOID methodInfoPtr)
#if defined(_TARGET_X86_)
hdrInfo info;
+ PTR_VOID methodInfoPtr = gcInfoToken.Info;
crackMethodInfoHdr(methodInfoPtr, 0, &info);
return info.methodSize;
#elif defined(USE_GC_INFO_DECODER)
- PTR_BYTE gcInfoAddr = PTR_BYTE(methodInfoPtr);
-
GcInfoDecoder gcInfoDecoder(
- gcInfoAddr,
+ gcInfoToken,
DECODE_CODE_LENGTH,
0
);
diff --git a/src/vm/exceptionhandling.cpp b/src/vm/exceptionhandling.cpp
index 3b60de0362..a99a20b312 100644
--- a/src/vm/exceptionhandling.cpp
+++ b/src/vm/exceptionhandling.cpp
@@ -94,7 +94,7 @@ bool FixNonvolatileRegisters(UINT_PTR uOriginalSP,
MethodDesc * GetUserMethodForILStub(Thread * pThread, UINT_PTR uStubSP, MethodDesc * pILStubMD, Frame ** ppFrameOut);
#ifdef FEATURE_PAL
-VOID PALAPI HandleHardwareException(PAL_SEHException* ex);
+BOOL PALAPI HandleHardwareException(PAL_SEHException* ex);
BOOL PALAPI IsSafeToHandleHardwareException(PCONTEXT contextRecord, PEXCEPTION_RECORD exceptionRecord);
#endif // FEATURE_PAL
@@ -4367,7 +4367,7 @@ VOID UnwindManagedExceptionPass2(PAL_SEHException& ex, CONTEXT* unwindStartConte
PVOID handlerData;
// Indicate that we are performing second pass.
- ex.ExceptionRecord.ExceptionFlags = EXCEPTION_UNWINDING;
+ ex.GetExceptionRecord()->ExceptionFlags = EXCEPTION_UNWINDING;
currentFrameContext = unwindStartContext;
callerFrameContext = &contextStorage;
@@ -4415,14 +4415,18 @@ VOID UnwindManagedExceptionPass2(PAL_SEHException& ex, CONTEXT* unwindStartConte
dispatcherContext.EstablisherFrame = establisherFrame;
dispatcherContext.ContextRecord = currentFrameContext;
+ EXCEPTION_RECORD* exceptionRecord = ex.GetExceptionRecord();
+
if (establisherFrame == ex.TargetFrameSp)
{
// We have reached the frame that will handle the exception.
- ex.ExceptionRecord.ExceptionFlags |= EXCEPTION_TARGET_UNWIND;
+ ex.GetExceptionRecord()->ExceptionFlags |= EXCEPTION_TARGET_UNWIND;
+ ExceptionTracker* pTracker = GetThread()->GetExceptionState()->GetCurrentExceptionTracker();
+ pTracker->TakeExceptionPointersOwnership(&ex);
}
// Perform unwinding of the current frame
- disposition = ProcessCLRException(&ex.ExceptionRecord,
+ disposition = ProcessCLRException(exceptionRecord,
establisherFrame,
currentFrameContext,
&dispatcherContext);
@@ -4436,7 +4440,6 @@ VOID UnwindManagedExceptionPass2(PAL_SEHException& ex, CONTEXT* unwindStartConte
}
else
{
- // TODO: This needs to implemented. Make it fail for now.
UNREACHABLE();
}
}
@@ -4513,15 +4516,15 @@ VOID DECLSPEC_NORETURN UnwindManagedExceptionPass1(PAL_SEHException& ex, CONTEXT
controlPc = GetIP(frameContext);
unwindStartContext = *frameContext;
- if (!ExecutionManager::IsManagedCode(GetIP(&ex.ContextRecord)))
+ if (!ExecutionManager::IsManagedCode(GetIP(ex.GetContextRecord())))
{
// This is the first time we see the managed exception, set its context to the managed frame that has caused
// the exception to be thrown
- ex.ContextRecord = *frameContext;
- ex.ExceptionRecord.ExceptionAddress = (VOID*)controlPc;
+ *ex.GetContextRecord() = *frameContext;
+ ex.GetExceptionRecord()->ExceptionAddress = (VOID*)controlPc;
}
- ex.ExceptionRecord.ExceptionFlags = 0;
+ ex.GetExceptionRecord()->ExceptionFlags = 0;
memset(&dispatcherContext, 0, sizeof(DISPATCHER_CONTEXT));
disposition = ExceptionContinueSearch;
@@ -4562,9 +4565,9 @@ VOID DECLSPEC_NORETURN UnwindManagedExceptionPass1(PAL_SEHException& ex, CONTEXT
dispatcherContext.ContextRecord = frameContext;
// Find exception handler in the current frame
- disposition = ProcessCLRException(&ex.ExceptionRecord,
+ disposition = ProcessCLRException(ex.GetExceptionRecord(),
establisherFrame,
- &ex.ContextRecord,
+ ex.GetContextRecord(),
&dispatcherContext);
if (disposition == ExceptionContinueSearch)
@@ -4657,7 +4660,7 @@ VOID DECLSPEC_NORETURN DispatchManagedException(PAL_SEHException& ex, bool isHar
// If the exception is hardware exceptions, we use the exception's context record directly
if (isHardwareException)
{
- frameContext = ex.ContextRecord;
+ frameContext = *ex.GetContextRecord();
}
else
{
@@ -4696,7 +4699,7 @@ VOID DECLSPEC_NORETURN DispatchManagedException(PAL_SEHException& ex, bool isHar
catch (PAL_SEHException& ex2)
{
isHardwareException = false;
- ex = ex2;
+ ex = std::move(ex2);
}
}
@@ -4717,7 +4720,7 @@ VOID DECLSPEC_NORETURN DispatchManagedException(PAL_SEHException& ex, bool isHar
if (pEHTracker == NULL)
{
CorruptionSeverity severity = NotCorrupting;
- if (CEHelper::IsProcessCorruptedStateException(ex.ExceptionRecord.ExceptionCode))
+ if (CEHelper::IsProcessCorruptedStateException(ex.GetExceptionRecord()->ExceptionCode))
{
severity = ProcessCorrupting;
}
@@ -5082,19 +5085,20 @@ BOOL PALAPI IsSafeToHandleHardwareException(PCONTEXT contextRecord, PEXCEPTION_R
IsIPInMarkedJitHelper(controlPc));
}
-VOID PALAPI HandleHardwareException(PAL_SEHException* ex)
+BOOL PALAPI HandleHardwareException(PAL_SEHException* ex)
{
- _ASSERTE(IsSafeToHandleHardwareException(&ex->ContextRecord, &ex->ExceptionRecord));
+ _ASSERTE(IsSafeToHandleHardwareException(ex->GetContextRecord(), ex->GetExceptionRecord()));
- if (ex->ExceptionRecord.ExceptionCode != STATUS_BREAKPOINT && ex->ExceptionRecord.ExceptionCode != STATUS_SINGLE_STEP)
+ if (ex->GetExceptionRecord()->ExceptionCode != STATUS_BREAKPOINT && ex->GetExceptionRecord()->ExceptionCode != STATUS_SINGLE_STEP)
{
// A hardware exception is handled only if it happened in a jitted code or
// in one of the JIT helper functions (JIT_MemSet, ...)
- PCODE controlPc = GetIP(&ex->ContextRecord);
- if (ExecutionManager::IsManagedCode(controlPc) && IsGcMarker(ex->ExceptionRecord.ExceptionCode, &ex->ContextRecord))
+ PCODE controlPc = GetIP(ex->GetContextRecord());
+ if (ExecutionManager::IsManagedCode(controlPc) && IsGcMarker(ex->GetExceptionRecord()->ExceptionCode, ex->GetContextRecord()))
{
- RtlRestoreContext(&ex->ContextRecord, &ex->ExceptionRecord);
- UNREACHABLE();
+ // Exception was handled, let the signal handler return to the exception context. Some registers in the context can
+ // have been modified by the GC.
+ return TRUE;
}
#ifdef _AMD64_
@@ -5104,11 +5108,11 @@ VOID PALAPI HandleHardwareException(PAL_SEHException* ex)
//
// Thus, we will attempt to decode the instruction @ RIP to determine if that
// is the case using the faulting context.
- if ((ex->ExceptionRecord.ExceptionCode == EXCEPTION_INT_DIVIDE_BY_ZERO) &&
- IsDivByZeroAnIntegerOverflow(&ex->ContextRecord))
+ if ((ex->GetExceptionRecord()->ExceptionCode == EXCEPTION_INT_DIVIDE_BY_ZERO) &&
+ IsDivByZeroAnIntegerOverflow(ex->GetContextRecord()))
{
// The exception was an integer overflow, so augment the exception code.
- ex->ExceptionRecord.ExceptionCode = EXCEPTION_INT_OVERFLOW;
+ ex->GetExceptionRecord()->ExceptionCode = EXCEPTION_INT_OVERFLOW;
}
#endif //_AMD64_
@@ -5125,16 +5129,16 @@ VOID PALAPI HandleHardwareException(PAL_SEHException* ex)
// managed code that called the helper, otherwise the stack
// walker would skip all the managed frames upto the next
// explicit frame.
- PAL_VirtualUnwind(&ex->ContextRecord, NULL);
- ex->ExceptionRecord.ExceptionAddress = (PVOID)GetIP(&ex->ContextRecord);
+ PAL_VirtualUnwind(ex->GetContextRecord(), NULL);
+ ex->GetExceptionRecord()->ExceptionAddress = (PVOID)GetIP(ex->GetContextRecord());
}
#ifdef _TARGET_ARM_
else if (IsIPinVirtualStub(controlPc))
{
- AdjustContextForVirtualStub(&ex->ExceptionRecord, &ex->ContextRecord);
+ AdjustContextForVirtualStub(ex->GetExceptionRecord(), ex->GetContextRecord());
}
#endif
- fef.InitAndLink(&ex->ContextRecord);
+ fef.InitAndLink(ex->GetContextRecord());
}
DispatchManagedException(*ex, true /* isHardwareException */);
@@ -5146,24 +5150,27 @@ VOID PALAPI HandleHardwareException(PAL_SEHException* ex)
Thread *pThread = GetThread();
if (pThread != NULL && g_pDebugInterface != NULL)
{
- if (ex->ExceptionRecord.ExceptionCode == STATUS_BREAKPOINT)
+ if (ex->GetExceptionRecord()->ExceptionCode == STATUS_BREAKPOINT)
{
// If this is breakpoint context, it is set up to point to an instruction after the break instruction.
// But debugger expects to see context that points to the break instruction, that's why we correct it.
- SetIP(&ex->ContextRecord, GetIP(&ex->ContextRecord) - CORDbg_BREAK_INSTRUCTION_SIZE);
- ex->ExceptionRecord.ExceptionAddress = (void *)GetIP(&ex->ContextRecord);
+ SetIP(ex->GetContextRecord(), GetIP(ex->GetContextRecord()) - CORDbg_BREAK_INSTRUCTION_SIZE);
+ ex->GetExceptionRecord()->ExceptionAddress = (void *)GetIP(ex->GetContextRecord());
}
- if (g_pDebugInterface->FirstChanceNativeException(&ex->ExceptionRecord,
- &ex->ContextRecord,
- ex->ExceptionRecord.ExceptionCode,
+ if (g_pDebugInterface->FirstChanceNativeException(ex->GetExceptionRecord(),
+ ex->GetContextRecord(),
+ ex->GetExceptionRecord()->ExceptionCode,
pThread))
{
- RtlRestoreContext(&ex->ContextRecord, &ex->ExceptionRecord);
- UNREACHABLE();
+ // Exception was handled, let the signal handler return to the exception context. Some registers in the context can
+ // have been modified by the debugger.
+ return TRUE;
}
}
}
+
+ return FALSE;
}
#endif // FEATURE_PAL
@@ -6997,8 +7004,14 @@ void ExceptionTracker::ReleaseResources()
#ifndef FEATURE_PAL
// Clear any held Watson Bucketing details
- GetWatsonBucketTracker()->ClearWatsonBucketDetails();
-#endif // !FEATURE_PAL
+ GetWatsonBucketTracker()->ClearWatsonBucketDetails();
+#else // !FEATURE_PAL
+ if (m_fOwnsExceptionPointers)
+ {
+ PAL_FreeExceptionRecords(m_ptrs.ExceptionRecord, m_ptrs.ContextRecord);
+ m_fOwnsExceptionPointers = FALSE;
+ }
+#endif // !FEATURE_PAL
#endif // DACCESS_COMPILE
}
diff --git a/src/vm/exceptionhandling.h b/src/vm/exceptionhandling.h
index 2a8181b08b..340cbc0d6d 100644
--- a/src/vm/exceptionhandling.h
+++ b/src/vm/exceptionhandling.h
@@ -108,6 +108,10 @@ public:
m_pInitialExplicitFrame = NULL;
m_pLimitFrame = NULL;
m_csfEHClauseOfCollapsedTracker.Clear();
+
+#ifdef FEATURE_PAL
+ m_fOwnsExceptionPointers = FALSE;
+#endif
}
ExceptionTracker(DWORD_PTR dwExceptionPc,
@@ -167,6 +171,10 @@ public:
m_sfLastUnwoundEstablisherFrame.Clear();
m_pInitialExplicitFrame = NULL;
m_csfEHClauseOfCollapsedTracker.Clear();
+
+#ifdef FEATURE_PAL
+ m_fOwnsExceptionPointers = FALSE;
+#endif
}
~ExceptionTracker()
@@ -385,6 +393,16 @@ public:
bool IsStackOverflowException();
+#ifdef FEATURE_PAL
+ void TakeExceptionPointersOwnership(PAL_SEHException* ex)
+ {
+ _ASSERTE(ex->GetExceptionRecord() == m_ptrs.ExceptionRecord);
+ _ASSERTE(ex->GetContextRecord() == m_ptrs.ContextRecord);
+ ex->Clear();
+ m_fOwnsExceptionPointers = TRUE;
+ }
+#endif // FEATURE_PAL
+
private:
DWORD_PTR
CallHandler(UINT_PTR dwHandlerStartPC,
@@ -700,6 +718,9 @@ private: ;
StackRange m_ScannedStackRange;
DAC_EXCEPTION_POINTERS m_ptrs;
+#ifdef FEATURE_PAL
+ BOOL m_fOwnsExceptionPointers;
+#endif
OBJECTHANDLE m_hThrowable;
StackTraceInfo m_StackTraceInfo;
UINT_PTR m_uCatchToCallPC;
diff --git a/src/vm/exceptmacros.h b/src/vm/exceptmacros.h
index 1c98253639..efed993a2d 100644
--- a/src/vm/exceptmacros.h
+++ b/src/vm/exceptmacros.h
@@ -250,28 +250,6 @@ LONG WINAPI CLRVectoredExceptionHandler(PEXCEPTION_POINTERS pExceptionInfo);
// Actual UEF worker prototype for use by GCUnhandledExceptionFilter.
extern LONG InternalUnhandledExceptionFilter_Worker(PEXCEPTION_POINTERS pExceptionInfo);
-// This function is the filter function for the "__except" setup in "gc1()"
-// in gc.cpp to handle exceptions that happen during GC.
-inline LONG CheckException(EXCEPTION_POINTERS* pExceptionPointers, PVOID pv)
-{
- WRAPPER_NO_CONTRACT;
-
- LONG result = CLRVectoredExceptionHandler(pExceptionPointers);
- if (result != EXCEPTION_EXECUTE_HANDLER)
- return result;
-
-#ifdef _DEBUG_IMPL
- _ASSERTE(!"Unexpected Exception");
-#else
- FreeBuildDebugBreak();
-#endif
-
- // Set the debugger to break on AV and return a value of EXCEPTION_CONTINUE_EXECUTION (-1)
- // here and you will bounce back to the point of the AV.
- return EXCEPTION_EXECUTE_HANDLER;
-
-}
-
//==========================================================================
// Installs a handler to unwind exception frames, but not catch the exception
//==========================================================================
@@ -330,7 +308,7 @@ VOID DECLSPEC_NORETURN DispatchManagedException(PAL_SEHException& ex, bool isHar
} \
catch (PAL_SEHException& ex) \
{ \
- exCopy = ex; \
+ exCopy = std::move(ex); \
hasCaughtException = true; \
} \
if (hasCaughtException) \
diff --git a/src/vm/fieldmarshaler.cpp b/src/vm/fieldmarshaler.cpp
index 23cbe1865b..0de71b592c 100644
--- a/src/vm/fieldmarshaler.cpp
+++ b/src/vm/fieldmarshaler.cpp
@@ -3364,14 +3364,22 @@ VOID FieldMarshaler_FixedStringAnsi::UpdateNativeImpl(OBJECTREF* pCLRValue, LPVO
nc = m_numchar - 1;
int cbwritten = InternalWideToAnsi(pString->GetBuffer(),
- nc,
- (CHAR*)pNativeValue,
- m_numchar,
- m_BestFitMap,
- m_ThrowOnUnmappableChar);
+ nc,
+ (CHAR*)pNativeValue,
+ m_numchar,
+ m_BestFitMap,
+ m_ThrowOnUnmappableChar);
+
+ // Handle the case where SizeConst == Number of bytes.For single byte chars
+ // this will never be the case since nc >= m_numchar check will truncate the last
+ // character, but for multibyte chars nc>= m_numchar check won't truncate since GetStringLength
+ // gives number of characters but not the actual number of bytes. For such cases need to make
+ // sure that we dont write one past the buffer.
+ if (cbwritten == (int) m_numchar)
+ --cbwritten;
+
((CHAR*)pNativeValue)[cbwritten] = '\0';
}
-
}
@@ -3572,10 +3580,10 @@ VOID FieldMarshaler_FixedArray::UpdateNativeImpl(OBJECTREF* pCLRValue, LPVOID pN
}
else
{
- // Make sure the size of the array is the same as specified in the MarshalAs attribute (via the SizeConst field).
+ // Make sure the size of the array is >= as specified in the MarshalAs attribute (via the SizeConst field).
if ((*pCLRValue)->GetNumComponents() < m_numElems)
COMPlusThrow(kArgumentException, IDS_WRONGSIZEARRAY_IN_NSTRUCT);
-
+
// Marshal the contents from the managed array to the native array.
const OleVariant::Marshaler *pMarshaler = OleVariant::GetMarshalerForVarType(m_vt, TRUE);
if (pMarshaler == NULL || pMarshaler->ComToOleArray == NULL)
@@ -3588,7 +3596,7 @@ VOID FieldMarshaler_FixedArray::UpdateNativeImpl(OBJECTREF* pCLRValue, LPVOID pN
// We never operate on an uninitialized native layout here, we have zero'ed it if needed.
// Therefore fOleArrayIsValid is always TRUE.
- pMarshaler->ComToOleArray((BASEARRAYREF*)pCLRValue, pNativeValue, pElementMT, m_BestFitMap, m_ThrowOnUnmappableChar, TRUE);
+ pMarshaler->ComToOleArray((BASEARRAYREF*)pCLRValue, pNativeValue, pElementMT, m_BestFitMap, m_ThrowOnUnmappableChar, TRUE, m_numElems);
}
}
}
diff --git a/src/vm/gccover.cpp b/src/vm/gccover.cpp
index 2dd7c9e2a5..3220cddd8e 100644
--- a/src/vm/gccover.cpp
+++ b/src/vm/gccover.cpp
@@ -79,7 +79,7 @@ void SetupAndSprinkleBreakpoints(
gcCover->methodRegion = methodRegionInfo;
gcCover->codeMan = pCodeInfo->GetCodeManager();
- gcCover->gcInfo = pCodeInfo->GetGCInfo();
+ gcCover->gcInfoToken = pCodeInfo->GetGCInfoToken();
gcCover->callerThread = 0;
gcCover->doingEpilogChecks = true;
@@ -286,7 +286,7 @@ class GCCoverageRangeEnumerator
private:
ICodeManager *m_pCodeManager;
- LPVOID m_pvGCInfo;
+ GCInfoToken m_pvGCTable;
BYTE *m_codeStart;
BYTE *m_codeEnd;
BYTE *m_curFuncletEnd;
@@ -318,7 +318,7 @@ private:
unsigned ofsLastInterruptible = m_pCodeManager->FindEndOfLastInterruptibleRegion(
static_cast<unsigned int>(pCurFunclet - m_codeStart),
static_cast<unsigned int>(m_curFuncletEnd - m_codeStart),
- m_pvGCInfo);
+ m_pvGCTable);
if (ofsLastInterruptible)
{
@@ -332,10 +332,10 @@ private:
public:
- GCCoverageRangeEnumerator (ICodeManager *pCodeManager, LPVOID pvGCInfo, BYTE *codeStart, SIZE_T codeSize)
+ GCCoverageRangeEnumerator (ICodeManager *pCodeManager, GCInfoToken pvGCTable, BYTE *codeStart, SIZE_T codeSize)
{
m_pCodeManager = pCodeManager;
- m_pvGCInfo = pvGCInfo;
+ m_pvGCTable = pvGCTable;
m_codeStart = codeStart;
m_codeEnd = codeStart + codeSize;
m_nextFunclet = codeStart;
@@ -458,9 +458,9 @@ void GCCoverageInfo::SprinkleBreakpoints(
#ifdef _TARGET_AMD64_
- GCCoverageRangeEnumerator rangeEnum(codeMan, gcInfo, codeStart, codeSize);
+ GCCoverageRangeEnumerator rangeEnum(codeMan, gcInfoToken, codeStart, codeSize);
- GcInfoDecoder safePointDecoder((const BYTE*)gcInfo, (GcInfoDecoderFlags)0, 0);
+ GcInfoDecoder safePointDecoder(gcInfoToken, (GcInfoDecoderFlags)0, 0);
bool fSawPossibleSwitch = false;
#endif
@@ -582,7 +582,7 @@ void GCCoverageInfo::SprinkleBreakpoints(
#ifdef _TARGET_X86_
// we will whack every instruction in the prolog and epilog to make certain
// our unwinding logic works there.
- if (codeMan->IsInPrologOrEpilog((cur - codeStart) + (DWORD)regionOffsetAdj, gcInfo, NULL)) {
+ if (codeMan->IsInPrologOrEpilog((cur - codeStart) + (DWORD)regionOffsetAdj, gcInfoToken.Info, NULL)) {
*cur = INTERRUPT_INSTR;
}
#endif
@@ -632,7 +632,7 @@ void GCCoverageInfo::SprinkleBreakpoints(
}
}
- GcInfoDecoder safePointDecoder((const BYTE*)gcInfo, (GcInfoDecoderFlags)0, 0);
+ GcInfoDecoder safePointDecoder(gcInfoToken, (GcInfoDecoderFlags)0, 0);
assert(methodRegion.hotSize > 0);
@@ -1469,7 +1469,7 @@ void DoGcStress (PCONTEXT regs, MethodDesc *pMD)
/* are we in a prolog or epilog? If so just test the unwind logic
but don't actually do a GC since the prolog and epilog are not
GC safe points */
- if (gcCover->codeMan->IsInPrologOrEpilog(offset, gcCover->gcInfo, NULL))
+ if (gcCover->codeMan->IsInPrologOrEpilog(offset, gcCover->gcInfoToken.Info, NULL))
{
// We are not at a GC safe point so we can't Suspend EE (Suspend EE will yield to GC).
// But we still have to update the GC Stress instruction. We do it directly without suspending
diff --git a/src/vm/gccover.h b/src/vm/gccover.h
index 0308f473f2..b2dedefa31 100644
--- a/src/vm/gccover.h
+++ b/src/vm/gccover.h
@@ -26,7 +26,7 @@ public:
// Following 6 variables are for prolog / epilog walking coverage
ICodeManager* codeMan; // CodeMan for this method
- void* gcInfo; // gcInfo for this method
+ GCInfoToken gcInfoToken; // gcInfo for this method
Thread* callerThread; // Thread associated with context callerRegs
T_CONTEXT callerRegs; // register state when method was entered
diff --git a/src/vm/gcenv.ee.cpp b/src/vm/gcenv.ee.cpp
index 1bb4ee815b..da36e726ba 100644
--- a/src/vm/gcenv.ee.cpp
+++ b/src/vm/gcenv.ee.cpp
@@ -132,7 +132,7 @@ inline bool SafeToReportGenericParamContext(CrawlFrame* pCF)
#else // USE_GC_INFO_DECODER
- GcInfoDecoder gcInfoDecoder((PTR_CBYTE)pCF->GetGCInfo(),
+ GcInfoDecoder gcInfoDecoder(pCF->GetGCInfoToken(),
DECODE_PROLOG_LENGTH,
0);
UINT32 prologLength = gcInfoDecoder.GetPrologSize();
@@ -199,8 +199,8 @@ bool FindFirstInterruptiblePointStateCB(
// the end is exclusive). Return -1 if no such point exists.
unsigned FindFirstInterruptiblePoint(CrawlFrame* pCF, unsigned offs, unsigned endOffs)
{
- PTR_BYTE gcInfoAddr = dac_cast<PTR_BYTE>(pCF->GetCodeInfo()->GetGCInfo());
- GcInfoDecoder gcInfoDecoder(gcInfoAddr, DECODE_FOR_RANGES_CALLBACK, 0);
+ GCInfoToken gcInfoToken = pCF->GetGCInfoToken();
+ GcInfoDecoder gcInfoDecoder(gcInfoToken, DECODE_FOR_RANGES_CALLBACK, 0);
FindFirstInterruptiblePointState state;
state.offs = offs;
@@ -281,9 +281,9 @@ StackWalkAction GcStackCrawlCallBack(CrawlFrame* pCF, VOID* pData)
#if defined(WIN64EXCEPTIONS)
if (pCF->ShouldParentToFuncletUseUnwindTargetLocationForGCReporting())
{
- PTR_BYTE gcInfoAddr = dac_cast<PTR_BYTE>(pCF->GetCodeInfo()->GetGCInfo());
+ GCInfoToken gcInfoToken = pCF->GetGCInfoToken();
GcInfoDecoder _gcInfoDecoder(
- gcInfoAddr,
+ gcInfoToken,
DECODE_CODE_LENGTH,
0
);
@@ -585,7 +585,7 @@ void GCToEEInterface::GcStartWork (int condemned, int max_gen)
{
CONTRACTL
{
- THROWS; // StubHelpers::ProcessByrefValidationList throws
+ NOTHROW;
GC_NOTRIGGER;
}
CONTRACTL_END;
@@ -660,7 +660,7 @@ void GCToEEInterface::GcBeforeBGCSweepWork()
{
CONTRACTL
{
- THROWS; // StubHelpers::ProcessByrefValidationList throws
+ NOTHROW;
GC_NOTRIGGER;
}
CONTRACTL_END;
@@ -695,12 +695,6 @@ void GCToEEInterface::SyncBlockCachePromotionsGranted(int max_gen)
SyncBlockCache::GetSyncBlockCache()->GCDone(FALSE, max_gen);
}
-void GCToEEInterface::SetGCSpecial(Thread * pThread)
-{
- WRAPPER_NO_CONTRACT;
- pThread->SetGCSpecial(true);
-}
-
alloc_context * GCToEEInterface::GetAllocContext(Thread * pThread)
{
WRAPPER_NO_CONTRACT;
@@ -747,7 +741,47 @@ void GCToEEInterface::DisablePreemptiveGC(Thread * pThread)
pThread->DisablePreemptiveGC();
}
-bool GCToEEInterface::CreateBackgroundThread(Thread** thread, GCBackgroundThreadFunction threadStart, void* arg)
+struct BackgroundThreadStubArgs
+{
+ Thread* thread;
+ GCBackgroundThreadFunction threadStart;
+ void* arg;
+ CLREvent threadStartedEvent;
+ bool hasStarted;
+};
+
+DWORD BackgroundThreadStub(void* arg)
+{
+ BackgroundThreadStubArgs* stubArgs = (BackgroundThreadStubArgs*)arg;
+ assert (stubArgs->thread != NULL);
+
+ ClrFlsSetThreadType (ThreadType_GC);
+ stubArgs->thread->SetGCSpecial(true);
+ STRESS_LOG_RESERVE_MEM (GC_STRESSLOG_MULTIPLY);
+
+ stubArgs->hasStarted = !!stubArgs->thread->HasStarted(FALSE);
+
+ Thread* thread = stubArgs->thread;
+ GCBackgroundThreadFunction realThreadStart = stubArgs->threadStart;
+ void* realThreadArg = stubArgs->arg;
+ bool hasStarted = stubArgs->hasStarted;
+
+ stubArgs->threadStartedEvent.Set();
+ // The stubArgs cannot be used once the event is set, since that releases wait on the
+ // event in the function that created this thread and the stubArgs go out of scope.
+
+ DWORD result = 0;
+
+ if (hasStarted)
+ {
+ result = realThreadStart(realThreadArg);
+ DestroyThread(thread);
+ }
+
+ return result;
+}
+
+Thread* GCToEEInterface::CreateBackgroundThread(GCBackgroundThreadFunction threadStart, void* arg)
{
CONTRACTL
{
@@ -756,29 +790,54 @@ bool GCToEEInterface::CreateBackgroundThread(Thread** thread, GCBackgroundThread
}
CONTRACTL_END;
- Thread* newThread = NULL;
+ BackgroundThreadStubArgs threadStubArgs;
+
+ threadStubArgs.arg = arg;
+ threadStubArgs.thread = NULL;
+ threadStubArgs.threadStart = threadStart;
+ threadStubArgs.hasStarted = false;
+
+ if (!threadStubArgs.threadStartedEvent.CreateAutoEventNoThrow(FALSE))
+ {
+ return NULL;
+ }
+
EX_TRY
{
- newThread = SetupUnstartedThread(FALSE);
- *thread = newThread;
+ threadStubArgs.thread = SetupUnstartedThread(FALSE);
}
EX_CATCH
{
}
EX_END_CATCH(SwallowAllExceptions);
- if ((newThread != NULL) && newThread->CreateNewThread(0, (LPTHREAD_START_ROUTINE)threadStart, arg))
+ if (threadStubArgs.thread == NULL)
{
- newThread->SetBackground (TRUE, FALSE);
+ threadStubArgs.threadStartedEvent.CloseEvent();
+ return NULL;
+ }
+
+ if (threadStubArgs.thread->CreateNewThread(0, (LPTHREAD_START_ROUTINE)BackgroundThreadStub, &threadStubArgs))
+ {
+ threadStubArgs.thread->SetBackground (TRUE, FALSE);
+ threadStubArgs.thread->StartThread();
- // wait for the thread to be in its main loop, this is to detect the situation
- // where someone triggers a GC during dll loading where the loader lock is
- // held.
- newThread->StartThread();
+ // Wait for the thread to be in its main loop
+ uint32_t res = threadStubArgs.threadStartedEvent.Wait(INFINITE, FALSE);
+ threadStubArgs.threadStartedEvent.CloseEvent();
+ _ASSERTE(res == WAIT_OBJECT_0);
- return true;
+ if (!threadStubArgs.hasStarted)
+ {
+ // The thread has failed to start and the Thread object was destroyed in the Thread::HasStarted
+ // failure code path.
+ return NULL;
+ }
+
+ return threadStubArgs.thread;
}
- *thread = NULL;
- return false;
+ // Destroy the Thread object
+ threadStubArgs.thread->DecExternalCount(FALSE);
+ return NULL;
}
diff --git a/src/vm/gcinfodecoder.cpp b/src/vm/gcinfodecoder.cpp
index 5a3bbd94eb..351e221d82 100644
--- a/src/vm/gcinfodecoder.cpp
+++ b/src/vm/gcinfodecoder.cpp
@@ -6,7 +6,6 @@
#include "common.h"
#include "gcinfodecoder.h"
-
#ifdef USE_GC_INFO_DECODER
#ifndef CHECK_APP_DOMAIN
@@ -84,28 +83,17 @@ bool GcInfoDecoder::SetIsInterruptibleCB (UINT32 startOffset, UINT32 stopOffset,
GcInfoDecoder::GcInfoDecoder(
- PTR_CBYTE gcInfoAddr,
+ GCInfoToken gcInfoToken,
GcInfoDecoderFlags flags,
UINT32 breakOffset
)
- : m_Reader( gcInfoAddr
-#ifdef VERIFY_GCINFO
- + sizeof(size_t)
-#endif
- )
+ : m_Reader(dac_cast<PTR_CBYTE>(gcInfoToken.Info))
, m_InstructionOffset(breakOffset)
, m_IsInterruptible(false)
#ifdef _DEBUG
, m_Flags( flags )
- , m_GcInfoAddress(gcInfoAddr)
-#endif
-#ifdef VERIFY_GCINFO
- , m_DbgDecoder(gcInfoAddr+
- (((UINT32)((PTR_BYTE)(TADDR)gcInfoAddr)[3])<<24)+
- (((UINT32)((PTR_BYTE)(TADDR)gcInfoAddr)[2])<<16)+
- (((UINT32)((PTR_BYTE)(TADDR)gcInfoAddr)[1])<<8)+
- ((PTR_BYTE)(TADDR)gcInfoAddr)[0],
- flags, breakOffset)
+ , m_GcInfoAddress(dac_cast<PTR_CBYTE>(gcInfoToken.Info))
+ , m_Version(gcInfoToken.Version)
#endif
{
_ASSERTE( (flags & (DECODE_INTERRUPTIBILITY | DECODE_GC_LIFETIMES)) || (0 == breakOffset) );
@@ -320,30 +308,6 @@ GcInfoDecoder::GcInfoDecoder(
{
EnumerateInterruptibleRanges(&SetIsInterruptibleCB, this);
}
-
-#ifdef VERIFY_GCINFO
-#if 0
- if(flags & DECODE_INTERRUPTIBILITY)
- _ASSERTE(IsInterruptible() == m_DbgDecoder.IsInterruptible());
-#endif
- if(flags & DECODE_SECURITY_OBJECT)
- _ASSERTE(GetSecurityObjectStackSlot() == m_DbgDecoder.GetSecurityObjectStackSlot());
- if(flags & DECODE_GENERICS_INST_CONTEXT)
- {
- _ASSERTE(GetGenericsInstContextStackSlot() == m_DbgDecoder.GetGenericsInstContextStackSlot());
- _ASSERTE(GetPSPSymStackSlot() == m_DbgDecoder.GetPSPSymStackSlot());
- }
- if(flags & DECODE_VARARG)
- _ASSERTE(GetIsVarArg() == m_DbgDecoder.GetIsVarArg());
- if(flags & DECODE_CODE_LENGTH)
- _ASSERTE(GetCodeLength() == m_DbgDecoder.GetCodeLength());
- _ASSERTE(GetStackBaseRegister() == m_DbgDecoder.GetStackBaseRegister());
- _ASSERTE(GetSizeOfEditAndContinuePreservedArea() == m_DbgDecoder.GetSizeOfEditAndContinuePreservedArea());
-#ifdef FIXED_STACK_PARAMETER_SCRATCH_AREA
- _ASSERTE(GetSizeOfStackParameterArea() == m_DbgDecoder.GetSizeOfStackParameterArea());
-#endif
-#endif
-
}
bool GcInfoDecoder::IsInterruptible()
@@ -587,16 +551,6 @@ bool GcInfoDecoder::EnumerateLiveSlots(
return true;
}
-#ifdef VERIFY_GCINFO
- m_DbgDecoder.EnumerateLiveSlots(
- pRD,
- reportScratchSlots,
- inputFlags,
- pCallBack,
- hCallBack
- );
-#endif
-
//
// If this is a non-leaf frame and we are executing a call, the unwinder has given us the PC
// of the call instruction. We should adjust it to the PC of the instruction after the call in order to
@@ -1073,13 +1027,6 @@ ReportUntracked:
ExitSuccess:
#endif
-#ifdef VERIFY_GCINFO
-#ifdef PARTIALLY_INTERRUPTIBLE_GC_SUPPORTED
- if(!executionAborted)
-#endif
- m_DbgDecoder.DoFinalVerification();
-#endif
-
return true;
}
diff --git a/src/vm/ilmarshalers.cpp b/src/vm/ilmarshalers.cpp
index ebd8250459..114fbe3ccb 100644
--- a/src/vm/ilmarshalers.cpp
+++ b/src/vm/ilmarshalers.cpp
@@ -4372,20 +4372,19 @@ FCIMPL3(void, MngdNativeArrayMarshaler::ConvertContentsToNative, MngdNativeArray
if (*pArrayRef != NULL)
{
const OleVariant::Marshaler* pMarshaler = OleVariant::GetMarshalerForVarType(pThis->m_vt, TRUE);
-
+ SIZE_T cElements = (*pArrayRef)->GetNumComponents();
if (pMarshaler == NULL || pMarshaler->ComToOleArray == NULL)
{
- SIZE_T cElements = (*pArrayRef)->GetNumComponents();
- SIZE_T cbArray = cElements;
- if ( (!SafeMulSIZE_T(&cbArray, OleVariant::GetElementSizeForVarType(pThis->m_vt, pThis->m_pElementMT))) || cbArray > MAX_SIZE_FOR_INTEROP)
+ if ( (!SafeMulSIZE_T(&cElements, OleVariant::GetElementSizeForVarType(pThis->m_vt, pThis->m_pElementMT))) || cElements > MAX_SIZE_FOR_INTEROP)
COMPlusThrow(kArgumentException, IDS_EE_STRUCTARRAYTOOLARGE);
_ASSERTE(!GetTypeHandleForCVType(OleVariant::GetCVTypeForVarType(pThis->m_vt)).GetMethodTable()->ContainsPointers());
- memcpyNoGCRefs(*pNativeHome, (*pArrayRef)->GetDataPtr(), cbArray);
+ memcpyNoGCRefs(*pNativeHome, (*pArrayRef)->GetDataPtr(), cElements);
}
else
{
- pMarshaler->ComToOleArray(pArrayRef, *pNativeHome, pThis->m_pElementMT, pThis->m_BestFitMap, pThis->m_ThrowOnUnmappableChar, pThis->m_NativeDataValid);
+ pMarshaler->ComToOleArray(pArrayRef, *pNativeHome, pThis->m_pElementMT, pThis->m_BestFitMap,
+ pThis->m_ThrowOnUnmappableChar, pThis->m_NativeDataValid, cElements);
}
}
HELPER_METHOD_FRAME_END();
@@ -4437,13 +4436,12 @@ FCIMPL3(void, MngdNativeArrayMarshaler::ConvertContentsToManaged, MngdNativeArra
if (pMarshaler == NULL || pMarshaler->OleToComArray == NULL)
{
SIZE_T cElements = (*pArrayRef)->GetNumComponents();
- SIZE_T cbArray = cElements;
- if ( (!SafeMulSIZE_T(&cbArray, OleVariant::GetElementSizeForVarType(pThis->m_vt, pThis->m_pElementMT))) || cbArray > MAX_SIZE_FOR_INTEROP)
+ if ( (!SafeMulSIZE_T(&cElements, OleVariant::GetElementSizeForVarType(pThis->m_vt, pThis->m_pElementMT))) || cElements > MAX_SIZE_FOR_INTEROP)
COMPlusThrow(kArgumentException, IDS_EE_STRUCTARRAYTOOLARGE);
// If we are copying variants, strings, etc, we need to use write barrier
_ASSERTE(!GetTypeHandleForCVType(OleVariant::GetCVTypeForVarType(pThis->m_vt)).GetMethodTable()->ContainsPointers());
- memcpyNoGCRefs((*pArrayRef)->GetDataPtr(), *pNativeHome, cbArray );
+ memcpyNoGCRefs((*pArrayRef)->GetDataPtr(), *pNativeHome, cElements);
}
else
{
diff --git a/src/vm/object.cpp b/src/vm/object.cpp
index d9ca2b3b77..7c47e26627 100644
--- a/src/vm/object.cpp
+++ b/src/vm/object.cpp
@@ -408,6 +408,31 @@ void Object::SetAppDomain(AppDomain *pDomain)
_ASSERTE(GetHeader()->GetAppDomainIndex().m_dwIndex != 0);
}
+BOOL Object::SetAppDomainNoThrow()
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ SO_INTOLERANT;
+ }
+ CONTRACTL_END;
+
+ BOOL success = FALSE;
+
+ EX_TRY
+ {
+ SetAppDomain();
+ success = TRUE;
+ }
+ EX_CATCH
+ {
+ _ASSERTE (!"Exception happened during Object::SetAppDomain");
+ }
+ EX_END_CATCH(RethrowTerminalExceptions)
+
+ return success;
+}
AppDomain *Object::GetAppDomain()
{
diff --git a/src/vm/object.h b/src/vm/object.h
index 2da0922bd3..c61defe2d7 100644
--- a/src/vm/object.h
+++ b/src/vm/object.h
@@ -326,6 +326,8 @@ class Object
#ifndef DACCESS_COMPILE
// Set app domain of object to current domain.
void SetAppDomain() { WRAPPER_NO_CONTRACT; SetAppDomain(::GetAppDomain()); }
+ BOOL SetAppDomainNoThrow();
+
#endif
// Set app domain of object to given domain - it can only be set once
diff --git a/src/vm/olevariant.cpp b/src/vm/olevariant.cpp
index ccf90a368f..75483fd5fe 100644
--- a/src/vm/olevariant.cpp
+++ b/src/vm/olevariant.cpp
@@ -1275,7 +1275,8 @@ void OleVariant::MarshalBoolArrayOleToCom(void *oleArray, BASEARRAYREF *pComArra
void OleVariant::MarshalBoolArrayComToOle(BASEARRAYREF *pComArray, void *oleArray,
MethodTable *pInterfaceMT, BOOL fBestFitMapping,
- BOOL fThrowOnUnmappableChar, BOOL fOleArrayIsValid)
+ BOOL fThrowOnUnmappableChar,
+ BOOL fOleArrayIsValid, SIZE_T cElements)
{
CONTRACTL
{
@@ -1288,10 +1289,9 @@ void OleVariant::MarshalBoolArrayComToOle(BASEARRAYREF *pComArray, void *oleArra
CONTRACTL_END;
ASSERT_PROTECTED(pComArray);
- SIZE_T elementCount = (*pComArray)->GetNumComponents();
VARIANT_BOOL *pOle = (VARIANT_BOOL *) oleArray;
- VARIANT_BOOL *pOleEnd = pOle + elementCount;
+ VARIANT_BOOL *pOleEnd = pOle + cElements;
UCHAR *pCom = (UCHAR *) (*pComArray)->GetDataPtr();
@@ -1365,7 +1365,8 @@ void OleVariant::MarshalWinBoolArrayOleToCom(void *oleArray, BASEARRAYREF *pComA
void OleVariant::MarshalWinBoolArrayComToOle(BASEARRAYREF *pComArray, void *oleArray,
MethodTable *pInterfaceMT, BOOL fBestFitMapping,
- BOOL fThrowOnUnmappableChar, BOOL fOleArrayIsValid)
+ BOOL fThrowOnUnmappableChar,
+ BOOL fOleArrayIsValid, SIZE_T cElements)
{
CONTRACTL
{
@@ -1378,10 +1379,9 @@ void OleVariant::MarshalWinBoolArrayComToOle(BASEARRAYREF *pComArray, void *oleA
CONTRACTL_END;
ASSERT_PROTECTED(pComArray);
- SIZE_T elementCount = (*pComArray)->GetNumComponents();
BOOL *pOle = (BOOL *) oleArray;
- BOOL *pOleEnd = pOle + elementCount;
+ BOOL *pOleEnd = pOle + cElements;
UCHAR *pCom = (UCHAR *) (*pComArray)->GetDataPtr();
@@ -1455,7 +1455,8 @@ void OleVariant::MarshalCBoolArrayOleToCom(void* oleArray, BASEARRAYREF* pComArr
void OleVariant::MarshalCBoolArrayComToOle(BASEARRAYREF* pComArray, void* oleArray,
MethodTable* pInterfaceMT, BOOL fBestFitMapping,
- BOOL fThrowOnUnmappableChar, BOOL fOleArrayIsValid)
+ BOOL fThrowOnUnmappableChar, BOOL fOleArrayIsValid,
+ SIZE_T cElements)
{
LIMITED_METHOD_CONTRACT;
@@ -1472,10 +1473,9 @@ void OleVariant::MarshalCBoolArrayComToOle(BASEARRAYREF* pComArray, void* oleArr
ASSERT_PROTECTED(pComArray);
_ASSERTE((*pComArray)->GetArrayElementType() == ELEMENT_TYPE_BOOLEAN);
-
- SIZE_T cbArray = (*pComArray)->GetNumComponents();
+
BYTE *pOle = (BYTE *) oleArray;
- BYTE *pOleEnd = pOle + cbArray;
+ BYTE *pOleEnd = pOle + cElements;
UCHAR *pCom = (UCHAR *) (*pComArray)->GetDataPtr();
@@ -1554,7 +1554,8 @@ void OleVariant::MarshalAnsiCharArrayOleToCom(void *oleArray, BASEARRAYREF *pCom
void OleVariant::MarshalAnsiCharArrayComToOle(BASEARRAYREF *pComArray, void *oleArray,
MethodTable *pInterfaceMT, BOOL fBestFitMapping,
- BOOL fThrowOnUnmappableChar, BOOL fOleArrayIsValid)
+ BOOL fThrowOnUnmappableChar, BOOL fOleArrayIsValid,
+ SIZE_T cElements)
{
CONTRACTL
{
@@ -1565,15 +1566,13 @@ void OleVariant::MarshalAnsiCharArrayComToOle(BASEARRAYREF *pComArray, void *ole
PRECONDITION(CheckPointer(pComArray));
}
CONTRACTL_END;
-
- SIZE_T elementCount = (*pComArray)->GetNumComponents();
const WCHAR *pCom = (const WCHAR *) (*pComArray)->GetDataPtr();
- if (!FitsIn<int>(elementCount))
+ if (!FitsIn<int>(cElements))
COMPlusThrowHR(COR_E_OVERFLOW);
- int cchCount = (int)elementCount;
+ int cchCount = (int)cElements;
int cbBuffer;
if (!ClrSafeInt<int>::multiply(cchCount, GetMaxDBCSCharByteSize(), cbBuffer))
@@ -1774,11 +1773,12 @@ void OleVariant::MarshalInterfaceArrayOleToCom(void *oleArray, BASEARRAYREF *pCo
void OleVariant::MarshalIUnknownArrayComToOle(BASEARRAYREF *pComArray, void *oleArray,
MethodTable *pElementMT, BOOL fBestFitMapping,
- BOOL fThrowOnUnmappableChar, BOOL fOleArrayIsValid)
+ BOOL fThrowOnUnmappableChar,
+ BOOL fOleArrayIsValid, SIZE_T cElements)
{
WRAPPER_NO_CONTRACT;
- MarshalInterfaceArrayComToOleHelper(pComArray, oleArray, pElementMT, FALSE);
+ MarshalInterfaceArrayComToOleHelper(pComArray, oleArray, pElementMT, FALSE, cElements);
}
void OleVariant::ClearInterfaceArray(void *oleArray, SIZE_T cElements, MethodTable *pInterfaceMT)
@@ -1919,7 +1919,8 @@ void OleVariant::MarshalBSTRArrayOleToCom(void *oleArray, BASEARRAYREF *pComArra
void OleVariant::MarshalBSTRArrayComToOle(BASEARRAYREF *pComArray, void *oleArray,
MethodTable *pInterfaceMT, BOOL fBestFitMapping,
- BOOL fThrowOnUnmappableChar, BOOL fOleArrayIsValid)
+ BOOL fThrowOnUnmappableChar,
+ BOOL fOleArrayIsValid, SIZE_T cElements)
{
CONTRACTL
{
@@ -1937,10 +1938,8 @@ void OleVariant::MarshalBSTRArrayComToOle(BASEARRAYREF *pComArray, void *oleArra
{
ASSERT_PROTECTED(pComArray);
- SIZE_T elementCount = (*pComArray)->GetNumComponents();
-
BSTR *pOle = (BSTR *) oleArray;
- BSTR *pOleEnd = pOle + elementCount;
+ BSTR *pOleEnd = pOle + cElements;
STRINGREF *pCom = (STRINGREF *) (*pComArray)->GetDataPtr();
@@ -2021,7 +2020,8 @@ void OleVariant::MarshalNonBlittableRecordArrayOleToCom(void *oleArray, BASEARRA
void OleVariant::MarshalNonBlittableRecordArrayComToOle(BASEARRAYREF *pComArray, void *oleArray,
MethodTable *pInterfaceMT, BOOL fBestFitMapping,
- BOOL fThrowOnUnmappableChar, BOOL fOleArrayIsValid)
+ BOOL fThrowOnUnmappableChar,
+ BOOL fOleArrayIsValid, SIZE_T cElements)
{
CONTRACTL
{
@@ -2035,12 +2035,11 @@ void OleVariant::MarshalNonBlittableRecordArrayComToOle(BASEARRAYREF *pComArray,
CONTRACTL_END;
ASSERT_PROTECTED(pComArray);
-
- SIZE_T elementCount = (*pComArray)->GetNumComponents();
+
SIZE_T elemSize = pInterfaceMT->GetNativeSize();
BYTE *pOle = (BYTE *) oleArray;
- BYTE *pOleEnd = pOle + elemSize * elementCount;
+ BYTE *pOleEnd = pOle + elemSize * cElements;
if (!fOleArrayIsValid)
{
@@ -2140,7 +2139,8 @@ void OleVariant::MarshalLPWSTRArrayOleToCom(void *oleArray, BASEARRAYREF *pComAr
void OleVariant::MarshalLPWSTRRArrayComToOle(BASEARRAYREF *pComArray, void *oleArray,
MethodTable *pInterfaceMT, BOOL fBestFitMapping,
- BOOL fThrowOnUnmappableChar, BOOL fOleArrayIsValid)
+ BOOL fThrowOnUnmappableChar,
+ BOOL fOleArrayIsValid, SIZE_T cElements)
{
CONTRACTL
{
@@ -2155,10 +2155,8 @@ void OleVariant::MarshalLPWSTRRArrayComToOle(BASEARRAYREF *pComArray, void *oleA
ASSERT_PROTECTED(pComArray);
- SIZE_T elementCount = (*pComArray)->GetNumComponents();
-
LPWSTR *pOle = (LPWSTR *) oleArray;
- LPWSTR *pOleEnd = pOle + elementCount;
+ LPWSTR *pOleEnd = pOle + cElements;
STRINGREF *pCom = (STRINGREF *) (*pComArray)->GetDataPtr();
@@ -2281,7 +2279,8 @@ void OleVariant::MarshalLPSTRArrayOleToCom(void *oleArray, BASEARRAYREF *pComArr
void OleVariant::MarshalLPSTRRArrayComToOle(BASEARRAYREF *pComArray, void *oleArray,
MethodTable *pInterfaceMT, BOOL fBestFitMapping,
- BOOL fThrowOnUnmappableChar, BOOL fOleArrayIsValid)
+ BOOL fThrowOnUnmappableChar,
+ BOOL fOleArrayIsValid, SIZE_T cElements)
{
CONTRACTL
{
@@ -2296,10 +2295,8 @@ void OleVariant::MarshalLPSTRRArrayComToOle(BASEARRAYREF *pComArray, void *oleAr
ASSERT_PROTECTED(pComArray);
- SIZE_T elementCount = (*pComArray)->GetNumComponents();
-
LPSTR *pOle = (LPSTR *) oleArray;
- LPSTR *pOleEnd = pOle + elementCount;
+ LPSTR *pOleEnd = pOle + cElements;
STRINGREF *pCom = (STRINGREF *) (*pComArray)->GetDataPtr();
@@ -2425,7 +2422,8 @@ void OleVariant::MarshalDateArrayOleToCom(void *oleArray, BASEARRAYREF *pComArra
void OleVariant::MarshalDateArrayComToOle(BASEARRAYREF *pComArray, void *oleArray,
MethodTable *pInterfaceMT, BOOL fBestFitMapping,
- BOOL fThrowOnUnmappableChar, BOOL fOleArrayIsValid)
+ BOOL fThrowOnUnmappableChar,
+ BOOL fOleArrayIsValid, SIZE_T cElements)
{
CONTRACTL
{
@@ -2438,11 +2436,9 @@ void OleVariant::MarshalDateArrayComToOle(BASEARRAYREF *pComArray, void *oleArra
CONTRACTL_END;
ASSERT_PROTECTED(pComArray);
-
- SIZE_T elementCount = (*pComArray)->GetNumComponents();
-
+
DATE *pOle = (DATE *) oleArray;
- DATE *pOleEnd = pOle + elementCount;
+ DATE *pOleEnd = pOle + cElements;
INT64 *pCom = (INT64 *) (*pComArray)->GetDataPtr();
@@ -2661,7 +2657,8 @@ void OleVariant::MarshalRecordArrayOleToCom(void *oleArray, BASEARRAYREF *pComAr
void OleVariant::MarshalRecordArrayComToOle(BASEARRAYREF *pComArray, void *oleArray,
MethodTable *pElementMT, BOOL fBestFitMapping,
- BOOL fThrowOnUnmappableChar, BOOL fOleArrayIsValid)
+ BOOL fThrowOnUnmappableChar,
+ BOOL fOleArrayIsValid, SIZE_T cElements)
{
CONTRACTL
{
@@ -2684,15 +2681,14 @@ void OleVariant::MarshalRecordArrayComToOle(BASEARRAYREF *pComArray, void *oleAr
{
// The array is blittable so we can simply copy it.
_ASSERTE(pComArray);
- SIZE_T elementCount = (*pComArray)->GetNumComponents();
SIZE_T elemSize = pElementMT->GetNativeSize();
- memcpyNoGCRefs(oleArray, (*pComArray)->GetDataPtr(), elementCount * elemSize);
+ memcpyNoGCRefs(oleArray, (*pComArray)->GetDataPtr(), cElements * elemSize);
}
else
{
// The array is non blittable so we need to marshal the elements.
_ASSERTE(pElementMT->HasLayout());
- MarshalNonBlittableRecordArrayComToOle(pComArray, oleArray, pElementMT, fBestFitMapping, fThrowOnUnmappableChar, fOleArrayIsValid);
+ MarshalNonBlittableRecordArrayComToOle(pComArray, oleArray, pElementMT, fBestFitMapping, fThrowOnUnmappableChar, fOleArrayIsValid, cElements);
}
}
@@ -3607,7 +3603,8 @@ void OleVariant::MarshalOleVariantForComVariant(VariantData *pCom, VARIANT *pOle
}
void OleVariant::MarshalInterfaceArrayComToOleHelper(BASEARRAYREF *pComArray, void *oleArray,
- MethodTable *pElementMT, BOOL bDefaultIsDispatch)
+ MethodTable *pElementMT, BOOL bDefaultIsDispatch,
+ SIZE_T cElements)
{
CONTRACTL
{
@@ -3620,7 +3617,7 @@ void OleVariant::MarshalInterfaceArrayComToOleHelper(BASEARRAYREF *pComArray, vo
CONTRACTL_END;
ASSERT_PROTECTED(pComArray);
- SIZE_T elementCount = (*pComArray)->GetNumComponents();
+
BOOL bDispatch = bDefaultIsDispatch;
BOOL bHeterogenous = (pElementMT == NULL);
@@ -3638,7 +3635,7 @@ void OleVariant::MarshalInterfaceArrayComToOleHelper(BASEARRAYREF *pComArray, vo
// Determine the start and the end of the data in the OLE array.
IUnknown **pOle = (IUnknown **) oleArray;
- IUnknown **pOleEnd = pOle + elementCount;
+ IUnknown **pOleEnd = pOle + cElements;
// Retrieve the start of the data in the managed array.
BASEARRAYREF unprotectedArray = *pComArray;
@@ -3787,11 +3784,12 @@ HRESULT OleVariant::ClearAndInsertContentsIntoByrefRecordVariant(VARIANT* pOle,
void OleVariant::MarshalIDispatchArrayComToOle(BASEARRAYREF *pComArray, void *oleArray,
MethodTable *pElementMT, BOOL fBestFitMapping,
- BOOL fThrowOnUnmappableChar, BOOL fOleArrayIsValid)
+ BOOL fThrowOnUnmappableChar, BOOL fOleArrayIsValid,
+ SIZE_T cElements)
{
WRAPPER_NO_CONTRACT;
- MarshalInterfaceArrayComToOleHelper(pComArray, oleArray, pElementMT, TRUE);
+ MarshalInterfaceArrayComToOleHelper(pComArray, oleArray, pElementMT, TRUE, cElements);
}
@@ -3913,7 +3911,8 @@ void OleVariant::MarshalCurrencyArrayOleToCom(void *oleArray, BASEARRAYREF *pCom
void OleVariant::MarshalCurrencyArrayComToOle(BASEARRAYREF *pComArray, void *oleArray,
MethodTable *pInterfaceMT, BOOL fBestFitMapping,
- BOOL fThrowOnUnmappableChar, BOOL fOleArrayIsValid)
+ BOOL fThrowOnUnmappableChar,
+ BOOL fOleArrayIsValid, SIZE_T cElements)
{
CONTRACTL
{
@@ -3925,11 +3924,10 @@ void OleVariant::MarshalCurrencyArrayComToOle(BASEARRAYREF *pComArray, void *ole
}
CONTRACTL_END;
- ASSERT_PROTECTED(pComArray);
- SIZE_T elementCount = (*pComArray)->GetNumComponents();
+ ASSERT_PROTECTED(pComArray);
CURRENCY *pOle = (CURRENCY *) oleArray;
- CURRENCY *pOleEnd = pOle + elementCount;
+ CURRENCY *pOleEnd = pOle + cElements;
DECIMAL *pCom = (DECIMAL *) (*pComArray)->GetDataPtr();
@@ -3992,7 +3990,8 @@ void OleVariant::MarshalVariantArrayOleToCom(void *oleArray, BASEARRAYREF *pComA
void OleVariant::MarshalVariantArrayComToOle(BASEARRAYREF *pComArray, void *oleArray,
MethodTable *pInterfaceMT, BOOL fBestFitMapping,
- BOOL fThrowOnUnmappableChar, BOOL fOleArrayIsValid)
+ BOOL fThrowOnUnmappableChar,
+ BOOL fOleArrayIsValid, SIZE_T cElements)
{
CONTRACTL
{
@@ -4607,9 +4606,9 @@ void OleVariant::MarshalSafeArrayForArrayRef(BASEARRAYREF *pArrayRef,
// of UnknownWrapper or DispatchWrapper. It shall use a different logic and marshal each
// element according to its specific default interface.
pInterfaceMT = NULL;
- }
- marshal->ComToOleArray(&Array, pSafeArray->pvData, pInterfaceMT, TRUE, FALSE, fSafeArrayIsValid);
- }
+ }
+ marshal->ComToOleArray(&Array, pSafeArray->pvData, pInterfaceMT, TRUE, FALSE, fSafeArrayIsValid, dwNumComponents);
+ }
if (pSafeArray->cDims != 1)
{
diff --git a/src/vm/olevariant.h b/src/vm/olevariant.h
index c733103e96..b89ace9d91 100644
--- a/src/vm/olevariant.h
+++ b/src/vm/olevariant.h
@@ -433,7 +433,8 @@ class OleVariant
// Helper called from MarshalIUnknownArrayComToOle and MarshalIDispatchArrayComToOle.
static void MarshalInterfaceArrayComToOleHelper(BASEARRAYREF* pComArray, void* oleArray,
- MethodTable* pElementMT, BOOL bDefaultIsDispatch);
+ MethodTable* pElementMT, BOOL bDefaultIsDispatch,
+ SIZE_T cElements);
#endif // FEATURE_COMINTEROP
struct Marshaler
@@ -445,7 +446,8 @@ class OleVariant
#endif // FEATURE_COMINTEROP
void (*OleToComArray)(void* oleArray, BASEARRAYREF* pComArray, MethodTable* pInterfaceMT);
void (*ComToOleArray)(BASEARRAYREF* pComArray, void* oleArray, MethodTable* pInterfaceMT,
- BOOL fBestFitMapping, BOOL fThrowOnUnmappableChar, BOOL fOleArrayIsValid);
+ BOOL fBestFitMapping, BOOL fThrowOnUnmappableChar,
+ BOOL fOleArrayIsValid,SIZE_T cElements);
void (*ClearOleArray)(void* oleArray, SIZE_T cElements, MethodTable* pInterfaceMT);
};
@@ -464,33 +466,38 @@ private:
static void MarshalBoolArrayOleToCom(void *oleArray, BASEARRAYREF* pComArray,
MethodTable* pInterfaceMT);
static void MarshalBoolArrayComToOle(BASEARRAYREF* pComArray, void* oleArray,
- MethodTable* pInterfaceMT, BOOL fBestFitMapping,
- BOOL fThrowOnUnmappableChar, BOOL fOleArrayIsValid);
+ MethodTable* pInterfaceMT, BOOL fBestFitMapping,
+ BOOL fThrowOnUnmappableChar, BOOL fOleArrayIsValid,
+ SIZE_T cElements);
static void MarshalWinBoolArrayOleToCom(void* oleArray, BASEARRAYREF* pComArray,
MethodTable* pInterfaceMT);
static void MarshalWinBoolArrayComToOle(BASEARRAYREF* pComArray, void* oleArray,
MethodTable* pInterfaceMT, BOOL fBestFitMapping,
- BOOL fThrowOnUnmappableChar, BOOL fOleArrayValid);
+ BOOL fThrowOnUnmappableChar, BOOL fOleArrayValid,
+ SIZE_T cElements);
static void MarshalCBoolVariantOleToCom(VARIANT* pOleVariant, VariantData* pComVariant);
static void MarshalCBoolVariantComToOle(VariantData* pComVariant, VARIANT* pOleVariant);
static void MarshalCBoolVariantOleRefToCom(VARIANT* pOleVariant, VariantData* pComVariant);
static void MarshalCBoolArrayOleToCom(void* oleArray, BASEARRAYREF* pComArray,
MethodTable* pInterfaceMT);
static void MarshalCBoolArrayComToOle(BASEARRAYREF* pComArray, void* oleArray,
- MethodTable* pInterfaceMT, BOOL fBestFitMapping,
- BOOL fThrowOnUnmappableChar, BOOL fOleArrayValid);
+ MethodTable* pInterfaceMT, BOOL fBestFitMapping,
+ BOOL fThrowOnUnmappableChar, BOOL fOleArrayValid,
+ SIZE_T cElements);
static void MarshalAnsiCharArrayOleToCom(void* oleArray, BASEARRAYREF* pComArray,
MethodTable* pInterfaceMT);
static void MarshalAnsiCharArrayComToOle(BASEARRAYREF* pComArray, void* oleArray,
MethodTable* pInterfaceMT, BOOL fBestFitMapping,
- BOOL fThrowOnUnmappableChar, BOOL fOleArrayValid);
+ BOOL fThrowOnUnmappableChar, BOOL fOleArrayValid,
+ SIZE_T cElements);
#ifdef FEATURE_COMINTEROP
static void MarshalIDispatchArrayComToOle(BASEARRAYREF* pComArray, void* oleArray,
MethodTable* pInterfaceMT, BOOL fBestFitMapping,
- BOOL fThrowOnUnmappableChar, BOOL fOleArrayValid);
+ BOOL fThrowOnUnmappableChar, BOOL fOleArrayValid,
+ SIZE_T cElements);
#endif // FEATURE_COMINTEROP
#ifdef FEATURE_COMINTEROP
@@ -498,7 +505,8 @@ private:
MethodTable* pInterfaceMT);
static void MarshalBSTRArrayComToOle(BASEARRAYREF* pComArray, void* oleArray,
MethodTable* pInterfaceMT, BOOL fBestFitMapping,
- BOOL fThrowOnUnmappableChar, BOOL fOleArrayValid);
+ BOOL fThrowOnUnmappableChar, BOOL fOleArrayValid,
+ SIZE_T cElements);
static void ClearBSTRArray(void* oleArray, SIZE_T cElements, MethodTable* pInterfaceMT);
#endif // FEATURE_COMINTEROP
@@ -506,32 +514,38 @@ private:
MethodTable* pInterfaceMT);
static void MarshalNonBlittableRecordArrayComToOle(BASEARRAYREF* pComArray, void* oleArray,
MethodTable* pInterfaceMT, BOOL fBestFitMapping,
- BOOL fThrowOnUnmappableChar, BOOL fOleArrayValid);
+ BOOL fThrowOnUnmappableChar, BOOL fOleArrayValid,
+ SIZE_T cElements);
static void ClearNonBlittableRecordArray(void* oleArray, SIZE_T cElements, MethodTable* pInterfaceMT);
static void MarshalLPWSTRArrayOleToCom(void* oleArray, BASEARRAYREF* pComArray,
MethodTable* pInterfaceMT);
static void MarshalLPWSTRRArrayComToOle(BASEARRAYREF* pComArray, void* oleArray,
MethodTable* pInterfaceMT, BOOL fBestFitMapping,
- BOOL fThrowOnUnmappableChar, BOOL fOleArrayValid);
+ BOOL fThrowOnUnmappableChar, BOOL fOleArrayValid,
+ SIZE_T cElements);
static void ClearLPWSTRArray(void* oleArray, SIZE_T cElements, MethodTable* pInterfaceMT);
static void MarshalLPSTRArrayOleToCom(void* oleArray, BASEARRAYREF* pComArray,
MethodTable* pInterfaceMT);
static void MarshalLPSTRRArrayComToOle(BASEARRAYREF* pComArray, void* oleArray,
MethodTable* pInterfaceMT, BOOL fBestFitMapping,
- BOOL fThrowOnUnmappableChar, BOOL fOleArrayValid);
+ BOOL fThrowOnUnmappableChar, BOOL fOleArrayValid,
+ SIZE_T cElements);
static void ClearLPSTRArray(void* oleArray, SIZE_T cElements, MethodTable* pInterfaceMT);
static void MarshalDateArrayOleToCom(void* oleArray, BASEARRAYREF* pComArray,
MethodTable* pInterfaceMT);
static void MarshalDateArrayComToOle(BASEARRAYREF* pComArray, void* oleArray,
MethodTable* pInterfaceMT, BOOL fBestFitMapping,
- BOOL fThrowOnUnmappableChar, BOOL fOleArrayValid);
+ BOOL fThrowOnUnmappableChar, BOOL fOleArrayValid,
+ SIZE_T cElements);
static void MarshalRecordArrayOleToCom(void* oleArray, BASEARRAYREF* pComArray, MethodTable* pElementMT);
static void MarshalRecordArrayComToOle(BASEARRAYREF* pComArray, void* oleArray, MethodTable* pElementMT,
- BOOL fBestFitMapping, BOOL fThrowOnUnmappableChar, BOOL fOleArrayValid);
+ BOOL fBestFitMapping, BOOL fThrowOnUnmappableChar,
+ BOOL fOleArrayValid,
+ SIZE_T cElements);
static void ClearRecordArray(void* oleArray, SIZE_T cElements, MethodTable* pElementMT);
#ifdef FEATURE_COMINTEROP
@@ -540,7 +554,8 @@ private:
MethodTable* pInterfaceMT);
static void MarshalIUnknownArrayComToOle(BASEARRAYREF* pComArray, void* oleArray,
MethodTable* pInterfaceMT, BOOL fBestFitMapping,
- BOOL fThrowOnUnmappableChar, BOOL fOleArrayValid);
+ BOOL fThrowOnUnmappableChar, BOOL fOleArrayValid,
+ SIZE_T cElements);
static void ClearInterfaceArray(void* oleArray, SIZE_T cElements, MethodTable* pInterfaceMT);
static void MarshalBoolVariantOleToCom(VARIANT* pOleVariant, VariantData* pComVariant);
@@ -581,13 +596,15 @@ private:
MethodTable* pInterfaceMT);
static void MarshalCurrencyArrayComToOle(BASEARRAYREF* pComArray, void* oleArray,
MethodTable* pInterfaceMT, BOOL fBestFitMapping,
- BOOL fThrowOnUnmappableChar, BOOL fOleArrayValid);
+ BOOL fThrowOnUnmappableChar, BOOL fOleArrayValid,
+ SIZE_T cElements);
static void MarshalVariantArrayOleToCom(void* oleArray, BASEARRAYREF* pComArray,
MethodTable* pInterfaceMT);
static void MarshalVariantArrayComToOle(BASEARRAYREF* pComArray, void* oleArray,
MethodTable* pInterfaceMT, BOOL fBestFitMapping,
- BOOL fThrowOnUnmappableChar, BOOL fOleArrayValid);
+ BOOL fThrowOnUnmappableChar, BOOL fOleArrayValid,
+ SIZE_T cElements);
static void ClearVariantArray(void* oleArray, SIZE_T cElements, MethodTable* pInterfaceMT);
#ifdef FEATURE_CLASSIC_COMINTEROP
diff --git a/src/vm/stackwalk.h b/src/vm/stackwalk.h
index 3d6dbdcb14..004d673a2a 100644
--- a/src/vm/stackwalk.h
+++ b/src/vm/stackwalk.h
@@ -324,6 +324,13 @@ public:
return &codeInfo;
}
+ GCInfoToken GetGCInfoToken()
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+ _ASSERTE(isFrameless);
+ return codeInfo.GetGCInfoToken();
+ }
+
PTR_VOID GetGCInfo()
{
LIMITED_METHOD_DAC_CONTRACT;
diff --git a/src/vm/stubhelpers.cpp b/src/vm/stubhelpers.cpp
index 673d96bfe6..5996f5ddee 100644
--- a/src/vm/stubhelpers.cpp
+++ b/src/vm/stubhelpers.cpp
@@ -143,7 +143,7 @@ void StubHelpers::ProcessByrefValidationList()
{
CONTRACTL
{
- THROWS;
+ NOTHROW;
GC_NOTRIGGER;
MODE_ANY;
}
@@ -168,8 +168,16 @@ void StubHelpers::ProcessByrefValidationList()
}
EX_CATCH
{
- FormatValidationMessage(entry.pMD, errorString);
- EEPOLICY_HANDLE_FATAL_ERROR_WITH_MESSAGE(COR_E_EXECUTIONENGINE, errorString.GetUnicode());
+ EX_TRY
+ {
+ FormatValidationMessage(entry.pMD, errorString);
+ EEPOLICY_HANDLE_FATAL_ERROR_WITH_MESSAGE(COR_E_EXECUTIONENGINE, errorString.GetUnicode());
+ }
+ EX_CATCH
+ {
+ EEPOLICY_HANDLE_FATAL_ERROR(COR_E_EXECUTIONENGINE);
+ }
+ EX_END_CATCH_UNREACHABLE;
}
EX_END_CATCH_UNREACHABLE;
@@ -1245,9 +1253,7 @@ FCIMPL2(void*, StubHelpers::GetDelegateTarget, DelegateObject *pThisUNSAFE, UINT
UINT_PTR target = (UINT_PTR)orefThis->GetMethodPtrAux();
// The lowest bit is used to distinguish between MD and target on 64-bit.
-#ifdef _TARGET_AMD64_
target = (target << 1) | 1;
-#endif // _TARGET_AMD64_
// On 64-bit we pass the real target to the stub-for-host through this out argument,
// see IL code gen in NDirectStubLinker::DoNDirect for details.
diff --git a/src/vm/synch.cpp b/src/vm/synch.cpp
index da51c948a8..216dd31587 100644
--- a/src/vm/synch.cpp
+++ b/src/vm/synch.cpp
@@ -60,6 +60,33 @@ void CLREventBase::CreateAutoEvent (BOOL bInitialState // If TRUE, initial stat
}
+BOOL CLREventBase::CreateAutoEventNoThrow (BOOL bInitialState // If TRUE, initial state is signalled
+ )
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ SO_TOLERANT;
+ // disallow creation of Crst before EE starts
+ // Can not assert here. ASP.Net uses our Threadpool before EE is started.
+ PRECONDITION((m_handle == INVALID_HANDLE_VALUE));
+ PRECONDITION((!IsOSEvent()));
+ }
+ CONTRACTL_END;
+
+ EX_TRY
+ {
+ CreateAutoEvent(bInitialState);
+ }
+ EX_CATCH
+ {
+ }
+ EX_END_CATCH(SwallowAllExceptions);
+
+ return IsValid();
+}
+
void CLREventBase::CreateManualEvent (BOOL bInitialState // If TRUE, initial state is signalled
)
{
@@ -100,6 +127,32 @@ void CLREventBase::CreateManualEvent (BOOL bInitialState // If TRUE, initial st
}
}
+BOOL CLREventBase::CreateManualEventNoThrow (BOOL bInitialState // If TRUE, initial state is signalled
+ )
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ SO_TOLERANT;
+ // disallow creation of Crst before EE starts
+ // Can not assert here. ASP.Net uses our Threadpool before EE is started.
+ PRECONDITION((m_handle == INVALID_HANDLE_VALUE));
+ PRECONDITION((!IsOSEvent()));
+ }
+ CONTRACTL_END;
+
+ EX_TRY
+ {
+ CreateManualEvent(bInitialState);
+ }
+ EX_CATCH
+ {
+ }
+ EX_END_CATCH(SwallowAllExceptions);
+
+ return IsValid();
+}
void CLREventBase::CreateMonitorEvent(SIZE_T Cookie)
{
@@ -340,6 +393,29 @@ void CLREventBase::CreateOSAutoEvent (BOOL bInitialState // If TRUE, initial st
m_handle = h;
}
+BOOL CLREventBase::CreateOSAutoEventNoThrow (BOOL bInitialState // If TRUE, initial state is signalled
+ )
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ // disallow creation of Crst before EE starts
+ PRECONDITION((m_handle == INVALID_HANDLE_VALUE));
+ }
+ CONTRACTL_END;
+
+ EX_TRY
+ {
+ CreateOSAutoEvent(bInitialState);
+ }
+ EX_CATCH
+ {
+ }
+ EX_END_CATCH(SwallowAllExceptions);
+
+ return IsValid();
+}
void CLREventBase::CreateOSManualEvent (BOOL bInitialState // If TRUE, initial state is signalled
)
@@ -365,6 +441,29 @@ void CLREventBase::CreateOSManualEvent (BOOL bInitialState // If TRUE, initial
m_handle = h;
}
+BOOL CLREventBase::CreateOSManualEventNoThrow (BOOL bInitialState // If TRUE, initial state is signalled
+ )
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ // disallow creation of Crst before EE starts
+ PRECONDITION((m_handle == INVALID_HANDLE_VALUE));
+ }
+ CONTRACTL_END;
+
+ EX_TRY
+ {
+ CreateOSManualEvent(bInitialState);
+ }
+ EX_CATCH
+ {
+ }
+ EX_END_CATCH(SwallowAllExceptions);
+
+ return IsValid();
+}
void CLREventBase::CloseEvent()
{
diff --git a/src/vm/synch.h b/src/vm/synch.h
index f63a78d10d..8605eea062 100644
--- a/src/vm/synch.h
+++ b/src/vm/synch.h
@@ -36,6 +36,10 @@ public:
void CreateAutoEvent(BOOL bInitialState);
void CreateManualEvent(BOOL bInitialState);
+ // Non-throwing variants of the functions above
+ BOOL CreateAutoEventNoThrow(BOOL bInitialState);
+ BOOL CreateManualEventNoThrow(BOOL bInitialState);
+
void CreateMonitorEvent(SIZE_T Cookie); // robust against initialization races - for exclusive use by AwareLock
#ifdef FEATURE_RWLOCK
@@ -47,6 +51,10 @@ public:
void CreateOSAutoEvent (BOOL bInitialState);
void CreateOSManualEvent (BOOL bInitialState);
+ // Non-throwing variants of the functions above
+ BOOL CreateOSAutoEventNoThrow (BOOL bInitialState);
+ BOOL CreateOSManualEventNoThrow (BOOL bInitialState);
+
void CloseEvent();
BOOL IsValid() const
diff --git a/src/vm/wks/CMakeLists.txt b/src/vm/wks/CMakeLists.txt
index a2468caba6..0ff0ccb9a6 100644
--- a/src/vm/wks/CMakeLists.txt
+++ b/src/vm/wks/CMakeLists.txt
@@ -60,7 +60,7 @@ endif()
add_custom_command(
# The AsmConstants.inc will be built in the pre-build phase of the cee_wks build
TARGET cee_wks PRE_BUILD
- COMMAND ${POWERSHELL} -NoProfile -ExecutionPolicy Bypass \"& \"\"${VM_DIR}/h2inc.ps1\"\"\" \"\"\"${VM_DIR}/${ARCH_SOURCES_DIR}/asmconstants.h\"\"\" >"${CMAKE_CURRENT_BINARY_DIR}/AsmConstants.tmp"
+ COMMAND ${POWERSHELL} -NoProfile -ExecutionPolicy Bypass -NonInteractive \"& \"\"${VM_DIR}/h2inc.ps1\"\"\" \"\"\"${VM_DIR}/${ARCH_SOURCES_DIR}/asmconstants.h\"\"\" >"${CMAKE_CURRENT_BINARY_DIR}/AsmConstants.tmp"
COMMAND ${CMAKE_CXX_COMPILER} ${DEFINITIONS} /EP "${CMAKE_CURRENT_BINARY_DIR}/AsmConstants.tmp" >"${CMAKE_CURRENT_BINARY_DIR}/AsmConstants.inc"
)
diff --git a/src/vm/wks/wks.targets b/src/vm/wks/wks.targets
index b9f57e882e..04562365f6 100644
--- a/src/vm/wks/wks.targets
+++ b/src/vm/wks/wks.targets
@@ -251,7 +251,6 @@
<ItemGroup>
<CppCompile Include="$(VmSourcesDir)\AssemblyNativeResource.cpp" />
<CppCompile Include="$(VmSourcesDir)\coverage.cpp" />
- <CppCompile Include="$(VmSourcesDir)\DbgGcInfoDecoder.cpp" />
<CppCompile Include="$(VmSourcesDir)\dwreport.cpp" />
<CppCompile Include="$(VmSourcesDir)\EnCEE.cpp" />
<CppCompile Include="$(VmSourcesDir)\ExceptionHandling.cpp" />
diff --git a/sync.sh b/sync.sh
index e1b6401fc1..ab23561ac0 100755
--- a/sync.sh
+++ b/sync.sh
@@ -26,7 +26,7 @@ if [ $# == 0 ]; then
sync_src=true
fi
-while [[ $# > 0 ]]
+while [[ $# -gt 0 ]]
do
opt="$1"
case $opt in
@@ -61,8 +61,8 @@ fi
if [ "$sync_packages" == true ]; then
options="$options /t:RestoreNETCorePlatforms /p:RestoreDuringBuild=true"
echo "Restoring all packages..."
- echo -e "\n$working_tree_root/Tools/corerun $working_tree_root/Tools/MSBuild.exe $working_tree_root/build.proj $options $unprocessedBuildArgs" >> $sync_log
- $working_tree_root/Tools/corerun $working_tree_root/Tools/MSBuild.exe $working_tree_root/build.proj $options $unprocessedBuildArgs
+ echo -e "\n$working_tree_root/Tools/dotnetcli/dotnet $working_tree_root/Tools/MSBuild.exe $working_tree_root/build.proj $options $unprocessedBuildArgs" >> $sync_log
+ $working_tree_root/Tools/dotnetcli/dotnet $working_tree_root/Tools/MSBuild.exe $working_tree_root/build.proj $options $unprocessedBuildArgs
if [ $? -ne 0 ]
then
echo -e "\nPackage restored failed. Aborting sync." >> $sync_log
diff --git a/tests/arm64/Tests.lst b/tests/arm64/Tests.lst
index 255e79a647..d120adef45 100644
--- a/tests/arm64/Tests.lst
+++ b/tests/arm64/Tests.lst
@@ -2839,7 +2839,7 @@ RelativePath=baseservices\threading\mutex\openexisting\openmutexpos4\openmutexpo
WorkingDir=baseservices\threading\mutex\openexisting\openmutexpos4
Expected=0
MaxAllowedDurationSeconds=600
-Categories=NEW;EXPECTED_PASS
+Categories=NEW;EXPECTED_PASS;GCSTRESS_FAIL;ISSUE_6060
HostStyle=0
[threadstartarray.cmd_406]
RelativePath=baseservices\threading\paramthreadstart\threadstartarray\threadstartarray.cmd
@@ -3329,7 +3329,7 @@ RelativePath=baseservices\threading\regressions\269336\objmonhelper\objmonhelper
WorkingDir=baseservices\threading\regressions\269336\objmonhelper
Expected=0
MaxAllowedDurationSeconds=600
-Categories=NEW;EXPECTED_PASS
+Categories=NEW;EXPECTED_PASS;GCSTRESS_FAIL;ISSUE_6065
HostStyle=0
[30032.cmd_476]
RelativePath=baseservices\threading\regressions\30032\30032\30032.cmd
@@ -40198,7 +40198,7 @@ RelativePath=JIT\Methodical\Arrays\lcs\_dbglcsvalbox\_dbglcsvalbox.cmd
WorkingDir=JIT\Methodical\Arrays\lcs\_dbglcsvalbox
Expected=0
MaxAllowedDurationSeconds=600
-Categories=Pri0;JIT;EXPECTED_PASS
+Categories=Pri0;JIT;EXPECTED_PASS;GCSTRESS_FAIL;ISSUE_6065
HostStyle=0
[_il_dbglcs_ldlen.cmd_5816]
RelativePath=JIT\Methodical\Arrays\lcs\_il_dbglcs_ldlen\_il_dbglcs_ldlen.cmd
@@ -40268,7 +40268,7 @@ RelativePath=JIT\Methodical\Arrays\lcs\_rellcsvalbox\_rellcsvalbox.cmd
WorkingDir=JIT\Methodical\Arrays\lcs\_rellcsvalbox
Expected=0
MaxAllowedDurationSeconds=600
-Categories=Pri0;JIT;EXPECTED_PASS
+Categories=Pri0;JIT;EXPECTED_PASS;GCSTRESS_FAIL;ISSUE_6065
HostStyle=0
[_speed_dbglcs.cmd_5826]
RelativePath=JIT\Methodical\Arrays\lcs\_speed_dbglcs\_speed_dbglcs.cmd
@@ -40324,7 +40324,7 @@ RelativePath=JIT\Methodical\Arrays\lcs\_speed_dbglcsvalbox\_speed_dbglcsvalbox.c
WorkingDir=JIT\Methodical\Arrays\lcs\_speed_dbglcsvalbox
Expected=0
MaxAllowedDurationSeconds=600
-Categories=Pri0;JIT;EXPECTED_PASS
+Categories=Pri0;JIT;EXPECTED_PASS;GCSTRESS_FAIL;ISSUE_6065
HostStyle=0
[_speed_rellcs.cmd_5834]
RelativePath=JIT\Methodical\Arrays\lcs\_speed_rellcs\_speed_rellcs.cmd
@@ -40380,7 +40380,7 @@ RelativePath=JIT\Methodical\Arrays\lcs\_speed_rellcsvalbox\_speed_rellcsvalbox.c
WorkingDir=JIT\Methodical\Arrays\lcs\_speed_rellcsvalbox
Expected=0
MaxAllowedDurationSeconds=600
-Categories=Pri0;JIT;EXPECTED_PASS
+Categories=Pri0;JIT;EXPECTED_PASS;GCSTRESS_FAIL;ISSUE_6065
HostStyle=0
[_dbgarrres.cmd_5842]
RelativePath=JIT\Methodical\Arrays\misc\_dbgarrres\_dbgarrres.cmd
@@ -55451,7 +55451,7 @@ RelativePath=JIT\Performance\CodeQuality\BenchmarksGame\binarytrees\binarytrees\
WorkingDir=JIT\Performance\CodeQuality\BenchmarksGame\binarytrees\binarytrees
Expected=0
MaxAllowedDurationSeconds=600
-Categories=Pri0;EXPECTED_PASS;LONG_RUNNING
+Categories=Pri0;EXPECTED_PASS;LONG_RUNNING;GCSTRESS_FAIL;ISSUE_6065
HostStyle=0
[fasta.cmd_8016]
RelativePath=JIT\Performance\CodeQuality\BenchmarksGame\fasta\fasta\fasta.cmd
@@ -55577,7 +55577,7 @@ RelativePath=JIT\Performance\CodeQuality\V8\DeltaBlue\DeltaBlue\DeltaBlue.cmd
WorkingDir=JIT\Performance\CodeQuality\V8\DeltaBlue\DeltaBlue
Expected=0
MaxAllowedDurationSeconds=1000
-Categories=Pri0;EXPECTED_PASS;LONG_RUNNING
+Categories=Pri0;EXPECTED_PASS;LONG_RUNNING;GCSTRESS_FAIL;ISSUE_6065
HostStyle=0
[Richards.cmd_8034]
RelativePath=JIT\Performance\CodeQuality\V8\Richards\Richards\Richards.cmd
@@ -61107,7 +61107,7 @@ RelativePath=JIT\Regression\CLR-x86-JIT\V1.1-M1-Beta1\b143840\b143840\b143840.cm
WorkingDir=JIT\Regression\CLR-x86-JIT\V1.1-M1-Beta1\b143840\b143840
Expected=0
MaxAllowedDurationSeconds=600
-Categories=Pri0;EXPECTED_PASS;GC_GEN0
+Categories=Pri0;EXPECTED_PASS
HostStyle=0
[b102879.cmd_8847]
RelativePath=JIT\Regression\CLR-x86-JIT\V1.2-Beta1\b102879\b102879\b102879.cmd
diff --git a/tests/buildtest.cmd b/tests/buildtest.cmd
index 6fcb3e7467..d5f89358ca 100644
--- a/tests/buildtest.cmd
+++ b/tests/buildtest.cmd
@@ -33,6 +33,7 @@ set __BuildSequential=
set __TestPriority=
set __msbuildCleanBuildArgs=
set __verbosity=normal
+set __UpdateInvalidPackagesArg=
REM unprocessedBuildArgs are args that we pass to msbuild (e.g. /p:__BuildArch=x64)
set "__args= %*"
@@ -49,32 +50,34 @@ if /i "%1" == "-h" goto Usage
if /i "%1" == "/help" goto Usage
if /i "%1" == "-help" goto Usage
-if /i "%1" == "x64" (set __BuildArch=x64&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop)
-if /i "%1" == "x86" (set __BuildArch=x86&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop)
-if /i "%1" == "arm" (set __BuildArch=arm&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop)
-if /i "%1" == "arm64" (set __BuildArch=arm64&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop)
+if /i "%1" == "x64" (set __BuildArch=x64&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop)
+if /i "%1" == "x86" (set __BuildArch=x86&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop)
+if /i "%1" == "arm" (set __BuildArch=arm&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop)
+if /i "%1" == "arm64" (set __BuildArch=arm64&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop)
+
+if /i "%1" == "debug" (set __BuildType=Debug&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop)
+if /i "%1" == "release" (set __BuildType=Release&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop)
+if /i "%1" == "checked" (set __BuildType=Checked&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop)
-if /i "%1" == "debug" (set __BuildType=Debug&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop)
-if /i "%1" == "release" (set __BuildType=Release&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop)
-if /i "%1" == "checked" (set __BuildType=Checked&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop)
+if /i "%1" == "clean" (set __CleanBuild=1&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop)
-if /i "%1" == "clean" (set __CleanBuild=1&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop)
+if /i "%1" == "vs2013" (set __VSVersion=%1&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop)
+if /i "%1" == "vs2015" (set __VSVersion=%1&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop)
-if /i "%1" == "vs2013" (set __VSVersion=%1&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop)
-if /i "%1" == "vs2015" (set __VSVersion=%1&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop)
+if /i "%1" == "crossgen" (set __crossgen=true&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop)
+if /i "%1" == "ilasmroundtrip" (set __ILAsmRoundtrip=true&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop)
+if /i "%1" == "sequential" (set __BuildSequential=1&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop)
+if /i "%1" == "priority" (set __TestPriority=%2&set processedArgs=!processedArgs! %1 %2&shift&shift&goto Arg_Loop)
-if /i "%1" == "crossgen" (set __crossgen=true&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop)
-if /i "%1" == "ilasmroundtrip" (set __ILAsmRoundtrip=true&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop)
-if /i "%1" == "sequential" (set __BuildSequential=1&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop)
-if /i "%1" == "priority" (set __TestPriority=%2&set processedArgs=!processedArgs! %1 %2&shift&shift&goto Arg_Loop)
+if /i "%1" == "verbose" (set __verbosity=detailed&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop)
-if /i "%1" == "verbose" (set __verbosity=detailed&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop)
+if /i "%1" == "skipmanaged" (set __SkipManaged=1&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop)
-if /i "%1" == "skipmanaged" (set __SkipManaged=1&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop)
+if /i "%1" == "updateinvalidpackages" (set __UpdateInvalidPackagesArg=/t:UpdateInvalidPackageVersions&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop)
@REM It was initially /toolset_dir. Not sure why, since it doesn't match the other usage.
-if /i "%1" == "/toolset_dir" (set __ToolsetDir=%2&set __PassThroughArgs=%__PassThroughArgs% %2&set processedArgs=!processedArgs! %1 %2&shift&shift&goto Arg_Loop)
-if /i "%1" == "toolset_dir" (set __ToolsetDir=%2&set __PassThroughArgs=%__PassThroughArgs% %2&set processedArgs=!processedArgs! %1 %2&shift&shift&goto Arg_Loop)
+if /i "%1" == "/toolset_dir" (set __ToolsetDir=%2&set __PassThroughArgs=%__PassThroughArgs% %2&set processedArgs=!processedArgs! %1 %2&shift&shift&goto Arg_Loop)
+if /i "%1" == "toolset_dir" (set __ToolsetDir=%2&set __PassThroughArgs=%__PassThroughArgs% %2&set processedArgs=!processedArgs! %1 %2&shift&shift&goto Arg_Loop)
if [!processedArgs!]==[] (
call set unprocessedBuildArgs=!__args!
@@ -183,6 +186,8 @@ REM ===
REM =========================================================================================
call %__TestDir%\setup-runtime-dependencies.cmd /arch %__BuildArch% /outputdir %__BinDir%
+if NOT "%__UpdateInvalidPackagesArg%" == "" goto skipnative
+
REM =========================================================================================
REM ===
REM === Native test build section
@@ -237,6 +242,8 @@ if errorlevel 1 exit /b 1
REM endlocal to rid us of environment changes from vcvarsall.bat
endlocal
+:skipnative
+
if defined __SkipManaged exit /b 0
REM =========================================================================================
@@ -272,7 +279,7 @@ if defined __TestPriority (
)
set __BuildLogRootName=Tests_Managed
-call :msbuild "%__ProjectFilesDir%\build.proj" %__msbuildManagedBuildArgs%
+call :msbuild "%__ProjectFilesDir%\build.proj" %__msbuildManagedBuildArgs% %__UpdateInvalidPackagesArg%
if errorlevel 1 exit /b 1
set CORE_ROOT=%__TestBinDir%\Tests\Core_Root
@@ -359,6 +366,7 @@ echo 666: Build all tests with priority 0, 1 ... 666
echo sequential: force a non-parallel build ^(default is to build in parallel
echo using all processors^).
echo IlasmRoundTrip: enables ilasm round trip build and run of the tests before executing them.
+echo updateinvalidpackages: enables updating package versions in all test project.json files
echo verbose: enables detailed file logging for the msbuild tasks into the msbuild log file.
exit /b 1
diff --git a/tests/dir.props b/tests/dir.props
index 870d4e39be..425b460b66 100644
--- a/tests/dir.props
+++ b/tests/dir.props
@@ -42,20 +42,28 @@
<PropertyGroup>
<ValidatePackageVersions>true</ValidatePackageVersions>
<ProhibitFloatingDependencies>true</ProhibitFloatingDependencies>
+
+ <CoreFxExpectedPrerelease>rc3-24117-00</CoreFxExpectedPrerelease>
+ <CoreClrPackageVersion>1.0.4-beta-24325-02</CoreClrPackageVersion>
+
+ <CoreFxVersionsIdentityRegex>^(?i)((System\..*)|(Microsoft\.CSharp)|(Microsoft\.NETCore.*)|(Microsoft\.Win32\..*)|(Microsoft\.VisualBasic))(?&lt;!TestData)$</CoreFxVersionsIdentityRegex>
</PropertyGroup>
<ItemGroup>
- <ValidationPattern Include="^(?i)((System\..%2A)|(Microsoft\.CSharp)|(Microsoft\.NETCore.%2A)|(Microsoft\.Win32\..%2A)|(Microsoft\.VisualBasic))(?&lt;!TestData)$">
- <ExpectedPrerelease>rc3-24117-00</ExpectedPrerelease>
+ <ValidationPattern Include="CoreFxVersions">
+ <IdentityRegex>$(CoreFxVersionsIdentityRegex)</IdentityRegex>
+ <ExpectedPrerelease>$(CoreFxExpectedPrerelease)</ExpectedPrerelease>
</ValidationPattern>
- <ValidationPattern Include="^(?i)(xunit(\.assert|\.core|\.runner\.(utility|msbuild))?)$">
+ <ValidationPattern Include="XunitPackageVersions">
+ <IdentityRegex>^(?i)(xunit(\.assert|\.core|\.runner\.(utility|msbuild))?)$</IdentityRegex>
<ExpectedVersion>$(XunitPackageVersion)</ExpectedVersion>
</ValidationPattern>
- <!-- Add a dummy value so that the item isn't removed by msbuild. Without the | this item doesn't show up later. -->
- <ValidationPattern Include="^(?i)(xunit\.console\.netcore|dummy value)$">
+ <ValidationPattern Include="XunitConsoleVersion">
+ <IdentityRegex>^(?i)(xunit\.console\.netcore)$</IdentityRegex>
<ExpectedVersion>1.0.2-prerelease-00101</ExpectedVersion>
</ValidationPattern>
- <ValidationPattern Include="^(?i)Microsoft\.DotNet\.xunit\.performance.%2A$">
+ <ValidationPattern Include="XunitPerformanceVersion">
+ <IdentityRegex>^(?i)Microsoft\.DotNet\.xunit\.performance.*$</IdentityRegex>
<ExpectedVersion>1.0.0-alpha-build0035</ExpectedVersion>
</ValidationPattern>
</ItemGroup>
diff --git a/tests/issues.targets b/tests/issues.targets
index dd4cff6565..ebb4e590da 100644
--- a/tests/issues.targets
+++ b/tests/issues.targets
@@ -308,6 +308,66 @@
<ExcludeList Include="$(XunitTestBinBase)\JIT\Directed\perffix\primitivevt\mixed1_cs_do\mixed1_cs_do.cmd">
<Issue>6097</Issue>
</ExcludeList>
+ <ExcludeList Include="$(XunitTestBinBase)\JIT\jit64\hfa\main\testA\hfa_sd2A_d\hfa_sd2A_d.cmd">
+ <Issue>6180</Issue>
+ </ExcludeList>
+ <ExcludeList Include="$(XunitTestBinBase)\JIT\jit64\hfa\main\testA\hfa_sd2A_r\hfa_sd2A_r.cmd">
+ <Issue>6180</Issue>
+ </ExcludeList>
+ <ExcludeList Include="$(XunitTestBinBase)\JIT\jit64\hfa\main\testA\hfa_sf2A_d\hfa_sf2A_d.cmd">
+ <Issue>6180</Issue>
+ </ExcludeList>
+ <ExcludeList Include="$(XunitTestBinBase)\JIT\jit64\hfa\main\testA\hfa_sf2A_r\hfa_sf2A_r.cmd">
+ <Issue>6180</Issue>
+ </ExcludeList>
+ <ExcludeList Include="$(XunitTestBinBase)\JIT\jit64\hfa\main\testB\hfa_sd2B_d\hfa_sd2B_d.cmd">
+ <Issue>6180</Issue>
+ </ExcludeList>
+ <ExcludeList Include="$(XunitTestBinBase)\JIT\jit64\hfa\main\testB\hfa_sd2B_r\hfa_sd2B_r.cmd">
+ <Issue>6180</Issue>
+ </ExcludeList>
+ <ExcludeList Include="$(XunitTestBinBase)\JIT\jit64\hfa\main\testB\hfa_sf2B_d\hfa_sf2B_d.cmd">
+ <Issue>6180</Issue>
+ </ExcludeList>
+ <ExcludeList Include="$(XunitTestBinBase)\JIT\jit64\hfa\main\testB\hfa_sf2B_r\hfa_sf2B_r.cmd">
+ <Issue>6180</Issue>
+ </ExcludeList>
+ <ExcludeList Include="$(XunitTestBinBase)\JIT\jit64\hfa\main\testC\hfa_sd2C_d\hfa_sd2C_d.cmd">
+ <Issue>6180</Issue>
+ </ExcludeList>
+ <ExcludeList Include="$(XunitTestBinBase)\JIT\jit64\hfa\main\testC\hfa_sd2C_r\hfa_sd2C_r.cmd">
+ <Issue>6180</Issue>
+ </ExcludeList>
+ <ExcludeList Include="$(XunitTestBinBase)\JIT\jit64\hfa\main\testC\hfa_sf2C_d\hfa_sf2C_d.cmd">
+ <Issue>6180</Issue>
+ </ExcludeList>
+ <ExcludeList Include="$(XunitTestBinBase)\JIT\jit64\hfa\main\testC\hfa_sf2C_r\hfa_sf2C_r.cmd">
+ <Issue>6180</Issue>
+ </ExcludeList>
+ <ExcludeList Include="$(XunitTestBinBase)\JIT\jit64\hfa\main\testE\hfa_sd2E_d\hfa_sd2E_d.cmd">
+ <Issue>6180</Issue>
+ </ExcludeList>
+ <ExcludeList Include="$(XunitTestBinBase)\JIT\jit64\hfa\main\testE\hfa_sd2E_r\hfa_sd2E_r.cmd">
+ <Issue>6180</Issue>
+ </ExcludeList>
+ <ExcludeList Include="$(XunitTestBinBase)\JIT\jit64\hfa\main\testE\hfa_sf2E_d\hfa_sf2E_d.cmd">
+ <Issue>6180</Issue>
+ </ExcludeList>
+ <ExcludeList Include="$(XunitTestBinBase)\JIT\jit64\hfa\main\testE\hfa_sf2E_r\hfa_sf2E_r.cmd">
+ <Issue>6180</Issue>
+ </ExcludeList>
+ <ExcludeList Include="$(XunitTestBinBase)\JIT\jit64\hfa\main\testG\hfa_sd2G_d\hfa_sd2G_d.cmd">
+ <Issue>6180</Issue>
+ </ExcludeList>
+ <ExcludeList Include="$(XunitTestBinBase)\JIT\jit64\hfa\main\testG\hfa_sd2G_r\hfa_sd2G_r.cmd">
+ <Issue>6180</Issue>
+ </ExcludeList>
+ <ExcludeList Include="$(XunitTestBinBase)\JIT\jit64\hfa\main\testG\hfa_sf2G_d\hfa_sf2G_d.cmd">
+ <Issue>6180</Issue>
+ </ExcludeList>
+ <ExcludeList Include="$(XunitTestBinBase)\JIT\jit64\hfa\main\testG\hfa_sf2G_r\hfa_sf2G_r.cmd">
+ <Issue>6180</Issue>
+ </ExcludeList>
</ItemGroup>
<!-- Tests that need to be triaged for vararg usage as that is not supported -->
@@ -483,13 +543,5 @@
<ExcludeList Include="$(XunitTestBinBase)\JIT\opt\Tailcall\TailcallVerifyWithPrefix\TailcallVerifyWithPrefix.cmd">
<Issue>needs triage</Issue>
</ExcludeList>
-
- <!-- GC.GetGeneration on weak references -->
- <ExcludeList Include="$(XunitTestBinBase)\GC\API\GC\GetGenerationWR\GetGenerationWR.cmd">
- <Issue>5514</Issue>
- </ExcludeList>
- <ExcludeList Include="$(XunitTestBinBase)\GC\API\GC\GetGenerationWR2\GetGenerationWR2.cmd">
- <Issue>5514</Issue>
- </ExcludeList>
</ItemGroup>
</Project>
diff --git a/tests/runtest.proj b/tests/runtest.proj
index ecca866cbf..aafa025b7a 100644
--- a/tests/runtest.proj
+++ b/tests/runtest.proj
@@ -362,12 +362,12 @@ namespace $([System.String]::Copy($(Category)).Replace(".","_").Replace("\","").
<PropertyGroup>
<CoreclrPackageFileName>%(CoreclrPackage.Filename)</CoreclrPackageFileName>
<!-- Get package version number from nuget package filename at core_root -->
- <CoreclrPackageVersion>$([System.String]::Copy('$(CoreclrPackageFileName)').Replace('Microsoft.NETCore.Runtime.CoreCLR.',''))</CoreclrPackageVersion>
+ <CoreClrPackageVersion Condition="'$(BuildTestsAgainstPackages)'!='true'">$([System.String]::Copy('$(CoreclrPackageFileName)').Replace('Microsoft.NETCore.Runtime.CoreCLR.',''))</CoreClrPackageVersion>
<TestRuntimeJsonContents>
<![CDATA[
{
"dependencies": {
- "Microsoft.NETCore.Runtime.CoreCLR": "$(CoreclrPackageVersion)",
+ "Microsoft.NETCore.Runtime.CoreCLR": "$(CoreClrPackageVersion)",
"Microsoft.NETCore.TestHost": "1.0.0-rc3-24117-00"
},
"frameworks": {
diff --git a/tests/runtest.sh b/tests/runtest.sh
index d0fb26a7f4..d76328ae9f 100755
--- a/tests/runtest.sh
+++ b/tests/runtest.sh
@@ -51,7 +51,7 @@ function print_usage {
echo ' --jitminopts : Runs the tests with COMPlus_JITMinOpts=1'
echo ' --jitforcerelocs : Runs the tests with COMPlus_ForceRelocs=1'
echo ' --gcstresslevel n : Runs the tests with COMPlus_GCStress=n'
- echo ' 0: None 1: GC on all allocs and 'easy' places'
+ echo ' 0: None 1: GC on all allocs and '"'easy'"' places'
echo ' 2: GC on transitions to preemptive GC 4: GC on every allowable JITed instr'
echo ' 8: GC on every allowable NGEN instr 16: GC only on a unique stack trace'
echo ' --long-gc : Runs the long GC tests'
diff --git a/tests/scripts/arm32_ci_script.sh b/tests/scripts/arm32_ci_script.sh
index 404673ac88..a9044bbd1c 100755
--- a/tests/scripts/arm32_ci_script.sh
+++ b/tests/scripts/arm32_ci_script.sh
@@ -1,31 +1,299 @@
#!/bin/bash
-usage() {
- echo 'ARM Emulator Cross Build Script'
+#Usage message
+function usage {
+ echo 'ARM Emulator Cross Build and Test Script'
+ echo 'This script cross builds coreclr source and tests the binaries generated'
echo ''
echo 'Typical usage:'
- echo './tests/scripts/arm32_ci_script.sh'
+ echo ' coreclr source is at ~/clr'
+ echo ' corefx source is at ~/cfx'
+ echo ' --testRootDir and --mscorlibDir have been built on Windows/downloaded from dotnet-ci.cloudapp.net'
+ echo ' --coreFxNativeBinDir has been built using cross build'
+ echo ' --coreFxBinDir has been built on Linux'
+ echo '$ cd ~/clr'
+ echo '$ ./tests/scripts/arm32_ci_script.sh'
echo ' --emulatorPath=/opt/linux-arm-emulator'
echo ' --mountPath=/opt/linux-arm-emulator-root'
echo ' --buildConfig=Release'
+ echo ' --testRootDir=~/Downloads/Windows_NT.x64.Release'
+ echo ' --mscorlibDir=~/clr/bin/Product/Linux.arm-softfp.Release'
+ echo ' --coreFxNativeBinDir=~/cfx/bin/Linux.arm-softfp.Release'
+ echo ' --coreFxBinDir="~/cfx/bin/Linux.AnyCPU.Release;~/cfx/bin/Unix.AnyCPU.Release;~/cfx/bin/AnyOS.AnyCPU.Release"'
+ echo ' --testDirFile=~/clr/tests/testsRunningInsideARM.txt'
echo ''
echo 'Required Arguments:'
+ echo ' --emulatorPath=<path> : Path of the emulator folder (without ending /)'
+ echo ' <path>/platform/rootfs-t30.ext4 should exist'
+ echo ' --mountPath=<path> : The desired path for mounting the emulator rootfs (without ending /)'
+ echo ' This path is created if not already present'
+ echo ' --buildConfig=<config> : The value of config should be either Debug or Release'
+ echo ' Any other value is not accepted'
+ echo 'Optional Arguments:'
+ echo ' --skipTests : Presenting this option skips testing the generated binaries'
+ echo ' If this option is not presented, then tests are run by default'
+ echo ' using the other test related options'
+ echo ' --skipmscorlib : Skips generating mscorlib.dll on Linux'
+ echo ' If tests are run and this option is not used,'
+ echo ' then --mscorlibDir option to this script is mandatory'
+ echo ' -v --verbose : Build made verbose'
+ echo ' -h --help : Prints this usage message and exits'
echo ''
- echo ' --emulatorPath=<path> Path of the emulator folder (without ending /)'
- echo ' <path>/platform/rootfs-t30.ext4 should exist'
- echo ' --mountPath=<path> The desired path for mounting the emulator rootfs (without ending /)'
- echo ' This path is created if not already present'
- echo ' --buildConfig=<config> The value of config should be either Debug or Release'
- echo ' Any other value is not accepted'
+ echo 'Test related Arguments (mandatory if --skipTests is not used):'
+ echo ' --testRootDir=<path> : The root directory of the test build'
+ echo ' --mscorlibDir=<path> : The directory containing the mscorlib.dll binary'
+ echo ' If provided, then the mscorlib.dll in this directory is'
+ echo ' used for tests instead of the built mscorlib.dll'
+ echo ' --coreFxNativeBinDir=<path> : The directory of the CoreFX native build'
+ echo ' --coreFxBinDir="<path>[;<path>]" : List one or more directories with CoreFX managed build binaries'
+ echo ' --testDirFile=<path> : Runs tests only in the directories specified by the file at <path>'
+ echo ' The directories are listed in lines in the file at <path>'
echo ''
- echo 'Any other argument triggers an error and this message is displayed'
+ echo 'Any other argument triggers an error and this usage message is displayed'
exit 1
}
+#Display error message and exit
+function exit_with_error {
+ set +x
+
+ local errorMessage="$1"
+ local printUsage=$2
+
+ echo "ERROR: $errorMessage"
+ if [ "$printUsage" == "true" ]; then
+ echo ''
+ usage
+ fi
+ exit 1
+}
+
+#Exit if input string is empty
+function exit_if_empty {
+ local inputString="$1"
+ local errorMessage="$2"
+ local printUsage=$3
+
+ if [ -z "$inputString" ]; then
+ exit_with_error "$errorMessage" $printUsage
+ fi
+}
+
+#Exit if the input path does not exist
+function exit_if_path_absent {
+ local path="$1"
+ local errorMessage="$2"
+ local printUsage=$3
+
+ if [ ! -f "$path" -a ! -d "$path" ]; then
+ exit_with_error "$errorMessage" $printUsage
+ fi
+}
+
+#Check if the git changes were reverted completely
+function check_git_head {
+ local currentGitHead=`git rev-parse --verify HEAD`
+
+ if [[ "$__initialGitHead" != "$currentGitHead" ]]; then
+ exit_with_error "Some changes made to the code history were not completely reverted. Intial Git HEAD: $__initialGitHead, current Git HEAD: $currentGitHead" false
+ fi
+}
+
+function unmount_rootfs {
+ local rootfsFolder="$1"
+
+ #Check if there are any open files in this directory.
+ if [ -d $rootfsFolder ]; then
+ #If we find information about the file
+ if sudo lsof +D $rootfsFolder; then
+ (set +x; echo 'See above for lsof information. Continuing with the build.')
+ fi
+ fi
+
+ if mountpoint -q -- "$rootfsFolder"; then
+ sudo umount "$rootfsFolder"
+ fi
+}
+
+#Clean the previous build files inside the emulator
+function clean_emulator {
+ #Remove any previous copies of the coreclr and the corefx directories in the emulator
+ sudo rm -rf "$__ARMRootfsCoreclrPath" "$__ARMRootfsCorefxPath"
+}
+
+#Clean the changes made to the environment by the script
+function clean_env {
+ #Clean the emulator
+ clean_emulator
+
+ #Check for revert of git changes
+ check_git_head
+}
+
+#Trap Ctrl-C and handle it
+function handle_ctrl_c {
+ set +x
+
+ echo 'ERROR: Ctrl-C handled. Script aborted before complete execution.'
+
+ exit 1
+}
+trap handle_ctrl_c INT
+
+#Trap Exit and handle it
+function handle_exit {
+ set +x
+
+ echo 'The script is exited. Cleaning environment..'
+
+ clean_env
+}
+trap handle_exit EXIT
+
+
+#Mount with checking to be already existed
+function mount_with_checking {
+ set +x
+ local options="$1"
+ local from="$2"
+ local rootfsFolder="$3"
+
+ if mountpoint -q -- "$rootfsFolder"; then
+ (set +x; echo "$rootfsFolder is already mounted.")
+ else {
+ (set -x; sudo mount $options "$from" "$rootfsFolder")
+ }
+ fi
+}
+
+#Mount emulator to the target mount path
+function mount_emulator {
+ #Check if the mount path exists and create if neccessary
+ if [ ! -d "$__ARMRootfsMountPath" ]; then
+ sudo mkdir "$__ARMRootfsMountPath"
+ fi
+
+ set +x
+ mount_with_checking "" "$__ARMEmulPath/platform/rootfs-t30.ext4" "$__ARMRootfsMountPath"
+ mount_with_checking "-t proc" "/proc" "$__ARMRootfsMountPath/proc"
+ mount_with_checking "-o bind" "/dev/" "$__ARMRootfsMountPath/dev"
+ mount_with_checking "-o bind" "/dev/pts" "$__ARMRootfsMountPath/dev/pts"
+ mount_with_checking "-t tmpfs" "shm" "$__ARMRootfsMountPath/run/shm"
+ mount_with_checking "-o bind" "/sys" "$__ARMRootfsMountPath/sys"
+}
+
+#Cross builds coreclr
+function cross_build_coreclr {
+#Export the needed environment variables
+ (set +x; echo 'Exporting LINUX_ARM_* environment variable')
+ source "$__ARMRootfsMountPath"/dotnet/setenv/setenv_incpath.sh "$__ARMRootfsMountPath"
+
+ #Apply the changes needed to build for the emulator rootfs
+ (set +x; echo 'Applying cross build patch to suit Linux ARM emulator rootfs')
+ git am < "$__ARMRootfsMountPath"/dotnet/setenv/coreclr_cross.patch
+
+ #Apply release optimization patch if needed
+ if [[ "$__buildConfig" == "Release" ]]; then
+ (set +x; echo 'Applying release optimization patch to build in Release mode')
+ git am < "$__ARMRootfsMountPath"/dotnet/setenv/coreclr_release.patch
+ fi
+
+ #Cross building for emulator rootfs
+ ROOTFS_DIR="$__ARMRootfsMountPath" CPLUS_INCLUDE_PATH=$LINUX_ARM_INCPATH CXXFLAGS=$LINUX_ARM_CXXFLAGS ./build.sh $__buildArch clean cross $__verboseFlag $__skipMscorlib clang3.5 $__buildConfig
+
+ #Reset the code to the upstream version
+ (set +x; echo 'Rewinding HEAD to master code')
+ git reset --hard HEAD^
+ if [[ "$__buildConfig" == "Release" ]]; then
+ git reset --hard HEAD^
+ fi
+}
+
+#Copy the needed files to the emulator to run tests
+function copy_to_emulator {
+
+ #Create the coreclr and corefx directories in the emulator
+ sudo mkdir -p "$__ARMRootfsCoreclrPath/bin/obj/$__buildDirName"
+ sudo mkdir -p "$__ARMRootfsCoreclrPath/bin/Product"
+ sudo mkdir "$__ARMRootfsCorefxPath"
+
+ #Copy all coreclr files to the coreclr root in the emulator and set the paths accordingly
+ local testRootDirBase=`basename "$__testRootDir"`
+ sudo cp -R "$__testRootDir" "$__ARMRootfsCoreclrPath/$testRootDirBase"
+ __testRootDirBase="$__ARMEmulCoreclr/$testRootDirBase"
+
+ sudo cp -R "./$__testNativeBinDirBase" "$__ARMRootfsCoreclrPath/$__testNativeBinDirBase"
+ __testNativeBinDirBase="$__ARMEmulCoreclr/$__testNativeBinDirBase"
+
+ sudo cp -R "./$__coreClrBinDirBase" "$__ARMRootfsCoreclrPath/$__coreClrBinDirBase"
+ if [ ! -z "$__mscorlibDir" ]; then
+ sudo cp "$__mscorlibDir/mscorlib.dll" "$__ARMRootfsCoreclrPath/$__coreClrBinDirBase/"
+ else
+ sudo cp "./$__coreClrBinDirBase/mscorlib.dll" "$__ARMRootfsCoreclrPath/$__coreClrBinDirBase/"
+ fi
+ __coreClrBinDirBase="$__ARMEmulCoreclr/$__coreClrBinDirBase"
+ __mscorlibDirBase="$__coreClrBinDirBase"
+
+ local testDirFileBase=`basename "$__testDirFile"`
+ sudo cp "$__testDirFile" "$__ARMRootfsCoreclrPath/$testDirFileBase"
+ __testDirFileBase="$__ARMEmulCoreclr/$testDirFileBase"
+
+ sudo cp -R ./tests "$__ARMRootfsCoreclrPath/"
+ sudo cp -R ./packages "$__ARMRootfsCoreclrPath/"
+ sudo cp -R ./Tools "$__ARMRootfsCoreclrPath/"
+
+ #Copy corefx binary directories to the corefx root in the emulator (first native and then managed)
+ local coreFxNativeBinDirBase=`basename "$__coreFxNativeBinDir"`
+ sudo cp -R "$__coreFxNativeBinDir" "$__ARMRootfsCorefxPath/$coreFxNativeBinDirBase"
+ __coreFxNativeBinDirBase="$__ARMEmulCorefx/$coreFxNativeBinDirBase"
+
+ __coreFxBinDirBase=
+ while IFS=';' read -ra coreFxBinDirectories; do
+ for currDir in "${coreFxBinDirectories[@]}"; do
+ local currDirBase=`basename "$currDir"`
+ sudo cp -R "$currDir" "$__ARMRootfsCorefxPath/$currDirBase"
+
+ if [ -z "$__coreFxBinDirBase" ]; then
+ __coreFxBinDirBase="$__ARMEmulCorefx/$currDirBase"
+ else
+ __coreFxBinDirBase="$__coreFxBinDirBase;$__ARMEmulCorefx/$currDirBase"
+ fi
+ done
+ done <<< "$__coreFxBinDir"
+}
+
+#Runs tests in an emulated mode
+function run_tests {
+ sudo chroot $__ARMRootfsMountPath /bin/bash -x <<EOF
+ cd /home/coreclr
+ ./tests/runtest.sh --testRootDir=$__testRootDirBase \
+ --mscorlibDir=$__mscorlibDirBase \
+ --coreFxNativeBinDir=$__coreFxNativeBinDirBase \
+ --coreFxBinDir="$__coreFxBinDirBase" \
+ --testDirFile=$__testDirFileBase \
+ --testNativeBinDir=$__testNativeBinDirBase \
+ --coreClrBinDir=$__coreClrBinDirBase
+EOF
+}
+
+#Define script variables
__ARMEmulPath=
__ARMRootfsMountPath=
-__BuildConfig=
+__buildConfig=
+__skipTests=0
+__skipMscorlib=
+__testRootDir=
+__mscorlibDir=
+__coreFxNativeBinDir=
+__coreFxBinDir=
+__testDirFile=
+__verboseFlag=
+__buildOS="Linux"
+__buildArch="arm-softfp"
+__buildDirName=
+__initialGitHead=`git rev-parse --verify HEAD`
+#Parse command line arguments
for arg in "$@"
do
case $arg in
@@ -36,41 +304,141 @@ do
__ARMRootfsMountPath=${arg#*=}
;;
--buildConfig=*)
- __BuildConfig="$(echo ${arg#*=} | awk '{print tolower($0)}')"
- if [[ "$__BuildConfig" != "debug" && "$__BuildConfig" != "release" ]]; then
- usage
+ __buildConfig="$(echo ${arg#*=} | awk '{print tolower($0)}')"
+ if [[ "$__buildConfig" != "debug" && "$__buildConfig" != "release" ]]; then
+ exit_with_error "--buildConfig can be only Debug or Release" true
fi
;;
- *)
+ --skipTests)
+ __skipTests=1
+ ;;
+ --skipmscorlib)
+ __skipMscorlib="skipmscorlib"
+ ;;
+ -v|--verbose)
+ __verboseFlag="verbose"
+ ;;
+ --testRootDir=*)
+ __testRootDir=${arg#*=}
+ ;;
+ --mscorlibDir=*)
+ __mscorlibDir=${arg#*=}
+ ;;
+ --coreFxNativeBinDir=*)
+ __coreFxNativeBinDir=${arg#*=}
+ ;;
+ --coreFxBinDir=*)
+ __coreFxBinDir=${arg#*=}
+ ;;
+ --testDirFile=*)
+ __testDirFile=${arg#*=}
+ ;;
+ -h|--help)
usage
;;
+ *)
+ exit_with_error "$arg not a recognized argument" true
+ ;;
esac
done
-if [ -z "$__ARMEmulPath" -o -z "$__ARMRootfsMountPath" -o -z "$__BuildConfig" ]; then
- usage
+#Check if there are any uncommited changes in the source directory as git adds and removes patches
+if [[ $(git status -s) != "" ]]; then
+ echo 'ERROR: There are some uncommited changes. To avoid losing these changes commit them and try again.'
+ echo ''
+ git status
+ exit 1
fi
+#Check if the compulsory arguments have been presented to the script and if the input paths exist
+exit_if_empty "$__ARMEmulPath" "--emulatorPath is a mandatory argument, not provided" true
+exit_if_empty "$__ARMRootfsMountPath" "--mountPath is a mandatory argument, not provided" true
+exit_if_empty "$__buildConfig" "--buildConfig is a mandatory argument, not provided" true
+exit_if_path_absent "$__ARMEmulPath/platform/rootfs-t30.ext4" "Path specified in --emulatorPath does not have the rootfs" false
+
+#Check if the optional arguments are present in the case that testing is to be done
+if [ $__skipTests == 0 ]; then
+ exit_if_empty "$__testRootDir" "Testing requested, but --testRootDir not provided" true
+ exit_if_path_absent "$__testRootDir" "Path specified in --testRootDir does not exist" false
+
+ exit_if_empty "$__coreFxNativeBinDir" "Testing requested but --coreFxNativeBinDir not provided" true
+ exit_if_path_absent "$__coreFxNativeBinDir" "Path specified in --coreFxNativeBinDir does not exist" false
+
+ exit_if_empty "$__coreFxBinDir" "Testing requested, but --coreFxBinDir not provided" true
+ while IFS=';' read -ra coreFxBinDirectories; do
+ for currDir in "${coreFxBinDirectories[@]}"; do
+ exit_if_path_absent "$currDir" "Path specified in --coreFxBinDir, $currDir does not exist" false
+ done
+ done <<< "$__coreFxBinDir"
+
+ exit_if_empty "$__testDirFile" "Testing requested, but --testDirFile not provided" true
+ exit_if_path_absent "$__testDirFile" "Path specified in --testDirFile does not exist" false
+
+ if [ ! -z "$__skipMscorlib" ]; then
+ exit_if_empty "$__mscorlibDir" "Testing and skipmscorlib requested, but --mscorlibDir not provided" true
+ fi
+ if [ ! -z "$__mscorlibDir" ]; then
+ echo '--mscorlibDir provided; will be using this path for running tests and ignoring the generated mscorlib.dll'
+ exit_if_path_absent "$__mscorlibDir/mscorlib.dll" "Path specified in --mscorlibDir does not contain mscorlib.dll"
+ fi
+fi
+
+#Change build configuration to the capitalized form to create build product paths correctly
+if [[ "$__buildConfig" == "release" ]]; then
+ __buildConfig="Release"
+else
+ __buildConfig="Debug"
+fi
+__buildDirName="$__buildOS.$__buildArch.$__buildConfig"
+
+#Define emulator paths
+__ARMRootfsCoreclrPath="$__ARMRootfsMountPath/home/coreclr"
+__ARMRootfsCorefxPath="$__ARMRootfsMountPath/home/corefx"
+__ARMEmulCoreclr="/home/coreclr"
+__ARMEmulCorefx="/home/corefx"
+__testRootDirBase=
+__mscorlibDirBase=
+__coreFxNativeBinDirBase=
+__coreFxBinDirBase=
+__testDirFileBase=
+__testNativeBinDirBase="bin/obj/$__buildDirName/tests"
+__coreClrBinDirBase="bin/Product/$__buildDirName"
+
set -x
set -e
-if [ ! -d $__ARMRootfsMountPath ]; then
- sudo mkdir $__ARMRootfsMountPath
-fi
+## Begin cross build
+(set +x; echo "Git HEAD @ $__initialGitHead")
+
+#Mount the emulator
+(set +x; echo 'Mounting emulator...')
+mount_emulator
+
+#Clean the emulator
+(set +x; echo 'Cleaning emulator...')
+clean_emulator
+
+#Complete the cross build
+(set +x; echo 'Building coreclr...')
+cross_build_coreclr
-if grep -qs $__ARMRootfsMountPath /proc/mounts; then
- sudo umount $__ARMRootfsMountPath
+#If tests are to be skipped end the script here, else continue
+if [ $__skipTests == 1 ]; then
+ exit 0
fi
-sudo mount $__ARMEmulPath/platform/rootfs-t30.ext4 $__ARMRootfsMountPath
+## Tests are going to be performed in an emulated environment
-echo "Exporting LINUX_ARM_* environment variable"
-source $__ARMRootfsMountPath/dotnet/setenv/setenv_incpath.sh $__ARMRootfsMountPath
+#Copy the needed files to the emulator before entering the emulated environment
+(set +x; echo 'Setting up emulator to run tests...')
+copy_to_emulator
-echo "Applying cross build patch to suit Linux ARM emulator rootfs"
-git am < $__ARMRootfsMountPath/dotnet/setenv/coreclr_cross.patch
+#Enter the emulated mode and run the tests
+(set +x; echo 'Running tests...')
+run_tests
-ROOTFS_DIR=$__ARMRootfsMountPath CPLUS_INCLUDE_PATH=$LINUX_ARM_INCPATH CXXFLAGS=$LINUX_ARM_CXXFLAGS ./build.sh arm-softfp clean cross verbose skipmscorlib clang3.5 $__BuildConfig
+#Clean the environment
+(set +x; echo 'Cleaning environment...')
+clean_env
-echo "Rewinding HEAD to master code"
-git reset --hard HEAD^
+(set +x; echo 'Build and test complete')
diff --git a/tests/src/Interop/CMakeLists.txt b/tests/src/Interop/CMakeLists.txt
index 370b699391..cf2cada7a6 100644
--- a/tests/src/Interop/CMakeLists.txt
+++ b/tests/src/Interop/CMakeLists.txt
@@ -17,3 +17,4 @@ add_subdirectory(StringMarshalling/LPTSTR)
add_subdirectory(StringMarshalling/UTF8)
add_subdirectory(MarshalAPI/FunctionPointer)
add_subdirectory(MarshalAPI/IUnknown)
+add_subdirectory(SizeConst)
diff --git a/tests/src/Interop/MarshalAPI/MarshalStructure/MarshalStructure.cs b/tests/src/Interop/MarshalAPI/MarshalStructure/MarshalStructure.cs
new file mode 100644
index 0000000000..0497f8fdc1
--- /dev/null
+++ b/tests/src/Interop/MarshalAPI/MarshalStructure/MarshalStructure.cs
@@ -0,0 +1,165 @@
+using System;
+using System.Runtime.InteropServices;
+
+class Program
+{
+ static int Main(string[] args)
+ {
+ VerifyByValBoolArray();
+ VerifyByValArrayInStruct();
+ VerfiyByValDateArray();
+ return 100;
+ }
+
+ static void VerifyByValBoolArray()
+ {
+ var structure1 = new StructWithBoolArray()
+ {
+ array = new bool[]
+ {
+ true,true,true,true
+ }
+ };
+
+ int size = Marshal.SizeOf(structure1);
+ IntPtr memory = Marshal.AllocHGlobal(size + sizeof(Int32));
+
+ try
+ {
+ Marshal.WriteInt32(memory, size, 0xFF);
+ Marshal.StructureToPtr(structure1, memory, false);
+
+ if (Marshal.ReadInt32(memory, size) != 0xFF)
+ throw new Exception("Marshal.StructureToPtr buffer overwritten...");
+ }
+ finally
+ {
+ Marshal.FreeHGlobal(memory);
+ }
+ }
+
+ static void VerifyByValArrayInStruct()
+ {
+ // equal
+ var structure1 = new StructWithByValArray()
+ {
+ array = new StructWithIntField[]
+ {
+ new StructWithIntField { value = 1 },
+ new StructWithIntField { value = 2 },
+ new StructWithIntField { value = 3 },
+ new StructWithIntField { value = 4 },
+ new StructWithIntField { value = 5 }
+ }
+ };
+ int size = Marshal.SizeOf(structure1);
+ IntPtr memory = Marshal.AllocHGlobal(size);
+ try
+ {
+ Marshal.StructureToPtr(structure1, memory, false);
+ }
+ finally
+ {
+ Marshal.FreeHGlobal(memory);
+ }
+
+ // underflow
+ var structure2 = new StructWithByValArray()
+ {
+ array = new StructWithIntField[]
+ {
+ new StructWithIntField { value = 1 },
+ new StructWithIntField { value = 2 },
+ new StructWithIntField { value = 3 },
+ new StructWithIntField { value = 4 }
+ }
+ };
+ bool expectedException = false;
+ size = Marshal.SizeOf(structure2);
+ memory = Marshal.AllocHGlobal(size);
+ try
+ {
+ Marshal.StructureToPtr(structure2, memory, false);
+ }
+ catch (ArgumentException)
+ {
+ expectedException = true;
+ }
+ finally
+ {
+ Marshal.FreeHGlobal(memory);
+ }
+ if (!expectedException)
+ throw new Exception("Expected ArgumentException");
+
+ // overflow
+ var structure3 = new StructWithByValArray()
+ {
+ array = new StructWithIntField[]
+ {
+ new StructWithIntField { value = 1 },
+ new StructWithIntField { value = 2 },
+ new StructWithIntField { value = 3 },
+ new StructWithIntField { value = 4 },
+ new StructWithIntField { value = 5 },
+ new StructWithIntField { value = 6 }
+ }
+ };
+
+ size = Marshal.SizeOf(structure3);
+ memory = Marshal.AllocHGlobal(size);
+ try
+ {
+ Marshal.StructureToPtr(structure3, memory, false);
+ }
+ finally
+ {
+ Marshal.FreeHGlobal(memory);
+ }
+ }
+
+ static void VerfiyByValDateArray()
+ {
+ var structure1 = new StructWithDateArray()
+ {
+ array = new DateTime[]
+ {
+ DateTime.Now, DateTime.Now , DateTime.Now, DateTime.Now, DateTime.Now, DateTime.Now , DateTime.Now, DateTime.Now
+ }
+ };
+
+ int size = Marshal.SizeOf(structure1);
+ IntPtr memory = Marshal.AllocHGlobal(size);
+ try
+ {
+ Marshal.StructureToPtr(structure1, memory, false);
+ }
+ finally
+ {
+ Marshal.FreeHGlobal(memory);
+ }
+ }
+
+ public struct StructWithIntField
+ {
+ public int value;
+ }
+
+ public struct StructWithByValArray
+ {
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)]
+ public StructWithIntField[] array;
+ }
+
+ public struct StructWithBoolArray
+ {
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
+ public bool[] array;
+ }
+
+ public struct StructWithDateArray
+ {
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
+ public DateTime[] array;
+ }
+} \ No newline at end of file
diff --git a/tests/src/Interop/MarshalAPI/MarshalStructure/MarshalStructure.csproj b/tests/src/Interop/MarshalAPI/MarshalStructure/MarshalStructure.csproj
new file mode 100644
index 0000000000..6146e277ea
--- /dev/null
+++ b/tests/src/Interop/MarshalAPI/MarshalStructure/MarshalStructure.csproj
@@ -0,0 +1,47 @@
+<?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>
+ <AssemblyName>MarshalStructure</AssemblyName>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{F1E66554-8C8E-4141-85CF-D0CD6A0CD0B0}</ProjectGuid>
+ <OutputType>Exe</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <FileAlignment>512</FileAlignment>
+ <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+ <ReferencePath>$(ProgramFiles)\Common Files\microsoft shared\VSTT\11.0\UITestExtensionPackages</ReferencePath>
+ <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir>
+
+ <NuGetPackageImportStamp>7a9bfb7d</NuGetPackageImportStamp>
+ <DefineConstants>$(DefineConstants);STATIC</DefineConstants>
+ </PropertyGroup>
+ <!-- Default configurations to help VS understand the configurations -->
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
+ </PropertyGroup>
+ <ItemGroup>
+ <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies">
+ <Visible>False</Visible>
+ </CodeAnalysisDependentAssemblyPaths>
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="*.cs" />
+ <Compile Include="..\..\common\Assertion.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="project.json" />
+ </ItemGroup>
+ <ItemGroup>
+ <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\..\..\Common\CoreCLRTestLibrary\CoreCLRTestLibrary.csproj">
+ <Project>{c8c0dc74-fac4-45b1-81fe-70c4808366e0}</Project>
+ <Name>CoreCLRTestLibrary</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+</Project>
diff --git a/tests/src/Interop/MarshalAPI/MarshalStructure/project.json b/tests/src/Interop/MarshalAPI/MarshalStructure/project.json
new file mode 100644
index 0000000000..025841ec29
--- /dev/null
+++ b/tests/src/Interop/MarshalAPI/MarshalStructure/project.json
@@ -0,0 +1,44 @@
+{
+ "dependencies": {
+ "Microsoft.NETCore.Platforms": "1.0.1-rc3-24117-00",
+ "System.Collections": "4.0.10",
+ "System.Collections.NonGeneric": "4.0.1-rc3-24117-00",
+ "System.Collections.Specialized": "4.0.1-rc3-24117-00",
+ "System.ComponentModel": "4.0.1-rc3-24117-00",
+ "System.Console": "4.0.0-rc3-24117-00",
+ "System.Diagnostics.Process": "4.1.0-rc3-24117-00",
+ "System.Globalization": "4.0.10",
+ "System.Globalization.Calendars": "4.0.0",
+ "System.IO": "4.0.10",
+ "System.IO.FileSystem": "4.0.1-rc3-24117-00",
+ "System.IO.FileSystem.Primitives": "4.0.0",
+ "System.Linq": "4.1.0-rc3-24117-00",
+ "System.Linq.Queryable": "4.0.1-rc3-24117-00",
+ "System.Reflection": "4.1.0-rc3-24117-00",
+ "System.Reflection.Primitives": "4.0.0",
+ "System.Runtime": "4.1.0-rc3-24117-00",
+ "System.Runtime.Extensions": "4.0.10",
+ "System.Runtime.Handles": "4.0.0",
+ "System.Runtime.InteropServices": "4.1.0-rc3-24117-00",
+ "System.Runtime.Loader": "4.0.0-rc3-24117-00",
+ "System.Text.Encoding": "4.0.10",
+ "System.Threading": "4.0.10",
+ "System.Threading.Thread": "4.0.0-rc3-24117-00",
+ "System.Xml.ReaderWriter": "4.0.11-rc3-24117-00",
+ "System.Xml.XDocument": "4.0.11-rc3-24117-00",
+ "System.Xml.XmlDocument": "4.0.1-rc3-24117-00",
+ "System.Xml.XmlSerializer": "4.0.11-rc3-24117-00"
+ },
+ "frameworks": {
+ "dnxcore50": {}
+ },
+ "runtimes": {
+ "win7-x86": {},
+ "win7-x64": {},
+ "ubuntu.14.04-x64": {},
+ "osx.10.10-x64": {},
+ "centos.7-x64": {},
+ "rhel.7-x64": {},
+ "debian.8-x64": {}
+ }
+}
diff --git a/tests/src/Interop/SizeConst/CMakeLists.txt b/tests/src/Interop/SizeConst/CMakeLists.txt
new file mode 100644
index 0000000000..3ec7dd3442
--- /dev/null
+++ b/tests/src/Interop/SizeConst/CMakeLists.txt
@@ -0,0 +1,11 @@
+cmake_minimum_required (VERSION 2.6)
+project (SizeConstNative)
+set(SOURCES SizeConstNative.cpp)
+
+# add the executable
+add_library (SizeConstNative SHARED ${SOURCES})
+
+# add the install targets
+install (TARGETS SizeConstNative DESTINATION bin)
+
+
diff --git a/tests/src/Interop/SizeConst/SizeConstNative.cpp b/tests/src/Interop/SizeConst/SizeConstNative.cpp
new file mode 100644
index 0000000000..8bb822a0e9
--- /dev/null
+++ b/tests/src/Interop/SizeConst/SizeConstNative.cpp
@@ -0,0 +1,12 @@
+// 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.
+
+#include <xplatform.h>
+
+const int ARRAY_SIZE = 100;
+typedef struct { char arr[ARRAY_SIZE]; } S_CHARByValArray;
+extern "C" DLL_EXPORT BOOL TakeByValTStr(S_CHARByValArray s, int size)
+{
+ return true;
+} \ No newline at end of file
diff --git a/tests/src/Interop/SizeConst/SizeConstTest.cs b/tests/src/Interop/SizeConst/SizeConstTest.cs
new file mode 100644
index 0000000000..bd081a6721
--- /dev/null
+++ b/tests/src/Interop/SizeConst/SizeConstTest.cs
@@ -0,0 +1,47 @@
+// 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;
+
+
+[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
+public struct S_CHARArray_ByValTStr
+{
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 4)]
+ public string arr;
+ public S_CHARArray_ByValTStr(string parr) { arr = parr; }
+}
+
+class Test
+{
+ internal const int ARRAY_SIZE = 100;
+
+ //UnmanagedType.ByValTStr
+ [DllImport("SizeConstNative",CharSet = CharSet.Ansi)]
+ static extern bool TakeByValTStr(S_CHARArray_ByValTStr s, int size);
+
+ static bool SizeConstByValTStr()
+ {
+ // always marshal managedArray.Length
+ S_CHARArray_ByValTStr s = new S_CHARArray_ByValTStr();
+ s.arr = "有个可爱";
+ TakeByValTStr(s, s.arr.Length);
+
+ // off by one byte since sizeconst == 4 and
+ // number of bytes == 4 . We used to write
+ // one past the buffer before but now we truncate at 3rd byte.
+ // In order to test this the locale of the machine need to
+ // a multibyte char set.
+ s.arr = "个个";
+ TakeByValTStr(s, s.arr.Length);
+ return true;
+ }
+
+ static int Main(string[] args)
+ {
+ SizeConstByValTStr();
+ return 100;
+ }
+}
diff --git a/tests/src/Interop/SizeConst/SizeConstTest.csproj b/tests/src/Interop/SizeConst/SizeConstTest.csproj
new file mode 100644
index 0000000000..03806a1f50
--- /dev/null
+++ b/tests/src/Interop/SizeConst/SizeConstTest.csproj
@@ -0,0 +1,48 @@
+<?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>
+ <AssemblyName>SizeConstTest</AssemblyName>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{F1E66554-8C8E-4141-85CF-D0CD6A0CD0B0}</ProjectGuid>
+ <OutputType>Exe</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <FileAlignment>512</FileAlignment>
+ <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+ <ReferencePath>$(ProgramFiles)\Common Files\microsoft shared\VSTT\11.0\UITestExtensionPackages</ReferencePath>
+ <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir>
+
+ <NuGetPackageImportStamp>7a9bfb7d</NuGetPackageImportStamp>
+ <DefineConstants>$(DefineConstants);STATIC</DefineConstants>
+ </PropertyGroup>
+ <!-- Default configurations to help VS understand the configurations -->
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
+ </PropertyGroup>
+ <ItemGroup>
+ <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies">
+ <Visible>False</Visible>
+ </CodeAnalysisDependentAssemblyPaths>
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="SizeConstTest.cs" />
+ <Compile Include="..\common\Assertion.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="project.json" />
+ </ItemGroup>
+ <ItemGroup>
+ <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\..\..\Common\CoreCLRTestLibrary\CoreCLRTestLibrary.csproj">
+ <Project>{c8c0dc74-fac4-45b1-81fe-70c4808366e0}</Project>
+ <Name>CoreCLRTestLibrary</Name>
+ </ProjectReference>
+ <ProjectReference Include="CMakeLists.txt" />
+ </ItemGroup>
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+</Project>
diff --git a/tests/src/Interop/SizeConst/project.json b/tests/src/Interop/SizeConst/project.json
new file mode 100644
index 0000000000..025841ec29
--- /dev/null
+++ b/tests/src/Interop/SizeConst/project.json
@@ -0,0 +1,44 @@
+{
+ "dependencies": {
+ "Microsoft.NETCore.Platforms": "1.0.1-rc3-24117-00",
+ "System.Collections": "4.0.10",
+ "System.Collections.NonGeneric": "4.0.1-rc3-24117-00",
+ "System.Collections.Specialized": "4.0.1-rc3-24117-00",
+ "System.ComponentModel": "4.0.1-rc3-24117-00",
+ "System.Console": "4.0.0-rc3-24117-00",
+ "System.Diagnostics.Process": "4.1.0-rc3-24117-00",
+ "System.Globalization": "4.0.10",
+ "System.Globalization.Calendars": "4.0.0",
+ "System.IO": "4.0.10",
+ "System.IO.FileSystem": "4.0.1-rc3-24117-00",
+ "System.IO.FileSystem.Primitives": "4.0.0",
+ "System.Linq": "4.1.0-rc3-24117-00",
+ "System.Linq.Queryable": "4.0.1-rc3-24117-00",
+ "System.Reflection": "4.1.0-rc3-24117-00",
+ "System.Reflection.Primitives": "4.0.0",
+ "System.Runtime": "4.1.0-rc3-24117-00",
+ "System.Runtime.Extensions": "4.0.10",
+ "System.Runtime.Handles": "4.0.0",
+ "System.Runtime.InteropServices": "4.1.0-rc3-24117-00",
+ "System.Runtime.Loader": "4.0.0-rc3-24117-00",
+ "System.Text.Encoding": "4.0.10",
+ "System.Threading": "4.0.10",
+ "System.Threading.Thread": "4.0.0-rc3-24117-00",
+ "System.Xml.ReaderWriter": "4.0.11-rc3-24117-00",
+ "System.Xml.XDocument": "4.0.11-rc3-24117-00",
+ "System.Xml.XmlDocument": "4.0.1-rc3-24117-00",
+ "System.Xml.XmlSerializer": "4.0.11-rc3-24117-00"
+ },
+ "frameworks": {
+ "dnxcore50": {}
+ },
+ "runtimes": {
+ "win7-x86": {},
+ "win7-x64": {},
+ "ubuntu.14.04-x64": {},
+ "osx.10.10-x64": {},
+ "centos.7-x64": {},
+ "rhel.7-x64": {},
+ "debian.8-x64": {}
+ }
+}
diff --git a/tests/src/JIT/Regression/JitBlue/GitHub_6238/GitHub_6238.cs b/tests/src/JIT/Regression/JitBlue/GitHub_6238/GitHub_6238.cs
new file mode 100644
index 0000000000..5f0c6b7f5b
--- /dev/null
+++ b/tests/src/JIT/Regression/JitBlue/GitHub_6238/GitHub_6238.cs
@@ -0,0 +1,46 @@
+// 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.
+
+// This test tests our signed contained compare logic
+// We should generate a signed set for the high compare, and an unsigned
+// set for the low compare
+//
+
+using System;
+using System.Runtime.CompilerServices;
+
+class Program
+{
+ uint i;
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ static int Test(long a, long b)
+ {
+ if (a < b)
+ {
+ return 5;
+ }
+ else
+ {
+ return 0;
+ }
+ }
+
+ static int Main()
+ {
+ const int Pass = 100;
+ const int Fail = -1;
+
+ if (Test(-2L, 0L) == 5)
+ {
+ Console.WriteLine("Passed");
+ return Pass;
+ }
+ else
+ {
+ Console.WriteLine("Failed");
+ return Fail;
+ }
+ }
+}
diff --git a/tests/src/JIT/Regression/JitBlue/GitHub_6238/GitHub_6238.csproj b/tests/src/JIT/Regression/JitBlue/GitHub_6238/GitHub_6238.csproj
new file mode 100644
index 0000000000..933fc1077e
--- /dev/null
+++ b/tests/src/JIT/Regression/JitBlue/GitHub_6238/GitHub_6238.csproj
@@ -0,0 +1,40 @@
+<?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>
+ <AssemblyName>$(MSBuildProjectName)</AssemblyName>
+ <ProjectGuid>{95DFC527-4DC1-495E-97D7-E94EE1F7140D}</ProjectGuid>
+ <OutputType>Exe</OutputType>
+ <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+ <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir>
+ <NuGetPackageImportStamp>7a9bfb7d</NuGetPackageImportStamp>
+ </PropertyGroup>
+ <!-- Default configurations to help VS understand the configurations -->
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ </PropertyGroup>
+ <PropertyGroup>
+ <DebugType></DebugType>
+ <Optimize>False</Optimize>
+ </PropertyGroup>
+ <ItemGroup>
+ <Compile Include="$(MSBuildProjectName).cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="app.config" />
+ <None Include="project.json" />
+ </ItemGroup>
+ <ItemGroup>
+ <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+ </ItemGroup>
+ <PropertyGroup>
+ <ProjectJson>project.json</ProjectJson>
+ <ProjectLockJson>project.lock.json</ProjectLockJson>
+ </PropertyGroup>
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+ <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' ">
+ </PropertyGroup>
+</Project>
diff --git a/tests/src/JIT/Regression/JitBlue/GitHub_6238/app.config b/tests/src/JIT/Regression/JitBlue/GitHub_6238/app.config
new file mode 100644
index 0000000000..62803f5972
--- /dev/null
+++ b/tests/src/JIT/Regression/JitBlue/GitHub_6238/app.config
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<configuration>
+ <runtime>
+ <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
+ <dependentAssembly>
+ <assemblyIdentity name="System.Runtime" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-4.0.20.0" newVersion="4.0.20.0" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="System.Text.Encoding" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-4.0.10.0" newVersion="4.0.10.0" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="System.Threading.Tasks" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-4.0.10.0" newVersion="4.0.10.0" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="System.IO" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-4.0.10.0" newVersion="4.0.10.0" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="System.Reflection" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-4.0.10.0" newVersion="4.0.10.0" />
+ </dependentAssembly>
+ </assemblyBinding>
+ </runtime>
+</configuration> \ No newline at end of file
diff --git a/tests/src/JIT/Regression/JitBlue/GitHub_6238/project.json b/tests/src/JIT/Regression/JitBlue/GitHub_6238/project.json
new file mode 100644
index 0000000000..ecf2e0894c
--- /dev/null
+++ b/tests/src/JIT/Regression/JitBlue/GitHub_6238/project.json
@@ -0,0 +1,45 @@
+{
+ "dependencies": {
+ "Microsoft.NETCore.Platforms": "1.0.1-rc3-24117-00",
+ "System.Collections": "4.0.10",
+ "System.Collections.NonGeneric": "4.0.1-rc3-24117-00",
+ "System.Collections.Specialized": "4.0.1-rc3-24117-00",
+ "System.ComponentModel": "4.0.1-rc3-24117-00",
+ "System.Console": "4.0.0-rc3-24117-00",
+ "System.Diagnostics.Process": "4.1.0-rc3-24117-00",
+ "System.Globalization": "4.0.10",
+ "System.Globalization.Calendars": "4.0.0",
+ "System.IO": "4.0.10",
+ "System.IO.FileSystem": "4.0.1-rc3-24117-00",
+ "System.IO.FileSystem.Primitives": "4.0.0",
+ "System.Linq": "4.1.0-rc3-24117-00",
+ "System.Linq.Queryable": "4.0.1-rc3-24117-00",
+ "System.Reflection": "4.1.0-rc3-24117-00",
+ "System.Reflection.Primitives": "4.0.0",
+ "System.Runtime": "4.1.0-rc3-24117-00",
+ "System.Runtime.Extensions": "4.0.10",
+ "System.Runtime.Handles": "4.0.0",
+ "System.Runtime.InteropServices": "4.1.0-rc3-24117-00",
+ "System.Runtime.Loader": "4.0.0-rc3-24117-00",
+ "System.Text.Encoding": "4.0.10",
+ "System.Threading": "4.0.10",
+ "System.Threading.Thread": "4.0.0-rc3-24117-00",
+ "System.Threading.ThreadPool": "4.0.10-rc3-24117-00",
+ "System.Xml.ReaderWriter": "4.0.11-rc3-24117-00",
+ "System.Xml.XDocument": "4.0.11-rc3-24117-00",
+ "System.Xml.XmlDocument": "4.0.1-rc3-24117-00",
+ "System.Xml.XmlSerializer": "4.0.11-rc3-24117-00"
+ },
+ "frameworks": {
+ "dnxcore50": {}
+ },
+ "runtimes": {
+ "win7-x86": {},
+ "win7-x64": {},
+ "ubuntu.14.04-x64": {},
+ "osx.10.10-x64": {},
+ "centos.7-x64": {},
+ "rhel.7-x64": {},
+ "debian.8-x64": {}
+ }
+}
diff --git a/tests/src/JIT/Regression/JitBlue/GitHub_6239/GitHub_6239.cs b/tests/src/JIT/Regression/JitBlue/GitHub_6239/GitHub_6239.cs
new file mode 100644
index 0000000000..3a57e4d594
--- /dev/null
+++ b/tests/src/JIT/Regression/JitBlue/GitHub_6239/GitHub_6239.cs
@@ -0,0 +1,46 @@
+// 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.
+
+// This test tests our signed uncontained compare logic
+// We should generate a signed jump for the high compare, and an unsigned
+// jump for the low compare.
+//
+
+using System;
+using System.Runtime.CompilerServices;
+
+class Program
+{
+ uint i;
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ static int Test(long a, long b)
+ {
+ if (a < b)
+ {
+ return 5;
+ }
+ else
+ {
+ return 0;
+ }
+ }
+
+ static int Main()
+ {
+ const int Pass = 100;
+ const int Fail = -1;
+
+ if (Test(-2147483649L, -2147483648L) == 5)
+ {
+ Console.WriteLine("Passed");
+ return Pass;
+ }
+ else
+ {
+ Console.WriteLine("Failed");
+ return Fail;
+ }
+ }
+}
diff --git a/tests/src/JIT/Regression/JitBlue/GitHub_6239/GitHub_6239.csproj b/tests/src/JIT/Regression/JitBlue/GitHub_6239/GitHub_6239.csproj
new file mode 100644
index 0000000000..cfb0d65b01
--- /dev/null
+++ b/tests/src/JIT/Regression/JitBlue/GitHub_6239/GitHub_6239.csproj
@@ -0,0 +1,40 @@
+<?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>
+ <AssemblyName>$(MSBuildProjectName)</AssemblyName>
+ <ProjectGuid>{95DFC527-4DC1-495E-97D7-E94EE1F7140D}</ProjectGuid>
+ <OutputType>Exe</OutputType>
+ <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+ <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir>
+ <NuGetPackageImportStamp>7a9bfb7d</NuGetPackageImportStamp>
+ </PropertyGroup>
+ <!-- Default configurations to help VS understand the configurations -->
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ </PropertyGroup>
+ <PropertyGroup>
+ <DebugType></DebugType>
+ <Optimize>True</Optimize>
+ </PropertyGroup>
+ <ItemGroup>
+ <Compile Include="$(MSBuildProjectName).cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="app.config" />
+ <None Include="project.json" />
+ </ItemGroup>
+ <ItemGroup>
+ <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+ </ItemGroup>
+ <PropertyGroup>
+ <ProjectJson>project.json</ProjectJson>
+ <ProjectLockJson>project.lock.json</ProjectLockJson>
+ </PropertyGroup>
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+ <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' ">
+ </PropertyGroup>
+</Project>
diff --git a/tests/src/JIT/Regression/JitBlue/GitHub_6239/app.config b/tests/src/JIT/Regression/JitBlue/GitHub_6239/app.config
new file mode 100644
index 0000000000..62803f5972
--- /dev/null
+++ b/tests/src/JIT/Regression/JitBlue/GitHub_6239/app.config
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<configuration>
+ <runtime>
+ <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
+ <dependentAssembly>
+ <assemblyIdentity name="System.Runtime" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-4.0.20.0" newVersion="4.0.20.0" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="System.Text.Encoding" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-4.0.10.0" newVersion="4.0.10.0" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="System.Threading.Tasks" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-4.0.10.0" newVersion="4.0.10.0" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="System.IO" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-4.0.10.0" newVersion="4.0.10.0" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="System.Reflection" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-4.0.10.0" newVersion="4.0.10.0" />
+ </dependentAssembly>
+ </assemblyBinding>
+ </runtime>
+</configuration> \ No newline at end of file
diff --git a/tests/src/JIT/Regression/JitBlue/GitHub_6239/project.json b/tests/src/JIT/Regression/JitBlue/GitHub_6239/project.json
new file mode 100644
index 0000000000..ecf2e0894c
--- /dev/null
+++ b/tests/src/JIT/Regression/JitBlue/GitHub_6239/project.json
@@ -0,0 +1,45 @@
+{
+ "dependencies": {
+ "Microsoft.NETCore.Platforms": "1.0.1-rc3-24117-00",
+ "System.Collections": "4.0.10",
+ "System.Collections.NonGeneric": "4.0.1-rc3-24117-00",
+ "System.Collections.Specialized": "4.0.1-rc3-24117-00",
+ "System.ComponentModel": "4.0.1-rc3-24117-00",
+ "System.Console": "4.0.0-rc3-24117-00",
+ "System.Diagnostics.Process": "4.1.0-rc3-24117-00",
+ "System.Globalization": "4.0.10",
+ "System.Globalization.Calendars": "4.0.0",
+ "System.IO": "4.0.10",
+ "System.IO.FileSystem": "4.0.1-rc3-24117-00",
+ "System.IO.FileSystem.Primitives": "4.0.0",
+ "System.Linq": "4.1.0-rc3-24117-00",
+ "System.Linq.Queryable": "4.0.1-rc3-24117-00",
+ "System.Reflection": "4.1.0-rc3-24117-00",
+ "System.Reflection.Primitives": "4.0.0",
+ "System.Runtime": "4.1.0-rc3-24117-00",
+ "System.Runtime.Extensions": "4.0.10",
+ "System.Runtime.Handles": "4.0.0",
+ "System.Runtime.InteropServices": "4.1.0-rc3-24117-00",
+ "System.Runtime.Loader": "4.0.0-rc3-24117-00",
+ "System.Text.Encoding": "4.0.10",
+ "System.Threading": "4.0.10",
+ "System.Threading.Thread": "4.0.0-rc3-24117-00",
+ "System.Threading.ThreadPool": "4.0.10-rc3-24117-00",
+ "System.Xml.ReaderWriter": "4.0.11-rc3-24117-00",
+ "System.Xml.XDocument": "4.0.11-rc3-24117-00",
+ "System.Xml.XmlDocument": "4.0.1-rc3-24117-00",
+ "System.Xml.XmlSerializer": "4.0.11-rc3-24117-00"
+ },
+ "frameworks": {
+ "dnxcore50": {}
+ },
+ "runtimes": {
+ "win7-x86": {},
+ "win7-x64": {},
+ "ubuntu.14.04-x64": {},
+ "osx.10.10-x64": {},
+ "centos.7-x64": {},
+ "rhel.7-x64": {},
+ "debian.8-x64": {}
+ }
+}
diff --git a/tests/testsFailingOutsideWindows.txt b/tests/testsFailingOutsideWindows.txt
index 0d7f09d5e7..b301a8b61f 100644
--- a/tests/testsFailingOutsideWindows.txt
+++ b/tests/testsFailingOutsideWindows.txt
@@ -70,6 +70,4 @@ GC/Features/BackgroundGC/foregroundgc/foregroundgc.sh
GC/Features/LOHFragmentation/lohfragmentation/lohfragmentation.sh
GC/Features/SustainedLowLatency/scenario/scenario.sh
GC/Regressions/dev10bugs/536168/536168/536168.sh
-GC/Stress/Framework/ReliabilityFramework/ReliabilityFramework.sh
-GC/API/GC/GetGenerationWR/GetGenerationWR.sh
-GC/API/GC/GetGenerationWR2/GetGenerationWR2.sh \ No newline at end of file
+GC/Stress/Framework/ReliabilityFramework/ReliabilityFramework.sh \ No newline at end of file
diff --git a/tests/testsRunningInsideARM.txt b/tests/testsRunningInsideARM.txt
new file mode 100644
index 0000000000..de33d2e86b
--- /dev/null
+++ b/tests/testsRunningInsideARM.txt
@@ -0,0 +1,22 @@
+JIT/Directed/coverage/importer/ldelemnullarr2/
+JIT/Methodical/Coverage/b39946/
+JIT/Regression/CLR-x86-JIT/V1-M09.5-PDC/b26863/b26863/
+JIT/Regression/CLR-x86-JIT/V1-M09.5-PDC/b28037/b28037/
+JIT/Regression/CLR-x86-JIT/V1-M09.5-PDC/b29068/b29068/
+JIT/Regression/CLR-x86-JIT/V1-M09.5-PDC/b32560/b32560/
+JIT/Regression/CLR-x86-JIT/V1-M11-Beta1/b31878/b31878/
+JIT/Regression/CLR-x86-JIT/V1-M11-Beta1/b36332/b36332/
+JIT/Regression/CLR-x86-JIT/V1-M11-Beta1/b37131/b37131/
+JIT/Regression/CLR-x86-JIT/V1-M11-Beta1/b37608/b37608/
+JIT/Regression/CLR-x86-JIT/V1-M11-Beta1/b39217/b39217/
+JIT/Regression/CLR-x86-JIT/V1-M11-Beta1/b39946/b39946/
+JIT/Regression/CLR-x86-JIT/V1-M11-Beta1/b41488/b41488/
+JIT/Regression/CLR-x86-JIT/V1-M12-Beta2/b47975/b47975/
+JIT/Regression/CLR-x86-JIT/V1-M12-Beta2/b49809/b49809/
+JIT/Regression/CLR-x86-JIT/V1-M12-Beta2/b80045/b80045/
+JIT/Regression/CLR-x86-JIT/V2.0-Beta2/b091942/b091942/
+JIT/Regression/VS-ia64-JIT/V1.2-M01/b12263/b12263/
+JIT/Regression/VS-ia64-JIT/V1.2-M02/b26496/b26496/
+JIT/Regression/VS-ia64-JIT/V2.0-RTM/b539509/b539509/
+JIT/SIMD/VectorReturn_ro/
+Loader/classloader/methodoverriding/regressions/549411/exploit/
diff --git a/tests/testsUnsupportedOutsideWindows.txt b/tests/testsUnsupportedOutsideWindows.txt
index 6bd83f08f2..4f68d7136f 100644
--- a/tests/testsUnsupportedOutsideWindows.txt
+++ b/tests/testsUnsupportedOutsideWindows.txt
@@ -355,3 +355,4 @@ JIT/Regression/VS-ia64-JIT/V2.0-Beta2/b410474/b410474/b410474.sh
JIT/Regression/VS-ia64-JIT/V2.0-RTM/b286991/b286991/b286991.sh
managed/Compilation/Compilation/Compilation.sh
Regressions/coreclr/0584/Test584/Test584.sh
+Interop/SizeConst/SizeConstTest/SizeConstTest.sh
diff --git a/tests/x86_jit32_issues.targets b/tests/x86_jit32_issues.targets
index 03a859de9d..097d8034ba 100644
--- a/tests/x86_jit32_issues.targets
+++ b/tests/x86_jit32_issues.targets
@@ -276,16 +276,6 @@
</ExcludeList>
</ItemGroup>
- <!-- GC.GetGeneration on weak references -->
- <ItemGroup>
- <ExcludeList Include="$(XunitTestBinBase)\GC\API\GC\GetGenerationWR\GetGenerationWR.cmd">
- <Issue>5514</Issue>
- </ExcludeList>
- <ExcludeList Include="$(XunitTestBinBase)\GC\API\GC\GetGenerationWR2\GetGenerationWR2.cmd">
- <Issue>5514</Issue>
- </ExcludeList>
- </ItemGroup>
-
<!-- Tests that need to be triaged for vararg usage as that is not supported -->
<ItemGroup Condition="'$(XunitTestBinBase)' != ''">
<ExcludeList Include="$(XunitTestBinBase)\JIT\Directed\PREFIX\unaligned\1\arglist\arglist.cmd">
diff --git a/tests/x86_legacy_backend_issues.targets b/tests/x86_legacy_backend_issues.targets
index 22b0638690..46cae374eb 100644
--- a/tests/x86_legacy_backend_issues.targets
+++ b/tests/x86_legacy_backend_issues.targets
@@ -370,14 +370,6 @@
<ExcludeList Include="$(XunitTestBinBase)\baseservices\threading\waithandle\waitall\waitallex8a\*">
<Issue>3832</Issue>
</ExcludeList>
-
- <!-- GC.GetGeneration on weak references -->
- <ExcludeList Include="$(XunitTestBinBase)\GC\API\GC\GetGenerationWR\GetGenerationWR.cmd">
- <Issue>5514</Issue>
- </ExcludeList>
- <ExcludeList Include="$(XunitTestBinBase)\GC\API\GC\GetGenerationWR2\GetGenerationWR2.cmd">
- <Issue>5514</Issue>
- </ExcludeList>
</ItemGroup>
<!-- Tests that need to be triaged for vararg usage as that is not supported -->